Skip to content

[HOLD] Ray job resource tab#6694

Open
dpanshug wants to merge 3 commits intoopendatahub-io:mainfrom
dpanshug:ray-job-resource-tab
Open

[HOLD] Ray job resource tab#6694
dpanshug wants to merge 3 commits intoopendatahub-io:mainfrom
dpanshug:ray-job-resource-tab

Conversation

@dpanshug
Copy link
Contributor

@dpanshug dpanshug commented Mar 12, 2026

RHOAIENG-49277

Description

Screenshot 2026-03-12 at 1 37 35 PM

How Has This Been Tested?

Click on ray job and check the resource tab

Test Impact

Added cypress tests

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

@tobiastal

Summary by CodeRabbit

Release Notes

  • New Features
    • Added expanded Ray Job details view with two new tabs. Details tab displays job summary, execution information (entrypoint command, submission mode), and management settings (shutdown policy, cluster name). Resources tab shows node configurations, worker group resource specifications including CPU and memory requests/limits, cluster queue details, and quota consumption information.

@openshift-ci
Copy link
Contributor

openshift-ci bot commented Mar 12, 2026

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by:
Once this PR has been reviewed and has the lgtm label, please assign mturley for approval. For more information see the Code Review Process.

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

Details 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

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Mar 12, 2026

📝 Walkthrough

Walkthrough

This pull request extends Ray job visualization capabilities by adding structured UI components and supporting infrastructure. It introduces two new Cypress page objects (RayJobDetailsTab, RayJobResourcesTab) with finder methods; creates new React components for displaying Ray job details and resource specifications; adds a new hook (useRayClusterSpec) for resolving cluster specs from inline or external sources; enhances mock factories to support worker group specs and cluster selectors; adds a new API function (getRayCluster) for fetching individual Ray clusters; and expands the test suite with comprehensive UI validation tests.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes


Actionable Issues

1. useRayClusterSpec: Potential null dereference in clusterSpec resolution

  • File: packages/model-training/src/hooks/useRayClusterSpec.ts
  • Issue: The hook returns clusterSpec: RayClusterSpec | undefined but the component RayJobResourcesTab renders derived values without null checks in all branches. If clusterSpec is undefined but loaded becomes true, components may fail. Verify that all consuming code handles undefined clusterSpec gracefully, particularly in RayJobResourcesTab line-by-line rendering.

2. Clipboard copy state management lacks error handling (CWE-755)

  • File: packages/model-training/src/global/rayJobDetailsDrawer/RayJobDetailsTab.tsx
  • Issue: The clipboard.writeText() call in copy-to-clipboard handler has no catch block. Browser clipboard API can fail (permission denied, user gesture required). Implement error handling or suppress silently with user feedback.

3. Unsafe test data index assumptions

  • File: packages/cypress/cypress/tests/mocked/modelTraining/modelTrainingRayJobs.cy.ts
  • Issue: Updated test expectations (counts changed from 1→2, 4→7, etc.) without explicit assertions that the mock data array order is stable. If mock insertion order changes, these hardcoded indices become brittle. Recommend using data-testid matching or filtering by specific mock identifiers instead.

4. Missing null guard in getAllConsumedResources usage

  • File: packages/model-training/src/global/rayJobDetailsDrawer/RayJobResourcesTab.tsx
  • Issue: getAllConsumedResources(clusterQueue, projectName) is called without checking if clusterQueue is defined. If clusterQueue is undefined but Kueue is enabled, this may fail. Verify clusterQueue exists before calling getAllConsumedResources or handle the return value's undefined case.

5. Mock factory lacks input validation

  • File: packages/model-training/src/__mocks__/mockRayClusterK8sResource.ts
  • Issue: The mockRayClusterK8sResource function accepts workerReplicas without validating it's a non-negative integer. Invalid input silently propagates to status.replicas. Add input validation or defensive defaults.

6. Type safety gap in RayJobDetailsDrawerProps

  • File: packages/model-training/src/global/rayJobDetailsDrawer/RayJobDetailsDrawer.tsx
  • Issue: nodeCount prop added to RayJobDetailsDrawerProps but not verified as required vs. optional. Caller in ModelTraining.tsx uses selectedJobNodeCount (defaults to 0 if missing); verify RayJobDetailsTab and RayJobResourcesTab handle nodeCount properly in all render paths.
