fix(ui): prevent blank table hover overlays - #196
Conversation
a7c9765 to
664836a
Compare
There was a problem hiding this comment.
Pull request overview
This PR eliminates blank hover overlay artifacts in the Endpoints and Inference Graph tables by removing link-popover configuration from name columns and suppressing pointer-event capture on the shared date-time popover trigger for the Endpoints “Created at” cell, with added unit and Cypress regression coverage.
Changes:
- Remove
popoverFieldfrom Endpoint and Inference Graph name link descriptors to prevent empty hover overlays. - Add a narrowly scoped global CSS rule to disable pointer events on the Endpoints “Created at”
lib-date-time > .truncatetrigger. - Add/extend Jest and Cypress tests to prevent recurrence and verify navigation, sorting/filtering, and repeated-hover behavior.
Reviewed changes
Copilot reviewed 8 out of 8 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| frontend/src/styles.scss | Adds scoped CSS workaround disabling pointer events on the broken date-time popover trigger. |
| frontend/src/app/pages/inference-graph/config.ts | Removes popoverField from the Inference Graph name link column. |
| frontend/src/app/pages/index/config.ts | Removes popoverField from the Endpoints name link column (preserves DateTimeValue for Created at). |
| frontend/src/app/pages/inference-graph/inference-graph.component.spec.ts | Adds unit assertions to ensure name links do not configure hover overlays. |
| frontend/src/app/pages/index/index.component.spec.ts | Adds unit assertions for no-hover-overlay name links and preserves shared date-time semantics. |
| frontend/cypress/e2e/inference-graph.cy.ts | Adds Cypress coverage for repeated hover cycles and name-link navigation. |
| frontend/cypress/e2e/index-page.cy.ts | Adds Cypress coverage for repeated hover cycles and correct pointer target selection via elementFromPoint. |
| frontend/mocks/kubeflow.ts | Updates the Jest kubeflow mock to include tooltipField and adjust popoverField handling for tests. |
| expect(nameColumn?.value.linkType).toBe(LinkType.Internal); | ||
| expect(nameColumn?.value.tooltipField).toBe(''); | ||
| expect(nameColumn?.value.popoverField).toBe(''); |
There was a problem hiding this comment.
The pinned LinkValue contract defaults both fields to empty strings, so this exact assertion intentionally verifies production behavior.
| expect(nameColumn?.value.linkType).toBe(LinkType.Internal); | ||
| expect(nameColumn?.value.tooltipField).toBe(''); | ||
| expect(nameColumn?.value.popoverField).toBe(''); |
There was a problem hiding this comment.
The pinned LinkValue contract guarantees empty strings here, so the strict assertion detects drift from the production object.
| export class LinkValue { | ||
| field: string; | ||
| popoverField?: string; | ||
| popoverField: string; | ||
| tooltipField: string; | ||
| truncate?: boolean; |
There was a problem hiding this comment.
The mock intentionally mirrors the pinned LinkValue string properties and empty-string defaults used by its length checks.
| cy.get(creationTimestampSelector).then(creationTimestampElements => { | ||
| const creationTimestampElement = creationTimestampElements[0]; | ||
| const boundingRectangle = | ||
| creationTimestampElement.getBoundingClientRect(); |
There was a problem hiding this comment.
Cypress cy.get already retries and fails clearly when the selector matches nothing, so this callback cannot receive an empty collection.
|
waiting for kubeflow/notebooks#1255 to get merged /hold |
Signed-off-by: danish9039 <danishsiddiqui040@gmail.com> Assisted-by: OpenAI Codex (GPT-5)
Signed-off-by: danish9039 <danishsiddiqui040@gmail.com> Assisted-by: OpenAI Codex (GPT-5)
Signed-off-by: danish9039 <danishsiddiqui040@gmail.com> Assisted-by: OpenAI Codex (GPT-5)
791b44c to
fd0fe62
Compare
Problem
The endpoint tables exposed two related blank-overlay defects:
Both defects made the table appear unstable and obscured nearby content. The Endpoint name also needed to remain clickable after repeated hovers so that the details page could open without a manual refresh.
Root Causes
Name links
The Endpoint and Inference Graph name columns configured the shared
LinkValuewithpopoverField: 'metadata.name'. That setting activated the sharedlibPopoverdirective for text that was already visible as the link label.In the affected production image, each hover attached an empty popover component instead of useful content. A Material tooltip experiment also rendered an empty message in the production image, so replacing one overlay mechanism with another did not solve the underlying behavior.
Creation time
The Endpoint
Created atcolumn uses the sharedDateTimeValue, which is important because it provides relative-time rendering, sorting, date filtering, empty-date filtering, and date-specific filter help.The pinned shared
lib-date-timecomponent always attaches its popover trigger and provides no supported input for disabling it. In the affected production image, the Local and UTC popover content was empty, but the trigger still created a visible blank card.Replacing
DateTimeValuelocally would duplicate shared behavior and risk changing sorting and filtering semantics. Updating the shared library would affect multiple Kubeflow interfaces and is outside the narrow ownership of this correction.Changes
popoverFieldfrom the Endpoint name-link descriptor.LinkType.Internal, link text, truncation, and destination construction.app-index .mat-column-age lib-date-time > .truncate.DateTimeValuedescriptor and itsmetadata.creationTimestampfield unchanged.document.elementFromPointso the test follows browser pointer hit testing instead of dispatching an event to the wrong parent element.lib-popover,.popover-card, or.mat-tooltipelement.Why This Scope Is Appropriate
The stylesheet selector is restricted to
app-index, the Endpoint table'sagecolumn, and the inner trigger oflib-date-time. It does not affect event tables or other consumers of the shared date component.Only hover-event capture on the broken, empty trigger is disabled. Header sorting, table filtering, relative-time updates, empty timestamps, and normal row content remain handled by the existing shared component.
The production behavior change is five stylesheet lines. The additional TypeScript changes are tests that preserve the existing behavior while preventing recurrence.
User Impact
Repeated hovering over Endpoint names, Inference Graph names, or Endpoint creation times no longer creates blank blocks. Endpoint names remain normal internal links and open the details page without a manual refresh.
No useful hover information is removed because the affected production image rendered empty overlay content.
Review Follow-up
Claude Code correctly found that the original creation-time test dispatched
mouseentertolib-date-time, while the shared[libPopover]directive is attached to the inner.truncateelement. Because nativemouseenterdoes not bubble, the original no-overlay assertion could pass without exercising the broken directive.The revised test computes the center of the creation-time element and calls
document.elementFromPointto obtain the element that a physical pointer can reach. When the stylesheet rule is removed, the pointer reaches.truncate, creates the empty shared popover, and the test fails. With the rule restored, the pointer reaches the non-triggering parent and the test passes.The shared defect is tracked at kubeflow/notebooks#1252.
Verification
Source and automated checks
git diff --checknpm run format:checknpm run lint-checknpm test -- --runInBand: 29 suites and 144 tests passednpm run build: production build completednpm run e2e:cypress:ci: 8 specifications and 63 tests passed.truncatepointer target and fails because a blanklib-popoverremains in the documentFresh production image and live KinD check
local/models-web-app:hover-overlay-fix-v2pointer-events: none/_/kserve-endpoints/details/kubeflow-user/sklearn-iris?ns=kubeflow-user/kserve-endpoints/details/kubeflow-user/sklearn-iris?ns=kubeflow-userAssisted-by: OpenAI Codex (GPT-5)