fix: enhance file upload handling and UI interactions#1326
Conversation
…resource-type-form, use-file-upload): enhance file upload handling and UI interactions - Added tooltips for better user guidance in the ResourceUpload component. - Updated file refresh logic to include resource types in WorkflowRunForm and CreateVariablesModal. - Simplified file validation and upload process in useFileUpload, ensuring better error handling and user feedback. - Improved UI messages for duplicate file names and file size limits. - Ensured consistent use of optional chaining and nullish coalescing for safer property access.
WalkthroughAdds toolstore/tool-install signature and UI changes, refactors file upload/refresh flow to accept resourceTypes and dynamic accept attributes, wraps a refresh Button with a Tooltip, removes an Empty-state branch from workflow-run, tweaks several UI labels, and adds four i18n keys. Changes
Sequence Diagram(s)sequenceDiagram
autonumber
participant User as User
participant UI as ResourceUpload / Modal
participant Form as WorkflowForm / CreateVariables
participant Hook as use-file-upload
participant Uploader as UploaderService
rect rgba(230,245,255,0.6)
note right of User: User clicks "Refresh file"
User->>UI: click refresh
UI->>Form: onRefresh(variableName)
Form->>Form: find workflowVariable by name -> resourceTypes
Form->>Hook: handleRefreshFile(fileList,onChange,resourceTypes)
end
rect rgba(240,255,240,0.6)
Hook->>Hook: generateAcceptAttribute(resourceTypes)
Hook->>UI: open file picker (accept = derived extensions)
UI-->>Hook: file selected
Hook->>Hook: validateFileSize(file)
alt size OK
Hook->>Uploader: processFileUpload(file)
Uploader-->>Hook: uploadResult { uid, storageKey, ... }
Hook->>Hook: replace file in list and call onChange(updatedList)
Hook-->>Form: success
Form->>Form: form.setFieldsValue({ [name]: updatedList })
else size fail / upload fail
Hook-->>Form: null/false (error feedback)
end
end
Estimated code review effort🎯 4 (Complex) | ⏱️ ~75 minutes Possibly related PRs
Suggested reviewers
Poem
✨ Finishing Touches
🧪 Generate 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. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. CodeRabbit Commands (Invoked using PR/Issue comments)Type Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
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 (2)
packages/ai-workspace-common/src/components/canvas/workflow-run/workflow-run-form.tsx (2)
92-95: Optional chaining missing foroptionvalues.
variable.valuecan be undefined; direct.mapwill throw.- } else if (variable.variableType === 'option') { - formValues[variable.name] = variable.value.map((v) => v.text); + } else if (variable.variableType === 'option') { + formValues[variable.name] = variable.value?.map((v) => v.text) ?? [];
121-137: Guard.mapcalls to avoid runtime errors when value is undefined.Both
optionandresourcebranches assume arrays.- } else if (variable.variableType === 'option') { + } else if (variable.variableType === 'option') { newVariables.push({ ...variable, - value: value.map((v) => ({ type: 'text', text: v })), + value: (Array.isArray(value) ? value : []).map((v) => ({ type: 'text', text: v })), }); } else if (variable.variableType === 'resource') { newVariables.push({ ...variable, - value: value.map((v) => ({ + value: (Array.isArray(value) ? value : []).map((v) => ({ type: 'resource', resource: { name: v.name, storageKey: v.url, fileType: getFileExtension(v.name), }, })), });
🧹 Nitpick comments (13)
packages/ai-workspace-common/src/components/canvas/workflow-variables/resource-type-form.tsx (2)
223-228: Add accessible name to icon-only Delete buttonIcon-only buttons should expose an accessible name. Add aria-label/title (and optionally bring back a tooltip) for screen readers and parity with the Refresh button.
- <Button - size="small" - type="text" - icon={<Delete size={16} color="var(--refly-text-1)" />} - onClick={() => handleRemove(file)} - /> + <Button + aria-label={t('common.delete') || 'Delete'} + title={t('common.delete') || 'Delete'} + size="small" + type="text" + icon={<Delete size={16} color="var(--refly-text-1)" />} + onClick={() => handleRemove(file)} + />
213-213: Suspicious class name "fl"Likely a typo for "flex". Replace with Tailwind utility to avoid a no-op class.
packages/i18n/src/en-US/ui.ts (1)
1335-1337: Tighten copy and pluralization for new keysMinor UX copy tweaks for correctness and tone.
- duplicateFileName: 'File with the same name already exists, please replace the file', - tooManyFiles: 'Maximum {{max}} file allowed', + duplicateFileName: 'A file with the same name already exists. Please replace the file.', + tooManyFiles: 'Maximum {{max}} files allowed',packages/ai-workspace-common/src/components/canvas/workflow-variables/create-variables-modal.tsx (1)
273-275: Defensive default for optional resourceTypesUse optional chaining/nullish coalescing to avoid passing undefined to refreshFile and align with guidelines.
- const handleRefreshFile = useCallback(() => { - refreshFile(fileList, handleFileListChange, resourceFormData.resourceTypes); - }, [fileList, handleFileListChange, refreshFile, resourceFormData.resourceTypes]); + const handleRefreshFile = useCallback(() => { + refreshFile( + fileList, + handleFileListChange, + resourceFormData?.resourceTypes ?? RESOURCE_TYPE + ); + }, [fileList, handleFileListChange, refreshFile, resourceFormData?.resourceTypes]);packages/ai-workspace-common/src/components/canvas/workflow-run/resource-upload.tsx (1)
147-155: Add accessible name to Refresh buttonIcon-only button should include an accessible name; reuse the tooltip text for aria-label/title.
- <Tooltip title={t('canvas.workflow.variables.reloadFile')}> - <Button + <Tooltip title={t('canvas.workflow.variables.reloadFile')}> + <Button + aria-label={t('canvas.workflow.variables.reloadFile')} + title={t('canvas.workflow.variables.reloadFile')} size="small" type="text" icon={<Refresh size={16} color="var(--refly-text-1)" />} onClick={handleRefresh} disabled={uploading} /> </Tooltip>packages/ai-workspace-common/src/components/canvas/workflow-run/workflow-run-form.tsx (4)
150-176: Fix stale dependencies in handleFileUpload.This callback uses
formandhandleValueChangebut doesn’t include them in the dependency array, risking stale closures.Apply:
- ); - // deps - [uploadFile, variableValues], + ); + // deps + [uploadFile, variableValues, form, handleValueChange],
179-189: Addformto handleFileRemove deps.
form.setFieldsValueis used butformisn’t listed in the deps.- ); - // deps - [variableValues, handleValueChange], + ); + // deps + [variableValues, handleValueChange, form],
15-22: Wrap pure subcomponents with React.memo.
RequiredTagTextandFormItemLabelare pure; memoize to avoid needless re-renders.-import { useState, useEffect, useCallback, useMemo } from 'react'; +import { useState, useEffect, useCallback, useMemo, memo } from 'react'; -const RequiredTagText = () => { +const RequiredTagText = memo(() => { const { t } = useTranslation(); return ( <div className="flex-shrink-0 text-[10px] text-refly-text-2 leading-[16px] px-1 border-[1px] border-solid border-refly-Card-Border rounded-[4px]"> {t('canvas.workflow.variables.required') || 'Required'} </div> ); -}; +}); -const FormItemLabel = ({ name, required }: { name: string; required: boolean }) => { +const FormItemLabel = memo(({ name, required }: { name: string; required: boolean }) => { return ( <div className="flex items-center gap-2 min-w-0"> <Typography.Paragraph ellipsis={{ rows: 1, tooltip: true }} className="!m-0 text-xs font-semibold text-refly-text-0 leading-4" > {name} </Typography.Paragraph> {required && <RequiredTagText />} </div> ); -}; +});Also applies to: 24-37, 8-8
338-345: Localize input/select placeholders.Hardcoded Chinese strings bypass i18n; use existing translation keys for consistency.
- <Input + <Input variant="filled" - placeholder="请输入" + placeholder={t('canvas.workflow.variables.inputPlaceholder')}- <Select + <Select variant="filled" - placeholder="请选择" + placeholder={t('canvas.workflow.variables.selectPlaceholder')}Also applies to: 361-369
packages/ai-workspace-common/src/components/canvas/workflow-variables/hooks/use-file-upload.ts (4)
6-12: Consolidate imports from the same module.Merge duplicate imports from
../constantsfor cleanliness and to follow import grouping rules.-import { ACCEPT_FILE_EXTENSIONS } from '../constants'; -import { - IMAGE_FILE_EXTENSIONS, - DOCUMENT_FILE_EXTENSIONS, - AUDIO_FILE_EXTENSIONS, - VIDEO_FILE_EXTENSIONS, -} from '../constants'; +import { + ACCEPT_FILE_EXTENSIONS, + IMAGE_FILE_EXTENSIONS, + DOCUMENT_FILE_EXTENSIONS, + AUDIO_FILE_EXTENSIONS, + VIDEO_FILE_EXTENSIONS, +} from '../constants';
20-43: Add explicit return types and a shared upload result type.Avoid implicit
anyand make control flow clearer.+type UploadData = { storageKey: string; url: string; uid: string }; + - const uploadFile = useCallback(async (file: File, uid: string) => { + const uploadFile = useCallback(async (file: File, uid: string): Promise<UploadData> => { @@ - return { + return { storageKey: data.data.storageKey, url: data.data.url || '', uid, };- const processFileUpload = useCallback( - async (file: File) => { + const processFileUpload = useCallback( + async (file: File): Promise<UploadData | null> => {- const handleFileUpload = useCallback( - async (file: File, fileList: UploadFile[]) => { + const handleFileUpload = useCallback( + async (file: File, fileList: UploadFile[]): Promise<UploadData | false> => {Also applies to: 69-95, 97-101
74-76: Use crypto.randomUUID (with fallback) instead of deprecated substr().Generates safer, collision-resistant IDs and avoids deprecated APIs.
- const tempUid = `file-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`; + const tempUid = + (typeof crypto !== 'undefined' && 'randomUUID' in crypto + ? crypto.randomUUID() + : `file-${Date.now()}-${Math.random().toString(36).slice(2)}`);
130-135: Strongly typeresourceTypesas a union.Prevents invalid values from propagating.
- resourceTypes?: string[], + resourceTypes?: Array<'document' | 'image' | 'audio' | 'video'>,
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (7)
packages/ai-workspace-common/src/components/canvas/workflow-run/resource-upload.tsx(2 hunks)packages/ai-workspace-common/src/components/canvas/workflow-run/workflow-run-form.tsx(1 hunks)packages/ai-workspace-common/src/components/canvas/workflow-variables/create-variables-modal.tsx(1 hunks)packages/ai-workspace-common/src/components/canvas/workflow-variables/hooks/use-file-upload.ts(5 hunks)packages/ai-workspace-common/src/components/canvas/workflow-variables/resource-type-form.tsx(1 hunks)packages/i18n/src/en-US/ui.ts(1 hunks)packages/i18n/src/zh-Hans/ui.ts(1 hunks)
🧰 Additional context used
📓 Path-based instructions (8)
**/*.{jsx,tsx}
📄 CodeRabbit inference engine (.cursorrules)
**/*.{jsx,tsx}: Always use tailwind css to style the component.
Always wrap pure components with React.memo to prevent unnecessary re-renders.
Always use useMemo for expensive computations or complex object creation.
Always use useCallback for function props to maintain referential equality.
Always specify proper dependency arrays in useEffect to prevent infinite loops.
Always avoid inline object/array creation in render to prevent unnecessary re-renders.
Always use proper key props when rendering lists.
Always split nested components with closures into separate components to avoid performance issues and improve code maintainability.
**/*.{jsx,tsx}: Always wrap pure components with React.memo to prevent unnecessary re-renders
Always use useMemo for expensive computations or complex object creation
Always use useCallback for function props to maintain referential equality
Always specify proper dependency arrays in useEffect to prevent infinite loops
Always avoid inline object/array creation in render to prevent unnecessary re-renders
Always use proper key props when rendering lists (avoid using index when possible)
Always split nested components with closures into separate components
Use lazy loading for components that are not immediately needed
Debounce handlers for events that might fire rapidly (resize, scroll, input)
Implement fallback UI for components that might fail
Use error boundaries to catch and handle runtime errors
Use Tailwind CSS for styling components
Group related utility classes together
Prefer Tailwind utilities over custom CSS when possible
**/*.{jsx,tsx}: Place each attribute on a new line when a component has multiple attributes in JSX
Use self-closing tags for elements without children in JSX
Keep JSX expressions simple, extract complex logic to variables
Put closing brackets for multi-line JSX on a new lineUse React best practices for frontend code
Files:
packages/ai-workspace-common/src/components/canvas/workflow-variables/create-variables-modal.tsxpackages/ai-workspace-common/src/components/canvas/workflow-variables/resource-type-form.tsxpackages/ai-workspace-common/src/components/canvas/workflow-run/resource-upload.tsxpackages/ai-workspace-common/src/components/canvas/workflow-run/workflow-run-form.tsx
**/*.{js,jsx,ts,tsx}
📄 CodeRabbit inference engine (.cursorrules)
**/*.{js,jsx,ts,tsx}: Always use optional chaining (?.) when accessing object properties.
Always use nullish coalescing (??) or default values for potentially undefined values.
Always check array existence before using array methods.
Always validate object properties before destructuring.
Always use single quotes for string literals in JavaScript/TypeScript code.Use JSDoc style comments for functions and classes in JavaScript/TypeScript
**/*.{js,jsx,ts,tsx}: Use single quotes for string literals
Always use optional chaining (?.) when accessing object properties
Always use nullish coalescing (??) or default values for potentially undefined values
Always check array existence before using array methods
Validate object properties before destructuring
Use ES6+ features like arrow functions, destructuring, and spread operators
Use async/await instead of raw promises for asynchronous code
**/*.{js,jsx,ts,tsx}: Maximum line length of 100 characters
Use 2 spaces for indentation, no tabs
Use semicolons at the end of statements
Include spaces around operators (e.g.,a + binstead ofa+b)
Always use curly braces for control statements
Place opening braces on the same line as their statement
No trailing whitespace at the end of lines
**/*.{js,jsx,ts,tsx}: Each file should contain only one main component
File names should match the component name
Keep component files focused with minimal dependencies
Group import statements in the following order: 1. React/framework libraries 2. Third-party libraries 3. Internal modules 4. Relative path imports (parent directories first, then child directories) 5. Type imports 6. Style imports
Sort imports alphabetically within each group
Leave a blank line between import groups
Components should be organized in the following order: 1. Import statements 2. Type definitions 3. Constant declarations 4. Component function 5. Hook calls 6. Event handlers 7. Helper render functions 8. JSX return statement
Extract complex logic in...
Files:
packages/ai-workspace-common/src/components/canvas/workflow-variables/create-variables-modal.tsxpackages/ai-workspace-common/src/components/canvas/workflow-variables/resource-type-form.tsxpackages/ai-workspace-common/src/components/canvas/workflow-run/resource-upload.tsxpackages/ai-workspace-common/src/components/canvas/workflow-run/workflow-run-form.tsxpackages/i18n/src/zh-Hans/ui.tspackages/i18n/src/en-US/ui.tspackages/ai-workspace-common/src/components/canvas/workflow-variables/hooks/use-file-upload.ts
**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/03-typescript-guidelines.mdc)
**/*.{ts,tsx}: Avoid usinganytype whenever possible - it defeats the purpose of TypeScript
When tempted to useany, useunknowntype instead and add proper type guards
Always define explicit return types for functions, especially for public APIs
Prefer extending existing types over creating entirely new ones
Use TypeScript's utility types to derive new types:Partial<T>,Pick<T, K>,Omit<T, K>,Readonly<T>,Record<K, T>
Use union types and intersection types to combine existing types
Always import types explicitly using theimport typesyntax
Group type imports separately from value imports
Minimize creating local type aliases for imported typesExplicitly type props interfaces/types
Files:
packages/ai-workspace-common/src/components/canvas/workflow-variables/create-variables-modal.tsxpackages/ai-workspace-common/src/components/canvas/workflow-variables/resource-type-form.tsxpackages/ai-workspace-common/src/components/canvas/workflow-run/resource-upload.tsxpackages/ai-workspace-common/src/components/canvas/workflow-run/workflow-run-form.tsxpackages/i18n/src/zh-Hans/ui.tspackages/i18n/src/en-US/ui.tspackages/ai-workspace-common/src/components/canvas/workflow-variables/hooks/use-file-upload.ts
**/*.{css,scss,sass,less,styl,js,jsx,ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/09-design-system.mdc)
**/*.{css,scss,sass,less,styl,js,jsx,ts,tsx}: Use Primary color (#155EEF) as the main brand color for buttons, links, and accents
Use Error color (#F04438) for error states and destructive actions
Use Success color (#12B76A) for success states and confirmations
Use Warning color (#F79009) for warnings and important notifications
Use Info color (#0BA5EC) for informational elements
Files:
packages/ai-workspace-common/src/components/canvas/workflow-variables/create-variables-modal.tsxpackages/ai-workspace-common/src/components/canvas/workflow-variables/resource-type-form.tsxpackages/ai-workspace-common/src/components/canvas/workflow-run/resource-upload.tsxpackages/ai-workspace-common/src/components/canvas/workflow-run/workflow-run-form.tsxpackages/i18n/src/zh-Hans/ui.tspackages/i18n/src/en-US/ui.tspackages/ai-workspace-common/src/components/canvas/workflow-variables/hooks/use-file-upload.ts
**/*.tsx
📄 CodeRabbit inference engine (.cursor/rules/09-i18n-guidelines.mdc)
**/*.tsx: Use the translation wrapper component when displaying user-facing text in components
Ensure all user-facing text in components is translatable
Files:
packages/ai-workspace-common/src/components/canvas/workflow-variables/create-variables-modal.tsxpackages/ai-workspace-common/src/components/canvas/workflow-variables/resource-type-form.tsxpackages/ai-workspace-common/src/components/canvas/workflow-run/resource-upload.tsxpackages/ai-workspace-common/src/components/canvas/workflow-run/workflow-run-form.tsx
**/*.{css,scss,less,styl,js,jsx,ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/11-ui-design-patterns.mdc)
**/*.{css,scss,less,styl,js,jsx,ts,tsx}: Use the primary blue (#155EEF) for main UI elements, CTAs, and active states
Use red (#F04438) only for errors, warnings, and destructive actions
Use green (#12B76A) for success states and confirmations
Use orange (#F79009) for warning states and important notifications
Use blue (#0BA5EC) for informational elements
Maintain a minimum contrast ratio of 4.5:1 for text
Files:
packages/ai-workspace-common/src/components/canvas/workflow-variables/create-variables-modal.tsxpackages/ai-workspace-common/src/components/canvas/workflow-variables/resource-type-form.tsxpackages/ai-workspace-common/src/components/canvas/workflow-run/resource-upload.tsxpackages/ai-workspace-common/src/components/canvas/workflow-run/workflow-run-form.tsxpackages/i18n/src/zh-Hans/ui.tspackages/i18n/src/en-US/ui.tspackages/ai-workspace-common/src/components/canvas/workflow-variables/hooks/use-file-upload.ts
**/*.ts
📄 CodeRabbit inference engine (.cursor/rules/08-contributing-guidelines.mdc)
Follow NestJS patterns for backend code
Files:
packages/i18n/src/zh-Hans/ui.tspackages/i18n/src/en-US/ui.tspackages/ai-workspace-common/src/components/canvas/workflow-variables/hooks/use-file-upload.ts
packages/i18n/src/{en-US,zh-Hans}/**
📄 CodeRabbit inference engine (.cursor/rules/09-i18n-guidelines.mdc)
packages/i18n/src/{en-US,zh-Hans}/**: Add new translation keys to both language files: packages/i18n/src/en-US and packages/i18n/src/zh-Hans
Maintain consistency in naming conventions for translation keys
Use descriptive keys that reflect the content in translation files
Group related translation keys together
Use namespaces for different sections of the application in translation keys
Follow a hierarchical structure for nested components in translation keys
Support dynamic content with placeholders in translation strings
Files:
packages/i18n/src/zh-Hans/ui.tspackages/i18n/src/en-US/ui.ts
🧠 Learnings (3)
📚 Learning: 2025-07-21T02:58:52.235Z
Learnt from: CR
PR: refly-ai/refly#0
File: .cursor/rules/09-i18n-guidelines.mdc:0-0
Timestamp: 2025-07-21T02:58:52.235Z
Learning: Applies to packages/i18n/src/{en-US,zh-Hans}/** : Add new translation keys to both language files: packages/i18n/src/en-US and packages/i18n/src/zh-Hans
Applied to files:
packages/i18n/src/zh-Hans/ui.tspackages/i18n/src/en-US/ui.ts
📚 Learning: 2025-07-21T02:58:52.235Z
Learnt from: CR
PR: refly-ai/refly#0
File: .cursor/rules/09-i18n-guidelines.mdc:0-0
Timestamp: 2025-07-21T02:58:52.235Z
Learning: Applies to packages/i18n/src/{en-US,zh-Hans}/** : Use descriptive keys that reflect the content in translation files
Applied to files:
packages/i18n/src/zh-Hans/ui.tspackages/i18n/src/en-US/ui.ts
📚 Learning: 2025-07-21T02:58:52.235Z
Learnt from: CR
PR: refly-ai/refly#0
File: .cursor/rules/09-i18n-guidelines.mdc:0-0
Timestamp: 2025-07-21T02:58:52.235Z
Learning: Applies to packages/i18n/src/{en-US,zh-Hans}/** : Maintain consistency in naming conventions for translation keys
Applied to files:
packages/i18n/src/zh-Hans/ui.ts
🧬 Code graph analysis (1)
packages/ai-workspace-common/src/components/canvas/workflow-variables/hooks/use-file-upload.ts (2)
packages/ai-workspace-common/src/components/canvas/workflow-variables/utils.ts (1)
getFileCategoryAndLimit(33-57)packages/ai-workspace-common/src/components/canvas/workflow-variables/constants.ts (5)
ACCEPT_FILE_EXTENSIONS(29-34)DOCUMENT_FILE_EXTENSIONS(5-23)IMAGE_FILE_EXTENSIONS(25-25)AUDIO_FILE_EXTENSIONS(26-26)VIDEO_FILE_EXTENSIONS(27-27)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: build / Build
🔇 Additional comments (3)
packages/i18n/src/zh-Hans/ui.ts (1)
1313-1315: LGTM: zh-Hans keys added and aligned with en-USWording and placeholders look correct and consistent.
packages/ai-workspace-common/src/components/canvas/workflow-run/workflow-run-form.tsx (2)
195-208: Resource-type-aware refresh looks correct.Good job deriving
resourceTypesfrom the variable and syncing the AntD form after refresh. Dependency array update to includeformandworkflowVariablesis appropriate.Also applies to: 210-210
195-208: NarrowresourceTypesto a string-literal union.If
WorkflowVariable['resourceTypes']isn’t already typed, prefer a union to prevent typos and align with the hook’s expectations.Would you confirm
WorkflowVariabledeclaresresourceTypes?: Array<'document' | 'image' | 'audio' | 'video'>? If not, I can provide a quick type patch.
| return types | ||
| .map((type) => { | ||
| switch (type) { | ||
| case 'document': | ||
| return DOCUMENT_FILE_EXTENSIONS.map((ext) => `.${ext}`).join(','); | ||
| case 'image': | ||
| return IMAGE_FILE_EXTENSIONS.map((ext) => `.${ext}`).join(','); | ||
| case 'audio': | ||
| return AUDIO_FILE_EXTENSIONS.map((ext) => `.${ext}`).join(','); | ||
| case 'video': | ||
| return VIDEO_FILE_EXTENSIONS.map((ext) => `.${ext}`).join(','); | ||
| default: | ||
| return ''; | ||
| } | ||
| }) | ||
| .filter(Boolean) | ||
| .join(','); | ||
| }; |
There was a problem hiding this comment.
🛠️ Refactor suggestion
Ensure unknown resourceTypes fall back to the full accept list.
Current default: '' can yield an empty accept, allowing any file type unintentionally.
- default:
- return '';
+ default:
+ return ACCEPT_FILE_EXTENSIONS.map((ext) => `.${ext}`).join(',');Optionally dedupe extensions by building a Set before joining if multiple categories are combined.
📝 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.
| return types | |
| .map((type) => { | |
| switch (type) { | |
| case 'document': | |
| return DOCUMENT_FILE_EXTENSIONS.map((ext) => `.${ext}`).join(','); | |
| case 'image': | |
| return IMAGE_FILE_EXTENSIONS.map((ext) => `.${ext}`).join(','); | |
| case 'audio': | |
| return AUDIO_FILE_EXTENSIONS.map((ext) => `.${ext}`).join(','); | |
| case 'video': | |
| return VIDEO_FILE_EXTENSIONS.map((ext) => `.${ext}`).join(','); | |
| default: | |
| return ''; | |
| } | |
| }) | |
| .filter(Boolean) | |
| .join(','); | |
| }; | |
| return types | |
| .map((type) => { | |
| switch (type) { | |
| case 'document': | |
| return DOCUMENT_FILE_EXTENSIONS.map((ext) => `.${ext}`).join(','); | |
| case 'image': | |
| return IMAGE_FILE_EXTENSIONS.map((ext) => `.${ext}`).join(','); | |
| case 'audio': | |
| return AUDIO_FILE_EXTENSIONS.map((ext) => `.${ext}`).join(','); | |
| case 'video': | |
| return VIDEO_FILE_EXTENSIONS.map((ext) => `.${ext}`).join(','); | |
| default: | |
| return ACCEPT_FILE_EXTENSIONS.map((ext) => `.${ext}`).join(','); | |
| } | |
| }) | |
| .filter(Boolean) | |
| .join(','); | |
| }; |
🤖 Prompt for AI Agents
In
packages/ai-workspace-common/src/components/canvas/workflow-variables/hooks/use-file-upload.ts
around lines 142 to 159, the switch's default branch returns an empty string
which can lead to an empty accept list when an unknown resourceType is present;
change the default to return the full accept list (i.e., a comma-joined list of
DOCUMENT_FILE_EXTENSIONS, IMAGE_FILE_EXTENSIONS, AUDIO_FILE_EXTENSIONS,
VIDEO_FILE_EXTENSIONS) so unknown types fall back to allowing known extensions,
and when mapping multiple types deduplicate extensions by collecting them into a
Set before joining to a comma-separated string.
…w-run-form, tool-store): enhance toolset handling and UI improvements - Updated label name logic in ToolSelectorPopover and ToolsDependencyContent to improve clarity based on toolset type. - Refactored WorkflowRun component to remove unused variables and streamline rendering logic. - Enhanced WorkflowRunForm to display a message when no workflow variables are defined. - Modified ToolStore to improve tool installation success messaging and UI interactions. - Ensured consistent use of optional chaining and nullish coalescing for safer property access.
There was a problem hiding this comment.
Actionable comments posted: 3
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (7)
packages/ai-workspace-common/src/components/canvas/workflow-run/index.tsx (2)
9-10: Wrap component with React.memo and add explicit return typePrevents unnecessary re-renders and satisfies explicit return type guidance.
-export const WorkflowRun = () => { +export const WorkflowRun = memo(function WorkflowRun(): JSX.Element { const { t } = useTranslation(); const { setShowWorkflowRun, setSidePanelVisible } = useCanvasResourcesPanelStoreShallow( @@ -}; +});Also applies to: 56-56
33-35: Add aria-label to icon-only button for screen readersImproves accessibility for keyboard/screen-reader users.
- <Button type="text" icon={<SideRight size={18} />} onClick={handleClose} /> + <Button + type="text" + icon={<SideRight size={18} />} + onClick={handleClose} + aria-label={t('canvas.toolbar.closeResourcesPanel')} + />packages/ai-workspace-common/src/components/settings/mcp-server/tools/tool-install-modal.tsx (1)
272-305: Gate form resets to modal open/close or source key changeReplace the current
useEffectso it only resets when the modal opens, closes, or the source key changes:- useEffect(() => { - if (visible && sourceData) { - form?.resetFields(); + useEffect(() => { + const opened = visible && !wasVisibleRef.current; + const closed = !visible && wasVisibleRef.current; + const keyChanged = prevSourceKeyRef.current !== sourceData?.key; + if (visible && sourceData && (opened || keyChanged)) { + form?.resetFields(); const initialValues: Record<string, unknown> = { name: defaultName, enabled: mode === 'update' ? (toolInstance?.enabled ?? true) : true, }; @@ - form.setFieldsValue(initialValues); - } else { - form?.resetFields(); - } - }, [visible, sourceData, mode, toolInstance, defaultName, form, authPatterns]); + form.setFieldsValue(initialValues); + } else if (closed) { + form?.resetFields(); + } + wasVisibleRef.current = visible; + prevSourceKeyRef.current = sourceData?.key; + }, [visible, sourceData?.key, mode, toolInstance, defaultName, form, authPatterns]);Also add at the top of the component:
const wasVisibleRef = React.useRef(false); const prevSourceKeyRef = React.useRef<string | undefined>(undefined);packages/ai-workspace-common/src/components/canvas/tools-dependency/index.tsx (1)
115-123: Fix TDZ runtime error: variable used before declaration
moreMenuItemsreferenceshandleLocateNodebefore it’s declared; this will throw at render time. MovehandleLocateNodeabove, or memoize items after the function.- const moreMenuItems = hiddenNodes.map((node) => ({ - key: node.id, - label: node.title, - icon: <NodeIcon type="skillResponse" small />, - onClick: () => handleLocateNode(node.entityId), - })); - - const handleLocateNode = (entityId: string) => { + const handleLocateNode = (entityId: string) => { const nodes = getNodes(); const foundNode = nodes.find((n) => n.data?.entityId === entityId); if (foundNode) { setNodeCenter(foundNode.id, true); } }; + const moreMenuItems = hiddenNodes.map((node) => ({ + key: node.id, + label: node.title, + icon: <NodeIcon type="skillResponse" small />, + onClick: () => handleLocateNode(node.entityId), + }));packages/ai-workspace-common/src/components/settings/mcp-server/tools/tool-store.tsx (3)
48-53: Guard against undefinedlabelDict.Direct indexing can throw when
labelDictis missing. Use optional chaining and a safe fallback.-const name = (tool.labelDict[currentLanguage] as string) ?? (tool.labelDict.en as string); +const name = + (tool.labelDict?.[currentLanguage] as string) ?? + (tool.labelDict?.en as string) ?? + tool.key;
191-199:Inputdoesn’t supportonClear; remove to prevent unknown-prop warnings.Rely on
allowClear+onChangeinstead.-<Input +<Input placeholder={t('settings.toolStore.searchPlaceholder')} prefix={<Search size={16} color="var(--refly-text-3)" />} value={searchText} onChange={handleSearchChange} - onClear={handleClearSearch} allowClear className="mb-4" />
210-218: Add missing i18n keys for empty states
settings.toolStore.noSearchResults and settings.toolStore.noTools aren’t defined in any locale JSON, causing fallback English. Add these keys to all locale files to ensure consistent translations.
🧹 Nitpick comments (17)
packages/ai-workspace-common/src/components/canvas/workflow-run/index.tsx (6)
7-7: Prefer Tailwind utilities over SCSS; verify the need for index.scssIf this SCSS only sets styles that can be expressed in Tailwind, drop it. If required (e.g., global resets or antd overrides), leave a short comment explaining why it’s needed.
11-16: Zustand selector minor: avoid object creation per renderReturning an object allocates each render. Consider selecting fields separately or using an array selector with shallow compare if supported by your store util.
Example:
const setShowWorkflowRun = useCanvasResourcesPanelStoreShallow(s => s.setShowWorkflowRun); const setSidePanelVisible = useCanvasResourcesPanelStoreShallow(s => s.setSidePanelVisible);
18-20: Guard against undefined workflow; avoid destructuring before validationAligns with “optional chaining and nullish coalescing” guidance and prevents potential runtime errors if workflow is momentarily undefined.
- const { workflow } = useCanvasContext(); - const { workflowVariables, workflowVariablesLoading, refetchWorkflowVariables } = workflow; + const { workflow } = useCanvasContext(); + const workflowVariables = workflow?.workflowVariables ?? []; + const workflowVariablesLoading = workflow?.workflowVariablesLoading ?? false; + const refetchWorkflowVariables = + workflow?.refetchWorkflowVariables ?? (async () => {});
21-27: Stabilize handler with useCallback and remove dead commentsKeeps referential equality for onClick and cleans up commented code.
- const handleClose = () => { + const handleClose = useCallback(() => { setShowWorkflowRun(false); setSidePanelVisible(false); - // if (activeNode) { - // setActiveNode(null); - // } - }; + }, [setShowWorkflowRun, setSidePanelVisible]);
30-31: Split long className to respect 100-char limit and improve readabilityNo behavior change; keeps Tailwind utilities grouped.
- <div className="flex flex-col w-full h-[calc(100vh-16px)] bg-refly-bg-content-z2 rounded-xl border-solid border border-refly-Card-Border shadow-refly-m"> + <div + className={` + flex flex-col w-full + h-[calc(100vh-16px)] + bg-refly-bg-content-z2 rounded-xl + border-solid border border-refly-Card-Border + shadow-refly-m + `} + >
44-46: Avoid inline object creation in render for Skeleton propsHoist via useMemo to keep prop identity stable.
- <div className="p-4"> - <Skeleton paragraph={{ rows: 10 }} active title={false} /> - </div> + <div className="p-4"> + <Skeleton {...useMemo(() => ({ paragraph: { rows: 10 }, active: true, title: false }), [])} /> + </div>Alternatively, define a
const skeletonProps = useMemo(..., [])above the return and spread here for readability.packages/ai-workspace-common/src/components/canvas/launchpad/tool-selector-panel/index.tsx (1)
186-189: Preserve i18n fallback for non-builtin toolsetsSwitching to plain name may regress localization. Consider falling back to the localized label when available.
- const labelName = - toolset?.type === 'regular' && toolset?.id === 'builtin' - ? (toolset?.toolset?.definition?.labelDict?.[currentLanguage] as string) - : toolset.name; + const labelName = + toolset?.type === 'regular' && toolset?.id === 'builtin' + ? (toolset?.toolset?.definition?.labelDict?.[currentLanguage] as string) ?? toolset.name + : toolset.name ?? + (toolset?.toolset?.definition?.labelDict?.[currentLanguage] as string);packages/ai-workspace-common/src/components/canvas/tools-dependency/index.tsx (1)
318-323: Keep localized label fallback consistent with selector panelFor non-builtin toolsets, fall back to the localized label when
nameis absent to avoid regressions and keep behavior consistent.- {toolset.type === 'regular' && toolset.id === 'builtin' - ? (toolset?.toolset?.definition?.labelDict?.[ - currentLanguage - ] as string) - : toolset.name} + {toolset.type === 'regular' && toolset.id === 'builtin' + ? (toolset?.toolset?.definition?.labelDict?.[ + currentLanguage + ] as string) ?? toolset.name + : toolset.name ?? + (toolset?.toolset?.definition?.labelDict?.[ + currentLanguage as string + ] as string)}packages/ai-workspace-common/src/components/settings/mcp-server/tools/tool-store.tsx (8)
3-5: Useimport typefor types and group them separately.Switch
ToolsetDefinitionto a type-only import to avoid bundling overhead.-import { ToolsetDefinition } from '@refly-packages/ai-workspace-common/requests'; +import type { ToolsetDefinition } from '@refly-packages/ai-workspace-common/requests';
40-44: MemoizeToolItemand define explicit props interface.Improves render perf and readability; satisfies guidelines for memo and explicit prop types.
-const ToolItem = ({ - tool, - setToolStoreVisible, -}: { tool: ToolsetDefinition; setToolStoreVisible: (visible: boolean) => void }) => { +interface ToolItemProps { + tool: ToolsetDefinition; + setToolStoreVisible: Dispatch<SetStateAction<boolean>>; +} + +const ToolItem = memo(({ tool, setToolStoreVisible }: ToolItemProps) => {(Remember to close with
});at Line 130.)
15-38: Memoize the skeleton component.This pure component should be wrapped with
memo.-const ToolItemSkeleton = () => { +const ToolItemSkeleton = memo(() => { return ( ... ); -}; +});
58-79: Stabilize success handler and close the install modal.Wrap in
useCallback; close the modal on success to avoid lingering state after store hides.-const handleInstallSuccess = () => { - const closeMessage = message.success( +const handleInstallSuccess = useCallback(() => { + setOpenInstallModal(false); + const closeMessage = message.success( ... - ); -}; + ); -}; +}, [t, setToolStoreVisible]);
100-106: Avoid inline object creation in JSX props.Memoize the
ellipsisconfig to maintain referential stability.+const paragraphEllipsis = useMemo(() => ({ rows: 3, tooltip: true as const }), []); ... -<Typography.Paragraph - className="text-refly-text-1 text-sm !mb-0" - ellipsis={{ rows: 3, tooltip: true }} -> +<Typography.Paragraph + className="text-refly-text-1 text-sm !mb-0" + ellipsis={paragraphEllipsis} +>
121-127: StabilizeonCancelhandler.Use
useCallbackto avoid recreating the function on each render.-<ToolInstallModal +const handleCancel = useCallback(() => setOpenInstallModal(false), []); +<ToolInstallModal ... - onCancel={() => setOpenInstallModal(false)} + onCancel={handleCancel} onSuccess={handleInstallSuccess} />
203-210: Avoid inline arrays and repeated allocations in render.Memoize
gutterand the skeleton list.+const gridGutter = useMemo(() => [16, 12] as const, []); +const skeletonItems = useMemo(() => Array.from({ length: 8 }), []); ... -<Row gutter={[16, 12]}> - {Array.from({ length: 8 }).map((_, index) => ( +<Row gutter={gridGutter}> + {skeletonItems.map((_, index) => ( <Col key={index} xs={24} sm={12} md={6} lg={6} xl={6}> <ToolItemSkeleton /> </Col> ))} </Row>
85-87: Provide a safe default for favicon URL.Prevents potential runtime issues if
tool.domainis undefined.-<Favicon url={tool.domain} size={24} /> +<Favicon url={tool.domain ?? ''} size={24} />packages/ai-workspace-common/src/components/settings/mcp-server/mcpServerTab.tsx (1)
140-141: LGTM: updatedToolStoreprop wiring.Passing the visibility setter enables close-on-install flow; matches the new API. Ensure
ToolStorePropsusesDispatch<SetStateAction<boolean>>for full compatibility.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (10)
packages/ai-workspace-common/src/components/canvas/launchpad/tool-selector-panel/index.tsx(1 hunks)packages/ai-workspace-common/src/components/canvas/tools-dependency/index.tsx(2 hunks)packages/ai-workspace-common/src/components/canvas/workflow-run/index.tsx(2 hunks)packages/ai-workspace-common/src/components/canvas/workflow-run/workflow-run-form.tsx(2 hunks)packages/ai-workspace-common/src/components/canvas/workflow-variables/create-variables-modal.tsx(2 hunks)packages/ai-workspace-common/src/components/settings/mcp-server/mcpServerTab.tsx(1 hunks)packages/ai-workspace-common/src/components/settings/mcp-server/tools/tool-install-modal.tsx(2 hunks)packages/ai-workspace-common/src/components/settings/mcp-server/tools/tool-store.tsx(6 hunks)packages/i18n/src/en-US/ui.ts(2 hunks)packages/i18n/src/zh-Hans/ui.ts(2 hunks)
🚧 Files skipped from review as they are similar to previous changes (4)
- packages/i18n/src/en-US/ui.ts
- packages/ai-workspace-common/src/components/canvas/workflow-variables/create-variables-modal.tsx
- packages/ai-workspace-common/src/components/canvas/workflow-run/workflow-run-form.tsx
- packages/i18n/src/zh-Hans/ui.ts
🧰 Additional context used
📓 Path-based instructions (7)
**/*.{jsx,tsx}
📄 CodeRabbit inference engine (.cursorrules)
**/*.{jsx,tsx}: Always use tailwind css to style the component.
Always wrap pure components with React.memo to prevent unnecessary re-renders.
Always use useMemo for expensive computations or complex object creation.
Always use useCallback for function props to maintain referential equality.
Always specify proper dependency arrays in useEffect to prevent infinite loops.
Always avoid inline object/array creation in render to prevent unnecessary re-renders.
Always use proper key props when rendering lists.
Always split nested components with closures into separate components to avoid performance issues and improve code maintainability.
**/*.{jsx,tsx}: Always wrap pure components with React.memo to prevent unnecessary re-renders
Always use useMemo for expensive computations or complex object creation
Always use useCallback for function props to maintain referential equality
Always specify proper dependency arrays in useEffect to prevent infinite loops
Always avoid inline object/array creation in render to prevent unnecessary re-renders
Always use proper key props when rendering lists (avoid using index when possible)
Always split nested components with closures into separate components
Use lazy loading for components that are not immediately needed
Debounce handlers for events that might fire rapidly (resize, scroll, input)
Implement fallback UI for components that might fail
Use error boundaries to catch and handle runtime errors
Use Tailwind CSS for styling components
Group related utility classes together
Prefer Tailwind utilities over custom CSS when possible
**/*.{jsx,tsx}: Place each attribute on a new line when a component has multiple attributes in JSX
Use self-closing tags for elements without children in JSX
Keep JSX expressions simple, extract complex logic to variables
Put closing brackets for multi-line JSX on a new lineUse React best practices for frontend code
Files:
packages/ai-workspace-common/src/components/settings/mcp-server/tools/tool-install-modal.tsxpackages/ai-workspace-common/src/components/settings/mcp-server/mcpServerTab.tsxpackages/ai-workspace-common/src/components/canvas/workflow-run/index.tsxpackages/ai-workspace-common/src/components/canvas/tools-dependency/index.tsxpackages/ai-workspace-common/src/components/canvas/launchpad/tool-selector-panel/index.tsxpackages/ai-workspace-common/src/components/settings/mcp-server/tools/tool-store.tsx
**/*.{js,jsx,ts,tsx}
📄 CodeRabbit inference engine (.cursorrules)
**/*.{js,jsx,ts,tsx}: Always use optional chaining (?.) when accessing object properties.
Always use nullish coalescing (??) or default values for potentially undefined values.
Always check array existence before using array methods.
Always validate object properties before destructuring.
Always use single quotes for string literals in JavaScript/TypeScript code.Use JSDoc style comments for functions and classes in JavaScript/TypeScript
**/*.{js,jsx,ts,tsx}: Use single quotes for string literals
Always use optional chaining (?.) when accessing object properties
Always use nullish coalescing (??) or default values for potentially undefined values
Always check array existence before using array methods
Validate object properties before destructuring
Use ES6+ features like arrow functions, destructuring, and spread operators
Use async/await instead of raw promises for asynchronous code
**/*.{js,jsx,ts,tsx}: Maximum line length of 100 characters
Use 2 spaces for indentation, no tabs
Use semicolons at the end of statements
Include spaces around operators (e.g.,a + binstead ofa+b)
Always use curly braces for control statements
Place opening braces on the same line as their statement
No trailing whitespace at the end of lines
**/*.{js,jsx,ts,tsx}: Each file should contain only one main component
File names should match the component name
Keep component files focused with minimal dependencies
Group import statements in the following order: 1. React/framework libraries 2. Third-party libraries 3. Internal modules 4. Relative path imports (parent directories first, then child directories) 5. Type imports 6. Style imports
Sort imports alphabetically within each group
Leave a blank line between import groups
Components should be organized in the following order: 1. Import statements 2. Type definitions 3. Constant declarations 4. Component function 5. Hook calls 6. Event handlers 7. Helper render functions 8. JSX return statement
Extract complex logic in...
Files:
packages/ai-workspace-common/src/components/settings/mcp-server/tools/tool-install-modal.tsxpackages/ai-workspace-common/src/components/settings/mcp-server/mcpServerTab.tsxpackages/ai-workspace-common/src/components/canvas/workflow-run/index.tsxpackages/ai-workspace-common/src/components/canvas/tools-dependency/index.tsxpackages/ai-workspace-common/src/components/canvas/launchpad/tool-selector-panel/index.tsxpackages/ai-workspace-common/src/components/settings/mcp-server/tools/tool-store.tsx
**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/03-typescript-guidelines.mdc)
**/*.{ts,tsx}: Avoid usinganytype whenever possible - it defeats the purpose of TypeScript
When tempted to useany, useunknowntype instead and add proper type guards
Always define explicit return types for functions, especially for public APIs
Prefer extending existing types over creating entirely new ones
Use TypeScript's utility types to derive new types:Partial<T>,Pick<T, K>,Omit<T, K>,Readonly<T>,Record<K, T>
Use union types and intersection types to combine existing types
Always import types explicitly using theimport typesyntax
Group type imports separately from value imports
Minimize creating local type aliases for imported typesExplicitly type props interfaces/types
Files:
packages/ai-workspace-common/src/components/settings/mcp-server/tools/tool-install-modal.tsxpackages/ai-workspace-common/src/components/settings/mcp-server/mcpServerTab.tsxpackages/ai-workspace-common/src/components/canvas/workflow-run/index.tsxpackages/ai-workspace-common/src/components/canvas/tools-dependency/index.tsxpackages/ai-workspace-common/src/components/canvas/launchpad/tool-selector-panel/index.tsxpackages/ai-workspace-common/src/components/settings/mcp-server/tools/tool-store.tsx
**/*.{css,scss,sass,less,styl,js,jsx,ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/09-design-system.mdc)
**/*.{css,scss,sass,less,styl,js,jsx,ts,tsx}: Use Primary color (#155EEF) as the main brand color for buttons, links, and accents
Use Error color (#F04438) for error states and destructive actions
Use Success color (#12B76A) for success states and confirmations
Use Warning color (#F79009) for warnings and important notifications
Use Info color (#0BA5EC) for informational elements
Files:
packages/ai-workspace-common/src/components/settings/mcp-server/tools/tool-install-modal.tsxpackages/ai-workspace-common/src/components/settings/mcp-server/mcpServerTab.tsxpackages/ai-workspace-common/src/components/canvas/workflow-run/index.tsxpackages/ai-workspace-common/src/components/canvas/tools-dependency/index.tsxpackages/ai-workspace-common/src/components/canvas/launchpad/tool-selector-panel/index.tsxpackages/ai-workspace-common/src/components/settings/mcp-server/tools/tool-store.tsx
**/*.tsx
📄 CodeRabbit inference engine (.cursor/rules/09-i18n-guidelines.mdc)
**/*.tsx: Use the translation wrapper component when displaying user-facing text in components
Ensure all user-facing text in components is translatable
Files:
packages/ai-workspace-common/src/components/settings/mcp-server/tools/tool-install-modal.tsxpackages/ai-workspace-common/src/components/settings/mcp-server/mcpServerTab.tsxpackages/ai-workspace-common/src/components/canvas/workflow-run/index.tsxpackages/ai-workspace-common/src/components/canvas/tools-dependency/index.tsxpackages/ai-workspace-common/src/components/canvas/launchpad/tool-selector-panel/index.tsxpackages/ai-workspace-common/src/components/settings/mcp-server/tools/tool-store.tsx
**/*.{css,scss,less,styl,js,jsx,ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/11-ui-design-patterns.mdc)
**/*.{css,scss,less,styl,js,jsx,ts,tsx}: Use the primary blue (#155EEF) for main UI elements, CTAs, and active states
Use red (#F04438) only for errors, warnings, and destructive actions
Use green (#12B76A) for success states and confirmations
Use orange (#F79009) for warning states and important notifications
Use blue (#0BA5EC) for informational elements
Maintain a minimum contrast ratio of 4.5:1 for text
Files:
packages/ai-workspace-common/src/components/settings/mcp-server/tools/tool-install-modal.tsxpackages/ai-workspace-common/src/components/settings/mcp-server/mcpServerTab.tsxpackages/ai-workspace-common/src/components/canvas/workflow-run/index.tsxpackages/ai-workspace-common/src/components/canvas/tools-dependency/index.tsxpackages/ai-workspace-common/src/components/canvas/launchpad/tool-selector-panel/index.tsxpackages/ai-workspace-common/src/components/settings/mcp-server/tools/tool-store.tsx
**/index.{js,jsx,ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/05-code-organization.mdc)
Use index files to export multiple components from a directory
Files:
packages/ai-workspace-common/src/components/canvas/workflow-run/index.tsxpackages/ai-workspace-common/src/components/canvas/tools-dependency/index.tsxpackages/ai-workspace-common/src/components/canvas/launchpad/tool-selector-panel/index.tsx
🧬 Code graph analysis (2)
packages/ai-workspace-common/src/components/settings/mcp-server/mcpServerTab.tsx (1)
packages/ai-workspace-common/src/components/settings/mcp-server/tools/tool-store.tsx (1)
ToolStore(132-231)
packages/ai-workspace-common/src/components/canvas/workflow-run/index.tsx (1)
packages/ai-workspace-common/src/context/canvas.tsx (1)
useCanvasContext(699-705)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: build / Build
🔇 Additional comments (5)
packages/ai-workspace-common/src/components/canvas/workflow-run/index.tsx (1)
48-51: WorkflowRunForm handoff looks goodProps passed align with the new responsibility split; empty-state rendering is now owned by WorkflowRunForm. No issues.
packages/ai-workspace-common/src/components/canvas/tools-dependency/index.tsx (1)
462-468: LGTM: uninstalled count gating is clearerReturning 0 when logged out or when no toolsets with nodes avoids noisy badges and unnecessary work.
packages/ai-workspace-common/src/components/settings/mcp-server/tools/tool-store.tsx (3)
85-87: LGTM: favicon overflow handling.Adding
overflow-hiddenprevents icon spillover in tight layouts.
111-118: Accessible install action looks good.Clear label and button semantics; style aligns with brand utilities.
117-118: Verify translation key presence in all locales
Automated searches didn’t locatesettings.toolStore.install.installin any JSON locale files; please confirm this key is defined across every locale.
| @@ -1,11 +1,8 @@ | |||
| import { Tooltip, Button, Skeleton, Empty } from 'antd'; | |||
| import { Tooltip, Button, Skeleton } from 'antd'; | |||
There was a problem hiding this comment.
🛠️ Refactor suggestion
Import React utilities to enable memoization and stable callbacks
To comply with guidelines (React.memo/useCallback/useMemo), import these from React.
+import { memo, useCallback, useMemo } from 'react';
import { Tooltip, Button, Skeleton } from 'antd';📝 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.
| import { Tooltip, Button, Skeleton } from 'antd'; | |
| import { memo, useCallback, useMemo } from 'react'; | |
| import { Tooltip, Button, Skeleton } from 'antd'; |
🤖 Prompt for AI Agents
In packages/ai-workspace-common/src/components/canvas/workflow-run/index.tsx
around lines 1 to 1, the file only imports UI components from 'antd' but is
missing React imports needed for memoization and stable callbacks; update the
top-level imports to include React utilities (import React, { memo, useCallback,
useMemo } from 'react') and then wrap/export the component with React.memo and
replace inline callback/derived values with useCallback/useMemo where
appropriate to ensure stable references and follow
React.memo/useCallback/useMemo guidelines.
| interface ToolStoreProps { | ||
| visible: boolean; | ||
| toolInstances: ToolsetInstance[]; | ||
| onInstallSuccess?: () => void; | ||
| setToolStoreVisible: (visible: boolean) => void; | ||
| } |
There was a problem hiding this comment.
🛠️ Refactor suggestion
Broaden setter type to React state dispatcher.
Accept Dispatch<SetStateAction<boolean>> to align with useState setters passed in.
-import { useState, useMemo, useCallback, useEffect } from 'react';
+import { useState, useMemo, useCallback, useEffect, memo } from 'react';
+import type { Dispatch, SetStateAction } from 'react';
interface ToolStoreProps {
visible: boolean;
- setToolStoreVisible: (visible: boolean) => void;
+ setToolStoreVisible: Dispatch<SetStateAction<boolean>>;
}📝 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.
| interface ToolStoreProps { | |
| visible: boolean; | |
| toolInstances: ToolsetInstance[]; | |
| onInstallSuccess?: () => void; | |
| setToolStoreVisible: (visible: boolean) => void; | |
| } | |
| import { useState, useMemo, useCallback, useEffect, memo } from 'react'; | |
| import type { Dispatch, SetStateAction } from 'react'; | |
| interface ToolStoreProps { | |
| visible: boolean; | |
| setToolStoreVisible: Dispatch<SetStateAction<boolean>>; | |
| } |
🤖 Prompt for AI Agents
In
packages/ai-workspace-common/src/components/settings/mcp-server/tools/tool-store.tsx
around lines 10 to 13, the prop type for setToolStoreVisible is currently
(visible: boolean) => void; change it to
React.Dispatch<React.SetStateAction<boolean>> (or import Dispatch and
SetStateAction from 'react' and use Dispatch<SetStateAction<boolean>>) so it
matches useState setters; update the import if needed and adjust any
callers/props to pass the raw useState setter without wrapping.
| {filteredTools.map((tool, index) => ( | ||
| <Col key={index} xs={24} sm={12} md={6} lg={6} xl={6}> | ||
| <ToolItem tool={tool} toolInstances={toolInstances} /> | ||
| <ToolItem tool={tool} setToolStoreVisible={setToolStoreVisible} /> | ||
| </Col> |
There was a problem hiding this comment.
🛠️ Refactor suggestion
Use stable keys when rendering tools.
Avoid index keys; use tool.key.
-{filteredTools.map((tool, index) => (
- <Col key={index} xs={24} sm={12} md={6} lg={6} xl={6}>
+{filteredTools.map((tool) => (
+ <Col key={tool.key} xs={24} sm={12} md={6} lg={6} xl={6}>
<ToolItem tool={tool} setToolStoreVisible={setToolStoreVisible} />
</Col>
))}📝 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.
| {filteredTools.map((tool, index) => ( | |
| <Col key={index} xs={24} sm={12} md={6} lg={6} xl={6}> | |
| <ToolItem tool={tool} toolInstances={toolInstances} /> | |
| <ToolItem tool={tool} setToolStoreVisible={setToolStoreVisible} /> | |
| </Col> | |
| {filteredTools.map((tool) => ( | |
| <Col key={tool.key} xs={24} sm={12} md={6} lg={6} xl={6}> | |
| <ToolItem tool={tool} setToolStoreVisible={setToolStoreVisible} /> | |
| </Col> | |
| ))} |
🤖 Prompt for AI Agents
In
packages/ai-workspace-common/src/components/settings/mcp-server/tools/tool-store.tsx
around lines 221 to 224, the list is using the array index as the React key
which is unstable; change the Col key to use a stable unique identifier like
tool.key (e.g., key={tool.key}) instead of index, and if tool.key might be
missing ensure a safe fallback (generate/assign an id upstream or use a
deterministic value) so each tool item has a stable, unique key.
…resource-type-form, use-file-upload): enhance file upload handling and UI interactions
Summary
Please include a summary of the change and which issue is fixed. Please also include relevant motivation and context. List any dependencies that are required for this change.
Tip
Close issue syntax:
Fixes #<issue number>orResolves #<issue number>, see documentation for more details.Impact Areas
Please check the areas this PR affects:
Screenshots/Videos
Checklist
Important
Please review the checklist below before submitting your pull request.
dev/reformat(backend) andcd web && npx lint-staged(frontend) to appease the lint godsSummary by CodeRabbit
New Features
UI Changes
Localization