Skip to content

Conversation

@Jos-Jerus
Copy link
Collaborator

@Jos-Jerus Jos-Jerus commented Oct 30, 2025

…ls assessment creation

  • Updated the assessment service to return job status for RVTools file processing.
  • Added polling mechanism to check job status until completion or failure.
  • Enhanced error handling for failed job status.
  • Adjusted the Provider component to accommodate new job handling logic.

Summary by CodeRabbit

  • New Features
    • RVTools assessment creation now runs as an asynchronous background job with automatic polling and a new job-status endpoint.
  • Bug Fixes
    • Improved error reporting for failed RVTools import jobs and better timeout handling.
  • Refactor
    • Assessment creation now returns a lightweight job handle while the final assessment is processed and later refreshed into the list.

@Jos-Jerus Jos-Jerus requested review from ammont82 and tupyy October 30, 2025 13:18
@openshift-ci
Copy link

openshift-ci bot commented Oct 30, 2025

[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 ammont82 for approval. For more information see the Code Review Process.

The full list of commands accepted by this bot can be found 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

@coderabbitai
Copy link

coderabbitai bot commented Oct 30, 2025

Walkthrough

RVTools assessment creation switched from synchronous to asynchronous: the frontend starts an RVTools job via AssessmentService, polls job status until completion/failure (interval + timeout), refreshes assessments on success, and returns a minimal Assessment-like object (id + name) while full data is refreshed separately.

Changes

Cohort / File(s) Summary
UI — RVTools job orchestration
src/migration-wizard/contexts/discovery-sources/Provider.tsx
RVTools path now starts an async job via createFromRVTools, polls getRVToolsJobStatus (interval + timeout), handles failure/timeouts, refreshes assessments on success, and returns a minimal Assessment object constructed from currentJob.assessment_id (or '') and the provided name.
Service — async job API & types
src/pages/assessment/assessmentService.ts
Added exported AsyncJob interface. createFromRVTools now POSTs to /api/v1/assessments/rvtools and returns Promise<AsyncJob>. Added getRVToolsJobStatus(jobId): Promise<AsyncJob>. createAssessment now returns Promise<AsyncJob> and delegates to RVTools flow when an RVTools file is provided; removed Assessment from public imports.

Sequence Diagram(s)

sequenceDiagram
    participant UI as Provider Component
    participant Service as AssessmentService
    participant API as Backend API

    UI->>Service: createAssessment(rvToolFile)
    Service->>API: POST /api/v1/assessments/rvtools
    API-->>Service: AsyncJob {id, status: pending}
    Service-->>UI: AsyncJob

    rect rgba(100,150,200,0.12)
        Note over UI,Service: Polling loop (every 2s, overall timeout)
        loop until status == completed or failed or timeout
            UI->>Service: getRVToolsJobStatus(jobId)
            Service->>API: GET /api/v1/rvtools/jobs/{jobId}
            API-->>Service: AsyncJob {status: running|completed|failed}
            Service-->>UI: AsyncJob
        end
    end

    rect rgba(100,200,120,0.12)
        Note over UI: On success -> refresh assessments list
        UI->>Service: refreshAssessmentsList()
        UI-->>UI: Return minimal Assessment { id: assessment_id, name }
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

  • Verify polling correctness (interval, total timeout/cancellation).
  • Confirm AsyncJob shape and error/status handling match backend contract.
  • Check public signature changes for callers and type imports (removed Assessment).
  • Inspect refreshed-assessments path to ensure UI receives full data after job completion.

Possibly related PRs

Suggested labels

lgtm

Suggested reviewers

  • tupyy

Poem

🐇 I kicked off a job and hopped away,
I check twice a second, then wait and sway,
When it finishes I fetch the full list,
Until then a tiny id is on my wrist,
Hooray for async — nibble, bounce, hooray! 🥕

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The PR title "ECOPROJECT-3446 | feat: Implement asynchronous job handling for RVToo…" directly and accurately captures the main change in the changeset. The changes across both files demonstrate a shift from synchronous assessment creation to asynchronous job-based processing for RVTools, which is exactly what the title conveys. The title is specific and clear—it uses conventional commit style with a meaningful descriptor ("Implement asynchronous job handling") and identifies the affected component ("RVTools"), making it easy for developers scanning history to understand the primary change without ambiguity.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • 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

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

@Jos-Jerus
Copy link
Collaborator Author

/retest

@Jos-Jerus Jos-Jerus force-pushed the rvtools-upload-async branch 2 times, most recently from 95a7566 to 8c05fa9 Compare October 30, 2025 13:36
Copy link

@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: 1

Caution

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

⚠️ Outside diff range comments (1)
src/pages/assessment/assessmentService.ts (1)

77-85: Incomplete implementation: missing inventory and agent handling.

The createAssessment method only handles the RVTools case, but the CreateAssessmentRequest interface defines sourceType as 'inventory' | 'rvtools' | 'agent'. This means:

  • Inventory-based assessments will fail with "RVTools file is required"
  • Agent-based assessments will fail with the same error
  • The method signature doesn't match its actual behavior

Either:

  1. Update this method to handle all three source types (inventory, agent, rvtools), or
  2. Create separate methods for each source type and update the interface accordingly, or
  3. If this service is RVTools-only by design, update the interface to remove inventory and agent from sourceType

Apply this diff if the service should remain RVTools-only:

 export interface CreateAssessmentRequest {
   name: string;
-  sourceType: 'inventory' | 'rvtools' | 'agent';
-  inventory?: Inventory;
-  sourceId?: string;
+  sourceType: 'rvtools';
   rvToolFile?: File;
 }

Or implement the missing cases:

   async createAssessment(request: CreateAssessmentRequest): Promise<AsyncJob> {
     const assessmentName =
       request.name || `Assessment-${new Date().toISOString()}`;
 
-    if (!request.rvToolFile) {
-      throw new Error('RVTools file is required for RVTools assessment');
+    if (request.sourceType === 'rvtools') {
+      if (!request.rvToolFile) {
+        throw new Error('RVTools file is required for RVTools assessment');
+      }
+      return this.createFromRVTools(assessmentName, request.rvToolFile);
+    } else if (request.sourceType === 'inventory') {
+      // TODO: Implement inventory assessment creation
+      throw new Error('Inventory assessment creation not yet implemented');
+    } else if (request.sourceType === 'agent') {
+      // TODO: Implement agent assessment creation
+      throw new Error('Agent assessment creation not yet implemented');
+    } else {
+      throw new Error(`Unsupported source type: ${request.sourceType}`);
     }
-    return this.createFromRVTools(assessmentName, request.rvToolFile);
   }
🧹 Nitpick comments (3)
src/migration-wizard/contexts/discovery-sources/Provider.tsx (3)

100-107: Consider a more robust approach for accessing the authenticated fetch function.

The type assertion (assessmentApi as any) to access internal configuration is fragile and could break if the API client implementation changes. Consider:

  • Exposing the fetch function through a proper public API
  • Using dependency injection to provide the authenticated fetch function
  • Documenting this workaround with a TODO comment if it must remain

174-183: Extract polling interval as a named constant.

The 2-second interval is hardcoded and appears in both the comment and the setTimeout call. Extract it as a constant for maintainability.

Apply this diff:

+      const POLL_INTERVAL_MS = 2000;
+
       // Create different request based on sourceType
       if (sourceType === 'inventory' && jsonValue) {
         // ... inventory handling ...
       } else if (sourceType === 'rvtools' && rvToolFile) {
         // Start async job
         const job = await assessmentService.createFromRVTools(
           assessmentName,
           rvToolFile,
         );
 
-        // Poll job status every 2 seconds until completed or failed
+        // Poll job status until completed or failed
         let currentJob = job;
         while (
           currentJob.status === 'pending' ||
           currentJob.status === 'running'
         ) {
-          // Wait 2 seconds before checking again
-          await new Promise((resolve) => setTimeout(resolve, 2000));
+          await new Promise((resolve) => setTimeout(resolve, POLL_INTERVAL_MS));
           currentJob = await assessmentService.getRVToolsJobStatus(job.id);
         }

195-201: Document the type safety limitation of the minimal Assessment object.

Returning a minimal object with a type assertion (as Assessment) could lead to runtime errors if calling code expects a fully populated Assessment object with properties beyond id and name. The comments explain the workaround, but this remains fragile.

Consider one of these alternatives:

  1. Update the return type of createAssessment to be Promise<Assessment | { id: string; name: string }> for the RVTools path
  2. Return null or a distinct type for async operations and update callers accordingly
  3. Add runtime validation in consuming code to check for complete Assessment objects

If keeping the current approach, add a comment warning about the incomplete object:

         // Return a minimal assessment object (the actual assessment is in the list)
         // We need to return something for type compatibility, but the actual
         // assessment data will come from the refreshed list
+        // WARNING: This is not a complete Assessment object - only id and name are populated
         return {
           id: currentJob.assessment_id || '',
           name: assessmentName,
         } as Assessment;
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 95a7566 and 8c05fa9.

📒 Files selected for processing (2)
  • src/migration-wizard/contexts/discovery-sources/Provider.tsx (1 hunks)
  • src/pages/assessment/assessmentService.ts (5 hunks)
⏰ 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). (1)
  • GitHub Check: Red Hat Konflux / migration-planner-ui-on-pull-request
🔇 Additional comments (5)
src/migration-wizard/contexts/discovery-sources/Provider.tsx (2)

168-172: LGTM - Async job initiation is correct.

The job is properly initiated with the assessment name and file.


186-190: LGTM - Error handling is appropriate.

The error handling properly checks the final job status and throws a descriptive error with the backend error message or a fallback.

src/pages/assessment/assessmentService.ts (3)

11-17: LGTM - AsyncJob interface is well-defined.

The interface appropriately models an asynchronous job with status tracking, error handling, and optional assessment ID reference.


31-56: LGTM - RVTools job creation is properly implemented.

The method correctly:

  • Uses FormData for file upload
  • Converts File to Blob with generic content type to avoid MIME issues
  • Returns AsyncJob for tracking
  • Provides clear error messages

58-75: LGTM - Job status polling is correctly implemented.

The method properly fetches job status from the backend and handles errors with descriptive messages.

@Jos-Jerus Jos-Jerus force-pushed the rvtools-upload-async branch from 8c05fa9 to 1b21124 Compare October 30, 2025 14:18
…ls assessment creation

- Updated the assessment service to return job status for RVTools file processing.
- Added polling mechanism to check job status until completion or failure.
- Enhanced error handling for failed job status.
- Adjusted the Provider component to accommodate new job handling logic.

Signed-off-by: yjacobi <[email protected]>
@Jos-Jerus Jos-Jerus force-pushed the rvtools-upload-async branch from 1b21124 to 578ea34 Compare October 30, 2025 14:23
Copy link

@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: 1

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 8c05fa9 and 578ea34.

📒 Files selected for processing (2)
  • src/migration-wizard/contexts/discovery-sources/Provider.tsx (1 hunks)
  • src/pages/assessment/assessmentService.ts (5 hunks)
⏰ 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). (1)
  • GitHub Check: Red Hat Konflux / migration-planner-ui-on-pull-request
🔇 Additional comments (4)
src/pages/assessment/assessmentService.ts (3)

11-17: LGTM! Well-defined AsyncJob interface.

The interface properly models an asynchronous job with appropriate fields and status enum values.


77-85: LGTM! Signature change aligns with async workflow.

The return type change from Promise<Assessment> to Promise<AsyncJob> is appropriate for the new asynchronous RVTools processing flow.


41-48: Verify backend implementation with the backend service team.

This is a frontend-only repository, and the backend implementation of these endpoints is not present in this codebase. The frontend code is calling:

  • POST /api/v1/assessments/rvtools (line 42)
  • GET /api/v1/rvtools/jobs/{jobId} (line 63)

Please confirm with the backend team that these endpoints are implemented and match the expected contracts (FormData file upload for the first, AsyncJob response for both).

src/migration-wizard/contexts/discovery-sources/Provider.tsx (1)

168-197: LGTM! Polling logic with proper timeout and error handling.

The implementation correctly:

  • Polls job status every 2 seconds
  • Implements a 5-minute timeout (150 attempts × 2 seconds)
  • Handles both timeout and failed job status with clear error messages
  • Includes error details from the job when available

Comment on lines +205 to +208
return {
id: currentJob.assessment_id || '',
name: assessmentName,
} as Assessment;
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Guard against missing assessment_id in completed job.

If currentJob.assessment_id is undefined or null after successful completion, using an empty string as fallback (line 206) could cause downstream issues in code that expects a valid assessment ID. This likely indicates a backend problem that should be surfaced rather than silently handled.

Consider adding validation:

+        // Validate that we got an assessment_id from the completed job
+        if (!currentJob.assessment_id) {
+          throw new Error(
+            'RVTools job completed but no assessment_id was returned',
+          );
+        }
+
         // Return a minimal assessment object (the actual assessment is in the list)
         // We need to return something for type compatibility, but the actual
         // assessment data will come from the refreshed list
         return {
-          id: currentJob.assessment_id || '',
+          id: currentJob.assessment_id,
           name: assessmentName,
         } as Assessment;
📝 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
return {
id: currentJob.assessment_id || '',
name: assessmentName,
} as Assessment;
// Validate that we got an assessment_id from the completed job
if (!currentJob.assessment_id) {
throw new Error(
'RVTools job completed but no assessment_id was returned',
);
}
// Return a minimal assessment object (the actual assessment is in the list)
// We need to return something for type compatibility, but the actual
// assessment data will come from the refreshed list
return {
id: currentJob.assessment_id,
name: assessmentName,
} as Assessment;
🤖 Prompt for AI Agents
In src/migration-wizard/contexts/discovery-sources/Provider.tsx around lines 205
to 208, the code currently falls back to an empty string when
currentJob.assessment_id is missing; instead validate that assessment_id exists
after job completion and surface an error if it does not. Update the function to
check if currentJob.assessment_id is null/undefined and, if so, either throw a
descriptive Error or return a rejected Promise (and log the condition) so the
caller can handle it, otherwise return the Assessment object with the guaranteed
id; ensure the error message includes job id/context to aid debugging.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants