Skip to content

KPMP 6797 create file drop box - #78

Merged
HaneenT merged 5 commits into
developfrom
KPMP-6797_create-file-drop-box
Aug 24, 2026
Merged

KPMP 6797 create file drop box#78
HaneenT merged 5 commits into
developfrom
KPMP-6797_create-file-drop-box

Conversation

@Dert1129

@Dert1129 Dert1129 commented Aug 24, 2026

Copy link
Copy Markdown
Contributor

Summary by CodeRabbit

  • New Features

    • Added a drag-and-drop bulk upload workflow for YAML/YML files.
    • Added file validation, duplicate filename prevention, upload progress tracking, and upload limits.
    • Added upload-state handling that disables relevant controls while uploads are in progress.
    • Added a step-based upload interface with cancel and submit actions.
  • Style

    • Added responsive styling and uploader gallery presentation.

@coderabbitai

coderabbitai Bot commented Aug 24, 2026

Copy link
Copy Markdown

Review Change Stack

Walkthrough

The PR integrates Fine Uploader for YAML uploads, adds Redux upload-status state, and replaces the bulk-upload interface with a three-step workflow. It also adds uploader styling, gallery CSS, new dependencies, and updates the development start script.

Changes

Upload workflow

Layer / File(s) Summary
Uploader dependencies and state foundation
package.json, src/actions/..., src/components/Upload/UploadReducer.js, src/initialState.json, src/reducers.js
Adds Fine Uploader dependencies and configuration. Adds the isUploading Redux state, action, reducer, and application wiring.
Upload component flow
src/components/Upload/BulkUpload.js, src/components/Upload/BulkUploadContainer.js, src/components/Upload/FileDropzone.js
Adds Fine Uploader lifecycle handling, duplicate-file checks, YAML file selection, upload status tracking, form submission state, and disabled controls.
Upload presentation and styling
src/index.js, src/index.scss
Imports gallery CSS and adds dropzone, form, section, footer, and image styles.

Sequence Diagram(s)

sequenceDiagram
  participant BulkUpload
  participant FileDropzone
  participant FineUploader
  participant ReduxStore
  BulkUpload->>FineUploader: Initialize uploader
  FileDropzone->>FineUploader: Select or drop YAML file
  FineUploader-->>BulkUpload: Report upload status
  BulkUpload->>ReduxStore: Dispatch SET_IS_UPLOADING
  ReduxStore-->>FileDropzone: Provide isUploading state
Loading

Merge Risk: 🟡 Moderate · up to 1ee74

File-drop uploads currently remain queued instead of starting, upload progress cannot update correctly, and stale callbacks may cause later upload attempts to fail; updated styles also will not be compiled during development. The PR is not merge-ready until these issues are fixed.

🚥 Pre-merge checks | ✅ 2
✅ Passed checks (2 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches 💡 1
🛠️ Fix failing CI checks 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch KPMP-6797_create-file-drop-box

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.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 3


ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: fdd2da42-6b7b-412b-bab9-a7f18d63ea5f

📥 Commits

Reviewing files that changed from the base of the PR and between e27cccf and 1ee74e7.

📒 Files selected for processing (12)
  • package.json
  • src/actions/Packages/packageActions.js
  • src/actions/actionNames.js
  • src/components/Upload/BulkUpload.js
  • src/components/Upload/BulkUploadContainer.js
  • src/components/Upload/FileDropzone.js
  • src/components/Upload/UploadReducer.js
  • src/components/Upload/fineUploader.js
  • src/index.js
  • src/index.scss
  • src/initialState.json
  • src/reducers.js

Included review availability: Your plan provides up to 1 included review per hour; 0 remain after this review.

Comment thread package.json
"scripts": {
"start-js": "react-scripts start",
"start": "npm-run-all -p watch-css start-js",
"start": "npm-run-all -p start-js",

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Keep Sass compilation in the development start command.

src/index.js imports src/index.css, but this PR changes src/index.scss. Removing watch-css means npm start does not run build-css, so the new upload styles are not present in the CSS loaded by the app.

Proposed fix
-    "start": "npm-run-all -p start-js",
+    "start": "npm-run-all -p start-js watch-css",
📝 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
"start": "npm-run-all -p start-js",
"start": "npm-run-all -p start-js watch-css",

Comment thread src/components/Upload/BulkUpload.js Outdated
Comment on lines +18 to +51
uploader.on('submit', () => {
let newCount = this.state.filesAdded + 1;
this.setState( { filesAdded: newCount } );
this.isSubmitDisabled();
return true;
});

uploader.on('cancel', () => {
let newCount = this.state.filesAdded - 1;
this.setState( { filesAdded: newCount });
this.isSubmitDisabled();
return true;
});

uploader.on('submit', (id, name) => {
let files = uploader.methods.getUploads({
status: [ qq.status.SUBMITTED, qq.status.PAUSED ]});

for(let fileIndex in files) {
let existingName = files[fileIndex].name;
if (existingName === name) {
alert("You have already selected " + existingName + " to upload.");
return false;
}
}
return true;
});

uploader.on('validateBatch', () => {
if (this.state.submitClicked) {
return false;
}
return true;
})

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -eu

printf '%s\n' '--- candidate files ---'
fd -i 'BulkUpload|fineUploader|package.json|yarn.lock|package-lock.json' . || true

printf '%s\n' '--- BulkUpload outline ---'
bulk="$(fd -i -t f 'BulkUpload' . | head -n 1)"
if [ -n "${bulk}" ]; then
  ast-grep outline "${bulk}" --view compact || true
  printf '%s\n' '--- BulkUpload source ---'
  cat -n "${bulk}"
fi

printf '%s\n' '--- FineUploader references ---'
rg -n -S "FineUploader|fineUploader|uploader\.on|uploader\.off|validateBatch|statusChange|submitClicked|componentWillUnmount|handleSubmit" . \
  -g '*.js' -g '*.jsx' -g '*.json' -g '*.md' || true

printf '%s\n' '--- dependency manifests ---'
for f in package.json yarn.lock package-lock.json; do
  if [ -f "$f" ]; then
    printf '%s\n' "--- $f ---"
    rg -n -C 3 -S "fine-uploader|fineUploader|fineuploader" "$f" || true
  fi
done

Repository: KPMP/libra-web

Length of output: 10710


🏁 Script executed:

#!/bin/bash
set -eu

printf '%s\n' '--- locate source files ---'
git ls-files | rg -i '(^|/)(BulkUpload|fineUploader)(\.[^.]+)?$|package(-lock)?\.json$|yarn\.lock$' || true

printf '%s\n' '--- locate symbols ---'
rg -n -S "class BulkUpload|function BulkUpload|componentWillUnmount|validateBatch|statusChange|submitClicked|uploader\.on|uploader\.off|handleSubmit" src package.json yarn.lock package-lock.json 2>/dev/null || true

Repository: KPMP/libra-web

Length of output: 1706


🏁 Script executed:

#!/bin/bash
set -eu

printf '%s\n' '--- uploader factory ---'
cat -n src/components/Upload/fineUploader.js

printf '%s\n' '--- upload component files ---'
for f in $(git ls-files 'src/components/Upload/*' | sort); do
  printf '%s\n' "--- $f ---"
  wc -l "$f"
done

printf '%s\n' '--- FileDropzone symbols and source ---'
dropzone="$(fd -i -t f 'FileDropzone' src | head -n 1 || true)"
if [ -n "$dropzone" ]; then
  rg -n -C 5 -S "uploader|methods|onSubmit|autoUpload|upload|submit|reset" "$dropzone" || true
  cat -n "$dropzone"
fi

printf '%s\n' '--- lockfile package entries ---'
rg -n -C 8 -S '"fine-uploader-wrappers"|"fine-uploader"|"react-fine-uploader"' package-lock.json package.json || true

printf '%s\n' '--- all uploader call sites ---'
rg -n -S "getUploader|FineUploaderTraditional|new FineUploader|\.methods\.(upload|uploadStoredFiles|reset)|\.on\(|\.off\(" src -g '*.js' -g '*.jsx' || true

Repository: KPMP/libra-web

Length of output: 5987


🌐 Web query:

Fine Uploader 5.16.2 validateBatch callback return false off event callback same reference documentation

💡 Result:

In Fine Uploader 5.16.2, the validateBatch callback allows you to perform custom validation on an entire batch of files selected for upload [1][2]. If your validation logic determines that the batch (or any file within it) should be rejected, returning false from this callback will prevent the files from being processed [1][2][3]. Key details regarding the validateBatch callback: 1. Functionality: The callback is triggered whenever files are selected, dropped, or added via addFiles, specifically before the default Fine Uploader validators execute [4][5]. 2. Returning false: If you return false, the entire batch submission is cancelled [2]. If you are using asynchronous validation, you may return a promise instead; calling failure on that promise is equivalent to returning false [4][5][3]. 3. Event reference: When using the jQuery integration, ensure you are using the correct event name validateBatch (case-sensitive) and remember that the first parameter passed to the callback is the event object [2]. Example implementation:.on('validateBatch', function(event, fileOrBlobDataArray) { var totalSize = 0; // Iterate through the array of files/blobs $.each(fileOrBlobDataArray, function(idx, fileOrBlobData) { totalSize += fileOrBlobData.size; }); // Reject the batch if it exceeds a custom limit if (totalSize > maxAllowedBatchSize) { return false; } }); Note that this client-side validation requires File API support (not available in IE9 and older) [2]. As with all client-side checks, this should be paired with server-side validation to ensure security and data integrity [2].

Citations:


🌐 Web query:

github fine-uploader-wrappers on off validateBatch callback source

💡 Result:

In the Fine Uploader Wrappers library, event listeners are managed using the.on method [1][2]. When using this method, the event name can be specified with or without an 'on' prefix [1][2]. If you include the prefix, it must follow strict lower-camel-case formatting (e.g., 'onValidateBatch', not 'onvalidatebatch') [1][2]. The validateBatch callback is a global event that allows you to perform custom validation on an entire batch of selected files before the default Fine Uploader validators execute [3][4][5]. Key details regarding the validateBatch callback: - Purpose: It is commonly used to enforce rules across all files in a single selection, such as limiting the total size of a batch [6]. - Return Value: If the handler returns false, the entire batch will be rejected [3][4][6]. - Asynchronous Support: You may return a Promise for non-blocking validation; the batch will be processed only after the promise is fulfilled [4][5]. - Parameters: The callback typically receives an array of file or blob data (containing name and size) as its primary argument [4][5][6]. If the files were submitted via a tracked button, the button container element is passed as the last argument [4][5][7]. Note: The case-sensitivity of the event name is critical [6]. For the wrappers, using 'validateBatch' or 'onValidateBatch' is required to correctly register the listener in the event pipeline [1][2].

Citations:


🌐 Web query:

site:github.com/fineuploader/fine-uploader "off: function" "callback" event handler remove

💡 Result:

In JavaScript and related environments, the mechanism to remove an event handler depends on the specific library or API being used. Standard JavaScript (DOM API) To remove an event listener added via addEventListener, you must use the removeEventListener method. It requires the same event type, the exact same function reference, and the same options (if any) used during registration. element.removeEventListener('click', yourFunction); jQuery In jQuery, the.off method is used to remove event handlers that were previously attached with.on. // Remove all handlers for a specific event $(selector).off('click'); // Remove a specific handler $(selector).off('click', yourFunction); Node.js EventEmitter In Node.js, the EventEmitter class provides both.removeListener and.off methods. The.off method is an alias for.removeListener and functions identically, requiring the event name and the specific callback function reference to be removed. emitter.off('eventName', callbackFunction); // Or emitter.removeListener('eventName', callbackFunction); If you are working with specific libraries like Fine Uploader, event management is typically handled through the library's internal callback configuration rather than generic DOM event removal methods. Always refer to the specific library documentation for its supported API.

Citations:


🌐 Web query:

Fine Uploader API off event callback handler reference remove listener

💡 Result:

To remove an event listener in Fine Uploader, you use the off(eventName, handlerFunction) method [1][2]. The off method requires two arguments: 1. eventName: The name of the event (e.g., 'complete', 'error'). You can provide this with or without the 'on' prefix (e.g., 'onComplete' or 'complete') [1][2]. 2. handlerFunction: The exact reference to the function that was originally passed to the on method when the listener was registered [1][2]. Example usage: const completeHandler = (id, name, response) => { // handle completed upload } // Register the listener uploader.on('complete', completeHandler) // Unregister the listener later uploader.off('complete', completeHandler) Important Considerations: - If you are using the jQuery plugin version of Fine Uploader, event handling and removal follow standard jQuery.on and.off patterns [3]. - When using the core library, ensure you are passing the exact function reference; passing an anonymous function or a different function instance will not successfully remove the listener [1][2].

Citations:


Remove all four constructor-registered callbacks from the shared uploader on unmount.

Each BulkUpload mount adds two submit handlers, one cancel handler, and one validateBatch handler. componentWillUnmount removes only statusChange. A retained handler from an instance with submitClicked === true can return false and reject file batches on later visits. Store each handler in a stable instance field and remove it with uploader.off using the same function reference.

🧰 Tools
🪛 React Doctor (0.9.3)

[error] 18-18: This class registers a listener or timer during mount without a matching teardown on every unmount path, so it can keep firing after the component unmounts; release it in componentWillUnmount.

Release listeners and timers acquired in componentDidMount/constructor by adding a componentWillUnmount that removes them (or use MobX disposeOnUnmount).

(class-component-missing-component-will-unmount-teardown)

Source: Linters/SAST tools

Comment on lines +76 to +88
handleUploadStatusChange = (id, oldStatus, status) => {
const removedStatuses = [
uploader.qq.status.CANCELED,
uploader.qq.status.REJECTED,
];
if (removedStatuses.includes(status)) {
this.fileIds.delete(id);
} else {
this.fileIds.add(id);
}

this.setState({hasFiles: this.fileIds.size > 0});
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -e
printf '%s\n' '--- candidate files ---'
git ls-files 'src/components/Upload/*' 'src/*' | sed -n '1,120p'
printf '%s\n' '--- BulkUpload outline ---'
ast-grep outline src/components/Upload/BulkUpload.js || true
printf '%s\n' '--- BulkUpload.js ---'
cat -n src/components/Upload/BulkUpload.js
printf '%s\n' '--- related symbols ---'
rg -n -C 4 'setIsUploading|isUploading|statusChange|onStatusChange|addEventListener|validateBatch|submitClicked|handleUploadStatusChange|FileDropzone|BulkUploadContainer' src
printf '%s\n' '--- uploader wrapper references ---'
rg -n -C 5 'uploader\.qq\.|autoUpload|uploadStoredFiles|upload\(' src/components/Upload src | sed -n '1,260p'

Repository: KPMP/libra-web

Length of output: 23888


🏁 Script executed:

#!/bin/bash
set -e
printf '%s\n' '--- BulkUploadContainer.js ---'
cat -n src/components/Upload/BulkUploadContainer.js
printf '%s\n' '--- fineUploader.js ---'
cat -n src/components/Upload/fineUploader.js
printf '%s\n' '--- UploadReducer.js ---'
cat -n src/components/Upload/UploadReducer.js
printf '%s\n' '--- setIsUploading call sites ---'
rg -n -C 6 'setIsUploading|SET_IS_UPLOADING|dispatch\(' src
printf '%s\n' '--- Fine Uploader dependency/version ---'
rg -n -C 2 '"fine-uploader"|"react-fine-uploader"' package.json package-lock.json yarn.lock 2>/dev/null || true
printf '%s\n' '--- source-level invariant probe ---'
python3 - <<'PY'
from pathlib import Path
bulk = Path("src/components/Upload/BulkUpload.js").read_text()
container = Path("src/components/Upload/BulkUploadContainer.js").read_text()
wrapper = Path("src/components/Upload/fineUploader.js").read_text()
print("statusChange registration:", "uploader.on('statusChange', this.handleUploadStatusChange)" in bulk)
print("statusChange handler dispatches setIsUploading:", "setIsUploading" in bulk)
print("container maps isUploading:", "isUploading: state.isUploading" in container)
print("container maps dispatch:", "mapDispatchToProps" in container and "dispatch" in container)
print("autoUpload false:", "autoUpload: false" in wrapper)
PY

Repository: KPMP/libra-web

Length of output: 11336


🌐 Web query:

Fine Uploader 5.16.2 statusChange event status constants UPLOADING SUBMITTING uploadStoredFiles

💡 Result:

In Fine Uploader 5.16.2, the statusChange event is triggered whenever an item's status changes [1][2]. The event callback provides the file ID, the old status, and the new status [1][2]. The status values correspond to the constants found in the qq.status object [1][2]. Based on official documentation for version 5.16.2, the available status constants are [1]: SUBMITTING: The file is being processed and validated after being selected [1][3]. SUBMITTED: The file has been successfully submitted and is ready for the uploader [1][3]. QUEUED: The file is waiting for an available connection to start uploading [1][3]. UPLOADING: The file is currently being uploaded [1][3]. UPLOAD_FINALIZING: The file's data has been sent and the uploader is waiting for the server's final response [1]. UPLOAD_RETRYING: The state before an automatic retry attempt begins [1][3]. UPLOAD_FAILED: The upload has failed after all retry attempts [1][3]. UPLOAD_SUCCESSFUL: The upload completed successfully [1][3]. CANCELED: The upload has been canceled [1][3]. REJECTED: The file failed validation [1][3]. DELETED: The file was successfully deleted [1][3]. DELETING: A delete attempt is in progress [1][3]. DELETE_FAILED: The last delete attempt failed [1][3]. PAUSED: The upload process is paused [1][3]. Regarding uploadStoredFiles, this is an API method rather than a status constant [4][5]. When autoUpload is set to false, files added to the uploader are not uploaded immediately [4][5]. Calling the uploadStoredFiles method manually triggers the upload process for these queued files [4][5].

Citations:


🏁 Script executed:

#!/bin/bash
set -e
printf '%s\n' '--- all uploader method/event call sites ---'
rg -n -C 5 'getUploader|uploader\.on|uploader\.off|uploader\.methods|uploadStoredFiles|upload\(' . -g '!*.map' -g '!package-lock.json' -g '!yarn.lock' | sed -n '1,360p'
printf '%s\n' '--- package scripts and upload-related docs ---'
cat -n package.json
rg -n -i -C 4 'bulk.?upload|uploadStoredFiles|isUploading|submit the upload|autoUpload' README* docs src 2>/dev/null | sed -n '1,260p' || true
printf '%s\n' '--- action definition ---'
cat -n src/actions/Packages/packageActions.js | sed -n '1,90p'
printf '%s\n' '--- source-level upload-start probe ---'
python3 - <<'PY'
from pathlib import Path
files = [p for p in Path('.').rglob('*') if p.is_file() and '.git' not in p.parts and p.suffix in {'.js', '.jsx', '.ts', '.tsx'}]
terms = ('uploadStoredFiles', '.upload(', 'methods.upload', 'setIsUploading')
for term in terms:
    hits = []
    for p in files:
        text = p.read_text(errors='ignore')
        if term in text:
            hits.append(str(p))
    print(f'{term}: {hits}')
PY

Repository: KPMP/libra-web

Length of output: 17752


Connect and update the Redux upload state, and start queued uploads.

BulkUploadContainer provides no dispatch prop, and handleUploadStatusChange never dispatches setIsUploading. autoUpload is false, and handleSubmit never calls uploader.methods.uploadStoredFiles(). Map setIsUploading, dispatch the aggregate active state, and start the queued upload on submit. Otherwise FileDropzone cannot reflect upload progress and selected files remain queued.

@HaneenT
HaneenT merged commit e99af7f into develop Aug 24, 2026
1 check failed
@HaneenT
HaneenT deleted the KPMP-6797_create-file-drop-box branch August 24, 2026 18:02
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