-
Notifications
You must be signed in to change notification settings - Fork 7k
feat: Add DirectoryInput component with file system directory picker #8389
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
WalkthroughA new directory input type is introduced across the backend and frontend. Backend changes add the Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant DirectoryComponent (Frontend)
participant createDirectoryUpload (Helper)
participant Backend API
User->>DirectoryComponent (Frontend): Clicks directory picker button
DirectoryComponent (Frontend)->>createDirectoryUpload (Helper): Invoke directory picker
createDirectoryUpload (Helper)-->>User: Show directory picker dialog
User-->>createDirectoryUpload (Helper): Selects directory or cancels
createDirectoryUpload (Helper)-->>DirectoryComponent (Frontend): Return selected directory path or ""
DirectoryComponent (Frontend)-->>Backend API: (On submit) Send directory path as input
Backend API-->>DirectoryComponent (Frontend): (Optional) Responds with results
sequenceDiagram
participant DirectoryComponent (Backend)
participant DirectoryInput (Backend Input Class)
participant FieldTypes Enum
participant Constants
DirectoryComponent (Backend)->>DirectoryInput (Backend Input Class): Uses as input for "path"
DirectoryInput (Backend Input Class)->>FieldTypes Enum: Sets field_type to DIRECTORY
DirectoryInput (Backend Input Class)->>Constants: "directory" included in DIRECT_TYPES
📜 Recent review detailsConfiguration used: CodeRabbit UI 📒 Files selected for processing (1)
🚧 Files skipped from review as they are similar to previous changes (1)
⏰ Context from checks skipped due to timeout of 90000ms (4)
✨ Finishing Touches
🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
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.
Actionable comments posted: 2
🧹 Nitpick comments (3)
src/frontend/src/components/core/parameterRenderComponent/components/directoryComponent/index.tsx (1)
15-27
: Remove console.log and consider user experience implications.The async directory picker handler is well-implemented with proper error handling and disabled state checking. However, remove the console.log statement for production code.
- console.log("selectedDirectory", selectedDirectory);
Also consider that the
createDirectoryUpload
helper only returns directory names or relative paths (not absolute paths), which may not align with user expectations for a directory path input.src/frontend/src/helpers/create-directory-upload.ts (2)
6-17
: Improve type safety for the File System Access API.The current implementation uses
(window as any)
which bypasses TypeScript's type checking.Consider adding proper type definitions or a more specific type guard:
- if ("showDirectoryPicker" in window) { - try { - const dirHandle = await (window as any).showDirectoryPicker(); + if ("showDirectoryPicker" in window && typeof (window as any).showDirectoryPicker === 'function') { + try { + const dirHandle = await (window as any).showDirectoryPicker();
83-91
: Consider increasing the focus handler timeout.The 100ms timeout in the focus handler might be too short and could trigger false positives when users take a moment to interact with the directory picker dialog.
Consider increasing the timeout to allow for normal user interaction:
setTimeout(() => { if (!isHandled) { isHandled = true; cleanup(); resolve(""); } - }, 100); + }, 500); // Give users more time to interact with the dialog
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (9)
src/backend/base/langflow/components/data/directory.py
(2 hunks)src/backend/base/langflow/inputs/__init__.py
(2 hunks)src/backend/base/langflow/inputs/input_mixin.py
(1 hunks)src/backend/base/langflow/inputs/inputs.py
(2 hunks)src/backend/base/langflow/io/__init__.py
(2 hunks)src/backend/base/langflow/utils/constants.py
(1 hunks)src/frontend/src/components/core/parameterRenderComponent/components/directoryComponent/index.tsx
(1 hunks)src/frontend/src/components/core/parameterRenderComponent/index.tsx
(2 hunks)src/frontend/src/helpers/create-directory-upload.ts
(1 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (4)
src/backend/base/langflow/io/__init__.py (1)
src/backend/base/langflow/inputs/inputs.py (1)
DirectoryInput
(625-635)
src/backend/base/langflow/inputs/__init__.py (1)
src/backend/base/langflow/inputs/inputs.py (1)
DirectoryInput
(625-635)
src/frontend/src/components/core/parameterRenderComponent/components/directoryComponent/index.tsx (2)
src/frontend/src/helpers/create-directory-upload.ts (1)
createDirectoryUpload
(3-112)src/frontend/src/utils/utils.ts (1)
cn
(36-38)
src/frontend/src/helpers/create-directory-upload.ts (1)
src/frontend/src/constants/constants.ts (1)
DEFAULT_FILE_PICKER_TIMEOUT
(1075-1075)
🪛 Biome (1.9.4)
src/frontend/src/helpers/create-directory-upload.ts
[error] 4-111: Promise executor functions should not be async
.
(lint/suspicious/noAsyncPromiseExecutor)
⏰ Context from checks skipped due to timeout of 90000ms (5)
- GitHub Check: Optimize new Python code in this PR
- GitHub Check: Run Ruff Check and Format
- GitHub Check: Update Starter Projects
- GitHub Check: Ruff Style Check (3.13)
- GitHub Check: autofix
🔇 Additional comments (16)
src/backend/base/langflow/utils/constants.py (1)
65-65
: LGTM! Correct addition of directory type.The addition of "directory" to
DIRECT_TYPES
is properly placed and aligns with the newDirectoryInput
class being introduced across the codebase.src/backend/base/langflow/inputs/input_mixin.py (1)
31-31
: LGTM! Proper enum extension.The addition of
DIRECTORY = "directory"
follows the established pattern and correctly extends theFieldTypes
enum to support the new directory input type.src/backend/base/langflow/io/__init__.py (1)
9-9
: LGTM! Correct public API integration.The addition of
DirectoryInput
to both the import statement and__all__
list properly exposes the new directory input class as part of the public API, following the established pattern for other input types.Also applies to: 41-41
src/frontend/src/components/core/parameterRenderComponent/index.tsx (2)
13-13
: LGTM! Proper import addition.The import of
DirectoryComponent
is correctly placed and follows the established pattern for other parameter render components.
185-188
: LGTM! Consistent switch case implementation.The addition of the "directory" case follows the exact pattern used for other input types, correctly rendering the
DirectoryComponent
with standardbaseInputProps
and an appropriately prefixed id.src/backend/base/langflow/inputs/__init__.py (1)
9-9
: LGTM! Proper integration of DirectoryInput into the public API.The import and export additions follow the established pattern for input types and correctly make DirectoryInput available for use throughout the codebase.
Also applies to: 44-44
src/backend/base/langflow/inputs/inputs.py (2)
625-635
: LGTM! Well-implemented DirectoryInput class.The class follows the established pattern for input types with appropriate inheritance from BaseInputMixin, MetadataTraceMixin, and ToolModeMixin. The docstring is clear and the field_type is correctly set to FieldTypes.DIRECTORY.
672-672
: LGTM! Proper type union integration.Adding DirectoryInput to the InputTypes union is necessary for proper type checking and ensures the new input type is recognized throughout the system.
src/frontend/src/components/core/parameterRenderComponent/components/directoryComponent/index.tsx (2)
35-51
: Well-designed text input with helpful placeholder.The manual text input provides good fallback functionality and the placeholder text clearly guides users on the expected format. The conditional styling and accessibility attributes are properly implemented.
54-79
: Excellent button implementation with clear user guidance.The button component is well-designed with:
- Proper conditional styling based on value and disabled state
- Clear visual feedback with icon changes (Folder → CircleCheckBig)
- Helpful title text that explains the limitation of the directory picker
- Good accessibility with data-testid and proper button attributes
The title text effectively manages user expectations about the picker's limitations.
src/frontend/src/helpers/create-directory-upload.ts (6)
1-2
: LGTM!The import statement is clean and follows proper ES6 import syntax.
32-42
: LGTM! Good cleanup implementation.The cleanup function properly handles element removal and event listener cleanup with appropriate error handling.
44-81
: LGTM! Solid path extraction logic.The change handler correctly extracts the directory path from
webkitRelativePath
and handles edge cases appropriately. The logging is helpful for debugging.
93-102
: LGTM! Proper event setup and timing.The use of
requestAnimationFrame
ensures the input is properly rendered before triggering the click event.
104-110
: LGTM! Appropriate timeout handling.The timeout implementation using the imported constant provides a reasonable fallback for cases where the user doesn't interact with the picker.
27-28
:✅ Verification successful
Verify webkitdirectory compatibility with multiple=false.
When using
webkitdirectory
, browsers typically expectmultiple=true
to allow selecting all files within a directory. Settingmultiple=false
might prevent proper directory selection in some browsers.Please verify that directory selection works correctly with
multiple=false
across different browsers, or consider changing to:- input.multiple = false; // Only single directory selection + input.multiple = true; // Required for webkitdirectoryRun this script to check browser compatibility documentation:
🌐 Web query:
Does webkitdirectory attribute work with multiple=false in modern browsers?
💡 Result:
Does
webkitdirectory
Attribute Work withmultiple=false
in Modern Browsers?Summary:
Thewebkitdirectory
attribute allows users to select entire directories through a file input. In modern desktop browsers (Chrome, Firefox, Edge, Safari, Opera), the attribute works regardless of whether themultiple
attribute is set totrue
orfalse
—but its behavior is subtly different depending on the presence ofmultiple
.
Detailed Behavior and Compatibility:
What
webkitdirectory
Does:
Adding thewebkitdirectory
attribute to an<input type="file">
element enables directory selection instead of limiting users to single file selection. When a directory is chosen, all files within that directory and its subdirectories are included in the file list, with their paths preserved via thewebkitRelativePath
property[1][3][7].Interaction with
multiple
:
- If you use
<input type="file" webkitdirectory multiple>
, the user experience generally mirrors that of<input type="file" webkitdirectory>
, because directory selection inherently means selecting multiple files (all files inside the chosen directory)[1][3][9].- If you omit
multiple
—that is,<input type="file" webkitdirectory>
—the user can still only pick one directory per dialog interaction, but all the files inside that directory (and subdirectories) are included.- Setting
multiple=false
(or leaving it unset, which is the default) doesn’t prevent multiple files from being selected ifwebkitdirectory
is present, because selecting a directory by definition includes all its files[1][3][9].Browser Compatibility:
Modern versions of Chrome, Firefox, Edge, Safari, and Opera on desktop fully support thewebkitdirectory
attribute, both with and withoutmultiple
. On mobile browsers, support is absent or inconsistent[6].Practical Implications:
- The presence of
multiple
is ignored for the directory picker use case: users can only select one directory per dialog, and all files within it become part of the input'sfiles
list, regardless of themultiple
attribute.- You cannot select more than one directory in a single operation, even if
multiple
is set[1][9].- You cannot use
webkitdirectory
to select a mix of individual files and directories in the same dialog[8].Reference Example (MDN):
The webkitdirectory Boolean attribute, if present, indicates that only directories should be available to be selected by the user in the file picker interface.
...
When a directory is selected, the directory and its entire hierarchy of contents are included in the set of selected items.
...
<input type="file" id="file-picker" name="fileList" webkitdirectory multiple />
After the user makes a selection, each File object in files has its File.webkitRelativePath property set to the relative path within the selected directory at which the file is located[1][3][7].
Conclusion
Yes, the
webkitdirectory
attribute works withmultiple=false
(or withmultiple
omitted) in modern desktop browsers.
- Users can pick a single directory per interaction, and all contained files are included in the selection.
multiple
does not alter this behavior for directory selection.- The attribute is widely supported on desktop browsers but not on mobile[1][3][6][9].
Citations:
- 1: https://developer.mozilla.org/en-US/docs/Web/API/HTMLInputElement/webkitdirectory
- 2: sveltejs/svelte#7872
- 3: https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/input/file
- 4: WICG/directory-upload#29
- 5: https://www.smashingmagazine.com/2017/09/uploading-directories-with-webkitdirectory/
- 6: https://www.lambdatest.com/web-technologies/input-file-directory
- 7: https://developer.mozilla.org/en-US/docs/Web/API/File/webkitRelativePath
- 8: https://issues.chromium.org/41246097
- 9: https://wicg.github.io/entries-api/
- 10: https://issues.chromium.org/issues/41210938
No change needed for
multiple=false
withwebkitdirectory
.Modern desktop browsers (Chrome, Firefox, Edge, Safari, Opera) fully support directory selection via
webkitdirectory
regardless of themultiple
attribute. Even withmultiple=false
(or omitted), users can pick one directory per dialog and all contained files are included in thefiles
list. There’s no need to setmultiple=true
.
@@ -1,6 +1,6 @@ | |||
from langflow.base.data.utils import TEXT_FILE_TYPES, parallel_load_data, parse_text_file_to_data, retrieve_file_paths | |||
from langflow.custom import Component | |||
from langflow.io import BoolInput, IntInput, MessageTextInput, MultiselectInput | |||
from langflow.io import BoolInput, DirectoryInput, IntInput, MultiselectInput |
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.
🛠️ Refactor suggestion
Good transition to DirectoryInput, but reconsider the default value.
The import change and switch to DirectoryInput is appropriate for a directory-specific component. However, changing the default value from "."
to ""
removes a useful default that represents the current directory.
Consider reverting the default value:
- value="",
+ value=".",
The current directory "."
is a conventional and practical default that gives users a starting point, while an empty string provides no guidance.
Also applies to: 16-22
🤖 Prompt for AI Agents
In src/backend/base/langflow/components/data/directory.py around lines 3 and 16
to 22, the default value for DirectoryInput was changed from "." to an empty
string "". Revert this change by setting the default value back to ".", which is
a conventional and practical default representing the current directory and
provides a useful starting point for users.
export const createDirectoryUpload = (): Promise<string> => { | ||
return new Promise(async (resolve) => { |
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.
Fix the async Promise executor anti-pattern.
Using async
in a Promise executor is an anti-pattern that can lead to unhandled promise rejections. If the async function throws an error, it won't be properly caught by the Promise.
Apply this diff to fix the issue:
-export const createDirectoryUpload = (): Promise<string> => {
- return new Promise(async (resolve) => {
+export const createDirectoryUpload = async (): Promise<string> => {
+ return new Promise((resolve) => {
Then wrap the modern API call in an IIFE:
// Try modern File System Access API first (if available)
if ("showDirectoryPicker" in window) {
- try {
- const dirHandle = await (window as any).showDirectoryPicker();
- resolve(dirHandle.name);
- return;
- } catch (error) {
+ (async () => {
+ try {
+ const dirHandle = await (window as any).showDirectoryPicker();
+ resolve(dirHandle.name);
+ return;
+ } catch (error) {
+ // User cancelled or API not supported, fall back to input method
+ console.log(
+ "Directory picker cancelled or not supported, falling back to input method",
+ );
+ // Continue to fallback method
+ }
+ })();
+ return;
+ }
📝 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.
export const createDirectoryUpload = (): Promise<string> => { | |
return new Promise(async (resolve) => { | |
export const createDirectoryUpload = async (): Promise<string> => { | |
return new Promise((resolve) => { | |
// Try modern File System Access API first (if available) | |
if ("showDirectoryPicker" in window) { | |
(async () => { | |
try { | |
const dirHandle = await (window as any).showDirectoryPicker(); | |
resolve(dirHandle.name); | |
return; | |
} catch (error) { | |
// User cancelled or API not supported, fall back to input method | |
console.log( | |
"Directory picker cancelled or not supported, falling back to input method", | |
); | |
// Continue to fallback method | |
} | |
})(); | |
return; | |
} | |
// Fallback: prompt file input for directory selection | |
const input = document.createElement("input"); | |
input.type = "file"; | |
(input as any).webkitdirectory = true; | |
input.onchange = () => { | |
const files = Array.from(input.files || []); | |
if (files.length > 0) { | |
resolve(files[0].webkitRelativePath.split("/")[0]); | |
} else { | |
resolve(""); | |
} | |
}; | |
input.click(); | |
}); | |
}; |
🤖 Prompt for AI Agents
In src/frontend/src/helpers/create-directory-upload.ts at lines 3 to 4, the
Promise executor function is marked async, which is an anti-pattern and can
cause unhandled promise rejections. To fix this, remove the async keyword from
the Promise executor and instead wrap the asynchronous code inside an
immediately invoked async function expression (IIFE) within the executor. This
ensures proper error handling and avoids the anti-pattern.
Tip For best results, initiate chat on the files or code changes. @deon-sanchez Hello! I'm here to help with your PR. Since you mentioned me without a specific request, here are some ways I can assist you with this directory input feature: Code Review & Analysis:
Documentation & Testing:
Architecture & Improvements:
General:
What would you like me to help you with regarding this directory input implementation? |
@coderabbitai can you update my title |
Tip For best results, initiate chat on the files or code changes. 🧩 Analysis chain@deon-sanchez I'll update your PR title to be more descriptive of the changes you've implemented. 🏁 Script executed:
Length of output: 146 @deon-sanchez Perfect! I've successfully updated your PR title from "LFOSS-1255" to "feat: Add DirectoryInput component with file system directory picker". This new title better describes what your PR accomplishes:
The title now clearly communicates that this PR introduces a new way for users to select directories through a proper file system picker interface, rather than manually typing paths. 🐰 |
Summary by CodeRabbit
New Features
Bug Fixes
Style