Skip to content

Conversation

athul-rs
Copy link
Contributor

Summary

  • Fixed SonarQube code smell in FileUpload.jsx where beforeUpload function had multiple identical return false statements
  • Consolidated logic to use a single return statement with proper conditional handling
  • Added explanatory comment for why the function always returns false (to prevent automatic upload in Ant Design)

Changes

  • Refactored beforeUpload function in /frontend/src/components/agency/file-upload/FileUpload.jsx
  • Used if-else structure instead of multiple returns
  • No functional changes - behavior remains the same

Test Plan

  • File upload still works as expected
  • Files are added to list when under the limit
  • Error message appears when max files exceeded
  • Manual upload on submit still functions correctly

🤖 Generated with Claude Code

athul-rs and others added 19 commits August 11, 2025 21:14
…WorkflowSerializer

Changed validation error to use field-specific error dictionary format
for better API response consistency when workflow_id is missing.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <[email protected]>
…code review

- Use RequestKey.REQUEST constant instead of string literal for consistency
- Make file count validation error field-specific (similar to workflow_id)
- Extract MAX_EXECUTION_FILES as a module constant for better maintainability
- Improve error message structure for better API response consistency

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <[email protected]>
- Moved MAX_EXECUTION_FILES to Django settings as MAX_WORKFLOW_EXECUTION_FILES
- Changed workflow_id field to required=True and removed redundant validation
- Fixed error message formatting by adding quotes around file count
- Added environment variable documentation in sample.env

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <[email protected]>
- Created WfConstants.js with MAX_WORKFLOW_EXECUTION_FILES constant
- Updated FileUpload component to validate max 2 files before submission
- Added client-side validation with proper error messages
- Enhanced Upload component with maxCount and multiple file support
- Improved user experience with immediate validation feedback

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <[email protected]>
…ling

Added 'max_file_limit_exceeded' error code to ValidationError in ExecuteWorkflowSerializer
to improve frontend error handling and API response consistency.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <[email protected]>
- Renamed setting to better indicate it's specific to workflow page functionality
- Updated backend settings, environment variables, and serializer
- Updated frontend constants and all references in FileUpload component
- Maintains same functionality with clearer naming convention

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <[email protected]>
- Consolidated multiple return false statements into single return
- Added comment explaining why false is always returned (manual upload)
- Resolves SonarQube code smell about functions with duplicate returns

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <[email protected]>
Copy link
Contributor

coderabbitai bot commented Aug 22, 2025

Summary by CodeRabbit

  • New Features
    • Added a configurable limit on files per workflow execution (default: 2), with clear client-side messages if the limit is exceeded or no files are selected.
    • Enabled multiple file selection with UI enforcement of the maximum.
  • Bug Fixes
    • Strengthened validation by requiring a workflow ID for execution, preventing invalid submissions.
  • Chores
    • Introduced a new environment variable to control the maximum files per workflow execution and updated the sample configuration.

Walkthrough

Introduces a new max-files-per-execution setting exposed via env and used in backend validation. Updates serializer to require workflow_id and enforce file count limit from settings. Adds frontend constants and client-side checks mirroring the limit, updates the file upload component, and modifies the continueWfExecution call to include a third parameter.

Changes

Cohort / File(s) Summary
Backend config
backend/backend/settings/base.py, backend/sample.env
Adds WORKFLOW_PAGE_MAX_FILES (default 2) in settings and sample.env with descriptive comments.
Backend workflow serializer
backend/workflow_manager/workflow_v2/serializers.py
Imports settings; makes ExecuteWorkflowSerializer.workflow_id required; replaces validation to enforce max uploaded files from request.FILES against settings.WORKFLOW_PAGE_MAX_FILES; raises ValidationError on exceed with code "max_file_limit_exceeded".
Frontend upload component
frontend/src/components/agency/file-upload/FileUpload.jsx
Adds client-side max-file checks using constants; shows error messages; sets Upload maxCount and multiple; adjusts continueWfExecution call to include a third argument; prevents auto-upload.
Frontend constants
frontend/src/components/agency/file-upload/WfConstants.js
New module exporting WORKFLOW_PAGE_MAX_FILES=2 and WORKFLOW_VALIDATION_MESSAGES (MAX_FILES_EXCEEDED, NO_FILES_SELECTED, WORKFLOW_ID_REQUIRED).

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor User
  participant UI as FileUpload.jsx
  participant Const as WfConstants.js
  participant API as Backend API
  participant Ser as ExecuteWorkflowSerializer

  User->>UI: Select files
  UI->>Const: Read WORKFLOW_PAGE_MAX_FILES
  alt Files exceed limit
    UI-->>User: Show MAX_FILES_EXCEEDED
  else Within limit
    User->>UI: Click Submit
    alt No files
      UI-->>User: Show NO_FILES_SELECTED
    else OK
      UI->>API: continueWfExecution(wfId, files, params)
      API->>Ser: Validate request (files, workflow_id)
      alt Exceeds server limit
        Ser-->>API: ValidationError (max_file_limit_exceeded)
        API-->>UI: 400 with error
        UI-->>User: Show error
      else Valid
        Ser-->>API: OK
        API-->>UI: 200 success
        UI-->>User: Close modal / proceed
      end
    end
  end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Tip