🚥 Pre-merge checks | ✅ 2
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title '[HOLD] Ray job resource tab' is specific and related to the main change (adding a Resource tab for Ray jobs), but the [HOLD] prefix signals the PR is not ready for merge.
Description check ✅ Passed The description includes linked issue, testing approach, test coverage, and a screenshot demonstrating the feature, with all key checklist items addressed.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


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

Comment @coderabbitai help to get the list of available commands and usage tips.

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: 4

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/model-training/src/__mocks__/mockRayJobK8sResource.ts (1)

15-28: ⚠️ Potential issue | 🟡 Minor

This fixture cannot model a RayJob with no cluster reference.

When clusterSelector is absent, the helper always manufactures an inline rayClusterSpec. RayJobKind allows both fields to be missing, so tests cannot exercise that branch and will get false confidence around useRayClusterSpec. Add an explicit opt-out such as rayClusterSpec: null or includeInlineSpec: false.

One way to make the state representable
-import { RayJobKind, RayWorkerGroupSpec } from '@odh-dashboard/model-training/k8sTypes';
+import {
+  RayJobKind,
+  RayClusterSpec,
+  RayWorkerGroupSpec,
+} from '@odh-dashboard/model-training/k8sTypes';
@@
   rayVersion?: string;
   shutdownAfterJobFinishes?: boolean;
+  rayClusterSpec?: RayClusterSpec | null;
@@
   shutdownAfterJobFinishes = true,
