Skip to content

Apply BitFileUpload improvements (#12778) - #12779

Open
msynk wants to merge 1 commit into
bitfoundation:developfrom
msynk:12778-blazorui-fileupload-improvements
Open

Apply BitFileUpload improvements (#12778)#12779
msynk wants to merge 1 commit into
bitfoundation:developfrom
msynk:12778-blazorui-fileupload-improvements

Conversation

@msynk

@msynk msynk commented Jul 29, 2026

Copy link
Copy Markdown
Member

closes #12778

Summary by CodeRabbit

  • New Features

    • Enhanced file uploads with previews, image dimensions, last-modified details, queue status, upload speed, and estimated remaining time.
    • Added drag-and-drop, paste, directory selection, camera capture, custom form fields, configurable requests, retries, and automatic chunk handling.
    • Added customizable styles, templates, button labels, icons, messages, and file-upload sizing.
    • Improved accessibility with semantic controls, ARIA attributes, live status updates, and clearer upload states.
  • Bug Fixes

    • Improved validation, progress tracking, cancellation, removal handling, error reporting, and memory cleanup.
    • Prevented invalid progress calculations and improved behavior for queued, canceled, and failed uploads.
  • Documentation

    • Expanded demos and documented new configuration, styling, accessibility, and theming options.

@coderabbitai

coderabbitai Bot commented Jul 29, 2026

Copy link
Copy Markdown

Review Change Stack

Walkthrough

BitFileUpload now supports richer file metadata, configurable browser uploads, queued and retryable transfers, accessible rendering, customizable styling, expanded demos, and broader automated coverage.

Changes

FileUpload improvements

Layer / File(s) Summary
Public metadata and component contracts
src/BlazorUI/Bit.BlazorUI/Components/Inputs/FileUpload/BitFileInfo.cs, BitFileUpload.razor.cs, BitFileUploadClassStyles.cs
Adds file previews, image dimensions, upload metrics, queue state, form fields, request options, lifecycle callbacks, messages, and style customization APIs.
Browser upload and interop pipeline
BitFileUpload.ts, BitFileUploadJsRuntimeExtensions.cs
Adds configurable drag/drop and paste handling, directory expansion, image probing, multipart fields, request options, and uploader cleanup.
Queue, transfer, retry, and removal engine
BitFileUpload.razor.cs
Refactors queue pumping, progress tracking, chunk retries, pause/cancel operations, status propagation, completion settling, and configurable removal requests.
Accessible file list and themed presentation
BitFileUpload.razor, _BitFileUploadItem.razor*, BitFileUpload.scss
Updates ARIA markup, previews, progress semantics, action buttons, status classes, CSS variables, color roles, and size modifiers.
Validation, demos, and theme contracts
BitFileUploadTests.cs, BitFileUploadDemo.razor*, component-css-variables.md
Expands workflow tests, demo examples, API metadata, embedded samples, and documented FileUpload CSS variables.

Estimated code review effort: 5 (Critical) | ~120 minutes

Suggested reviewers: yasmoradi, cyrus-sushiant, mhrastegari

Poem

A rabbit uploads through the breeze,
With queued little files at ease.
Buttons hop, previews gleam,
Retries paddle down the stream.
CSS carrots line the way—
Hooray for FileUpload today!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 9.43% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title is concise and accurately summarizes the BitFileUpload improvement work tied to issue #12778.
Linked Issues check ✅ Passed The changes add missing FileUpload features, demo examples, and improved demo descriptions as requested in #12778.
Out of Scope Changes check ✅ Passed The modified files all support the FileUpload component, its demos, tests, or theming, with no clear unrelated changes.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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

🧹 Nitpick comments (7)
src/BlazorUI/Bit.BlazorUI/Components/Inputs/FileUpload/BitFileUpload.ts (1)

388-416: 🩺 Stability & Availability | 🔵 Trivial | 💤 Low value

Optional: cap the directory walk.

collectEntry recurses without a depth or total-file limit, so a deeply nested (or cyclic, via symlinked directories on some platforms) dropped folder can recurse/iterate unbounded before the change event ever fires. A depth cap plus a max-files guard would bound the worst case.

♻️ Sketch
-        private static async collectEntry(entry: any, files: File[]): Promise<void> {
+        private static async collectEntry(entry: any, files: File[], depth: number = 0): Promise<void> {
+            if (depth > 32 || files.length >= 10000) return;
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/BlazorUI/Bit.BlazorUI/Components/Inputs/FileUpload/BitFileUpload.ts`
around lines 388 - 416, Optionally bound the directory traversal in
FileUpload.collectEntry by adding a recursion-depth limit and a maximum
collected-file limit. Propagate the current depth through recursive calls, stop
walking when either limit is reached, and prevent files beyond the maximum from
being added while preserving normal file and directory traversal behavior.
src/BlazorUI/Bit.BlazorUI/Components/Inputs/FileUpload/BitFileUpload.scss (1)

1-1: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Stylelint flags the .scss extension in @import.

scss/load-partial-extension fires on this line. If the rest of the repo keeps the extension, consider disabling the rule instead of touching every file; otherwise drop the extension here.

🎨 Extension-less import
-@import "../../../Styles/functions.scss";
+@import "../../../Styles/functions";
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/BlazorUI/Bit.BlazorUI/Components/Inputs/FileUpload/BitFileUpload.scss` at
line 1, Update the FileUpload stylesheet import to comply with the repository’s
Stylelint convention: either remove the .scss extension from the `@import` path
or, if extensions are intentionally retained across the repository, disable
scss/load-partial-extension for this file or rule configuration. Keep the
referenced functions partial unchanged.

Source: Linters/SAST tools

src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/FileUpload/BitFileUploadDemo.razor (1)

6-9: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Consider splitting the page description into shorter sentences.

Both the PageOutlet Description (used as the meta description, where search engines truncate at ~160 chars) and the DemoPage Description are single ~1000-word run-on blocks. A short lead sentence plus a few sentences would read better and make the meta description usable.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/FileUpload/BitFileUploadDemo.razor`
around lines 6 - 9, Shorten both the PageOutlet Description and DemoPage
Description into concise, readable sentences. Make the PageOutlet text a brief
meta description of roughly 160 characters, and replace the DemoPage run-on
block with a short lead sentence followed by a few focused sentences covering
the primary upload capabilities.
src/BlazorUI/Tests/Bit.BlazorUI.Tests/Components/Inputs/FileUpload/BitFileUploadTests.cs (2)

2673-2680: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

HttpClient/handler are never disposed.

Each SetupHttpClient call leaks a handler for the lifetime of the test context. Registering it so bUnit's container owns disposal (or disposing in cleanup) keeps the suite tidy.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@src/BlazorUI/Tests/Bit.BlazorUI.Tests/Components/Inputs/FileUpload/BitFileUploadTests.cs`
around lines 2673 - 2680, Update SetupHttpClient so the registered HttpClient
and its FakeHttpMessageHandler are owned and disposed by the test context, using
the existing service-registration or cleanup mechanism. Preserve the method’s
current status-code setup and return value while ensuring repeated calls do not
leak resources.

2119-2141: 📐 Maintainability & Code Quality | 🔵 Trivial | 🏗️ Heavy lift

Wall-clock Task.Delay couples these tests to internal timing thresholds.

This test (and Lines 2154, 2445, 2568, plus the 300 ms AutoRetryDelay race at Lines 866-887) depends on real elapsed time exceeding the component's speed-sampling / repaint-throttling windows. On a loaded CI agent the ordering can invert, and the sleeps add seconds to the suite. If the component exposed the sampling interval / a time provider as an injectable seam, these could assert deterministically.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@src/BlazorUI/Tests/Bit.BlazorUI.Tests/Components/Inputs/FileUpload/BitFileUploadTests.cs`
around lines 2119 - 2141, The upload timing tests, including
BitFileUploadShouldMeasureTheSpeedAndTheRemainingTimeOfARunningUpload and the
other referenced cases, rely on wall-clock delays and are flaky. Expose the
component’s speed-sampling, repaint-throttling, and AutoRetryDelay timing
through an injectable interval or time-provider seam, then update the tests to
control and advance that seam deterministically instead of using Task.Delay or
real-time races.
src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/FileUpload/BitFileUploadDemo.razor.cs (2)

1340-1344: 🎯 Functional Correctness | 🔵 Trivial | 💤 Low value

Zero-byte file renders as 100% before it is uploaded.

file.Size == 0 → 100 makes a freshly selected empty file show a full progress bar. The component itself reports 0% for that case until it settles (see BitFileUploadShouldNotReportAnEmptyFileAsUploadedBeforeItIsSent in BitFileUploadTests.cs), so the demo helper reads differently from the built-in view. Guarding only the division would keep them aligned. The same logic is duplicated in the embedded example27CsharpCode (Line 1948-1953).

♻️ Proposed alignment
-        if (file.Size == 0 || file.TotalUploadedSize >= file.Size) return 100;
+        if (file.Size == 0) return file.Status == BitFileUploadStatus.Completed ? 100 : 0;
+
+        if (file.TotalUploadedSize >= file.Size) return 100;
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/FileUpload/BitFileUploadDemo.razor.cs`
around lines 1340 - 1344, Update GetFileUploadPercent so a zero-byte file
returns 0% until upload progress is reported, while preserving the 100% result
for files whose uploaded size reaches or exceeds their total size and avoiding
division by zero. Apply the same logic to the duplicated helper implementation
in example27CsharpCode so both demo paths match the built-in component behavior.

1297-1338: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Drop the now-dead Files null guards.

Files is documented in this same file (Line 1151-1152) as non-null IReadOnlyList<BitFileInfo> defaulting to [], so bitFileUpload.Files?... ?? true and if (bitFileUpload.Files is null) return; can never trigger. Since these snippets are copied by users, the simpler form is worth showing (the embedded example27CsharpCode at Line 1939-1946 carries the same guards).

♻️ Proposed simplification
-    private bool FileUploadIsEmpty() => !bitFileUpload.Files?.Any(f => f.Status != BitFileUploadStatus.Removed) ?? true;
+    private bool FileUploadIsEmpty() => !bitFileUpload.Files.Any(f => f.Status != BitFileUploadStatus.Removed);
@@
-    private async Task HandleUploadOnClick()
-    {
-        if (bitFileUpload.Files is null) return;
-
-        await bitFileUpload.Upload();
-    }
+    private Task HandleUploadOnClick() => bitFileUpload.Upload();
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/FileUpload/BitFileUploadDemo.razor.cs`
around lines 1297 - 1338, Remove the unreachable null guards for the non-null
Files collection: simplify FileUploadIsEmpty to evaluate the collection directly
without ?. or ?? true, and remove the bitFileUpload.Files null-return check from
HandleUploadOnClick while preserving the upload call. Apply the same
simplification to the duplicated example27CsharpCode snippet.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@src/BlazorUI/Bit.BlazorUI/Components/Inputs/FileUpload/BitFileUpload.razor.cs`:
- Around line 1664-1666: The headers conditional in the file upload logic is not
target-typed because it uses var with an empty collection expression. Declare
headers explicitly as Dictionary<string, string> while preserving the existing
null and copied-fileHeaders branches.

In `@src/BlazorUI/Bit.BlazorUI/Components/Inputs/FileUpload/BitFileUpload.ts`:
- Around line 227-238: Update the paste handling in setupDragDrop and onPaste so
paste events are captured from window or document rather than only the
non-focusable dropZoneElement. Accept the clipboard files when the
focused/active target belongs to the upload component or its input, while
preserving the existing allowPaste and disabled checks, then register the
listener on the global target.

---

Nitpick comments:
In `@src/BlazorUI/Bit.BlazorUI/Components/Inputs/FileUpload/BitFileUpload.scss`:
- Line 1: Update the FileUpload stylesheet import to comply with the
repository’s Stylelint convention: either remove the .scss extension from the
`@import` path or, if extensions are intentionally retained across the repository,
disable scss/load-partial-extension for this file or rule configuration. Keep
the referenced functions partial unchanged.

In `@src/BlazorUI/Bit.BlazorUI/Components/Inputs/FileUpload/BitFileUpload.ts`:
- Around line 388-416: Optionally bound the directory traversal in
FileUpload.collectEntry by adding a recursion-depth limit and a maximum
collected-file limit. Propagate the current depth through recursive calls, stop
walking when either limit is reached, and prevent files beyond the maximum from
being added while preserving normal file and directory traversal behavior.

In
`@src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/FileUpload/BitFileUploadDemo.razor`:
- Around line 6-9: Shorten both the PageOutlet Description and DemoPage
Description into concise, readable sentences. Make the PageOutlet text a brief
meta description of roughly 160 characters, and replace the DemoPage run-on
block with a short lead sentence followed by a few focused sentences covering
the primary upload capabilities.

In
`@src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/FileUpload/BitFileUploadDemo.razor.cs`:
- Around line 1340-1344: Update GetFileUploadPercent so a zero-byte file returns
0% until upload progress is reported, while preserving the 100% result for files
whose uploaded size reaches or exceeds their total size and avoiding division by
zero. Apply the same logic to the duplicated helper implementation in
example27CsharpCode so both demo paths match the built-in component behavior.
- Around line 1297-1338: Remove the unreachable null guards for the non-null
Files collection: simplify FileUploadIsEmpty to evaluate the collection directly
without ?. or ?? true, and remove the bitFileUpload.Files null-return check from
HandleUploadOnClick while preserving the upload call. Apply the same
simplification to the duplicated example27CsharpCode snippet.

In
`@src/BlazorUI/Tests/Bit.BlazorUI.Tests/Components/Inputs/FileUpload/BitFileUploadTests.cs`:
- Around line 2673-2680: Update SetupHttpClient so the registered HttpClient and
its FakeHttpMessageHandler are owned and disposed by the test context, using the
existing service-registration or cleanup mechanism. Preserve the method’s
current status-code setup and return value while ensuring repeated calls do not
leak resources.
- Around line 2119-2141: The upload timing tests, including
BitFileUploadShouldMeasureTheSpeedAndTheRemainingTimeOfARunningUpload and the
other referenced cases, rely on wall-clock delays and are flaky. Expose the
component’s speed-sampling, repaint-throttling, and AutoRetryDelay timing
through an injectable interval or time-provider seam, then update the tests to
control and advance that seam deterministically instead of using Task.Delay or
real-time races.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 6779f57b-0544-42ac-82ba-3885a57364f2

📥 Commits

Reviewing files that changed from the base of the PR and between 059e7fa and f78cb36.

📒 Files selected for processing (15)
  • src/BlazorUI/Bit.BlazorUI/Components/Inputs/FileUpload/BitFileInfo.cs
  • src/BlazorUI/Bit.BlazorUI/Components/Inputs/FileUpload/BitFileUpload.razor
  • src/BlazorUI/Bit.BlazorUI/Components/Inputs/FileUpload/BitFileUpload.razor.cs
  • src/BlazorUI/Bit.BlazorUI/Components/Inputs/FileUpload/BitFileUpload.scss
  • src/BlazorUI/Bit.BlazorUI/Components/Inputs/FileUpload/BitFileUpload.ts
  • src/BlazorUI/Bit.BlazorUI/Components/Inputs/FileUpload/BitFileUploadClassStyles.cs
  • src/BlazorUI/Bit.BlazorUI/Components/Inputs/FileUpload/BitFileUploadJsRuntimeExtensions.cs
  • src/BlazorUI/Bit.BlazorUI/Components/Inputs/FileUpload/BitFileUploadStatus.cs
  • src/BlazorUI/Bit.BlazorUI/Components/Inputs/FileUpload/_BitFileUploadItem.razor
  • src/BlazorUI/Bit.BlazorUI/Components/Inputs/FileUpload/_BitFileUploadItem.razor.cs
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/FileUpload/BitFileUploadDemo.razor
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/FileUpload/BitFileUploadDemo.razor.cs
  • src/BlazorUI/Demo/Client/Bit.BlazorUI.Demo.Client.Core/Pages/Components/Inputs/FileUpload/BitFileUploadDemo.razor.scss
  • src/BlazorUI/Tests/Bit.BlazorUI.Tests/Components/Inputs/FileUpload/BitFileUploadTests.cs
  • src/BlazorUI/Tests/Bit.BlazorUI.Tests/Utils/Theme/component-css-variables.md

Comment on lines +1664 to +1666
var headers = fileHeaders is null
? []
: new Dictionary<string, string>(fileHeaders);

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

🧩 Analysis chain

🌐 Web query:

C# conditional expression collection expression [] assigned to var CS0173 error

💡 Result:

The CS0173 error occurs when using a collection expression (e.g., [1][2]) within a conditional (ternary) operator assigned to a variable declared with 'var' because the compiler cannot infer a definitive type for the expression [1][2][3]. When you use 'var', there is no explicit target type to guide the compiler's type inference [1][4]. Because collection expressions are target-typed—meaning their type is determined by the variable or parameter they are assigned to—using them in a conditional expression without an explicit type leaves the compiler unable to resolve a common type between the two branches [1][5]. This frequently manifests when using spread operators (e.g.,.. condition? [...]: []) inside collection literals, where the compiler fails to propagate the outer collection's type to the inner ternary expression [2][3]. To resolve this issue, use one of the following approaches: 1. Explicitly specify the variable type: Instead of 'var', declare the variable with the concrete collection type [1]. // Change this: var list = condition? [1][2]: [4][3]; // To this: List list = condition? [1][2]: [4][3]; 2. Explicitly cast one or both branches: If you must use 'var', cast the expressions to the desired type so the compiler can determine a common type [1][6]. var list = condition? (IEnumerable)[1][2]: [4][3]; This error is a known limitation when the compiler lacks sufficient context to perform target-typing, especially in nested or implicitly typed scenarios [2][3]. In some cases, such as IDE suggestions for collection simplification, this behavior has been tracked and addressed in updates to the.NET SDK and Roslyn compiler [7].

Citations:


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== Candidate file =="
fd -a 'BitFileUpload\.razor\.cs$' . || true

echo "== Project files nearby =="
git ls-files | rg '(^|/)([^/]+\.csproj|Directory\.Build\.props|Directory\.Build\.targets)$' | head -100

echo "== File snippet and surrounding headers =="
file=$(fd 'BitFileUpload\.razor\.cs$' . | head -n1 || true)
if [ -n "${file:-}" ]; then
  wc -l "$file"
  sed -n '1630,1685p' "$file" | cat -n | sed "s/^/$file:/"
fi

echo "== Project files with target frameworks/SDKs =="
for f in $(git ls-files | rg '(^|/)([^/]+\.csproj|Directory\.Build\.props|Directory\.Build\.targets)$'); do
  if rg -q 'net8|net9|LangVersion|ImplicitUsings|TargetFramework|TargetFrameworks' "$f"; then
    echo "-- $f --"
    sed -n '1,120p' "$f"
  fi
done

echo "== Deterministic source probe for exact expression pattern =="
python3 - <<'PY'
from pathlib import Path
pats = [
    "var headers = fileHeaders is null ? [] : new Dictionary<string, string>(fileHeaders);",
    "var headers = fileHeaders is null\n                        ? []\n                        : new Dictionary<string, string>(fileHeaders);",
]
for p in pats:
    print("exact:", p in pathlib.Path("src/BlazorUI/Bit.BlazorUI/Components/Inputs/FileUpload/BitFileUpload.razor.cs").read_text() if pathlib.Path("src/BlazorUI/Bit.BlazorUI/Components/Inputs/FileUpload/BitFileUpload.razor.cs").exists() else "missing")
PY

Repository: bitfoundation/bitplatform

Length of output: 6076


🌐 Web query:

C# CS0176 ambiguous conversion conditional expression var collection expression [] CS9176 implicit type 'var' cannot be used in target-typed conversion in conditional expression

💡 Result:

The compiler errors you are encountering relate to two distinct features in C#: static member access and collection expressions. CS0176: Static member cannot be accessed with an instance reference This error occurs when you attempt to access a static member (method, property, or field) using an instance of a class rather than the class name itself [1][2][3]. Fix: Qualify the static member with the name of the class where it is defined [1][2]. Example: // Incorrect var instance = new MyClass; int val = instance.MyStaticMember; // Triggers CS0176 // Correct int val = MyClass.MyStaticMember; // Correct usage CS9176: There is no target type for the collection expression This error occurs because C# collection expressions (e.g., [1][2][3]) are target-typed, meaning they do not have a natural type on their own [4][5][6]. They require a specific destination type to be inferred by the compiler [4][7]. Because of this, you cannot assign a collection expression to a variable declared with 'var' [5][6][7]. Fix: Explicitly declare the type of the variable instead of using 'var' [5][6][7]. Example: // Incorrect var myCollection = [1][2][3]; // Triggers CS9176 // Correct int[] myCollection = [1][2][3]; // Explicit type provided List myOtherCollection = [1][2][3]; // Works with other compatible types Note: If you were attempting to use a conditional expression (ternary operator) involving 'var' and target-typed conversions, ensure that both branches of the conditional operator are explicitly typed or compatible with the target type, as 'var' cannot be used when the compiler cannot infer a common natural type for the expression [4][8][9].

Citations:


🏁 Script executed:

#!/bin/bash
set -euo pipefail

file=$(fd 'BitFileUpload\.razor\.cs$' . | head -n1 || true)
echo "== $file line count and relevant snippet =="
if [ -n "${file:-}" ]; then
  wc -l "$file"
  sed -n '1645,1675p' "$file" | cat -n
fi

echo "== Direct project LangVersion/TargetFramework info =="
sed -n '1,120p' src/BlazorUI/Bit.BlazorUI/Bit.BlazorUI.csproj
if [ -f src/BlazorUI/Directory.Build.props ]; then
  sed -n '1,120p' src/BlazorUI/Directory.Build.props
else
  sed -n '1,120p' Directory.Build.props
fi
git ls-files Directory.Build.props src/Directory.Build.props | while read -r f; do
  echo "-- $f --"
  sed -n '1,120p' "$f"
done

echo "== Relevant exact identifiers in source =="
rg -n "var headers = fileHeaders is null|fileHeaders is null \\? \\[\\]|Dicti|C#|csharp" src/BlazorUI/Bit.BlazorUI/Bit.BlazorUI.csproj src/BlazorUI/Directory.Build.props src/Directory.Build.props Directory.Build.props src/BlazorUI/Bit.BlazorUI/Components/Inputs/FileUpload/BitFileUpload.razor.cs 2>/dev/null || true

Repository: bitfoundation/bitplatform

Length of output: 8880


🏁 Script executed:

#!/bin/bash
set -euo pipefail

for f in $(git ls-files | rg '(^|/)Bit\.Build\.props$'); do
  echo "-- $f --"
  sed -n '1,160p' "$f"
done

echo "== C# conditional collection-expression var probe (if dotnet is available) =="
if command -v dotnet >/dev/null 2>&1; then
  tmp="$(mktemp -d)"
  cat > "$tmp/Probe.csproj" <<'XML'
<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFrameworks>net8.0;net9.0;net10.0</TargetFrameworks>
    <OutputType>Library</OutputType>
    <ImplicitUsings>disable</ImplicitUsings>
  </PropertyGroup>
</Project>
XML
  cat > "$tmp/Probe.cs" <<'CS'
class Probe
{
    static System.Collections.Generic.Dictionary<string, string>? Get(System.Collections.Generic.IReadOnlyDictionary<string, string>? fileHeaders = null)
    {
        var headers = fileHeaders is null
                        ? []
                        : new System.Collections.Generic.Dictionary<string, string>(fileHeaders);
        return null;
    }
}
CS

  dotnet build "$tmp/Probe.csproj"
else
  echo "dotnet command not available"
fi

Repository: bitfoundation/bitplatform

Length of output: 3803


Make the conditional collection expression target-typed.

This runs under <LangVersion>preview</LangVersion> with net8.0/net9.0/net10.0; the [] branch has no natural type while var leaves the ternary without a target type. Declare headers as Dictionary<string, string> or cast one branch so the compiler can resolve the collection expression.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@src/BlazorUI/Bit.BlazorUI/Components/Inputs/FileUpload/BitFileUpload.razor.cs`
around lines 1664 - 1666, The headers conditional in the file upload logic is
not target-typed because it uses var with an empty collection expression.
Declare headers explicitly as Dictionary<string, string> while preserving the
existing null and copied-fileHeaders branches.

Comment on lines 227 to 238
function onPaste(e: ClipboardEvent) {
inputElement.files = e.clipboardData!.files;
const event = new Event('change', { bubbles: true });
inputElement.dispatchEvent(event);
if (!allowPaste || inputElement.disabled) return;
if (!e.clipboardData || e.clipboardData.files.length === 0) return;

setFiles(e.clipboardData.files);
}

dropZoneElement.addEventListener("dragenter", onDragHover);
dropZoneElement.addEventListener("dragover", onDragHover);
dropZoneElement.addEventListener("dragenter", onDragEnter);
dropZoneElement.addEventListener("dragover", onDragOver);
dropZoneElement.addEventListener("dragleave", onDragLeave);
dropZoneElement.addEventListener("drop", onDrop);
dropZoneElement.addEventListener('paste', onPaste);

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

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
fd -H 'BitFileUpload.razor$' --exec cat -n {}

Repository: bitfoundation/bitplatform

Length of output: 3751


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Locate and inspect FileUpload TS/JS without executing repository code.
fd -H 'BitFileUpload\.(ts|js)$' --exec sh -c '
  echo "===== $1 ====="
  wc -l "$1"
  sed -n "1,120p" "$1" | cat -n
  sed -n "180,260p" "$1" | cat -n
' sh {}

# Search for focus/tabindex/contenteditable drop-zone references in FileUpload component files.
echo "===== focused search ====="
rg -n "dropZone|addPointerFocus|focusable|tabindex|contenteditable|allowPaste|paste" src/BlazorUI/Bit.BlazorUI/Components/Inputs/FileUpload || true

Repository: bitfoundation/bitplatform

Length of output: 16824


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "===== JSRuntime extension call ====="
sed -n '55,75p' src/BlazorUI/Bit.BlazorUI/Components/Inputs/FileUpload/BitFileUploadJsRuntimeExtensions.cs | cat -n

echo "===== C# setup/update/cleanup area ====="
sed -n '1120,1215p' src/BlazorUI/Bit.BlazorUI/Components/Inputs/FileUpload/BitFileUpload.razor.cs | cat -n
sed -n '2048,2073p' src/BlazorUI/Bit.BlazorUI/Components/Inputs/FileUpload/BitFileUpload.razor.cs | cat -n

echo "===== behavioral probe for paste target based on same DOM shape ====="
python3 - <<'PY'
from pathlib import Path
razor = Path('src/BlazorUI/Bit.BlazorUI/Components/Inputs/FileUpload/BitFileUpload.razor').read_text()
for target in ['dropZoneElement', 'RootElement', 'inputElement']:
    print(f"{target}: event listener attached in setupDragDrop? True" if target == "dropZoneElement" or target == "inputElement" else f"{target}: N/A")
lines = razor.splitlines()
# Print element attributes around RootElement/input.
for i, line in enumerate(lines):
    if '`@ref`="RootElement"' in line or '`@ref`="_inputRef"' in line or 'tabindex' in line or 'contenteditable' in line:
        print(f"line {i+1}: {line.strip()}")
PY

Repository: bitfoundation/bitplatform

Length of output: 6974


Make paste work without requiring focus on the drop zone.

setupDragDrop attaches the paste listener to dropZoneElement, but BitFileUpload.razor passes RootElement and that markup is a plain non-focusable div; a paste to the hidden file input is not gated by !e.clipboardData.files.length or inputElement.disabled. Attach paste to window/document and fire setFiles when the active element is the upload component / input, or make this work from the actual focused target rather than assuming the drop zone receives the event.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/BlazorUI/Bit.BlazorUI/Components/Inputs/FileUpload/BitFileUpload.ts`
around lines 227 - 238, Update the paste handling in setupDragDrop and onPaste
so paste events are captured from window or document rather than only the
non-focusable dropZoneElement. Accept the clipboard files when the
focused/active target belongs to the upload component or its input, while
preserving the existing allowPaste and disabled checks, then register the
listener on the global target.

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.

The BitFileUpload improvements

1 participant