🔌 Remote MCP (Model Context Protocol) integration is now available!

Pro plan users can now connect to remote MCP servers from the Integrations page. Connect with popular remote MCPs such as Notion and Linear to add more context to your reviews and chats.

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch UN-1720-Introducing-workflow-page-limit

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.

@athul-rs athul-rs changed the title Fix: Refactor beforeUpload to resolve SonarQube duplicate return issue UN-1720 [FIX] Refactor to resolve SonarQube duplicate return issue Aug 22, 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: 1

Caution

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

⚠️ Outside diff range comments (1)
frontend/src/components/agency/file-upload/FileUpload.jsx (1)

17-19: Use functional state updates in onRemove to avoid stale closures.

setFileList(fileList.filter(...)) captures a potentially stale fileList when Ant Design batches updates. Use the functional form.

Apply this diff:

-  const onRemove = (file) => {
-    setFileList(fileList.filter((item) => item.uid !== file.uid));
-  };
+  const onRemove = (file) => {
+    setFileList((prev) => prev.filter((item) => item.uid !== file.uid));
+  };
🧹 Nitpick comments (6)
backend/sample.env (1)

186-187: Good addition, but avoid FE/BE drift for this limit.

Defining WORKFLOW_PAGE_MAX_FILES here is useful, but the frontend currently hard-codes the same numeric value. If ops change this env in production without a coordinated FE deploy, the UX and server validation will diverge.

  • Consider exposing this limit via a small public config endpoint (or injecting via window.APP_CONFIG at runtime) so the FE reads it dynamically, or pass it as a prop from a parent that fetches config once.
  • Document the expected range (>= 1) in this sample file.
frontend/src/components/agency/file-upload/WfConstants.js (2)

5-7: Don’t hard-code the max file count in FE; make it configurable.

Hard-coding 2 here risks configuration drift with the backend setting. Prefer reading from a runtime config (e.g., window.APP_CONFIG.WORKFLOW_PAGE_MAX_FILES with a sane default) or pass it down as a prop so dynamic environments don’t require FE rebuilds.

Apply this minimal diff if you already have a runtime config object:

-// Maximum number of files allowed per workflow page execution
-export const WORKFLOW_PAGE_MAX_FILES = 2;
+// Maximum number of files allowed per workflow page execution (fallback to 2)
+export const WORKFLOW_PAGE_MAX_FILES =
+  (window.__APP_CONFIG__ && Number(window.__APP_CONFIG__.WORKFLOW_PAGE_MAX_FILES)) || 2;

9-13: Consider centralizing messages into your i18n/locale system.

If the project uses a localization framework elsewhere, move these strings to the shared messages catalog to keep UX consistent and localizable.

frontend/src/components/agency/file-upload/FileUpload.jsx (1)

69-69: Update button label for multiple selection.

Minor UX nit: with multiple={true}, label should be plural.

Apply this diff:

-        <Button icon={<UploadOutlined />}>Select File</Button>
+        <Button icon={<UploadOutlined />}>Select Files</Button>
backend/backend/settings/base.py (1)

69-71: Clamp/validate the limit to avoid misconfiguration.

If WORKFLOW_PAGE_MAX_FILES is unset or set to an invalid/negative value, behavior becomes undefined. Clamp at a minimum of 1 (and optionally enforce a reasonable upper bound).

Apply this diff:

-# Maximum number of files allowed per workflow page execution
-WORKFLOW_PAGE_MAX_FILES = int(os.environ.get("WORKFLOW_PAGE_MAX_FILES", 2))
+# Maximum number of files allowed per workflow page execution
+# Clamp to minimum of 1 to avoid accidental 0/negative values
+WORKFLOW_PAGE_MAX_FILES = max(1, int(os.environ.get("WORKFLOW_PAGE_MAX_FILES", 2)))
backend/workflow_manager/workflow_v2/serializers.py (1)

90-103: Server-side enforcement is good; align form field name and improve message.

  • The validator looks for request.FILES.getlist("files"). Confirm the FE uses the same field name ("files") when constructing FormData; otherwise this will silently not enforce the limit.
  • Consider singular/plural grammar and removing single quotes around numbers.
  • Optional: centralize the error message (and limit) so FE and BE share one source of truth.

If the field name differs, adapt as:

-            files = request.FILES.getlist("files")
+            files = request.FILES.getlist("files") or request.FILES.getlist("file")

Or make it configurable.

Also, tweak the copy:

-                            f"Maximum {settings.WORKFLOW_PAGE_MAX_FILES} files are allowed for workflow execution. "
-                            f"You have uploaded '{len(files)}' files."
+                            f"Maximum {settings.WORKFLOW_PAGE_MAX_FILES} files are allowed for workflow execution. "
+                            f"You have uploaded {len(files)}."
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Cache: Disabled due to Reviews > Disable Cache setting

Knowledge Base: Disabled due to Reviews > Disable Knowledge Base setting

📥 Commits

Reviewing files that changed from the base of the PR and between cbf6931 and ff1d202.

📒 Files selected for processing (5)
  • backend/backend/settings/base.py (1 hunks)
  • backend/sample.env (1 hunks)
  • backend/workflow_manager/workflow_v2/serializers.py (3 hunks)
  • frontend/src/components/agency/file-upload/FileUpload.jsx (3 hunks)
  • frontend/src/components/agency/file-upload/WfConstants.js (1 hunks)
🔇 Additional comments (5)
frontend/src/components/agency/file-upload/FileUpload.jsx (4)

31-38: Client-side submit validation looks good.

Redundant with the strengthened beforeUpload/maxCount checks, but keeping this defensive check is fine and improves UX.


66-67: Nice: Using maxCount and multiple for UX.

maxCount guards the UI, while we also validate in code and on the server. Good layering.


4-7: Potential scope drift vs PR description.

PR description mentions a minor refactor to deduplicate return statements in beforeUpload, but this change also introduces new constants and ties to backend limits. Please update the PR description and test plan accordingly.


39-43: Confirm handleWfExecution signature for the new 3-arg call

  • In FileUpload (frontend/src/components/agency/file-upload/FileUpload.jsx lines 39–43), you now invoke
    continueWfExecution(
      wfExecutionParams[0],
      wfExecutionParams[1],
      wfExecutionParams[2]
    );
  • The continueWfExecution prop is wired up in Agency (frontend/src/components/agency/agency/Agency.jsx at line 1276) as continueWfExecution={handleWfExecution}.

I wasn’t able to locate the definition of handleWfExecution to confirm its parameters. Please manually verify that handleWfExecution has been updated to accept three arguments—otherwise passing three values here will result in undefined or unexpected behavior.

backend/workflow_manager/workflow_v2/serializers.py (1)

69-69: workflow_id is now mandatory: please verify all usages

The workflow_id field on ExecuteWorkflowSerializer has been changed to required=True. While this is the correct enforcement, it risks breaking any existing clients or tests that submit requests without this field. Our automated search of backend/**/test_*.py files did not reveal any direct instantiations of ExecuteWorkflowSerializer in tests, but coverage may be incomplete—especially outside of the endpoint_v2/tests directory.

Please manually audit the following before merging:

  • All backend tests that instantiate or use ExecuteWorkflowSerializer (including any custom or non–test_*.py patterns).
  • Any frontend or SDK clients that construct requests against the “execute workflow” endpoint.
  • API documentation (OpenAPI/Swagger, Markdown docs, etc.) to ensure workflow_id is always listed as required.
  • Any code generation or code samples in developer guides to include workflow_id.

If all usages are updated and documentation is aligned, this change can be safely merged.

Comment on lines 21 to 28
const beforeUpload = (file) => {
if (fileList.length >= WORKFLOW_PAGE_MAX_FILES) {
message.error(WORKFLOW_VALIDATION_MESSAGES.MAX_FILES_EXCEEDED);
return false;
} else {
setFileList([...fileList, file]);
}
setFileList([...fileList, file]);
return false;
return false; // Always prevent automatic upload (manual upload on submit)
};
Copy link
Contributor

@coderabbitai coderabbitai bot Aug 22, 2025

Choose a reason for hiding this comment

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

⚠️ Potential issue

Fix multi-select race: use functional updates inside beforeUpload.

When selecting multiple files at once (multiple={true}), React may batch setState calls and each beforeUpload invocation reads the same captured fileList. This can drop files or exceed limits. Use a functional updater and decide based on prev length. Also de-duplicate the error message with a stable key.

Apply this diff:

-  const beforeUpload = (file) => {
-    if (fileList.length >= WORKFLOW_PAGE_MAX_FILES) {
-      message.error(WORKFLOW_VALIDATION_MESSAGES.MAX_FILES_EXCEEDED);
-    } else {
-      setFileList([...fileList, file]);
-    }
-    return false; // Always prevent automatic upload (manual upload on submit)
-  };
+  const beforeUpload = (file) => {
+    let rejected = false;
+    setFileList((prev) => {
+      if (prev.length >= WORKFLOW_PAGE_MAX_FILES) {
+        rejected = true;
+        return prev;
+      }
+      return [...prev, file];
+    });
+    if (rejected) {
+      message.error({
+        key: "max-files",
+        content: WORKFLOW_VALIDATION_MESSAGES.MAX_FILES_EXCEEDED,
+      });
+    }
+    return false; // Always prevent automatic upload (manual upload on submit)
+  };
📝 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
const beforeUpload = (file) => {
if (fileList.length >= WORKFLOW_PAGE_MAX_FILES) {
message.error(WORKFLOW_VALIDATION_MESSAGES.MAX_FILES_EXCEEDED);
return false;
} else {
setFileList([...fileList, file]);
}
setFileList([...fileList, file]);
return false;
return false; // Always prevent automatic upload (manual upload on submit)
};
const beforeUpload = (file) => {
let rejected = false;
setFileList((prev) => {
if (prev.length >= WORKFLOW_PAGE_MAX_FILES) {
rejected = true;
return prev;
}
return [...prev, file];
});
if (rejected) {
message.error({
key: "max-files",
content: WORKFLOW_VALIDATION_MESSAGES.MAX_FILES_EXCEEDED,
});
}
return false; // Always prevent automatic upload (manual upload on submit)
};
🤖 Prompt for AI Agents
In frontend/src/components/agency/file-upload/FileUpload.jsx around lines 21 to
28, the beforeUpload handler reads a stale fileList when multiple files are
selected causing lost files and duplicated messages; change setFileList to use
the functional updater (setFileList(prev => { compute newList based on prev,
enforce WORKFLOW_PAGE_MAX_FILES limit, and return the new array })) and base the
limit check on prev.length so each call is consistent; also dedupe the error
notification by passing a stable key to message.error (e.g.
'max-files-exceeded') so the error is shown only once per selection; keep
returning false to prevent automatic upload.

Copy link
Contributor

Choose a reason for hiding this comment

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

@athul-rs check if this is valid

Copy link
Contributor

Choose a reason for hiding this comment

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

Seems like the humans are having a chat. I'll hop back into my burrow for now. If you need me again, just tag @CodeRabbit in a new comment, and I'll come hopping out!

Copy link
Contributor

filepath function $$\textcolor{#23d18b}{\tt{passed}}$$ SUBTOTAL
$$\textcolor{#23d18b}{\tt{runner/src/unstract/runner/clients/test\_docker.py}}$$ $$\textcolor{#23d18b}{\tt{test\_logs}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{runner/src/unstract/runner/clients/test\_docker.py}}$$ $$\textcolor{#23d18b}{\tt{test\_cleanup}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{runner/src/unstract/runner/clients/test\_docker.py}}$$ $$\textcolor{#23d18b}{\tt{test\_cleanup\_skip}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{runner/src/unstract/runner/clients/test\_docker.py}}$$ $$\textcolor{#23d18b}{\tt{test\_client\_init}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{runner/src/unstract/runner/clients/test\_docker.py}}$$ $$\textcolor{#23d18b}{\tt{test\_get\_image\_exists}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{runner/src/unstract/runner/clients/test\_docker.py}}$$ $$\textcolor{#23d18b}{\tt{test\_get\_image}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{runner/src/unstract/runner/clients/test\_docker.py}}$$ $$\textcolor{#23d18b}{\tt{test\_get\_container\_run\_config}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{runner/src/unstract/runner/clients/test\_docker.py}}$$ $$\textcolor{#23d18b}{\tt{test\_get\_container\_run\_config\_without\_mount}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{runner/src/unstract/runner/clients/test\_docker.py}}$$ $$\textcolor{#23d18b}{\tt{test\_run\_container}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{runner/src/unstract/runner/clients/test\_docker.py}}$$ $$\textcolor{#23d18b}{\tt{test\_get\_image\_for\_sidecar}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{runner/src/unstract/runner/clients/test\_docker.py}}$$ $$\textcolor{#23d18b}{\tt{test\_sidecar\_container}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{TOTAL}}$$ $$\textcolor{#23d18b}{\tt{11}}$$ $$\textcolor{#23d18b}{\tt{11}}$$

Copy link

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.

3 participants