+  rayClusterSpec,
@@
         ...(clusterSelector
           ? { clusterSelector }
+          : rayClusterSpec === null
+            ? {}
           : {
-              rayClusterSpec: {
+              rayClusterSpec: rayClusterSpec ?? {
                 rayVersion,
                 headGroupSpec: {
                   template: {
@@
-              },
+              },
             }),

Also applies to: 121-163

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/model-training/src/__mocks__/mockRayJobK8sResource.ts` around lines
15 - 28, The mock currently always produces an inline rayClusterSpec when
clusterSelector is missing, preventing tests from representing a RayJob with no
cluster reference; update the fixture generator to accept an explicit opt-out
(e.g., a new boolean flag includeInlineSpec or allow rayClusterSpec: null) and
when that flag is set (or rayClusterSpec is null) leave both clusterSelector and
rayClusterSpec undefined so callers can test the branch where RayJobKind has
neither field; update the mock creation logic that references
clusterSelector/rayClusterSpec and add tests/examples showing useRayClusterSpec
behavior remains testable.
🧹 Nitpick comments (2)
packages/model-training/src/global/rayJobDetailsDrawer/RayJobResourcesTab.tsx (2)

169-203: DescriptionListGroup without DescriptionListTerm.

Line 169 opens a DescriptionListGroup that contains only a DescriptionListDescription (line 171). PatternFly DescriptionList semantics expect term-description pairs. This may cause accessibility/screen reader issues.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@packages/model-training/src/global/rayJobDetailsDrawer/RayJobResourcesTab.tsx`
around lines 169 - 203, The DescriptionListGroup currently renders only a
DescriptionListDescription when clusterQueueDataLoaded is true, which breaks
PatternFly term/description semantics; update the JSX inside the top-level
DescriptionListGroup so it always includes a paired DescriptionListTerm and
DescriptionListDescription (e.g., add a term like "Consumed quota" or a
visually-hidden DescriptionListTerm) and move the consumedResources mapping into
the DescriptionListDescription block; ensure DescriptionListTerm /
DescriptionListDescription pairs are present for both the consumedResources
non-empty branch and the '-' fallback, referencing the existing
DescriptionListGroup, DescriptionListTerm, DescriptionListDescription and
consumedResources map to locate where to add the term.

75-82: Unused error variable from hook destructuring.

error from useClusterQueueFromLocalQueue is destructured but only used on line 163 for quota source display. If an error occurs during local queue fetch, the UI still shows a skeleton indefinitely because clusterQueueLoaded may never become true with a proper error state. Consider displaying an error state.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@packages/model-training/src/global/rayJobDetailsDrawer/RayJobResourcesTab.tsx`
around lines 75 - 82, The hook useClusterQueueFromLocalQueue currently
destructures an error that isn't used to update the UI; in RayJobResourcesTab
update the rendering logic to handle that error: when the hook returns an error
(error from useClusterQueueFromLocalQueue) show an explicit error state/message
(or fallback UI) for the cluster-queue/quota source section instead of leaving
the skeleton, or treat the error as a loaded state so the component can render
the quota source error UI; modify the conditional checks that rely on
clusterQueueLoaded to also consider error (e.g., if (clusterQueueLoaded ||
error) render quota source/error UI) and surface the error text where quota
source is displayed.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/model-training/src/global/ModelTraining.tsx`:
- Around line 140-146: The code currently maps a missing/unknown workspace
RayCluster to 0 via getUnifiedJobNodeCount()/nodeCountMap and passes
selectedJobNodeCount into RayJobDetailsDrawer, which causes a false zero to
display while the cluster watch is loading or failed; change the logic so that
node count is nullable/undefined when the cluster is unresolved instead of
defaulting to 0 (i.e., let selectedJobNodeCount be null/undefined when
nodeCountMap lacks selectedJobId), or obtain the node count from the same
resolved cluster spec used by the drawer (use selectedRayJob or its
resolvedClusterSpec to derive a definitive count) and only pass a numeric
nodeCount when the cluster is actually resolved. Ensure references:
getUnifiedJobNodeCount, nodeCountMap, selectedJobNodeCount, selectedRayJob,
RayJobDetailsDrawer, selectedJobDisplayName.

In `@packages/model-training/src/global/rayJobDetailsDrawer/RayJobDetailsTab.tsx`:
- Around line 36-41: The handleCopy callback currently calls
navigator.clipboard.writeText without awaiting or handling rejection, causing
setCopied(true) to be set even if the copy fails; update handleCopy (the
function tied to job.spec.entrypoint and setCopied) to be async, await
navigator.clipboard.writeText(job.spec.entrypoint) inside a try/catch, call
setCopied(true) only on successful await, and in the catch block
setCopied(false) (or leave unchanged) and log or surface the error (e.g.,
console.error or existing logger); also guard for navigator.clipboard
availability and fallback or handle that error path accordingly.

In
`@packages/model-training/src/global/rayJobDetailsDrawer/RayJobResourcesTab.tsx`:
- Around line 98-100: The rendering of node count in RayJobResourcesTab uses a
falsy check (nodeCount || '-') which treats 0 as missing; update the render
logic in the RayJobResourcesTab component (the DescriptionListDescription with
data-testid="nodes-value") to use the nullish coalescing operator (nodeCount ??
'-') so that 0 is displayed while still falling back to '-' only for
null/undefined.

In `@packages/model-training/src/hooks/useRayClusterSpec.ts`:
- Around line 21-35: The fetched RayCluster payload (fetchedCluster from
useFetch/getRayCluster returning RayClusterKind) must be runtime-validated
before exposing clusterSpec: add a runtime shape check that ensures
fetchedCluster is an object with a non-null spec and required nested fields you
read downstream (e.g., spec.headGroupSpec, spec.workerGroupSpecs or whatever
your tabs expect) and if the check fails set/return an error instead of the
spec; update the return values (clusterSpec, loaded, error) so clusterSpec only
uses inlineSpec ?? fetchedCluster.spec when the runtime check passes and
otherwise set error and avoid exposing malformed data (adjust the useFetch
callback/post-process where fetchedCluster is consumed and reference
getRayCluster, fetchedCluster, RayClusterKind, clusterSpec, loaded, and error).

---

Outside diff comments:
In `@packages/model-training/src/__mocks__/mockRayJobK8sResource.ts`:
- Around line 15-28: The mock currently always produces an inline rayClusterSpec
when clusterSelector is missing, preventing tests from representing a RayJob
with no cluster reference; update the fixture generator to accept an explicit
opt-out (e.g., a new boolean flag includeInlineSpec or allow rayClusterSpec:
null) and when that flag is set (or rayClusterSpec is null) leave both
clusterSelector and rayClusterSpec undefined so callers can test the branch
where RayJobKind has neither field; update the mock creation logic that
references clusterSelector/rayClusterSpec and add tests/examples showing
useRayClusterSpec behavior remains testable.

---

Nitpick comments:
In
`@packages/model-training/src/global/rayJobDetailsDrawer/RayJobResourcesTab.tsx`:
- Around line 169-203: The DescriptionListGroup currently renders only a
DescriptionListDescription when clusterQueueDataLoaded is true, which breaks
PatternFly term/description semantics; update the JSX inside the top-level
DescriptionListGroup so it always includes a paired DescriptionListTerm and
DescriptionListDescription (e.g., add a term like "Consumed quota" or a
visually-hidden DescriptionListTerm) and move the consumedResources mapping into
the DescriptionListDescription block; ensure DescriptionListTerm /
DescriptionListDescription pairs are present for both the consumedResources
non-empty branch and the '-' fallback, referencing the existing
DescriptionListGroup, DescriptionListTerm, DescriptionListDescription and
consumedResources map to locate where to add the term.
- Around line 75-82: The hook useClusterQueueFromLocalQueue currently
destructures an error that isn't used to update the UI; in RayJobResourcesTab
update the rendering logic to handle that error: when the hook returns an error
(error from useClusterQueueFromLocalQueue) show an explicit error state/message
(or fallback UI) for the cluster-queue/quota source section instead of leaving
the skeleton, or treat the error as a loaded state so the component can render
the quota source error UI; modify the conditional checks that rely on
clusterQueueLoaded to also consider error (e.g., if (clusterQueueLoaded ||
error) render quota source/error UI) and surface the error text where quota
source is displayed.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Central YAML (base), Organization UI (inherited)

Review profile: CHILL

Plan: Pro

Run ID: 4b33bd9f-8e68-4fd3-81a2-3f569bd81764

📥 Commits

Reviewing files that changed from the base of the PR and between c6b29d4 and 310ce59.

📒 Files selected for processing (12)
  • packages/cypress/cypress/pages/modelTraining.ts
  • packages/cypress/cypress/tests/mocked/modelTraining/modelTrainingRayJobs.cy.ts
  • packages/model-training/src/__mocks__/mockRayClusterK8sResource.ts
  • packages/model-training/src/__mocks__/mockRayJobK8sResource.ts
  • packages/model-training/src/api/__tests__/rayClusters.spec.ts
  • packages/model-training/src/api/rayClusters.ts
  • packages/model-training/src/global/ModelTraining.tsx
  • packages/model-training/src/global/rayJobDetailsDrawer/RayJobDetailsDrawer.tsx
  • packages/model-training/src/global/rayJobDetailsDrawer/RayJobDetailsTab.tsx
  • packages/model-training/src/global/rayJobDetailsDrawer/RayJobResourcesTab.tsx
  • packages/model-training/src/hooks/__tests__/useRayClusterSpec.spec.ts
  • packages/model-training/src/hooks/useRayClusterSpec.ts

Comment on lines +140 to +146
const selectedJobNodeCount = selectedJobId ? nodeCountMap.get(selectedJobId) ?? 0 : 0;

const panelContent = selectedRayJob ? (
<RayJobDetailsDrawer
job={selectedRayJob}
displayName={selectedJobDisplayName}
nodeCount={selectedJobNodeCount}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Stop encoding “workspace RayCluster not resolved” as 0 nodes.

getUnifiedJobNodeCount() falls back to 0 when the referenced cluster is missing from the watched list. Passing that straight through here makes the new Resources tab show an actual node count of zero while the cluster watch is still loading, stale, or failed. Keep this nullable/loading, or derive it from the same resolved cluster spec the drawer already uses.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/model-training/src/global/ModelTraining.tsx` around lines 140 - 146,
The code currently maps a missing/unknown workspace RayCluster to 0 via
getUnifiedJobNodeCount()/nodeCountMap and passes selectedJobNodeCount into
RayJobDetailsDrawer, which causes a false zero to display while the cluster
watch is loading or failed; change the logic so that node count is
nullable/undefined when the cluster is unresolved instead of defaulting to 0
(i.e., let selectedJobNodeCount be null/undefined when nodeCountMap lacks
selectedJobId), or obtain the node count from the same resolved cluster spec
used by the drawer (use selectedRayJob or its resolvedClusterSpec to derive a
definitive count) and only pass a numeric nodeCount when the cluster is actually
resolved. Ensure references: getUnifiedJobNodeCount, nodeCountMap,
selectedJobNodeCount, selectedRayJob, RayJobDetailsDrawer,
selectedJobDisplayName.

Comment on lines +98 to +100
<DescriptionListDescription data-testid="nodes-value">
{nodeCount || '-'}
</DescriptionListDescription>
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Falsy check on nodeCount treats 0 as missing.

nodeCount || '-' displays '-' when nodeCount is 0. If 0 nodes is a valid state that should be displayed, use nullish coalescing instead.

Proposed fix
 <DescriptionListDescription data-testid="nodes-value">
-  {nodeCount || '-'}
+  {nodeCount ?? '-'}
 </DescriptionListDescription>
📝 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
<DescriptionListDescription data-testid="nodes-value">
{nodeCount || '-'}
</DescriptionListDescription>
<DescriptionListDescription data-testid="nodes-value">
{nodeCount ?? '-'}
</DescriptionListDescription>
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@packages/model-training/src/global/rayJobDetailsDrawer/RayJobResourcesTab.tsx`
around lines 98 - 100, The rendering of node count in RayJobResourcesTab uses a
falsy check (nodeCount || '-') which treats 0 as missing; update the render
logic in the RayJobResourcesTab component (the DescriptionListDescription with
data-testid="nodes-value") to use the nullish coalescing operator (nodeCount ??
'-') so that 0 is displayed while still falling back to '-' only for
null/undefined.

Comment on lines +21 to +35
} = useFetch<RayClusterKind | null>(
React.useCallback(() => {
if (inlineSpec || !workspaceClusterName) {
return Promise.reject(new NotReadyError('Inline spec available or no workspace cluster'));
}
return getRayCluster(workspaceClusterName, job.metadata.namespace);
}, [inlineSpec, workspaceClusterName, job.metadata.namespace]),
null,
{ initialPromisePurity: true },
);

return {
clusterSpec: inlineSpec ?? fetchedCluster?.spec,
loaded: !!inlineSpec || !workspaceClusterName || fetchLoaded,
error,
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Validate fetched RayCluster payloads before returning clusterSpec.

k8sGetResource() is only type-safe at compile time. If this comes back without a valid spec, the new drawer tabs will receive malformed data and can fail when they read nested resource fields. Gate the response with a runtime shape check and surface an error instead of rendering it. As per coding guidelines, "Validate all API responses before rendering".

Minimal guard
+const isRayClusterSpec = (spec: unknown): spec is RayClusterSpec =>
+  !!spec && typeof spec === 'object' && 'headGroupSpec' in spec;
+
 export const useRayClusterSpec = (
   job: RayJobKind,
 ): { clusterSpec: RayClusterSpec | undefined; loaded: boolean; error: Error | undefined } => {
@@
+  const fetchedSpec =
+    fetchedCluster && isRayClusterSpec(fetchedCluster.spec) ? fetchedCluster.spec : undefined;
+
   return {
-    clusterSpec: inlineSpec ?? fetchedCluster?.spec,
+    clusterSpec: inlineSpec ?? fetchedSpec,
     loaded: !!inlineSpec || !workspaceClusterName || fetchLoaded,
-    error,
+    error:
+      fetchedCluster && !isRayClusterSpec(fetchedCluster.spec)
+        ? new Error('Invalid RayCluster response')
+        : error,
   };
 };
📝 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
} = useFetch<RayClusterKind | null>(
React.useCallback(() => {
if (inlineSpec || !workspaceClusterName) {
return Promise.reject(new NotReadyError('Inline spec available or no workspace cluster'));
}
return getRayCluster(workspaceClusterName, job.metadata.namespace);
}, [inlineSpec, workspaceClusterName, job.metadata.namespace]),
null,
{ initialPromisePurity: true },
);
return {
clusterSpec: inlineSpec ?? fetchedCluster?.spec,
loaded: !!inlineSpec || !workspaceClusterName || fetchLoaded,
error,
const isRayClusterSpec = (spec: unknown): spec is RayClusterSpec =>
!!spec && typeof spec === 'object' && 'headGroupSpec' in spec;
export const useRayClusterSpec = (
job: RayJobKind,
): { clusterSpec: RayClusterSpec | undefined; loaded: boolean; error: Error | undefined } => {
} = useFetch<RayClusterKind | null>(
React.useCallback(() => {
if (inlineSpec || !workspaceClusterName) {
return Promise.reject(new NotReadyError('Inline spec available or no workspace cluster'));
}
return getRayCluster(workspaceClusterName, job.metadata.namespace);
}, [inlineSpec, workspaceClusterName, job.metadata.namespace]),
null,
{ initialPromisePurity: true },
);
const fetchedSpec =
fetchedCluster && isRayClusterSpec(fetchedCluster.spec) ? fetchedCluster.spec : undefined;
return {
clusterSpec: inlineSpec ?? fetchedSpec,
loaded: !!inlineSpec || !workspaceClusterName || fetchLoaded,
error:
fetchedCluster && !isRayClusterSpec(fetchedCluster.spec)
? new Error('Invalid RayCluster response')
: error,
};
};
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/model-training/src/hooks/useRayClusterSpec.ts` around lines 21 - 35,
The fetched RayCluster payload (fetchedCluster from useFetch/getRayCluster
returning RayClusterKind) must be runtime-validated before exposing clusterSpec:
add a runtime shape check that ensures fetchedCluster is an object with a
non-null spec and required nested fields you read downstream (e.g.,
spec.headGroupSpec, spec.workerGroupSpecs or whatever your tabs expect) and if
the check fails set/return an error instead of the spec; update the return
values (clusterSpec, loaded, error) so clusterSpec only uses inlineSpec ??
fetchedCluster.spec when the runtime check passes and otherwise set error and
avoid exposing malformed data (adjust the useFetch callback/post-process where
fetchedCluster is consumed and reference getRayCluster, fetchedCluster,
RayClusterKind, clusterSpec, loaded, and error).

@codecov
Copy link

codecov bot commented Mar 12, 2026

Codecov Report

❌ Patch coverage is 75.13514% with 92 lines in your changes missing coverage. Please review.
✅ Project coverage is 64.14%. Comparing base (ba87395) to head (310ce59).
⚠️ Report is 1 commits behind head on main.

Files with missing lines Patch % Lines
.../global/rayJobDetailsDrawer/RayJobResourcesTab.tsx 73.60% 52 Missing ⚠️
...rc/global/rayJobDetailsDrawer/RayJobDetailsTab.tsx 79.36% 26 Missing ⚠️
...ages/model-training/src/hooks/useRayClusterSpec.ts 72.72% 9 Missing ⚠️
...global/rayJobDetailsDrawer/RayJobDetailsDrawer.tsx 50.00% 3 Missing ⚠️
packages/model-training/src/api/rayClusters.ts 66.66% 2 Missing ⚠️
Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##             main    #6694      +/-   ##
==========================================
+ Coverage   64.02%   64.14%   +0.11%     
==========================================
  Files        2499     2505       +6     
  Lines       75200    75735     +535     
  Branches    18956    19055      +99     
==========================================
+ Hits        48149    48579     +430     
- Misses      27051    27156     +105     
Files with missing lines Coverage Δ
...ckages/model-training/src/global/ModelTraining.tsx 83.49% <100.00%> (+0.16%) ⬆️
packages/model-training/src/api/rayClusters.ts 36.36% <66.66%> (+17.61%) ⬆️
...global/rayJobDetailsDrawer/RayJobDetailsDrawer.tsx 72.95% <50.00%> (-2.46%) ⬇️
...ages/model-training/src/hooks/useRayClusterSpec.ts 72.72% <72.72%> (ø)
...rc/global/rayJobDetailsDrawer/RayJobDetailsTab.tsx 79.36% <79.36%> (ø)
.../global/rayJobDetailsDrawer/RayJobResourcesTab.tsx 73.60% <73.60%> (ø)

... and 30 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 c6b29d4...310ce59. 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.

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.

1 participant