Skip to content

Conversation

emilys314
Copy link
Contributor

@emilys314 emilys314 commented Aug 7, 2025

Towards https://issues.redhat.com/browse/RHOAIENG-31943

Description

This should fix all tests except the start stop

How Has This Been Tested?

Enable the flag and run the servingRuntimeList.cy.ts cypress mock test

Test Impact

Request review criteria:

Self checklist (all need to be checked):

  • The developer has manually tested the changes and verified that the changes work
  • Testing instructions have been added in the PR body (for PRs involving changes that are not immediately obvious).
  • The developer has added tests or explained why testing cannot be added (unit or cypress tests for related changes)
  • The code follows our Best Practices (React coding standards, PatternFly usage, performance considerations)

If you have UI changes:

  • Included any necessary screenshots or gifs if it was a UI change.
  • Included tags to the UX team if it was a UI/UX change.

After the PR is posted & before it merges:

  • The developer has tested their solution on a cluster by using the image produced by the PR to main

Summary by CodeRabbit

  • New Features

    • None.
  • Bug Fixes

    • Deploy button no longer stays disabled while templates are still loading.
    • Projects without a model-serving platform now correctly show as loaded (no spinner).
    • More reliable error messages when fetching or removing components.
    • “Project-scoped” label now appears only when the feature is available.
    • Deployments table initializes with the correct default sort.
  • Style

    • Updated label from “Replicas” to “Model server replicas”.
  • Refactor

    • Unified loading state for platform selection for clearer, more precise UI indicators.
  • Tests

    • Cypress tests updated for Model Mesh–first scenarios and improved mocks.

@openshift-ci openshift-ci bot added the do-not-merge/work-in-progress This PR is in WIP state label Aug 7, 2025
Copy link
Contributor

openshift-ci bot commented Aug 7, 2025

Skipping CI for Draft Pull Request.
If you want CI signal for your change, please convert it to an actual PR.
You can still manually trigger a test run with /test all

Copy link
Contributor

coderabbitai bot commented Aug 7, 2025

Walkthrough

Updates refine loading and state handling across model-serving UI: introduce a unified loadingState in platform selection/reset flows, adjust template-loading logic in DeployButton, add EmptyProjectWatcher to mark projects without watchers as loaded, tweak deployments table/row presentation, gate scoped labels by area availability, harden service error handling, and revise Cypress tests to Model Mesh-first.

Changes

Cohort / File(s) Summary
Template loading gating
frontend/packages/modelServing/src/components/deploy/DeployButton.tsx, frontend/packages/modelServing/src/concepts/servingRuntimeTemplates/useServingRuntimeTemplates.ts
useServingRuntimeTemplates now returns [templates, templatesLoaded]; DeployButton disables only when templates are empty and loaded.
Deployments table UI tweaks
frontend/packages/modelServing/src/components/deployments/DeploymentsTable.tsx, frontend/packages/modelServing/src/components/deployments/DeploymentsTableRow.tsx, frontend/packages/modelServing/src/components/deployments/DeploymentsTableRowExpandedSection.tsx
Default sort column wired; ActionsColumn replaced with internal ResourceActionsColumn passing resource; added data-testid on expand cell; label text changed to “Model server replicas”.
Per-project deployments loading
frontend/packages/modelServing/src/concepts/ModelDeploymentsContext.tsx
Adds EmptyProjectWatcher to set empty/loaded for projects without watchers; pre-initializes per-project state; maintains watcher behavior and unload on cleanup.
Area-gated scoped label
frontend/src/pages/modelServing/screens/global/InferenceServiceServingRuntime.tsx, frontend/src/pages/modelServing/screens/global/InferenceServiceTableRow.tsx
Scoped label visibility now depends on useIsAreaAvailable; component prop isProjectScoped removed and call sites updated.
Service error handling hardening
frontend/src/services/componentsServices.ts
Optional chaining and fallbacks in errors: use e.response?.data?.message/error
Platform loading refactor
frontend/packages/modelServing/src/concepts/useProjectServingPlatform.ts, .../components/overview/ModelPlatformSection.tsx, .../components/projectDetails/ModelsProjectDetailsView.tsx, .../components/projectDetails/SelectPlatformView.tsx
Introduces LoadingState { type: 'platform'
Cypress tests Model Mesh-first
frontend/src/__tests__/cypress/cypress/tests/mocked/modelServing/runtime/servingRuntimeList.cy.ts, frontend/src/__tests__/cypress/cypress/tests/mocked/projects/projectDetails.cy.ts
Add ODH/NIM mocks; per-namespace intercepts; remove a UI test block; switch expectations to Model Mesh-first; add waits/refreshes; alias templates and ensure template load in project details tests.

Sequence Diagram(s)

sequenceDiagram
  participant UI as UI
  participant Hook as useProjectServingPlatform
  participant API as Backend

  UI->>Hook: selectPlatform(platform)
  Hook->>Hook: loadingState = { type: 'platform', platform }
  Hook->>API: apply platform
  API-->>Hook: success or error
  alt success
    Hook->>Hook: loadingState = { type: null }
    Hook-->>UI: updated projectPlatform
  else error
    Hook->>Hook: loadingState = { type: null }
    Hook-->>UI: error
  end

  UI->>Hook: resetPlatform()
  Hook->>Hook: loadingState = { type: 'reset' }
  Hook->>API: reset platform
  API-->>Hook: success or error
  Hook->>Hook: loadingState = { type: null }
  Hook-->>UI: updated state/error
Loading
sequenceDiagram
  participant Ctx as ModelDeploymentsContext
  participant Proj as Project
  participant Watch as ProjectDeploymentWatcher

  Ctx->>Proj: check platform/watcher
  alt watcher exists
    Ctx->>Watch: mount watcher(project)
    Watch-->>Ctx: onStateChange({ deployments, loaded:true, error? })
    Ctx->>Ctx: store per-project state
    Watch-->>Ctx: cleanup -> unload project
  else no watcher/platform
    Ctx->>Ctx: mount EmptyProjectWatcher
    Ctx->>Ctx: onStateChange({ deployments:[], loaded:true })
    Ctx-->>Ctx: on unmount -> unload project
  end
Loading
sequenceDiagram
  participant UI as DeployButton
  participant Hook as useServingRuntimeTemplates

  UI->>Hook: [templates, loaded] = useServingRuntimeTemplates()
  UI->>UI: isMissingTemplates = templates.length===0 && loaded
  UI-->>UI: Disable only when isMissingTemplates true
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

A twitch of ears, a platform set,
LoadingState hops—no fuss, no sweat.
Empty burrows marked as clear,
Templates loaded, button near.
Mesh or KServe, paths align—
With gentled errors, all is fine.
Thump-thump: shipped on rabbit time. 🐇🚀


📜 Recent review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 31dff4d and c7de79b.

📒 Files selected for processing (10)
  • frontend/packages/modelServing/src/components/deployments/DeploymentsTable.tsx (1 hunks)
  • frontend/packages/modelServing/src/components/deployments/DeploymentsTableRow.tsx (3 hunks)
  • frontend/packages/modelServing/src/components/deployments/DeploymentsTableRowExpandedSection.tsx (1 hunks)
  • frontend/packages/modelServing/src/components/overview/ModelPlatformSection.tsx (3 hunks)
  • frontend/packages/modelServing/src/components/projectDetails/ModelsProjectDetailsView.tsx (3 hunks)
  • frontend/packages/modelServing/src/components/projectDetails/SelectPlatformView.tsx (2 hunks)
  • frontend/packages/modelServing/src/concepts/ModelDeploymentsContext.tsx (3 hunks)
  • frontend/packages/modelServing/src/concepts/useProjectServingPlatform.ts (6 hunks)
  • frontend/src/__tests__/cypress/cypress/tests/mocked/modelServing/runtime/servingRuntimeList.cy.ts (30 hunks)
  • frontend/src/__tests__/cypress/cypress/tests/mocked/projects/projectDetails.cy.ts (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (10)
  • frontend/packages/modelServing/src/components/deployments/DeploymentsTableRowExpandedSection.tsx
  • frontend/packages/modelServing/src/components/deployments/DeploymentsTable.tsx
  • frontend/packages/modelServing/src/concepts/ModelDeploymentsContext.tsx
  • frontend/packages/modelServing/src/components/projectDetails/ModelsProjectDetailsView.tsx
  • frontend/packages/modelServing/src/components/deployments/DeploymentsTableRow.tsx
  • frontend/packages/modelServing/src/components/projectDetails/SelectPlatformView.tsx
  • frontend/packages/modelServing/src/components/overview/ModelPlatformSection.tsx
  • frontend/src/tests/cypress/cypress/tests/mocked/modelServing/runtime/servingRuntimeList.cy.ts
  • frontend/src/tests/cypress/cypress/tests/mocked/projects/projectDetails.cy.ts
  • frontend/packages/modelServing/src/concepts/useProjectServingPlatform.ts
✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR/Issue comments)

Type @coderabbitai help to get the list of available commands.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@emilys314 emilys314 force-pushed the serving-runtime-list-fixes branch from 3644967 to 994a8e8 Compare August 7, 2025 19:55
@emilys314 emilys314 force-pushed the serving-runtime-list-fixes branch from 994a8e8 to 7f59dda Compare August 11, 2025 15:42
@emilys314 emilys314 marked this pull request as ready for review August 12, 2025 16:08
@openshift-ci openshift-ci bot removed the do-not-merge/work-in-progress This PR is in WIP state label Aug 12, 2025
@emilys314
Copy link
Contributor Author

/hold

@openshift-ci openshift-ci bot added the do-not-merge/hold This PR is hold for some reason label Aug 12, 2025
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🔭 Outside diff range comments (2)
frontend/packages/modelServing/src/concepts/ModelDeploymentsContext.tsx (1)

123-125: allLoaded can turn true prematurely when projects change; compute against current projects

allLoaded uses Object.values(projectDeployments).every(...). If a project is added to props but hasn’t reported state yet, it won’t be in projectDeployments and the check can incorrectly pass. Compute allLoaded against the projects prop to ensure correctness.

Apply this diff:

-    const allLoaded =
-      deploymentWatchersLoaded && Object.values(projectDeployments).every((state) => state.loaded);
+    const allLoaded =
+      deploymentWatchersLoaded &&
+      projects.every((p) => projectDeployments[p.metadata.name]?.loaded === true);

Optionally, also reconcile state on project list changes to keep entries in sync:

// place below useState
React.useEffect(() => {
  setProjectDeployments((prev) => {
    const next = { ...prev };
    // ensure all current projects have an entry
    for (const p of projects) {
      const name = p.metadata.name;
      if (!(name in next)) next[name] = { loaded: false };
    }
    // remove entries for projects no longer present
    for (const name of Object.keys(next)) {
      if (!projects.some((p) => p.metadata.name === name)) {
        delete next[name];
      }
    }
    return next;
  });
}, [projects]);
frontend/src/__tests__/cypress/cypress/tests/mocked/modelServing/runtime/servingRuntimeList.cy.ts (1)

727-735: Typo in statusPredictor field: use restUrl (not restUtl)

The mock uses restUtl; UI code expects restUrl. This will hide the REST endpoint in the popover and fail assertions.

Apply this diff:

-            statusPredictor: {
-              grpcUrl: 'grpc://modelmesh-serving.app:8033',
-              restUtl: 'http:///modelmesh-serving.app:8000',
-            },
+            statusPredictor: {
+              grpcUrl: 'grpc://modelmesh-serving.app:8033',
+              restUrl: 'http:///modelmesh-serving.app:8000',
+            },

And similarly below:

-            statusPredictor: {
-              grpcUrl: 'grpc://modelmesh-serving.app:8033',
-              restUtl: 'http:///modelmesh-serving.app:8000',
-            },
+            statusPredictor: {
+              grpcUrl: 'grpc://modelmesh-serving.app:8033',
+              restUrl: 'http:///modelmesh-serving.app:8000',
+            },

Also applies to: 807-815

🧹 Nitpick comments (7)
frontend/packages/modelServing/src/components/deployments/DeploymentsTableRow.tsx (1)

90-96: Make data-testid unique per row to avoid ambiguous selectors

Using only the platformId will duplicate data-testids across rows (e.g., multiple rows under “kserve”). Consider including the model name to ensure uniqueness.

-          <Td
-            data-testid={`${deployment.modelServingPlatformId}-model-row-item`}
+          <Td
+            data-testid={`${deployment.modelServingPlatformId}-${deployment.model.metadata.name}-model-row-item`}
             expand={{
               rowIndex,
               expandId: `${deployment.modelServingPlatformId}-model-row-item`,
               isExpanded,
               onToggle: () => setExpanded(!isExpanded),
             }}
           />

Note: expandId can remain as-is; rowIndex differentiates expansion wiring.

frontend/src/__tests__/cypress/cypress/tests/mocked/projects/projectDetails.cy.ts (1)

141-141: Use a more explicit alias name to reduce ambiguity

“templates” is generic and may be reused elsewhere. Prefer a specific alias name for clarity and to prevent future collisions.

-  ).as('templates');
+  ).as('servingRuntimeTemplates');

And update the wait accordingly:

-  cy.wait('@templates');
+  cy.wait('@servingRuntimeTemplates');

Also applies to: 483-483

frontend/src/services/componentsServices.ts (1)

15-16: Safer error extraction is good; consider preserving the original error as cause and adding status context

Optional chaining with a fallback to e.message prevents undefined-access crashes. To aid debugging, preserve the original error as the cause and add HTTP status text when available.

-      throw new Error(e.response?.data?.message || e.message);
+      const status = (e as any)?.response?.status;
+      const statusText = (e as any)?.response?.statusText;
+      const serverMsg = (e as any)?.response?.data?.message;
+      const fallback = (e as any)?.message ?? 'Request failed';
+      const msg = serverMsg ?? (status ? `${status} ${statusText || ''}`.trim() : fallback);
+      // Preserve original error for debugging
+      throw new Error(msg, { cause: e as Error });
-      throw new Error(e.response?.data?.error || e.message);
+      const status = (e as any)?.response?.status;
+      const statusText = (e as any)?.response?.statusText;
+      const serverErr = (e as any)?.response?.data?.error;
+      const fallback = (e as any)?.message ?? 'Request failed';
+      const msg = serverErr ?? (status ? `${status} ${statusText || ''}`.trim() : fallback);
+      throw new Error(msg, { cause: e as Error });

If the project targets environments without Error.cause support, we can gate that with a small helper; happy to provide one.

Also applies to: 30-31

frontend/packages/modelServing/src/components/deploy/DeployButton.tsx (1)

15-21: Avoid duplicate watches of serving runtime templates by lifting state and passing into the modal.

Both DeployButton and DeployButtonModal call useServingRuntimeTemplates() which results in two watchers and redundant work. Lift the templates to the parent and pass them as a prop to the modal to reduce API load and re-renders.

Apply this diff within this file:

@@
-const DeployButtonModal: React.FC<{
-  platform?: ServingRuntimePlatform;
-  currentProject: ProjectKind;
-  onClose: (submit: boolean) => void;
-}> = ({ platform, currentProject, onClose }) => {
-  const [templates] = useServingRuntimeTemplates();
-  const connections = useConnections(currentProject.metadata.name);
+const DeployButtonModal: React.FC<{
+  platform?: ServingRuntimePlatform;
+  currentProject: ProjectKind;
+  onClose: (submit: boolean) => void;
+  templates: ReturnType<typeof useServingRuntimeTemplates>[0];
+}> = ({ platform, currentProject, onClose, templates }) => {
+  const connections = useConnections(currentProject.metadata.name);
@@
-  const [globalTemplates, globalTemplatesLoaded] = useServingRuntimeTemplates();
+  const [globalTemplates, globalTemplatesLoaded] = useServingRuntimeTemplates();
   const isMissingTemplates = globalTemplates.length === 0 && globalTemplatesLoaded;
@@
         <DeployButtonModal
           platform={legacyServingRuntimePlatform}
           currentProject={project}
+          templates={globalTemplates}
           onClose={onSubmit}
         />

Note: Using ReturnType<typeof useServingRuntimeTemplates>[0] avoids introducing a new import for the template type while keeping type safety.

Also applies to: 76-79, 112-116

frontend/src/pages/modelServing/screens/global/InferenceServiceServingRuntime.tsx (1)

25-27: Good shift from prop-driven gating to area-availability gating.

Using useIsAreaAvailable(SupportedArea.DS_PROJECT_SCOPED).status removes the need for the isProjectScoped prop and centralizes feature gating logic.

Optional micro-cleanup for readability/perf (avoid repeating getServingRuntimeVersion):

// near the top of the component body
const srvVersion = servingRuntime ? getServingRuntimeVersion(servingRuntime) : undefined;

// later in JSX
{srvVersion && <ServingRuntimeVersionLabel version={srvVersion} isCompact />}
{versionStatus && (
  <ServingRuntimeVersionStatus
    isOutdated={versionStatus === ServingRuntimeVersionStatusLabel.OUTDATED}
    version={srvVersion || ''}
    templateVersion={getServingRuntimeVersion(template) || ''}
  />
)}

Also applies to: 63-69

frontend/packages/modelServing/src/concepts/ModelDeploymentsContext.tsx (1)

90-90: Avoid rebuilding the initial state on every render; use a lazy initializer

Object.fromEntries(projects.map(...)) is computed on every render but only used on the first. Switch to a lazy initializer to prevent unnecessary work.

Apply this diff:

-  }>(Object.fromEntries(projects.map((p) => [p.metadata.name, { loaded: false }])));
+  }>(() =>
+    Object.fromEntries(projects.map((p) => [p.metadata.name, { loaded: false }]))
+  );
frontend/src/__tests__/cypress/cypress/tests/mocked/modelServing/runtime/servingRuntimeList.cy.ts (1)

175-186: ODH/NIM intercepts: drop the null parameter for clarity

The interceptOdh overload doesn’t require an explicit null options argument. Prefer the 2-arg form for readability and consistency with other calls in this file.

Apply this diff:

-  cy.interceptOdh('GET /api/components', null, [mockOdhApplication({})]);
+  cy.interceptOdh('GET /api/components', [mockOdhApplication({})]);
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 830b072 and a8d747a.

📒 Files selected for processing (14)
  • frontend/packages/modelServing/extensions/odh.ts (3 hunks)
  • frontend/packages/modelServing/src/components/deploy/DeployButton.tsx (1 hunks)
  • frontend/packages/modelServing/src/components/deployments/DeploymentsTable.tsx (1 hunks)
  • frontend/packages/modelServing/src/components/deployments/DeploymentsTableRow.tsx (3 hunks)
  • frontend/packages/modelServing/src/components/deployments/DeploymentsTableRowExpandedSection.tsx (1 hunks)
  • frontend/packages/modelServing/src/components/projectDetails/ProjectDeploymentsTable.tsx (1 hunks)
  • frontend/packages/modelServing/src/concepts/ModelDeploymentsContext.tsx (3 hunks)
  • frontend/src/__tests__/cypress/cypress/tests/mocked/modelServing/runtime/servingRuntimeList.cy.ts (20 hunks)
  • frontend/src/__tests__/cypress/cypress/tests/mocked/projects/projectDetails.cy.ts (2 hunks)
  • frontend/src/pages/modelServing/screens/global/InferenceServiceServingRuntime.tsx (2 hunks)
  • frontend/src/pages/modelServing/screens/global/InferenceServiceTableRow.tsx (1 hunks)
  • frontend/src/plugins/extensions/navigation.ts (1 hunks)
  • frontend/src/plugins/extensions/routes.ts (1 hunks)
  • frontend/src/services/componentsServices.ts (2 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
frontend/src/__tests__/cypress/cypress/**/*.{ts,tsx}

📄 CodeRabbit Inference Engine (.cursor/rules/cypress-e2e.mdc)

frontend/src/__tests__/cypress/cypress/**/*.{ts,tsx}: Don't create TypeScript interfaces for test data; use direct object access patterns.
All linting errors must be fixed: use object destructuring, proper formatting, no unused variables/imports, no any types unless necessary.
Never hardcode namespaces in tests or utilities; always derive namespaces from test variables or environment variables.

Files:

  • frontend/src/__tests__/cypress/cypress/tests/mocked/projects/projectDetails.cy.ts
  • frontend/src/__tests__/cypress/cypress/tests/mocked/modelServing/runtime/servingRuntimeList.cy.ts
🧠 Learnings (7)
📚 Learning: 2025-07-21T11:49:57.416Z
Learnt from: CR
PR: opendatahub-io/odh-dashboard#0
File: .cursor/rules/cypress-e2e.mdc:0-0
Timestamp: 2025-07-21T11:49:57.416Z
Learning: Applies to frontend/src/__tests__/cypress/cypress/**/*.{ts,tsx} : Don't create TypeScript interfaces for test data; use direct object access patterns.

Applied to files:

  • frontend/src/__tests__/cypress/cypress/tests/mocked/projects/projectDetails.cy.ts
📚 Learning: 2025-07-21T11:49:57.416Z
Learnt from: CR
PR: opendatahub-io/odh-dashboard#0
File: .cursor/rules/cypress-e2e.mdc:0-0
Timestamp: 2025-07-21T11:49:57.416Z
Learning: Applies to frontend/src/__tests__/cypress/cypress/**/*.{ts,tsx} : Never hardcode namespaces in tests or utilities; always derive namespaces from test variables or environment variables.

Applied to files:

  • frontend/src/__tests__/cypress/cypress/tests/mocked/projects/projectDetails.cy.ts
📚 Learning: 2025-07-21T11:49:57.416Z
Learnt from: CR
PR: opendatahub-io/odh-dashboard#0
File: .cursor/rules/cypress-e2e.mdc:0-0
Timestamp: 2025-07-21T11:49:57.416Z
Learning: Applies to frontend/src/__tests__/cypress/cypress/tests/e2e/**/*.cy.ts : Delete test projects, PVCs, and other resources after tests using after() hooks.

Applied to files:

  • frontend/src/__tests__/cypress/cypress/tests/mocked/projects/projectDetails.cy.ts
📚 Learning: 2025-07-21T11:49:57.416Z
Learnt from: CR
PR: opendatahub-io/odh-dashboard#0
File: .cursor/rules/cypress-e2e.mdc:0-0
Timestamp: 2025-07-21T11:49:57.416Z
Learning: Applies to frontend/src/__tests__/cypress/cypress/tests/e2e/**/*.cy.ts : Use .navigate() methods in page objects for navigation instead of cy.visit() in tests.

Applied to files:

  • frontend/src/__tests__/cypress/cypress/tests/mocked/projects/projectDetails.cy.ts
📚 Learning: 2025-07-21T11:49:57.416Z
Learnt from: CR
PR: opendatahub-io/odh-dashboard#0
File: .cursor/rules/cypress-e2e.mdc:0-0
Timestamp: 2025-07-21T11:49:57.416Z
Learning: Applies to frontend/src/__tests__/cypress/cypress/tests/e2e/**/*.cy.ts : Use cy.step('Description') instead of cy.log() for step documentation in tests.

Applied to files:

  • frontend/src/__tests__/cypress/cypress/tests/mocked/projects/projectDetails.cy.ts
📚 Learning: 2025-07-21T11:49:57.416Z
Learnt from: CR
PR: opendatahub-io/odh-dashboard#0
File: .cursor/rules/cypress-e2e.mdc:0-0
Timestamp: 2025-07-21T11:49:57.416Z
Learning: Applies to frontend/src/__tests__/cypress/cypress/tests/e2e/**/*.cy.ts : Use descriptive file names matching feature area, e.g., testFeatureName.cy.ts for main functionality.

Applied to files:

  • frontend/src/__tests__/cypress/cypress/tests/mocked/projects/projectDetails.cy.ts
📚 Learning: 2025-06-19T20:38:32.485Z
Learnt from: christianvogt
PR: opendatahub-io/odh-dashboard#4381
File: frontend/src/__tests__/cypress/tsconfig.json:9-9
Timestamp: 2025-06-19T20:38:32.485Z
Learning: In the ODH Dashboard project, the `frontend/src/__tests__/cypress/tsconfig.json` file intentionally has an empty `files` array to disable type checking for Cypress test files. This is part of the monorepo structure where Cypress was separated into its own package but type checking is deliberately disabled for it.

Applied to files:

  • frontend/src/__tests__/cypress/cypress/tests/mocked/projects/projectDetails.cy.ts
🧬 Code Graph Analysis (6)
frontend/src/__tests__/cypress/cypress/tests/mocked/projects/projectDetails.cy.ts (1)
frontend/src/__tests__/cypress/cypress/pages/projects.ts (1)
  • projectDetails (420-420)
frontend/src/pages/modelServing/screens/global/InferenceServiceServingRuntime.tsx (2)
frontend/src/k8sTypes.ts (1)
  • ServingRuntimeKind (464-485)
frontend/src/concepts/areas/index.ts (1)
  • SupportedArea (11-11)
frontend/packages/modelServing/extensions/odh.ts (1)
frontend/src/concepts/areas/index.ts (1)
  • SupportedArea (11-11)
frontend/packages/modelServing/src/concepts/ModelDeploymentsContext.tsx (1)
frontend/packages/modelServing/extension-points/index.ts (1)
  • Deployment (52-62)
frontend/src/__tests__/cypress/cypress/tests/mocked/modelServing/runtime/servingRuntimeList.cy.ts (5)
frontend/src/__mocks__/mockOdhApplication.ts (1)
  • mockOdhApplication (48-112)
frontend/src/api/models/kserve.ts (2)
  • InferenceServiceModel (10-15)
  • ServingRuntimeModel (3-8)
frontend/src/__mocks__/mockK8sResourceList.ts (1)
  • mockK8sResourceList (3-17)
frontend/src/__tests__/cypress/cypress/pages/servingRuntimes.ts (1)
  • servingRuntimes (155-155)
frontend/src/__mocks__/mockInferenceServiceK8sResource.ts (1)
  • mockInferenceServiceK8sResource (85-238)
frontend/packages/modelServing/src/components/deploy/DeployButton.tsx (1)
frontend/packages/modelServing/src/concepts/servingRuntimeTemplates/useServingRuntimeTemplates.ts (1)
  • useServingRuntimeTemplates (46-80)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Cypress-Setup
  • GitHub Check: Lint
🔇 Additional comments (14)
frontend/packages/modelServing/src/components/deployments/DeploymentsTableRowExpandedSection.tsx (1)

84-86: Clearer label text — looks good

Renaming to “Model server replicas” improves clarity without affecting logic.

frontend/packages/modelServing/src/components/deployments/DeploymentsTableRow.tsx (2)

2-5: Switch to ResourceActionsColumn is appropriate

Replacing PatternFly’s ActionsColumn with the internal ResourceActionsColumn (with resource={deployment.model}) aligns actions with RBAC/context and keeps behavior intact.


156-179: Actions column wiring looks correct

Providing resource={deployment.model} plus action items mirrors the previous UX and correctly disables actions while starting/stopping.

frontend/src/__tests__/cypress/cypress/tests/mocked/projects/projectDetails.cy.ts (1)

480-481: Good synchronization addition

Initializing empty model-serving intercepts before navigation reduces flakiness where the UI requests runtime lists early.

frontend/packages/modelServing/src/components/deploy/DeployButton.tsx (1)

76-79: Correctly gates “missing templates” on the loaded flag — avoids false-disable while loading.

The new check globalTemplates.length === 0 && globalTemplatesLoaded prevents disabling the Deploy button during template load. This fixes the premature disablement UX.

frontend/packages/modelServing/extensions/odh.ts (1)

37-38: Migration to enum-based gating (SupportedArea.MODEL_SERVING) looks correct and consistent.

Switching to SupportedArea.MODEL_SERVING in flags aligns with the newer area-availability approach and keeps the plugin’s extensions coherently gated.

Also applies to: 48-49, 54-55, 71-72

frontend/src/plugins/extensions/routes.ts (1)

81-90: /modelServing routes remain registered by the ModelServing extension

  • Verified that frontend/packages/modelServing/extensions/odh.ts defines a catch-all route at
    path: '/modelServing/:namespace?/*' (lines 61–69), ensuring deep links (e.g. /modelServing/<ns>/metrics/<name>) continue to resolve through the plugin.
  • The commented-out host routes in frontend/src/plugins/extensions/navigation.ts and routes.ts can safely be removed without breaking /modelServing/*.
frontend/src/pages/modelServing/screens/global/InferenceServiceTableRow.tsx (1)

110-114: LGTM: Prop cleanup aligns with the updated InferenceServiceServingRuntime API.

Dropping isProjectScoped here matches the component’s new signature and centralizes gating logic.

frontend/packages/modelServing/src/concepts/ModelDeploymentsContext.tsx (2)

55-71: EmptyProjectWatcher: good approach to mark non-platform projects as loaded

Introducing EmptyProjectWatcher avoids “dangling” loaded states and fits the existing onStateChange/unload pattern.


145-153: Rendering EmptyProjectWatcher for non-platform projects is correct and consistent

This ensures per-project loaded state is set deterministically even when no watcher exists.

frontend/packages/modelServing/src/components/deployments/DeploymentsTable.tsx (1)

65-71: defaultSortColumn prop confirmed
The Table component in frontend/src/components/table/Table.tsx declares and destructures a defaultSortColumn prop with a default value of 0—confirming it’s supported and zero-based.

No changes required.

frontend/src/__tests__/cypress/cypress/tests/mocked/modelServing/runtime/servingRuntimeList.cy.ts (3)

102-102: NIM mocks import is appropriate

Importing mockOdhApplication to support expanded error detection flows in plugin code is appropriate.


509-509: Test toggles for platform flags look consistent

Switching to explicitly enable Model Mesh/KServe per scenario aligns with the PR goal and the updated flows.

Also applies to: 609-609, 641-641, 727-727, 803-803, 1280-1280, 1396-1396, 1491-1491, 1689-1689, 1719-1726


200-203: Avoid hardcoding namespaces in tests; derive from env/test vars

Per repository test guidelines, don’t hardcode namespaces. These new namespaced list intercepts embed 'test-project'. Use a derived namespace variable (e.g., Cypress.env) and apply it across intercepts.

Apply this diff:

-  cy.interceptK8sList(
-    { model: InferenceServiceModel, ns: 'test-project' },
-    mockK8sResourceList(inferenceServices),
-  );
+  const ns = Cypress.env('TEST_NAMESPACE') ?? 'test-project';
+  cy.interceptK8sList({ model: InferenceServiceModel, ns }, mockK8sResourceList(inferenceServices));
-  cy.interceptK8sList(
-    { model: ServingRuntimeModel, ns: 'test-project' },
-    mockK8sResourceList(servingRuntimes),
-  );
+  cy.interceptK8sList({ model: ServingRuntimeModel, ns }, mockK8sResourceList(servingRuntimes));

If you want, I can generate a follow-up patch to replace remaining hardcoded 'test-project' usages throughout this file to comply fully with the guideline.

Also applies to: 326-329

⛔ Skipped due to learnings
Learnt from: CR
PR: opendatahub-io/odh-dashboard#0
File: .cursor/rules/cypress-e2e.mdc:0-0
Timestamp: 2025-07-21T11:49:57.416Z
Learning: Applies to frontend/src/__tests__/cypress/cypress/**/*.{ts,tsx} : Never hardcode namespaces in tests or utilities; always derive namespaces from test variables or environment variables.
Learnt from: dpanshug
PR: opendatahub-io/odh-dashboard#4571
File: frontend/src/__tests__/cypress/cypress/tests/mocked/featureStore/featureViews.cy.ts:16-18
Timestamp: 2025-07-29T15:44:19.024Z
Learning: In the ODH Dashboard project, the correct pattern for handling namespaces in Cypress tests is to define them as constants at the top of test files (e.g., `const k8sNamespace = 'default';`), not to use environment variables or other dynamic approaches.
Learnt from: dpanshug
PR: opendatahub-io/odh-dashboard#4571
File: frontend/src/__tests__/cypress/cypress/tests/mocked/featureStore/featureServices.cy.ts:16-18
Timestamp: 2025-07-29T15:43:30.907Z
Learning: In the ODH Dashboard project, `Cypress.env()` is not the correct approach for configuring namespace values in Cypress tests.
Learnt from: dpanshug
PR: opendatahub-io/odh-dashboard#4571
File: frontend/src/__tests__/cypress/cypress/tests/mocked/featureStore/featureViews.cy.ts:16-18
Timestamp: 2025-07-29T15:44:19.024Z
Learning: In the ODH Dashboard project, environment variables are not used in Cypress tests for namespace configuration, as clarified by dpanshug.

@@ -29,6 +29,7 @@ export const ProjectDeploymentsTable: React.FC<{
loaded={loaded && tableExtensionLoaded}
showExpandedInfo={!!expandedInfoExtension}
platformColumns={tableExtension?.properties.columns()}
defaultSortColumn={1}
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Default sort column should depend on expanded view

With showExpandedInfo=false, column 0 is “Model deployment name”. With showExpandedInfo=true, an expand column is prepended, and the “name” column shifts to index 1. Passing 1 unconditionally sorts by the wrong column (and may hit a non-sortable column when expanded view is off).

Apply this diff:

-      defaultSortColumn={1}
+      defaultSortColumn={expandedInfoExtension ? 1 : 0}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
defaultSortColumn={1}
defaultSortColumn={expandedInfoExtension ? 1 : 0}
🤖 Prompt for AI Agents
frontend/packages/modelServing/src/components/projectDetails/ProjectDeploymentsTable.tsx
around line 32: the defaultSortColumn is hardcoded to 1 which is correct only
when showExpandedInfo is true (name column at index 1) but wrong when
showExpandedInfo is false (name at index 0); update the prop to compute the
index based on showExpandedInfo (use showExpandedInfo ? 1 : 0) so the table
sorts by the "Model deployment name" column in both modes.

Comment on lines 69 to 82
// {
// type: 'app.navigation/href',
// flags: {
// required: [SupportedArea.MODEL_SERVING],
// disallowed: [SupportedArea.PLUGIN_MODEL_SERVING],
// },
// properties: {
// id: 'modelServing',
// title: 'Model deployments',
// href: '/modelServing',
// section: 'models',
// path: '/modelServing/*',
// },
// },
Copy link
Contributor

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

Commented-out navigation: add follow-up context and verify no lingering references

If this route is intentionally disabled, add a TODO with the tracking issue to avoid bitrot. Also verify no code/tests still reference “/modelServing”.

Note: If re-enabling later, replace disallowed: [SupportedArea.PLUGIN_MODEL_SERVING] with the proper enum-based gating consistent with the rest of the PR.


🏁 Script executed:

#!/bin/bash
# Check for lingering references to the removed /modelServing nav/route
set -euo pipefail

echo "Searching for '/modelServing' references..."
rg -n --no-heading "/modelServing(\\b|/)" -S || true

echo
echo "Searching for 'modelServing' nav id or route usage near extensions..."
rg -n --no-heading "id:\\s*'modelServing'|modelServing" -S -A3 -B3 frontend || true

echo
echo "Searching Cypress tests for navigation to /modelServing..."
rg -n --no-heading "visit\\([^)]*modelServing" frontend/src/__tests__/cypress -S || true

Length of output: 271869


Commented-out Model Serving nav: add TODO & clean up lingering “/modelServing” references

Even though you’ve disabled the in-app nav entry for Model Serving, there are hundreds of imports, links, tests and routes still pointing to /modelServing. To avoid breakage or bitrot:

  • In frontend/src/plugins/extensions/navigation.ts (lines 69–82), add a // TODO (track in ISSUE-NNN):… above the commented-out nav item with the issue URL so we don’t lose context.
  • Remove or update all surviving /modelServing references, for example:
    • In frontend/src/plugins/extensions/routes.ts (lines 84–85, 195).
    • In unit tests and Cypress specs (search under frontend/src/__tests__/…).
    • In page components and hooks that call navigate('/modelServing…') or render <Link to="/modelServing">.
  • If you intend to re-enable this later, replace the old disallowed: [SupportedArea.PLUGIN_MODEL_SERVING] flag with the proper enum-based gating (as in this PR) at both the nav and routes extensions.

Please clean up or guard these references so the codebase continues to build and test green.

🤖 Prompt for AI Agents
In frontend/src/plugins/extensions/navigation.ts around lines 69–82, add a
single-line TODO comment above the commented-out Model Serving nav item that
references the tracking issue (e.g. // TODO (track in ISSUE-NNN): link-to-issue)
so the rationale is preserved; then find and either remove or guard all
remaining "/modelServing" references (notably
frontend/src/plugins/extensions/routes.ts lines ~84–85 and ~195, unit tests
under frontend/src/__tests__, Cypress specs, page components, and hooks that
call navigate('/modelServing...') or <Link to="/modelServing">) — update those
to the new guarded enum-based gating or delete/redirect them as appropriate; if
you plan to re-enable the nav later, replace the old disallowed:
[SupportedArea.PLUGIN_MODEL_SERVING] flag with the proper enum-based gating used
elsewhere before re-adding the nav entry.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ignore, I will remove the toggle after review. I just figure this is easier to review with it on

Comment on lines +76 to +77
const [globalTemplates, globalTemplatesLoaded] = useServingRuntimeTemplates();
const isMissingTemplates = globalTemplates.length === 0 && globalTemplatesLoaded;
Copy link
Contributor Author

Choose a reason for hiding this comment

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

99% of the time a user will have runtime templates installed, so this reducing a loading flicker state by only disabling once the check is completed

@@ -69,7 +87,7 @@ export const ModelDeploymentsProvider: React.FC<ModelDeploymentsProviderProps> =

const [projectDeployments, setProjectDeployments] = React.useState<{
[key: string]: { deployments?: Deployment[]; loaded: boolean; error?: Error };
}>({});
}>(Object.fromEntries(projects.map((p) => [p.metadata.name, { loaded: false }])));
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Initializing the projects as loaded: false, it will prevent loading flicker on first render

@@ -184,6 +197,10 @@ const initIntercepts = ({
mockProjectK8sResource({ enableModelMesh: projectEnableModelMesh }),
);
cy.interceptK8sList(InferenceServiceModel, mockK8sResourceList(inferenceServices));
cy.interceptK8sList(
{ model: InferenceServiceModel, ns: 'test-project' },
Copy link
Contributor Author

Choose a reason for hiding this comment

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

The refactor has namespaced api calls, the old code did a cluster wide one

Comment on lines -484 to -490
components: undefined,
installedComponents: { kserve: false, 'model-mesh': false },
}),
);

cy.reload();
projectDetails.findResetPlatformButton().should('exist');
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This didn't really make sense, if there are no model platforms, it should be showing the "No serving platforms talk to an admin" screen

Copy link
Contributor

Choose a reason for hiding this comment

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

oh yeah that was from this PR
the "No serving platforms talk to an admin" does show up, but lets say your project is kserve and then you go disable kserve, the button to change platforms should exist but you'll be on a page saying "kserve is no longer enabled" then when you hit the change button it lets you know there aren't any platforms enabled

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Gotcha, I guess this isn't needed for the refactor? Because it will go straight to the no platforms page already

Because with the refactor, if a platform isn't installed, there is no way to know that your project no longer has a platform that is removed. Because the extensions are disabled

@@ -1646,6 +1643,7 @@ describe('Serving Runtime List', () => {
mockK8sResourceList([]),
).as('getPods');

cy.reload();
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I can't find any other way to make the start / stop button update. Clicking the button doesn't call for a refresh anymore and the webhook will just get the new data. but cypress isn't able to force a webhook update with the cy.wsk8s function

Copy link
Contributor

Choose a reason for hiding this comment

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

yeah it's a pain to try and mock this. Haven't looked into it with webhooks implemented now but before there was no way to mock it because the app was only calling for pods one time. I think it's okay for us to rely on e2e testing here more (which we have already)

Copy link
Contributor

@Griffin-Sullivan Griffin-Sullivan left a comment

Choose a reason for hiding this comment

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

Everything LGTM. There's only one more failure coming from modelServingGlobal. Should we merge this and have @katieperry4 rebase and fix it in #4686?

Comment on lines +2606 to 2609
disableModelMeshConfig: false,
disableProjectScoped: false,
inferenceServices: [
mockInferenceServiceK8sResource({ name: 'test-inference', isModelMesh: true }),
Copy link
Contributor

Choose a reason for hiding this comment

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

why were so many of these wrong?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

No idea 😶

@katieperry4
Copy link
Contributor

@Griffin-Sullivan
@emilys314 just approved #4686 so that should merge shortly 👍 but if this one goes first I can totally rebase 💯
the test that failed here should pass once #4686 goes in

@emilys314 emilys314 force-pushed the serving-runtime-list-fixes branch from 31dff4d to c7de79b Compare August 13, 2025 14:13
@emilys314
Copy link
Contributor Author

/unhold

@Griffin-Sullivan @katieperry4 i re-disabled the refactor plugin so it's ready for approving

@openshift-ci openshift-ci bot removed the do-not-merge/hold This PR is hold for some reason label Aug 13, 2025
Copy link
Contributor

openshift-ci bot commented Aug 13, 2025

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: Griffin-Sullivan

The full list of commands accepted by this bot can be found here.

The pull request process is described here

Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

Copy link

codecov bot commented Aug 13, 2025

Codecov Report

❌ Patch coverage is 18.18182% with 18 lines in your changes missing coverage. Please review.
✅ Project coverage is 29.56%. Comparing base (830b072) to head (c7de79b).
⚠️ Report is 8 commits behind head on main.

Files with missing lines Patch % Lines
...elServing/src/concepts/ModelDeploymentsContext.tsx 0.00% 8 Missing ⚠️
...lServing/src/concepts/useProjectServingPlatform.ts 16.66% 5 Missing ⚠️
...odelServing/src/components/deploy/DeployButton.tsx 0.00% 2 Missing ⚠️
frontend/src/services/componentsServices.ts 0.00% 2 Missing ⚠️
...ng/src/components/deployments/DeploymentsTable.tsx 0.00% 1 Missing ⚠️
Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##             main    #4644      +/-   ##
==========================================
+ Coverage   29.34%   29.56%   +0.22%     
==========================================
  Files        1846     1921      +75     
  Lines       38288    39386    +1098     
  Branches    11766    12130     +364     
==========================================
+ Hits        11234    11643     +409     
- Misses      27054    27743     +689     
Files with missing lines Coverage Δ
...src/components/deployments/DeploymentsTableRow.tsx 53.57% <ø> (ø)
...deployments/DeploymentsTableRowExpandedSection.tsx 2.00% <ø> (ø)
...g/src/components/overview/ModelPlatformSection.tsx 0.00% <ø> (ø)
...onents/projectDetails/ModelsProjectDetailsView.tsx 0.00% <ø> (ø)
...c/components/projectDetails/SelectPlatformView.tsx 0.00% <ø> (ø)
.../screens/global/InferenceServiceServingRuntime.tsx 91.66% <100.00%> (+0.36%) ⬆️
...erving/screens/global/InferenceServiceTableRow.tsx 0.00% <ø> (ø)
...ng/src/components/deployments/DeploymentsTable.tsx 0.00% <0.00%> (ø)
...odelServing/src/components/deploy/DeployButton.tsx 0.00% <0.00%> (ø)
frontend/src/services/componentsServices.ts 10.00% <0.00%> (ø)
... and 2 more

... and 80 files with indirect coverage changes


Continue to review full report in Codecov by Sentry.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 830b072...c7de79b. Read the comment docs.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@openshift-merge-bot openshift-merge-bot bot merged commit be7854e into opendatahub-io:main Aug 13, 2025
41 checks passed
antowaddle pushed a commit to antowaddle/odh-dashboard that referenced this pull request Aug 15, 2025
* Fixes

* Most things fixed

* Better initial loading state

* move defaultSortColumn

* Fix more feature flag toggles for test inits

* Force update start stop view

* Add loading state to reset platform button plus consistency
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants