-
Notifications
You must be signed in to change notification settings - Fork 29
Initial implementation of File Storage binding and UI #2106
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
Release OptionsShould a new version be published when this PR is merged? React with an emoji to vote on the release type:
Current version: Deployment
|
089866b to
70aeb04
Compare
ced1f65 to
a017c0f
Compare
a017c0f to
e4bad96
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
5 issues found across 23 files
Prompt for AI agents (all issues)
Check if these issues are valid — if so, understand the root cause of each and fix them.
<file name="apps/mesh/src/web/components/details/connection/collection-tab.tsx">
<violation number="1" location="apps/mesh/src/web/components/details/connection/collection-tab.tsx:245">
P1: Using `file.name` as the unique identifier is problematic. Multiple files with the same name can be uploaded, causing: (1) duplicate React keys, and (2) incorrect state updates where all files with matching names get updated together. Consider adding a unique ID (e.g., `crypto.randomUUID()`) to each upload entry.</violation>
<violation number="2" location="apps/mesh/src/web/components/details/connection/collection-tab.tsx:289">
P2: Significant code duplication between `handleFileDrop` and `handleFileInputChange`. Both functions share nearly identical upload logic (~35 lines). Consider extracting the shared logic into a reusable `processFileUploads(files: File[])` function.</violation>
</file>
<file name="apps/mesh/src/web/components/files/file-browser.tsx">
<violation number="1" location="apps/mesh/src/web/components/files/file-browser.tsx:106">
P2: Using folder name as React key can cause collisions for paths with duplicate folder names (e.g., `/data/archive/data/`). Use `index` as the key since breadcrumb order is stable and items aren't reordered.</violation>
</file>
<file name="apps/mesh/src/web/hooks/use-file-storage.ts">
<violation number="1" location="apps/mesh/src/web/hooks/use-file-storage.ts:157">
P2: The `invalidateFileQueries` helper function exists but is not used in `useFileUpload`. This duplicates the query invalidation logic. Use the helper function for consistency and maintainability.</violation>
</file>
<file name="apps/mesh/src/web/components/files/text-editor.tsx">
<violation number="1" location="apps/mesh/src/web/components/files/text-editor.tsx:100">
P2: State initialized from `initialContent` prop won't update if the prop changes (e.g., when switching files). Consider adding a `useEffect` to reset state when `initialContent` changes, or ensure the parent uses a `key` prop to force remount.</violation>
</file>
Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.
| ) : null; | ||
|
|
||
| // Handle file uploads from button click | ||
| const handleFileInputChange = async (files: FileList | null) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
P2: Significant code duplication between handleFileDrop and handleFileInputChange. Both functions share nearly identical upload logic (~35 lines). Consider extracting the shared logic into a reusable processFileUploads(files: File[]) function.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/mesh/src/web/components/details/connection/collection-tab.tsx, line 289:
<comment>Significant code duplication between `handleFileDrop` and `handleFileInputChange`. Both functions share nearly identical upload logic (~35 lines). Consider extracting the shared logic into a reusable `processFileUploads(files: File[])` function.</comment>
<file context>
@@ -195,6 +285,78 @@ export function CollectionTab({
) : null;
+ // Handle file uploads from button click
+ const handleFileInputChange = async (files: FileList | null) => {
+ if (!files || files.length === 0) return;
+
</file context>
|
|
||
| // Add files to uploading state | ||
| const newUploads = files.map((f) => ({ | ||
| name: f.name, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
P1: Using file.name as the unique identifier is problematic. Multiple files with the same name can be uploaded, causing: (1) duplicate React keys, and (2) incorrect state updates where all files with matching names get updated together. Consider adding a unique ID (e.g., crypto.randomUUID()) to each upload entry.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/mesh/src/web/components/details/connection/collection-tab.tsx, line 245:
<comment>Using `file.name` as the unique identifier is problematic. Multiple files with the same name can be uploaded, causing: (1) duplicate React keys, and (2) incorrect state updates where all files with matching names get updated together. Consider adding a unique ID (e.g., `crypto.randomUUID()`) to each upload entry.</comment>
<file context>
@@ -183,6 +209,70 @@ export function CollectionTab({
+
+ // Add files to uploading state
+ const newUploads = files.map((f) => ({
+ name: f.name,
+ status: "uploading" as const,
+ }));
</file context>
| > | ||
| / | ||
| </button> | ||
| {breadcrumbParts.map((part, index) => ( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
P2: Using folder name as React key can cause collisions for paths with duplicate folder names (e.g., /data/archive/data/). Use index as the key since breadcrumb order is stable and items aren't reordered.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/mesh/src/web/components/files/file-browser.tsx, line 106:
<comment>Using folder name as React key can cause collisions for paths with duplicate folder names (e.g., `/data/archive/data/`). Use `index` as the key since breadcrumb order is stable and items aren't reordered.</comment>
<file context>
@@ -0,0 +1,174 @@
+ >
+ /
+ </button>
+ {breadcrumbParts.map((part, index) => (
+ <span key={part} className="flex items-center gap-1">
+ <span className="text-muted-foreground">/</span>
</file context>
|
|
||
| return result as { file: FileEntity }; | ||
| }, | ||
| onSuccess: () => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
P2: The invalidateFileQueries helper function exists but is not used in useFileUpload. This duplicates the query invalidation logic. Use the helper function for consistency and maintainability.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/mesh/src/web/hooks/use-file-storage.ts, line 157:
<comment>The `invalidateFileQueries` helper function exists but is not used in `useFileUpload`. This duplicates the query invalidation logic. Use the helper function for consistency and maintainability.</comment>
<file context>
@@ -0,0 +1,287 @@
+
+ return result as { file: FileEntity };
+ },
+ onSuccess: () => {
+ // Invalidate file lists to refresh
+ queryClient.invalidateQueries({
</file context>
| initialContent, | ||
| className, | ||
| }: TextEditorProps) { | ||
| const [content, setContent] = useState(initialContent); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
P2: State initialized from initialContent prop won't update if the prop changes (e.g., when switching files). Consider adding a useEffect to reset state when initialContent changes, or ensure the parent uses a key prop to force remount.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/mesh/src/web/components/files/text-editor.tsx, line 100:
<comment>State initialized from `initialContent` prop won't update if the prop changes (e.g., when switching files). Consider adding a `useEffect` to reset state when `initialContent` changes, or ensure the parent uses a `key` prop to force remount.</comment>
<file context>
@@ -0,0 +1,196 @@
+ initialContent,
+ className,
+}: TextEditorProps) {
+ const [content, setContent] = useState(initialContent);
+ const [hasChanges, setHasChanges] = useState(false);
+ const fileMutations = useFileMutations(connectionId);
</file context>
338d152 to
84ea598
Compare
What is this contribution about?
Screenshots/Demonstration
Review Checklist
Summary by cubic
Adds first-class file storage with a local filesystem provider, MCP tools, and a simple file browser/preview with drag‑and‑drop uploads and a basic text editor. Enables reading, writing, and managing files via the FILE_STORAGE_BINDING, and supports uploading files directly from chat.
New Features
Migration
Written for commit 84ea598. Summary will update on new commits.