Skip to content

fix: enhance file upload handling and UI interactions#1326

Merged
mrcfps merged 2 commits intomainfrom
fix/variable-resource
Sep 2, 2025
Merged

fix: enhance file upload handling and UI interactions#1326
mrcfps merged 2 commits intomainfrom
fix/variable-resource

Conversation

@CH1111
Copy link
Copy Markdown
Contributor

@CH1111 CH1111 commented Sep 2, 2025

…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.

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> or Resolves #<issue number>, see documentation for more details.

Impact Areas

Please check the areas this PR affects:

  • Multi-threaded Dialogues
  • AI-Powered Capabilities (Web Search, Knowledge Base Search, Question Recommendations)
  • Context Memory & References
  • Knowledge Base Integration & RAG
  • Quotes & Citations
  • AI Document Editing & WYSIWYG
  • Free-form Canvas Interface
  • Other

Screenshots/Videos

Before After
... ...

Checklist

Important

Please review the checklist below before submitting your pull request.

  • This change requires a documentation update, included: Refly Documentation
  • I understand that this PR may be closed in case there was no previous discussion or issues. (This doesn't apply to typos!)
  • I've added a test for each change that was introduced, and I tried as much as possible to make a single atomic change.
  • I've updated the documentation accordingly.
  • I ran dev/reformat(backend) and cd web && npx lint-staged(frontend) to appease the lint gods

Summary by CodeRabbit

  • New Features

    • Refresh button shows a tooltip; file refresh is contextual per variable and updates the form.
    • Upload picker adapts to allowed resource types and enforces size limits with clearer feedback.
    • Tool store install flow shows success with a View action that closes the store.
  • UI Changes

    • Removed empty-state placeholder in workflow run; delete action no longer shows a tooltip.
    • Toolset labels and referenced-node display improved with overflow handling.
  • Localization

    • Added translations for view, duplicate-file-name, too-many-files, and an empty-state message.

…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.
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Sep 2, 2025

Walkthrough

Adds 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

Cohort / File(s) Summary
File upload hook & refresh API
packages/ai-workspace-common/src/components/canvas/workflow-variables/hooks/use-file-upload.ts
Refactors upload flow into helpers, removes MIME/unknown-category checks, validates size via getFileCategoryAndLimit, builds accept from resourceTypes, and updates handleRefreshFile signature to accept resourceTypes?: string[].
Workflow run form refresh
packages/ai-workspace-common/src/components/canvas/workflow-run/workflow-run-form.tsx
handleRefreshFile now finds the matching workflowVariable, passes its resourceTypes to refreshFile, and updates the form field via form.setFieldsValue; rendering now shows an empty-state when no variables.
Create Variables modal refresh
packages/ai-workspace-common/src/components/canvas/workflow-variables/create-variables-modal.tsx
handleRefreshFile passes resourceFormData.resourceTypes to refreshFile; dependency array updated; minor View button class tweak.
Resource upload UI tooltip
packages/ai-workspace-common/src/components/canvas/workflow-run/resource-upload.tsx
Wraps the refresh Button with an AntD Tooltip using canvas.workflow.variables.reloadFile; button props unchanged.
Resource type form delete button
packages/ai-workspace-common/src/components/canvas/workflow-variables/resource-type-form.tsx
Removes Tooltip wrapper around the Delete button; handler unchanged.
Workflow-run container render simplification
packages/ai-workspace-common/src/components/canvas/workflow-run/index.tsx
Removed empty-state UI and related imports/logic; component now always renders WorkflowRunForm when not loading and reads only workflow from context.
Toolstore / MCP server UI & API surface
packages/ai-workspace-common/src/components/settings/mcp-server/mcpServerTab.tsx, .../tools/tool-store.tsx, .../tools/tool-install-modal.tsx
ToolStore prop changed from toolInstancessetToolStoreVisible; ToolItem simplified (install flow only), ToolInstallModal uses form.resetFields() and exposes onSuccess; install success shows message with View action that closes store.
Tool labeling & referenced nodes UI
packages/ai-workspace-common/src/components/canvas/launchpad/tool-selector-panel/index.tsx, packages/ai-workspace-common/src/components/canvas/tools-dependency/index.tsx
Builtin regular toolsets keep localized label; others use toolset.name; ToolsDependency adds ReferencedNodesDisplay to adaptively show node labels and recalculates uninstalledCount using toolsets-with-nodes vs installed toolsets.
i18n additions
packages/i18n/src/en-US/ui.ts, packages/i18n/src/zh-Hans/ui.ts
Adds translation keys: common.view, workflow.variables.duplicateFileName, workflow.variables.tooManyFiles, and workflow.run.empty (English and zh-Hans).

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
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~75 minutes

Possibly related PRs

Suggested reviewers

  • anthhub
  • mrcfps

Poem

I nibble bugs and patch a seam,
I teach the picker what to dream.
New keys I hum, two voices more,
A tooltip whispers at the door.
Carrot-clutch, I hop — features soar. 🥕🐇

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch fix/variable-resource

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
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR/Issue comments)

Type @coderabbitai help to get the list of available commands.

Other keywords and placeholders

  • Add @coderabbitai ignore or @coderabbit ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@mrcfps mrcfps changed the title refactor(resource-upload, workflow-run-form, create-variables-modal, … fix: enhance file upload handling and UI interactions Sep 2, 2025
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

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 for option values.

variable.value can be undefined; direct .map will 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 .map calls to avoid runtime errors when value is undefined.

Both option and resource branches 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 button

Icon-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 keys

Minor 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 resourceTypes

Use 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 button

Icon-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 form and handleValueChange but doesn’t include them in the dependency array, risking stale closures.

Apply:

-  );
-  // deps
-  [uploadFile, variableValues],
+  );
+  // deps
+  [uploadFile, variableValues, form, handleValueChange],

179-189: Add form to handleFileRemove deps.

form.setFieldsValue is used but form isn’t listed in the deps.

-  );
-  // deps
-  [variableValues, handleValueChange],
+  );
+  // deps
+  [variableValues, handleValueChange, form],

15-22: Wrap pure subcomponents with React.memo.

RequiredTagText and FormItemLabel are 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 ../constants for 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 any and 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 type resourceTypes as 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.

📥 Commits

Reviewing files that changed from the base of the PR and between 879ef8f and 1814181.

📒 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 line

Use React best practices for frontend code

Files:

  • packages/ai-workspace-common/src/components/canvas/workflow-variables/create-variables-modal.tsx
  • packages/ai-workspace-common/src/components/canvas/workflow-variables/resource-type-form.tsx
  • packages/ai-workspace-common/src/components/canvas/workflow-run/resource-upload.tsx
  • packages/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 + b instead of a+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.tsx
  • packages/ai-workspace-common/src/components/canvas/workflow-variables/resource-type-form.tsx
  • packages/ai-workspace-common/src/components/canvas/workflow-run/resource-upload.tsx
  • packages/ai-workspace-common/src/components/canvas/workflow-run/workflow-run-form.tsx
  • packages/i18n/src/zh-Hans/ui.ts
  • packages/i18n/src/en-US/ui.ts
  • packages/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 using any type whenever possible - it defeats the purpose of TypeScript
When tempted to use any, use unknown type 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 the import type syntax
Group type imports separately from value imports
Minimize creating local type aliases for imported types

Explicitly type props interfaces/types

Files:

  • packages/ai-workspace-common/src/components/canvas/workflow-variables/create-variables-modal.tsx
  • packages/ai-workspace-common/src/components/canvas/workflow-variables/resource-type-form.tsx
  • packages/ai-workspace-common/src/components/canvas/workflow-run/resource-upload.tsx
  • packages/ai-workspace-common/src/components/canvas/workflow-run/workflow-run-form.tsx
  • packages/i18n/src/zh-Hans/ui.ts
  • packages/i18n/src/en-US/ui.ts
  • packages/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.tsx
  • packages/ai-workspace-common/src/components/canvas/workflow-variables/resource-type-form.tsx
  • packages/ai-workspace-common/src/components/canvas/workflow-run/resource-upload.tsx
  • packages/ai-workspace-common/src/components/canvas/workflow-run/workflow-run-form.tsx
  • packages/i18n/src/zh-Hans/ui.ts
  • packages/i18n/src/en-US/ui.ts
  • packages/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.tsx
  • packages/ai-workspace-common/src/components/canvas/workflow-variables/resource-type-form.tsx
  • packages/ai-workspace-common/src/components/canvas/workflow-run/resource-upload.tsx
  • packages/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.tsx
  • packages/ai-workspace-common/src/components/canvas/workflow-variables/resource-type-form.tsx
  • packages/ai-workspace-common/src/components/canvas/workflow-run/resource-upload.tsx
  • packages/ai-workspace-common/src/components/canvas/workflow-run/workflow-run-form.tsx
  • packages/i18n/src/zh-Hans/ui.ts
  • packages/i18n/src/en-US/ui.ts
  • packages/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.ts
  • packages/i18n/src/en-US/ui.ts
  • packages/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.ts
  • packages/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.ts
  • packages/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.ts
  • packages/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-US

Wording 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 resourceTypes from the variable and syncing the AntD form after refresh. Dependency array update to include form and workflowVariables is appropriate.

Also applies to: 210-210


195-208: Narrow resourceTypes to 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 WorkflowVariable declares resourceTypes?: Array<'document' | 'image' | 'audio' | 'video'>? If not, I can provide a quick type patch.

Comment on lines +142 to +159
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(',');
};
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🛠️ 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.

Suggested change
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.
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

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 type

Prevents 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 readers

Improves 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 change

Replace the current useEffect so 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

moreMenuItems references handleLocateNode before it’s declared; this will throw at render time. Move handleLocateNode above, 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 undefined labelDict.

Direct indexing can throw when labelDict is 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: Input doesn’t support onClear; remove to prevent unknown-prop warnings.

Rely on allowClear + onChange instead.

-<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.scss

If 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 render

Returning 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 validation

Aligns 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 comments

Keeps 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 readability

No 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 props

Hoist 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 toolsets

Switching 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 panel

For non-builtin toolsets, fall back to the localized label when name is 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: Use import type for types and group them separately.

Switch ToolsetDefinition to 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: Memoize ToolItem and 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 ellipsis config 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: Stabilize onCancel handler.

Use useCallback to 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 gutter and 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.domain is 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: updated ToolStore prop wiring.

Passing the visibility setter enables close-on-install flow; matches the new API. Ensure ToolStoreProps uses Dispatch<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.

📥 Commits

Reviewing files that changed from the base of the PR and between 1814181 and d2de634.

📒 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 line

Use React best practices for frontend code

Files:

  • packages/ai-workspace-common/src/components/settings/mcp-server/tools/tool-install-modal.tsx
  • packages/ai-workspace-common/src/components/settings/mcp-server/mcpServerTab.tsx
  • packages/ai-workspace-common/src/components/canvas/workflow-run/index.tsx
  • packages/ai-workspace-common/src/components/canvas/tools-dependency/index.tsx
  • packages/ai-workspace-common/src/components/canvas/launchpad/tool-selector-panel/index.tsx
  • packages/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 + b instead of a+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.tsx
  • packages/ai-workspace-common/src/components/settings/mcp-server/mcpServerTab.tsx
  • packages/ai-workspace-common/src/components/canvas/workflow-run/index.tsx
  • packages/ai-workspace-common/src/components/canvas/tools-dependency/index.tsx
  • packages/ai-workspace-common/src/components/canvas/launchpad/tool-selector-panel/index.tsx
  • packages/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 using any type whenever possible - it defeats the purpose of TypeScript
When tempted to use any, use unknown type 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 the import type syntax
Group type imports separately from value imports
Minimize creating local type aliases for imported types

Explicitly type props interfaces/types

Files:

  • packages/ai-workspace-common/src/components/settings/mcp-server/tools/tool-install-modal.tsx
  • packages/ai-workspace-common/src/components/settings/mcp-server/mcpServerTab.tsx
  • packages/ai-workspace-common/src/components/canvas/workflow-run/index.tsx
  • packages/ai-workspace-common/src/components/canvas/tools-dependency/index.tsx
  • packages/ai-workspace-common/src/components/canvas/launchpad/tool-selector-panel/index.tsx
  • packages/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.tsx
  • packages/ai-workspace-common/src/components/settings/mcp-server/mcpServerTab.tsx
  • packages/ai-workspace-common/src/components/canvas/workflow-run/index.tsx
  • packages/ai-workspace-common/src/components/canvas/tools-dependency/index.tsx
  • packages/ai-workspace-common/src/components/canvas/launchpad/tool-selector-panel/index.tsx
  • packages/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.tsx
  • packages/ai-workspace-common/src/components/settings/mcp-server/mcpServerTab.tsx
  • packages/ai-workspace-common/src/components/canvas/workflow-run/index.tsx
  • packages/ai-workspace-common/src/components/canvas/tools-dependency/index.tsx
  • packages/ai-workspace-common/src/components/canvas/launchpad/tool-selector-panel/index.tsx
  • packages/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.tsx
  • packages/ai-workspace-common/src/components/settings/mcp-server/mcpServerTab.tsx
  • packages/ai-workspace-common/src/components/canvas/workflow-run/index.tsx
  • packages/ai-workspace-common/src/components/canvas/tools-dependency/index.tsx
  • packages/ai-workspace-common/src/components/canvas/launchpad/tool-selector-panel/index.tsx
  • packages/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.tsx
  • packages/ai-workspace-common/src/components/canvas/tools-dependency/index.tsx
  • packages/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 good

Props 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 clearer

Returning 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-hidden prevents 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 locate settings.toolStore.install.install in 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';
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🛠️ 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.

Suggested change
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.

Comment on lines 10 to 13
interface ToolStoreProps {
visible: boolean;
toolInstances: ToolsetInstance[];
onInstallSuccess?: () => void;
setToolStoreVisible: (visible: boolean) => void;
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🛠️ 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.

Suggested change
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.

Comment on lines 221 to 224
{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>
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🛠️ 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.

Suggested change
{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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants