- Notifications
You must be signed in to change notification settings - Fork 421
Feat/workflow dogfooding #1569
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Feat/workflow dogfooding #1569
Conversation
…e layout - Added state management for email form expansion in the LoginModal component. - Implemented a button to toggle the visibility of the email form, improving user interaction. - Ensured compliance with coding standards, including the use of Tailwind CSS for styling and optional chaining for safe property access.
- Introduced workflow app integration in the CanvasDetailModel and updated the canvasPO2DTO function to include workflow app data. - Enhanced CanvasService to fetch and map workflow apps associated with canvases. - Updated translations for workflow app publish status in both English and Chinese. - Ensured compliance with coding standards, including the use of optional chaining and Tailwind CSS for styling.
…ions - Refactored the WorkflowList component to consolidate rendering logic for workflow titles and status indicators, improving readability and maintainability. - Updated translations for the 'shared' status in Chinese to enhance user experience. - Ensured compliance with coding standards, including the use of optional chaining and Tailwind CSS for styling.
…slations - Removed unused imports and simplified the DocumentNode component by eliminating unnecessary content previews and time display. - Updated translation strings to reflect changes in terminology from 'canvas' to 'workflow' for better clarity. - Ensured compliance with coding standards, including the use of optional chaining and Tailwind CSS for styling.
…reation and deletion - Added optimistic updates for variable creation and deletion in the CreateVariablesModal and VariableItem components, improving user experience by reflecting changes immediately in the UI. - Utilized React Query's cache management to handle optimistic updates and rollbacks on failure, ensuring data consistency. - Ensured compliance with coding standards, including the use of optional chaining and Tailwind CSS for styling.
- Added a display for the document's creation time in the DocumentNode component, utilizing the time utility for formatting. - Integrated language support for the time display based on the current language setting. - Ensured compliance with coding standards, including the use of optional chaining and Tailwind CSS for styling.
… functionality - Replaced the use of `useIsLogin` and `useNavigate` with `useUserStoreShallow` and `useAuthStoreShallow` for improved state management in the WorkflowAPPForm component. - Updated login check logic to open the login modal instead of redirecting, enhancing user experience. - Refactored the remix button's onClick handler to utilize a new `handleRemix` function, ensuring proper login validation before executing the original workflow copy function. - Ensured compliance with coding standards, including the use of optional chaining and Tailwind CSS for styling.
… group display - Introduced a new ContactCard for the Notion document in the ContactUsPopover component, enhancing user access to documentation. - Reorganized the WeChat group display for better visibility and consistency with other contact options. - Updated translations for the Notion document and its button text to support multilingual users. - Ensured compliance with coding standards, including the use of optional chaining and Tailwind CSS for styling.
- Changed the Notion document link in the ContactUsPopover component to include the 'https://' protocol for proper navigation. - Ensured compliance with coding standards, including the use of optional chaining and Tailwind CSS for styling.
…e-collapse, sider): update collapse state management and improve performance - Refactored components to utilize the new collapseState instead of boolean collapse for better state management. - Integrated setIsManualCollapse in multiple components to ensure consistent sidebar behavior on navigation and workflow edits. - Enhanced performance by using useMemo for derived values and ensuring proper dependency arrays in useEffect hooks. - Ensured compliance with coding standards, including the use of optional chaining and Tailwind CSS for styling.
- Updated the collapsed height from 64 to 48 for better visual consistency in the SiderLoggedIn component. - Adjusted padding in the main container to enhance the overall layout and spacing. - Ensured compliance with coding standards, including the use of optional chaining and Tailwind CSS for styling.
…ility - Replaced the direct rendering of elements in the collapsed state with a new SiderMenuSettingList component to enhance code organization and maintainability. - Ensured compliance with coding standards, including the use of optional chaining and Tailwind CSS for styling.
…y and improve user feedback - Updated the WorkflowActionDropdown component to replace the share functionality with separate copy link and copy template link actions, improving clarity and usability. - Introduced loading states for the copy link actions to provide better user feedback during asynchronous operations. - Added new translation strings for copy link and template link functionalities to support multilingual users. - Ensured compliance with coding standards, including the use of optional chaining and Tailwind CSS for styling.
…up props - Eliminated the afterShare callback function as it was no longer needed, simplifying the component logic. - Updated the WorkflowList component to remove the onShareSuccess prop from the workflow rendering, enhancing clarity and maintainability. - Ensured compliance with coding standards, including the use of optional chaining and Tailwind CSS for styling.
…ng state handling - Removed the icon from the modal title for a cleaner appearance, retaining the confirmation message. - Adjusted the okButtonProps to only include the loading state, enhancing clarity. - Ensured compliance with coding standards, including the use of optional chaining and Tailwind CSS for styling.
…or improved clarity - Eliminated the interactive code artifact creation functionality from the PreCode component, simplifying the code and enhancing maintainability. - Updated the component to ensure compliance with coding standards, including the use of optional chaining and Tailwind CSS for styling.
… improve UI interactions - Introduced a delete canvas option in the ActionsInCanvasDropdown component, allowing users to delete canvases directly from the dropdown. - Integrated the openDeleteModal function to handle canvas deletion, enhancing user experience and interaction. - Updated the component to ensure compliance with coding standards, including the use of optional chaining and Tailwind CSS for styling.
…styling - Replaced the Sider component with a div wrapper to enhance layout flexibility and maintainability. - Updated the styling to use Tailwind CSS for better visual consistency and responsiveness. - Ensured proper handling of overflow and height based on the source prop. - Maintained compliance with coding standards, including the use of optional chaining and nullish coalescing.
…firmations across components - Replaced Popconfirm components with Modal for delete confirmations in various components, enhancing user experience and consistency. - Implemented loading states for delete actions to provide better feedback during asynchronous operations. - Ensured compliance with coding standards, including the use of optional chaining and Tailwind CSS for styling.
…rkflow-dogfooding
WalkthroughThis PR integrates workflow app metadata into canvas data models, refactors sider collapse state management, replaces Popconfirm dialogs with Modal components throughout the UI, implements optimistic React Query updates for variable operations, restructures workflow list visualization, and adds support for collapsible sider with manual collapse state tracking. Changes
Sequence Diagram(s)sequenceDiagram participant User participant UI as Modal Confirm UI participant Store as React Query Store participant API as Backend API participant DB as IndexedDB User->>UI: Click Delete Variable UI->>UI: Open Modal User->>UI: Confirm Delete UI->>Store: Optimistic Update (remove from cache) UI->>API: DELETE /variable par Success Path API->>API: Delete succeeds API-->>UI: Success response UI->>UI: Close modal and Failure Path API->>API: Delete fails API-->>UI: Error response UI->>Store: Rollback (restore from workflowVariables) UI->>UI: Show error message end sequenceDiagram participant User participant Sider as Sider Component participant Store as Sider Store participant Route as Route Hook Note over User,Route: Manual Collapse User->>Sider: Click Collapse Toggle Sider->>Store: setIsManualCollapse(true)<br/>setCollapseState('hidden') Store-->>Sider: State updated Note over User,Route: Route Change (Manual=false) Route->>Store: Get collapseState, isManualCollapse Route->>Store: isManualCollapse is false? Route->>Store: setCollapseState(nextState)<br/>based on route Store-->>Route: Auto-collapse updated Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes
Possibly related PRs
Suggested reviewers
Pre-merge checks and finishing touches❌ Failed checks (2 warnings, 1 inconclusive)
✨ Finishing touches
🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 19
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
packages/web-core/src/components/login-modal/index.tsx (1)
223-353: Restore the email login path when OAuth isn't available.Line 241 currently renders the email form only when
isEmailFormExpandedis true. However, the toggle button that can flip this state only appears when either GitHub or Google OAuth is enabled (Lines 198-239). In a deployment where both OAuth providers are disabled and email login is the sole option, the toggle never renders, sosetIsEmailFormExpandedis never invoked and the email form stays hidden. That leaves users with no way to log in—a release blocker.Please default the email form to open automatically when no OAuth providers are configured and keep the toggle-controlled path for mixed setups. One way to do that is to derive a
showEmailWithoutToggleflag and use it both to auto-expand and to decide whether the form should render:@@ -const [isEmailFormExpanded, setIsEmailFormExpanded] = useState(false); +const [isEmailFormExpanded, setIsEmailFormExpanded] = useState(false); @@ -const { isGithubEnabled, isGoogleEnabled, isEmailEnabled } = useMemo(() => { +const { isGithubEnabled, isGoogleEnabled, isEmailEnabled } = useMemo(() => { … }, [authConfig?.data, isAuthConfigLoading]); + +const showEmailWithoutToggle = useMemo( + () => !isGithubEnabled && !isGoogleEnabled, + [isGithubEnabled, isGoogleEnabled], +); + +useEffect(() => { + if (showEmailWithoutToggle) { + setIsEmailFormExpanded(true); + } +}, [showEmailWithoutToggle]); @@ - {isEmailEnabled && isEmailFormExpanded && ( + {isEmailEnabled && (showEmailWithoutToggle || isEmailFormExpanded) && (This preserves the new toggle UX while ensuring the fallback email login path remains reachable in production.
packages/ai-workspace-common/src/components/sider/layout.tsx (1)
300-304: Fix stale avatar alignment in memoized avatar renderer
renderUserAvatarcloses overavatarAlignbut the dependency list omits it, so switchingavatarAlign(e.g., when reused with a right-aligned layout) keeps rendering the old alignment and breaks spacing. IncludeavatarAlignin the memo dependencies so the avatar updates correctly.- const renderUserAvatar = useMemo( - () => <UserAvatar showName={showName} userProfile={userProfile} avatarAlign={avatarAlign} />, - [showName, userProfile], - ); + const renderUserAvatar = useMemo( + () => <UserAvatar showName={showName} userProfile={userProfile} avatarAlign={avatarAlign} />, + [showName, userProfile, avatarAlign], + );
🧹 Nitpick comments (8)
packages/ai-workspace-common/src/components/contact-us-popover/index.tsx (2)
32-34: Consider using useCallback for event handlers.The handler follows the existing pattern correctly. However, per coding guidelines, event handlers passed as props should be wrapped with
useCallbackto maintain referential equality and prevent unnecessary re-renders.Apply this pattern to all event handlers in the component:
+ const handleNotionDocumentClick = React.useCallback(() => { - const handleNotionDocumentClick = () => { window.open('https://notion.so/reflydoc/Contact-us-28dd62ce607180318ae6c944e2db6abf', '_blank'); - }; + }, []);As per coding guidelines.
76-88: Consider extracting WeChat card into a separate component.The inline implementation is functional and appropriate given the different layout requirements (QR code display). However, extracting it into a reusable component (e.g.,
QRCodeContactCard) would improve maintainability and follow the pattern established withContactCard.Example structure in
contact-card.tsx:export const QRCodeContactCard: React.FC<{ qrCodeUrl: string; title: string; altText: string; }> = ({ qrCodeUrl, title, altText }) => { return ( <div className="w-[156px] h-[176px] flex flex-col items-center text-center p-2 rounded-xl border-solid border-[1px] border-refly-Card-Border"> <div className="w-[140px] h-[140px] rounded-lg overflow-hidden"> <img src={qrCodeUrl} alt={altText} className="w-full h-full object-contain" /> </div> <div className="text-xs text-refly-text-0 mt-1 font-semibold leading-4">{title}</div> </div> ); };packages/ai-workspace-common/src/components/canvas/top-toolbar/actions-in-canvas-dropdown.tsx (1)
313-316: Consider dependency array optimization for performance.The addition of
canvasId,canvasName, andonDeleteSuccessto the dependency array ensures correctness but may cause theitemsarray to be recreated more frequently than necessary.Since
canvasIdtypically won't change without a full component remount andonDeleteSuccessmay not be stable if the parent doesn't wrap it inuseCallback, consider whether all these dependencies are necessary for the memoization to be effective.If parent components aren't wrapping
onDeleteSuccessinuseCallback, the items array will be recreated on every parent render, partially defeating the purpose ofuseMemo.No action required if parent components properly memoize their callbacks. This is noted for awareness in case performance profiling reveals unnecessary re-renders.
packages/ai-workspace-common/src/components/canvas/node-preview/start.tsx (1)
55-56: Remove the unused refetch prop instead of masking the lint warning.The
void refetchWorkflowVariables;line is a no-op solely to satisfy linting. Either invokerefetchWorkflowVariablesafter the mutation or drop it from this component's props and callers to avoid dead code.apps/api/src/modules/canvas/canvas.service.ts (1)
156-170: Scope query to needed fields and guard empty input.
- If canvasIds is empty, skip the workflowApp query to save a roundtrip.
- Select only needed fields to reduce payload and coupling (e.g., appId, shareId, title, description, canvasId, query, variables, resultNodeIds, remixEnabled, coverUrl, createdAt, updatedAt).
Example:
-const workflowApps = await this.prisma.workflowApp.findMany({ - where: { canvasId: { in: canvasIds }, deletedAt: null }, - orderBy: { createdAt: 'desc' }, -}); +const workflowApps = canvasIds.length + ? await this.prisma.workflowApp.findMany({ + where: { canvasId: { in: canvasIds }, deletedAt: null }, + orderBy: { createdAt: 'desc' }, + select: { + appId: true, shareId: true, title: true, description: true, + canvasId: true, query: true, variables: true, resultNodeIds: true, + remixEnabled: true, coverUrl: true, createdAt: true, updatedAt: true, + }, + }) + : [];packages/ai-workspace-common/src/components/canvas/nodes/document.tsx (2)
80-86: Prefer nullish coalescing for potentially undefined canvasId.Use canvasId ?? '' instead of || to avoid falsy collisions.
-const { status: executionStatus } = useNodeExecutionStatus({ - canvasId: canvasId || '', +const { status: executionStatus } = useNodeExecutionStatus({ + canvasId: canvasId ?? '', nodeId: id, });
129-133: Make user-facing text translatable.'Skill' should use i18n.
- title: 'Skill', + title: t('canvas.nodeTypes.skill'),Also add t to deps if not already.
packages/ai-workspace-common/src/components/canvas/front-page/index.tsx (1)
79-81: Minor: open new tab safely.Add rel="noopener noreferrer" to prevent tab-nabbing.
- window.open('https://reflydoc.notion.site/how-to-use-refly', '_blank'); + window.open('https://reflydoc.notion.site/how-to-use-refly', '_blank', 'noopener,noreferrer');
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (33)
apps/api/src/modules/canvas/canvas.dto.ts(3 hunks)apps/api/src/modules/canvas/canvas.service.ts(1 hunks)packages/ai-workspace-common/src/components/app-manager/app-card.tsx(3 hunks)packages/ai-workspace-common/src/components/canvas/front-page/index.tsx(2 hunks)packages/ai-workspace-common/src/components/canvas/front-page/recent-workflow.tsx(2 hunks)packages/ai-workspace-common/src/components/canvas/launchpad/rich-chat-input/mentionList.tsx(4 hunks)packages/ai-workspace-common/src/components/canvas/modals/canvas-delete.tsx(1 hunks)packages/ai-workspace-common/src/components/canvas/node-preview/start.tsx(3 hunks)packages/ai-workspace-common/src/components/canvas/nodes/document.tsx(1 hunks)packages/ai-workspace-common/src/components/canvas/top-toolbar/actions-in-canvas-dropdown.tsx(4 hunks)packages/ai-workspace-common/src/components/canvas/workflow-variables/create-variables-modal.tsx(3 hunks)packages/ai-workspace-common/src/components/contact-us-popover/index.tsx(4 hunks)packages/ai-workspace-common/src/components/editor/components/selectors/create-memo-selector.tsx(1 hunks)packages/ai-workspace-common/src/components/markdown/plugins/code/render.tsx(0 hunks)packages/ai-workspace-common/src/components/settings/model-config/index.tsx(3 hunks)packages/ai-workspace-common/src/components/settings/model-providers/index.tsx(3 hunks)packages/ai-workspace-common/src/components/settings/tools-config/McpServerList.tsx(3 hunks)packages/ai-workspace-common/src/components/settings/tools-config/tools/tool-list.tsx(4 hunks)packages/ai-workspace-common/src/components/sider/layout.tsx(6 hunks)packages/ai-workspace-common/src/components/workflow-list/index.tsx(4 hunks)packages/ai-workspace-common/src/components/workflow-list/workflowActionDropdown.tsx(4 hunks)packages/ai-workspace-common/src/hooks/canvas/use-delete-canvas.ts(2 hunks)packages/ai-workspace-common/src/hooks/use-route-collapse.ts(2 hunks)packages/ai-workspace-common/src/requests/types.gen.ts(1 hunks)packages/i18n/src/en-US/ui.ts(4 hunks)packages/i18n/src/zh-Hans/ui.ts(4 hunks)packages/openapi-schema/schema.yml(1 hunks)packages/openapi-schema/src/schemas.gen.ts(1 hunks)packages/openapi-schema/src/types.gen.ts(1 hunks)packages/request/src/requests/types.gen.ts(1 hunks)packages/stores/src/stores/sider.ts(4 hunks)packages/web-core/src/components/login-modal/index.tsx(4 hunks)packages/web-core/src/pages/workflow-app/workflow-app-form.tsx(6 hunks)
💤 Files with no reviewable changes (1)
- packages/ai-workspace-common/src/components/markdown/plugins/code/render.tsx
🧰 Additional context used
📓 Path-based instructions (9)
**/*.{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:
apps/api/src/modules/canvas/canvas.service.tspackages/openapi-schema/src/types.gen.tspackages/ai-workspace-common/src/components/settings/model-providers/index.tsxpackages/openapi-schema/src/schemas.gen.tspackages/ai-workspace-common/src/components/editor/components/selectors/create-memo-selector.tsxpackages/ai-workspace-common/src/components/canvas/nodes/document.tsxpackages/ai-workspace-common/src/components/app-manager/app-card.tsxpackages/ai-workspace-common/src/components/contact-us-popover/index.tsxpackages/ai-workspace-common/src/components/canvas/node-preview/start.tsxpackages/ai-workspace-common/src/components/canvas/launchpad/rich-chat-input/mentionList.tsxpackages/ai-workspace-common/src/components/settings/model-config/index.tsxapps/api/src/modules/canvas/canvas.dto.tspackages/request/src/requests/types.gen.tspackages/ai-workspace-common/src/components/canvas/modals/canvas-delete.tsxpackages/ai-workspace-common/src/hooks/use-route-collapse.tspackages/ai-workspace-common/src/components/workflow-list/workflowActionDropdown.tsxpackages/ai-workspace-common/src/hooks/canvas/use-delete-canvas.tspackages/ai-workspace-common/src/components/canvas/front-page/recent-workflow.tsxpackages/ai-workspace-common/src/components/canvas/front-page/index.tsxpackages/ai-workspace-common/src/requests/types.gen.tspackages/ai-workspace-common/src/components/canvas/workflow-variables/create-variables-modal.tsxpackages/ai-workspace-common/src/components/settings/tools-config/McpServerList.tsxpackages/web-core/src/components/login-modal/index.tsxpackages/i18n/src/zh-Hans/ui.tspackages/web-core/src/pages/workflow-app/workflow-app-form.tsxpackages/ai-workspace-common/src/components/canvas/top-toolbar/actions-in-canvas-dropdown.tsxpackages/ai-workspace-common/src/components/workflow-list/index.tsxpackages/ai-workspace-common/src/components/settings/tools-config/tools/tool-list.tsxpackages/stores/src/stores/sider.tspackages/i18n/src/en-US/ui.tspackages/ai-workspace-common/src/components/sider/layout.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:
apps/api/src/modules/canvas/canvas.service.tspackages/openapi-schema/src/types.gen.tspackages/ai-workspace-common/src/components/settings/model-providers/index.tsxpackages/openapi-schema/src/schemas.gen.tspackages/ai-workspace-common/src/components/editor/components/selectors/create-memo-selector.tsxpackages/ai-workspace-common/src/components/canvas/nodes/document.tsxpackages/ai-workspace-common/src/components/app-manager/app-card.tsxpackages/ai-workspace-common/src/components/contact-us-popover/index.tsxpackages/ai-workspace-common/src/components/canvas/node-preview/start.tsxpackages/ai-workspace-common/src/components/canvas/launchpad/rich-chat-input/mentionList.tsxpackages/ai-workspace-common/src/components/settings/model-config/index.tsxapps/api/src/modules/canvas/canvas.dto.tspackages/request/src/requests/types.gen.tspackages/ai-workspace-common/src/components/canvas/modals/canvas-delete.tsxpackages/ai-workspace-common/src/hooks/use-route-collapse.tspackages/ai-workspace-common/src/components/workflow-list/workflowActionDropdown.tsxpackages/ai-workspace-common/src/hooks/canvas/use-delete-canvas.tspackages/ai-workspace-common/src/components/canvas/front-page/recent-workflow.tsxpackages/ai-workspace-common/src/components/canvas/front-page/index.tsxpackages/ai-workspace-common/src/requests/types.gen.tspackages/ai-workspace-common/src/components/canvas/workflow-variables/create-variables-modal.tsxpackages/ai-workspace-common/src/components/settings/tools-config/McpServerList.tsxpackages/web-core/src/components/login-modal/index.tsxpackages/i18n/src/zh-Hans/ui.tspackages/web-core/src/pages/workflow-app/workflow-app-form.tsxpackages/ai-workspace-common/src/components/canvas/top-toolbar/actions-in-canvas-dropdown.tsxpackages/ai-workspace-common/src/components/workflow-list/index.tsxpackages/ai-workspace-common/src/components/settings/tools-config/tools/tool-list.tsxpackages/stores/src/stores/sider.tspackages/i18n/src/en-US/ui.tspackages/ai-workspace-common/src/components/sider/layout.tsx
**/*.ts
📄 CodeRabbit inference engine (.cursor/rules/08-contributing-guidelines.mdc)
Follow NestJS patterns for backend code
Files:
apps/api/src/modules/canvas/canvas.service.tspackages/openapi-schema/src/types.gen.tspackages/openapi-schema/src/schemas.gen.tsapps/api/src/modules/canvas/canvas.dto.tspackages/request/src/requests/types.gen.tspackages/ai-workspace-common/src/hooks/use-route-collapse.tspackages/ai-workspace-common/src/hooks/canvas/use-delete-canvas.tspackages/ai-workspace-common/src/requests/types.gen.tspackages/i18n/src/zh-Hans/ui.tspackages/stores/src/stores/sider.tspackages/i18n/src/en-US/ui.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:
apps/api/src/modules/canvas/canvas.service.tspackages/openapi-schema/src/types.gen.tspackages/ai-workspace-common/src/components/settings/model-providers/index.tsxpackages/openapi-schema/src/schemas.gen.tspackages/ai-workspace-common/src/components/editor/components/selectors/create-memo-selector.tsxpackages/ai-workspace-common/src/components/canvas/nodes/document.tsxpackages/ai-workspace-common/src/components/app-manager/app-card.tsxpackages/ai-workspace-common/src/components/contact-us-popover/index.tsxpackages/ai-workspace-common/src/components/canvas/node-preview/start.tsxpackages/ai-workspace-common/src/components/canvas/launchpad/rich-chat-input/mentionList.tsxpackages/ai-workspace-common/src/components/settings/model-config/index.tsxapps/api/src/modules/canvas/canvas.dto.tspackages/request/src/requests/types.gen.tspackages/ai-workspace-common/src/components/canvas/modals/canvas-delete.tsxpackages/ai-workspace-common/src/hooks/use-route-collapse.tspackages/ai-workspace-common/src/components/workflow-list/workflowActionDropdown.tsxpackages/ai-workspace-common/src/hooks/canvas/use-delete-canvas.tspackages/ai-workspace-common/src/components/canvas/front-page/recent-workflow.tsxpackages/ai-workspace-common/src/components/canvas/front-page/index.tsxpackages/ai-workspace-common/src/requests/types.gen.tspackages/ai-workspace-common/src/components/canvas/workflow-variables/create-variables-modal.tsxpackages/ai-workspace-common/src/components/settings/tools-config/McpServerList.tsxpackages/web-core/src/components/login-modal/index.tsxpackages/i18n/src/zh-Hans/ui.tspackages/web-core/src/pages/workflow-app/workflow-app-form.tsxpackages/ai-workspace-common/src/components/canvas/top-toolbar/actions-in-canvas-dropdown.tsxpackages/ai-workspace-common/src/components/workflow-list/index.tsxpackages/ai-workspace-common/src/components/settings/tools-config/tools/tool-list.tsxpackages/stores/src/stores/sider.tspackages/i18n/src/en-US/ui.tspackages/ai-workspace-common/src/components/sider/layout.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:
apps/api/src/modules/canvas/canvas.service.tspackages/openapi-schema/src/types.gen.tspackages/ai-workspace-common/src/components/settings/model-providers/index.tsxpackages/openapi-schema/src/schemas.gen.tspackages/ai-workspace-common/src/components/editor/components/selectors/create-memo-selector.tsxpackages/ai-workspace-common/src/components/canvas/nodes/document.tsxpackages/ai-workspace-common/src/components/app-manager/app-card.tsxpackages/ai-workspace-common/src/components/contact-us-popover/index.tsxpackages/ai-workspace-common/src/components/canvas/node-preview/start.tsxpackages/ai-workspace-common/src/components/canvas/launchpad/rich-chat-input/mentionList.tsxpackages/ai-workspace-common/src/components/settings/model-config/index.tsxapps/api/src/modules/canvas/canvas.dto.tspackages/request/src/requests/types.gen.tspackages/ai-workspace-common/src/components/canvas/modals/canvas-delete.tsxpackages/ai-workspace-common/src/hooks/use-route-collapse.tspackages/ai-workspace-common/src/components/workflow-list/workflowActionDropdown.tsxpackages/ai-workspace-common/src/hooks/canvas/use-delete-canvas.tspackages/ai-workspace-common/src/components/canvas/front-page/recent-workflow.tsxpackages/ai-workspace-common/src/components/canvas/front-page/index.tsxpackages/ai-workspace-common/src/requests/types.gen.tspackages/ai-workspace-common/src/components/canvas/workflow-variables/create-variables-modal.tsxpackages/ai-workspace-common/src/components/settings/tools-config/McpServerList.tsxpackages/web-core/src/components/login-modal/index.tsxpackages/i18n/src/zh-Hans/ui.tspackages/web-core/src/pages/workflow-app/workflow-app-form.tsxpackages/ai-workspace-common/src/components/canvas/top-toolbar/actions-in-canvas-dropdown.tsxpackages/ai-workspace-common/src/components/workflow-list/index.tsxpackages/ai-workspace-common/src/components/settings/tools-config/tools/tool-list.tsxpackages/stores/src/stores/sider.tspackages/i18n/src/en-US/ui.tspackages/ai-workspace-common/src/components/sider/layout.tsx
**/*.{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/model-providers/index.tsxpackages/ai-workspace-common/src/components/editor/components/selectors/create-memo-selector.tsxpackages/ai-workspace-common/src/components/canvas/nodes/document.tsxpackages/ai-workspace-common/src/components/app-manager/app-card.tsxpackages/ai-workspace-common/src/components/contact-us-popover/index.tsxpackages/ai-workspace-common/src/components/canvas/node-preview/start.tsxpackages/ai-workspace-common/src/components/canvas/launchpad/rich-chat-input/mentionList.tsxpackages/ai-workspace-common/src/components/settings/model-config/index.tsxpackages/ai-workspace-common/src/components/canvas/modals/canvas-delete.tsxpackages/ai-workspace-common/src/components/workflow-list/workflowActionDropdown.tsxpackages/ai-workspace-common/src/components/canvas/front-page/recent-workflow.tsxpackages/ai-workspace-common/src/components/canvas/front-page/index.tsxpackages/ai-workspace-common/src/components/canvas/workflow-variables/create-variables-modal.tsxpackages/ai-workspace-common/src/components/settings/tools-config/McpServerList.tsxpackages/web-core/src/components/login-modal/index.tsxpackages/web-core/src/pages/workflow-app/workflow-app-form.tsxpackages/ai-workspace-common/src/components/canvas/top-toolbar/actions-in-canvas-dropdown.tsxpackages/ai-workspace-common/src/components/workflow-list/index.tsxpackages/ai-workspace-common/src/components/settings/tools-config/tools/tool-list.tsxpackages/ai-workspace-common/src/components/sider/layout.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/settings/model-providers/index.tsxpackages/ai-workspace-common/src/components/contact-us-popover/index.tsxpackages/ai-workspace-common/src/components/settings/model-config/index.tsxpackages/ai-workspace-common/src/components/canvas/front-page/index.tsxpackages/web-core/src/components/login-modal/index.tsxpackages/ai-workspace-common/src/components/workflow-list/index.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/model-providers/index.tsxpackages/ai-workspace-common/src/components/editor/components/selectors/create-memo-selector.tsxpackages/ai-workspace-common/src/components/canvas/nodes/document.tsxpackages/ai-workspace-common/src/components/app-manager/app-card.tsxpackages/ai-workspace-common/src/components/contact-us-popover/index.tsxpackages/ai-workspace-common/src/components/canvas/node-preview/start.tsxpackages/ai-workspace-common/src/components/canvas/launchpad/rich-chat-input/mentionList.tsxpackages/ai-workspace-common/src/components/settings/model-config/index.tsxpackages/ai-workspace-common/src/components/canvas/modals/canvas-delete.tsxpackages/ai-workspace-common/src/components/workflow-list/workflowActionDropdown.tsxpackages/ai-workspace-common/src/components/canvas/front-page/recent-workflow.tsxpackages/ai-workspace-common/src/components/canvas/front-page/index.tsxpackages/ai-workspace-common/src/components/canvas/workflow-variables/create-variables-modal.tsxpackages/ai-workspace-common/src/components/settings/tools-config/McpServerList.tsxpackages/web-core/src/components/login-modal/index.tsxpackages/web-core/src/pages/workflow-app/workflow-app-form.tsxpackages/ai-workspace-common/src/components/canvas/top-toolbar/actions-in-canvas-dropdown.tsxpackages/ai-workspace-common/src/components/workflow-list/index.tsxpackages/ai-workspace-common/src/components/settings/tools-config/tools/tool-list.tsxpackages/ai-workspace-common/src/components/sider/layout.tsx
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 (25)
📚 Learning: 2025-09-10T02:51:12.185Z
Learnt from: mrcfps Repo: refly-ai/refly PR: 1348 File: apps/api/src/modules/workflow-app/workflow-app.service.ts:88-101 Timestamp: 2025-09-10T02:51:12.185Z Learning: In the WorkflowApp model in apps/api/prisma/schema.prisma, the `appId` field has a `unique` constraint, making `findUnique` the correct and preferred Prisma method when querying by appId alone. Applied to files:
apps/api/src/modules/canvas/canvas.service.ts
📚 Learning: 2025-07-21T01:56:03.072Z
Learnt from: CR Repo: refly-ai/refly PR: 0 File: .cursor/rules/02-project-structure.mdc:0-0 Timestamp: 2025-07-21T01:56:03.072Z Learning: Shared UI components and utilities are located in packages/ai-workspace-common Applied to files:
packages/ai-workspace-common/src/components/settings/model-providers/index.tsxpackages/ai-workspace-common/src/components/canvas/nodes/document.tsxpackages/ai-workspace-common/src/components/canvas/node-preview/start.tsxpackages/ai-workspace-common/src/components/canvas/front-page/recent-workflow.tsxpackages/ai-workspace-common/src/components/canvas/front-page/index.tsxpackages/web-core/src/pages/workflow-app/workflow-app-form.tsxpackages/ai-workspace-common/src/components/workflow-list/index.tsx
📚 Learning: 2025-07-21T01:55:21.585Z
Learnt from: CR Repo: refly-ai/refly PR: 0 File: .cursorrules:0-0 Timestamp: 2025-07-21T01:55:21.585Z Learning: Applies to **/*.{jsx,tsx} : Always wrap pure components with React.memo to prevent unnecessary re-renders. Applied to files:
packages/ai-workspace-common/src/components/editor/components/selectors/create-memo-selector.tsxpackages/ai-workspace-common/src/components/canvas/modals/canvas-delete.tsxpackages/ai-workspace-common/src/components/workflow-list/workflowActionDropdown.tsx
📚 Learning: 2025-07-21T01:55:52.528Z
Learnt from: CR Repo: refly-ai/refly PR: 0 File: .cursor/rules/01-code-style.mdc:0-0 Timestamp: 2025-07-21T01:55:52.528Z Learning: Applies to **/*.{jsx,tsx} : Always wrap pure components with React.memo to prevent unnecessary re-renders Applied to files:
packages/ai-workspace-common/src/components/editor/components/selectors/create-memo-selector.tsxpackages/ai-workspace-common/src/components/canvas/modals/canvas-delete.tsx
📚 Learning: 2025-07-21T01:56:57.973Z
Learnt from: CR Repo: refly-ai/refly PR: 0 File: .cursor/rules/05-code-organization.mdc:0-0 Timestamp: 2025-07-21T01:56:57.973Z Learning: Applies to **/*.{js,jsx,ts,tsx} : Use context for sharing state across multiple components Applied to files:
packages/ai-workspace-common/src/components/canvas/node-preview/start.tsx
📚 Learning: 2025-07-21T01:55:21.585Z
Learnt from: CR Repo: refly-ai/refly PR: 0 File: .cursorrules:0-0 Timestamp: 2025-07-21T01:55:21.585Z Learning: Applies to **/*.{jsx,tsx} : Always use useCallback for function props to maintain referential equality. Applied to files:
packages/ai-workspace-common/src/components/canvas/node-preview/start.tsxpackages/ai-workspace-common/src/components/canvas/launchpad/rich-chat-input/mentionList.tsxpackages/ai-workspace-common/src/components/workflow-list/workflowActionDropdown.tsxpackages/web-core/src/components/login-modal/index.tsx
📚 Learning: 2025-07-10T02:52:10.899Z
Learnt from: CR Repo: refly-ai/refly PR: 0 File: .cursor/rules/08-contributing-guidelines.mdc:0-0 Timestamp: 2025-07-10T02:52:10.899Z Learning: Applies to **/*.{jsx,tsx} : Use React best practices for frontend code Applied to files:
packages/ai-workspace-common/src/components/canvas/node-preview/start.tsxpackages/ai-workspace-common/src/components/workflow-list/workflowActionDropdown.tsxpackages/web-core/src/components/login-modal/index.tsx
📚 Learning: 2025-07-21T01:55:52.528Z
Learnt from: CR Repo: refly-ai/refly PR: 0 File: .cursor/rules/01-code-style.mdc:0-0 Timestamp: 2025-07-21T01:55:52.528Z Learning: Applies to **/*.{jsx,tsx} : Always use useCallback for function props to maintain referential equality Applied to files:
packages/ai-workspace-common/src/components/canvas/node-preview/start.tsxpackages/ai-workspace-common/src/components/canvas/launchpad/rich-chat-input/mentionList.tsxpackages/ai-workspace-common/src/components/workflow-list/workflowActionDropdown.tsxpackages/web-core/src/components/login-modal/index.tsx
📚 Learning: 2025-07-21T01:55:21.585Z
Learnt from: CR Repo: refly-ai/refly PR: 0 File: .cursorrules:0-0 Timestamp: 2025-07-21T01:55:21.585Z Learning: Applies to **/*.{jsx,tsx} : Always use useMemo for expensive computations or complex object creation. Applied to files:
packages/ai-workspace-common/src/components/canvas/launchpad/rich-chat-input/mentionList.tsx
📚 Learning: 2025-07-21T01:55:52.528Z
Learnt from: CR Repo: refly-ai/refly PR: 0 File: .cursor/rules/01-code-style.mdc:0-0 Timestamp: 2025-07-21T01:55:52.528Z Learning: Applies to **/*.{jsx,tsx} : Always use useMemo for expensive computations or complex object creation Applied to files:
packages/ai-workspace-common/src/components/canvas/launchpad/rich-chat-input/mentionList.tsx
📚 Learning: 2025-07-21T01:56:57.973Z
Learnt from: CR Repo: refly-ai/refly PR: 0 File: .cursor/rules/05-code-organization.mdc:0-0 Timestamp: 2025-07-21T01:56:57.973Z Learning: Applies to **/*.{js,jsx,ts,tsx} : Use React state hooks for component internal state Applied to files:
packages/ai-workspace-common/src/hooks/use-route-collapse.tspackages/web-core/src/components/login-modal/index.tsx
📚 Learning: 2025-07-21T01:56:57.973Z
Learnt from: CR Repo: refly-ai/refly PR: 0 File: .cursor/rules/05-code-organization.mdc:0-0 Timestamp: 2025-07-21T01:56:57.973Z Learning: Applies to **/*.{js,jsx,ts,tsx} : Use useReducer for complex state logic Applied to files:
packages/ai-workspace-common/src/hooks/use-route-collapse.ts
📚 Learning: 2025-07-21T01:56:57.973Z
Learnt from: CR Repo: refly-ai/refly PR: 0 File: .cursor/rules/05-code-organization.mdc:0-0 Timestamp: 2025-07-21T01:56:57.973Z Learning: Applies to **/*.{js,jsx,ts,tsx} : Split complex state into multiple state variables Applied to files:
packages/ai-workspace-common/src/hooks/use-route-collapse.ts
📚 Learning: 2025-07-21T01:55:52.528Z
Learnt from: CR Repo: refly-ai/refly PR: 0 File: .cursor/rules/01-code-style.mdc:0-0 Timestamp: 2025-07-21T01:55:52.528Z Learning: Applies to **/*.{jsx,tsx} : Implement fallback UI for components that might fail Applied to files:
packages/ai-workspace-common/src/components/workflow-list/workflowActionDropdown.tsx
📚 Learning: 2025-07-21T06:47:12.834Z
Learnt from: CR Repo: refly-ai/refly PR: 0 File: .cursor/rules/11-ui-design-patterns.mdc:0-0 Timestamp: 2025-07-21T06:47:12.834Z Learning: Applies to **/*Button*.{js,jsx,ts,tsx,css,scss,less,styl} : Use consistent padding, border radius, and hover states for all buttons Applied to files:
packages/web-core/src/components/login-modal/index.tsxpackages/ai-workspace-common/src/components/sider/layout.tsx
📚 Learning: 2025-07-21T01:56:57.973Z
Learnt from: CR Repo: refly-ai/refly PR: 0 File: .cursor/rules/05-code-organization.mdc:0-0 Timestamp: 2025-07-21T01:56:57.973Z Learning: Applies to **/*.{js,jsx,ts,tsx} : Extract complex logic into custom hooks Applied to files:
packages/web-core/src/components/login-modal/index.tsxpackages/web-core/src/pages/workflow-app/workflow-app-form.tsx
📚 Learning: 2025-07-21T06:47:12.834Z
Learnt from: CR Repo: refly-ai/refly PR: 0 File: .cursor/rules/11-ui-design-patterns.mdc:0-0 Timestamp: 2025-07-21T06:47:12.834Z Learning: Applies to **/*Button*.{js,jsx,ts,tsx} : Include appropriate loading states for async actions Applied to files:
packages/web-core/src/components/login-modal/index.tsxpackages/ai-workspace-common/src/components/sider/layout.tsx
📚 Learning: 2025-07-21T02:58:52.235Z
Learnt from: CR Repo: refly-ai/refly PR: 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 Repo: refly-ai/refly PR: 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}/** : Group related translation keys together 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 Repo: refly-ai/refly PR: 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 Repo: refly-ai/refly PR: 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.tspackages/i18n/src/en-US/ui.ts
📚 Learning: 2025-07-21T02:58:52.235Z
Learnt from: CR Repo: refly-ai/refly PR: 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 namespaces for different sections of the application in translation keys 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 Repo: refly-ai/refly PR: 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}/** : Support dynamic content with placeholders in translation strings Applied to files:
packages/i18n/src/zh-Hans/ui.ts
📚 Learning: 2025-07-21T06:47:12.834Z
Learnt from: CR Repo: refly-ai/refly PR: 0 File: .cursor/rules/11-ui-design-patterns.mdc:0-0 Timestamp: 2025-07-21T06:47:12.834Z Learning: Applies to **/*Form*.{js,jsx,ts,tsx} : Ensure proper labeling and accessibility Applied to files:
packages/web-core/src/pages/workflow-app/workflow-app-form.tsx
📚 Learning: 2025-07-21T06:47:12.834Z
Learnt from: CR Repo: refly-ai/refly PR: 0 File: .cursor/rules/11-ui-design-patterns.mdc:0-0 Timestamp: 2025-07-21T06:47:12.834Z Learning: Applies to **/*Button*.{js,jsx,ts,tsx,css,scss,less,styl} : Follow fixed button sizes based on their importance and context Applied to files:
packages/ai-workspace-common/src/components/sider/layout.tsx
🧬 Code graph analysis (15)
packages/openapi-schema/src/types.gen.ts (2)
packages/ai-workspace-common/src/requests/types.gen.ts (1)
WorkflowApp(6658-6711)packages/request/src/requests/types.gen.ts (1)
WorkflowApp(6658-6711)
packages/ai-workspace-common/src/components/app-manager/app-card.tsx (1)
packages/ai-workspace-common/src/components/common/hover-card.tsx (1)
HoverCardContainer(11-76)
packages/ai-workspace-common/src/components/contact-us-popover/index.tsx (1)
packages/ai-workspace-common/src/components/contact-us-popover/contact-card.tsx (1)
ContactCard(12-35)
packages/ai-workspace-common/src/components/canvas/launchpad/rich-chat-input/mentionList.tsx (1)
packages/ai-workspace-common/src/hooks/canvas/use-variable-view.ts (1)
useVariableView(11-44)
packages/ai-workspace-common/src/components/settings/model-config/index.tsx (1)
packages/ai-workspace-common/src/components/common/icon.tsx (1)
IconDelete(145-145)
apps/api/src/modules/canvas/canvas.dto.ts (1)
apps/api/src/modules/workflow-app/workflow-app.dto.ts (1)
workflowAppPO2DTO(5-39)
packages/request/src/requests/types.gen.ts (2)
packages/ai-workspace-common/src/requests/types.gen.ts (1)
WorkflowApp(6658-6711)packages/openapi-schema/src/types.gen.ts (1)
WorkflowApp(6658-6711)
packages/ai-workspace-common/src/hooks/use-route-collapse.ts (1)
packages/stores/src/stores/sider.ts (1)
useSiderStoreShallow(94-96)
packages/ai-workspace-common/src/components/workflow-list/workflowActionDropdown.tsx (1)
packages/ai-workspace-common/src/utils/share.ts (1)
getShareLink(1-17)
packages/ai-workspace-common/src/components/canvas/front-page/recent-workflow.tsx (1)
packages/stores/src/stores/sider.ts (1)
useSiderStoreShallow(94-96)
packages/ai-workspace-common/src/components/canvas/front-page/index.tsx (1)
packages/stores/src/stores/sider.ts (1)
useSiderStoreShallow(94-96)
packages/ai-workspace-common/src/requests/types.gen.ts (2)
packages/openapi-schema/src/types.gen.ts (1)
WorkflowApp(6658-6711)packages/request/src/requests/types.gen.ts (1)
WorkflowApp(6658-6711)
packages/ai-workspace-common/src/components/canvas/workflow-variables/create-variables-modal.tsx (1)
apps/api/src/modules/common/redis.service.ts (1)
getClient(83-85)
packages/ai-workspace-common/src/components/workflow-list/index.tsx (2)
packages/stores/src/stores/sider.ts (1)
useSiderStoreShallow(94-96)packages/openapi-schema/src/types.gen.ts (1)
Canvas(581-630)
packages/ai-workspace-common/src/components/sider/layout.tsx (5)
apps/web/src/utils/cn.ts (1)
cn(3-5)packages/ai-workspace-common/src/components/common/logo/index.tsx (1)
Logo(17-70)packages/ai-workspace-common/src/components/sider-menu-setting-list/index.tsx (1)
SiderMenuSettingList(159-331)packages/stores/src/stores/sider.ts (1)
useSiderStoreShallow(94-96)packages/ai-workspace-common/src/components/contact-us-popover/index.tsx (1)
ContactUsPopover(17-114)
⏰ 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 (20)
packages/ai-workspace-common/src/components/contact-us-popover/index.tsx (2)
4-4: LGTM - Import added correctly.The Notion icon import follows the existing pattern and is properly used in the component.
50-56: LGTM - Notion card added consistently.The implementation follows the existing pattern for contact cards and properly uses translation keys. The integration is clean and consistent with Discord and Twitter cards.
packages/ai-workspace-common/src/components/canvas/top-toolbar/actions-in-canvas-dropdown.tsx (2)
14-14: LGTM! Store integration follows best practices.The import and usage of
useCanvasOperationStoreShallowcorrectly implements the delete modal integration with proper shallow selection for performance.Also applies to: 72-74
60-60: LGTM! Prop definition and destructuring are correct.The optional callback prop is properly typed and destructured, providing flexibility for parent components to handle delete success scenarios.
Also applies to: 65-65
packages/ai-workspace-common/src/hooks/canvas/use-delete-canvas.ts (1)
55-57: Good call on resetting the removal flag.Wrapping the deletion flow in a
try/finallyguaranteesisRemovingflips back to false, which prevents the UI from getting stuck in a disabled state if the request fails.packages/request/src/requests/types.gen.ts (1)
606-609: LGTM! Type definition is correct.The addition of the optional
workflowAppfield to theCanvastype is properly defined with correct type reference and follows the established pattern in this generated file.packages/openapi-schema/src/types.gen.ts (1)
606-609: LGTM! The optionalworkflowAppfield is properly integrated with correct consuming patterns.Verification confirms that code accessing the optional
workflowAppfield from theCanvastype correctly handles its optional nature:
- Frontend components use optional chaining:
workflow.workflowApp?.shareIdand type narrowing in conditional expressions- Backend services guard all accesses with null checks before accessing properties
- Type narrowing is correctly applied in the one direct property access pattern found
The type definition addition and its consumption throughout the codebase align with the coding guidelines for optional property handling.
packages/ai-workspace-common/src/components/canvas/nodes/document.tsx (1)
53-55: LGTM on the useTranslation destructure.No behavioral change; safe.
packages/ai-workspace-common/src/components/canvas/front-page/index.tsx (2)
47-50: Good addition: restore sider state before creating a workflow.Selector + setIsManualCollapse wiring looks correct.
67-71: LGTM on handler dependencies.Including setIsManualCollapse avoids stale closure issues.
packages/ai-workspace-common/src/components/canvas/front-page/recent-workflow.tsx (2)
18-21: Correct state wiring for manual collapse.useSiderStoreShallow selection is minimal and shallow-compared. Good.
22-28: Restore sider before navigation.Calling setIsManualCollapse(false) prior to navigate prevents collapsed sider after entry. Dependency array updated correctly.
packages/i18n/src/zh-Hans/ui.ts (4)
662-664: Notion doc entries added — looks good and matches en-US.
Keys align with en-US (contactUs.notionDocument/viewNotionDocument). No action needed.
To double-check section placement parity, you can run the script in my other comment. Based on learnings.
1309-1309: Terminology shift to “工作流” — please confirm consistency.
This string now says “同时删除工作流中的资源和文档”, while most canvas toolbar texts still reference “画布”. If “工作流” is the new user-facing concept here, consider aligning adjacent texts; otherwise keep “画布” for consistency.
Would you like me to scan and propose a minimal terminology alignment diff? Based on learnings.
1440-1440: Delete success message updated — OK.
Message now matches workflow terminology and mirrors en-US.
3898-3921: All workflow publish/share keys present and aligned—translation parity verified.The verification script confirmed all specified translation keys are present in both locales:
published/unpublished,share/unshare✓copyLink,copyLinkTooltip,copyLinkSuccess,copyLinkFailed✓templateLink,templateLinkCopied,templateNotPublishedTooltip,templateLinkFailed✓tableTitle.publishStatus✓Additional keys (contactUs.notionDocument/viewNotionDocument, canvas.toolbar.deleteCanvasFile, canvas.action.deleteSuccess) are also correctly paired. Chinese translations are linguistically appropriate and maintain semantic alignment with English versions.
packages/i18n/src/en-US/ui.ts (4)
704-706: Notion doc entries added — OK.
Keys and wording are clear and match zh-Hans structure. Based on learnings.
1309-1309: deleteCanvasFile updated to workflow — OK.
Terminology aligns with the broader shift; mirrors zh-Hans.
1443-1443: Delete success message aligns with workflow — OK.
Matches zh-Hans counterpart.
3869-3891: Workflow publish/share set — looks good and consistent.
published/unpublished, copyLink*, templateLink*, and tableTitle.publishStatus added with clear wording; consistent with zh-Hans intent.
Please run the parity script in my zh-Hans comment to confirm section placement. Based on learnings.Also applies to: 3883-3885
| return canvases.map((canvas) => ({ | ||
| ...canvas, | ||
| owner, | ||
| shareRecord: shareRecordMap.get(canvas.canvasId) || null, | ||
| workflowApp: workflowAppMap.get(canvas.canvasId) || null, | ||
| minimapUrl: canvas.minimapStorageKey |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
Avoid returning null for optional fields; ensure owner is non-null.
- Return undefined (omit) when absent to match optional typing in public types.
- If owner could be null, don’t attach it; or assert non-null earlier.
return canvases.map((canvas) => ({ ...canvas, owner, - shareRecord: shareRecordMap.get(canvas.canvasId) || null, - workflowApp: workflowAppMap.get(canvas.canvasId) || null, + // Omit when absent to align with optional fields in types + ...(shareRecordMap.has(canvas.canvasId) + ? { shareRecord: shareRecordMap.get(canvas.canvasId) } + : {}), + ...(workflowAppMap.has(canvas.canvasId) + ? { workflowApp: workflowAppMap.get(canvas.canvasId) } + : {}), }));Confirm DTO nullability to avoid breaking consumers:
🏁 Script executed:
#!/bin/bash rg -nP "(interface|type)\s+CanvasDetailModel" -C5 apps/api/src/modules/canvas rg -nP "workflowApp\??:\s*WorkflowApp" -C2 apps/api/src/modules/canvas rg -nP "shareRecord\??:\s*ShareRecord" -C2 apps/api/src/modules/canvasLength of output: 1723
--- 🏁 Script executed: ```shell #!/bin/bash # Check the context around lines 171-176 to verify owner's presence and nullability rg -nP -A10 -B10 "return canvases.map" apps/api/src/modules/canvas/canvas.service.ts | head -30 Length of output: 85
--- 🏁 Script executed: ```shell #!/bin/bash # Find and examine the canvas.service.ts file fd -e ts canvas.service.ts Length of output: 45
--- 🏁 Script executed: ```shell #!/bin/bash # View context around lines 171-176 in canvas.service.ts sed -n '160,185p' apps/api/src/modules/canvas/canvas.service.ts Length of output: 853
--- 🏁 Script executed: ```shell #!/bin/bash # Find function definition for the method containing lines 171-176 sed -n '140,175p' apps/api/src/modules/canvas/canvas.service.ts Length of output: 1124
--- 🏁 Script executed: ```shell #!/bin/bash # Find function start and owner variable definition sed -n '100,165p' apps/api/src/modules/canvas/canvas.service.ts Length of output: 1819
Address nullability of all three fields to comply with optional DTO definitions.
The DTO defines owner, shareRecord, and workflowApp as optional fields, which means they should be omitted (undefined) when absent, not set to null. The current code has three issues:
shareRecordandworkflowAppreturnnullwhen not found, violating the optional field contractowneris always spread without checking if it's null (line 128:findUniquereturnsnullif the user is not found)minimapUrlcorrectly usesundefined(line 176-178) and should remain unchanged
Refactor the return statement to conditionally spread all three fields:
return canvases.map((canvas) => ({ ...canvas, + ...(owner ? { owner } : {}), - owner, shareRecord: shareRecordMap.get(canvas.canvasId) || null, - workflowApp: workflowAppMap.get(canvas.canvasId) || null, + ...(shareRecordMap.has(canvas.canvasId) + ? { shareRecord: shareRecordMap.get(canvas.canvasId) } + : {}), + ...(workflowAppMap.has(canvas.canvasId) + ? { workflowApp: workflowAppMap.get(canvas.canvasId) } + : {}), minimapUrl: canvas.minimapStorageKey📝 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 canvases.map((canvas) => ({ | |
| ...canvas, | |
| owner, | |
| shareRecord: shareRecordMap.get(canvas.canvasId) || null, | |
| workflowApp: workflowAppMap.get(canvas.canvasId) || null, | |
| minimapUrl: canvas.minimapStorageKey | |
| return canvases.map((canvas) => ({ | |
| ...canvas, | |
| ...(owner ? { owner } : {}), | |
| ...(shareRecordMap.has(canvas.canvasId) | |
| ? { shareRecord: shareRecordMap.get(canvas.canvasId) } | |
| : {}), | |
| ...(workflowAppMap.has(canvas.canvasId) | |
| ? { workflowApp: workflowAppMap.get(canvas.canvasId) } | |
| : {}), | |
| minimapUrl: canvas.minimapStorageKey |
🤖 Prompt for AI Agents
In apps/api/src/modules/canvas/canvas.service.ts around lines 171 to 176, the return mapping currently forces owner, shareRecord, and workflowApp into the DTO even when absent (using a direct spread and null values), violating the optional field contract; change it to conditionally include each field only when present: spread owner only if owner !== null/undefined, set shareRecord to shareRecordMap.get(canvas.canvasId) only if that value is not undefined (omit otherwise), and likewise include workflowApp from workflowAppMap.get(...) only when defined; leave minimapUrl as is (undefined when absent). | <Modal | ||
| title={t('common.deleteConfirmMessage')} | ||
| centered | ||
| width={416} | ||
| open={modalVisible} | ||
| onOk={handleUnpublish} | ||
| onCancel={() => setModalVisible(false)} | ||
| okText={t('common.confirm')} | ||
| cancelText={t('common.cancel')} | ||
| okButtonProps={{ loading: isDeleting }} | ||
| destroyOnHidden | ||
| closeIcon={null} | ||
| confirmLoading={isDeleting} | ||
| > |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Update Modal prop to destroyOnClose
Ant Design only supports destroyOnClose; using destroyOnHidden prevents this component from compiling. Swap to the supported prop.
- destroyOnHidden + destroyOnClose📝 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.
| <Modal | |
| title={t('common.deleteConfirmMessage')} | |
| centered | |
| width={416} | |
| open={modalVisible} | |
| onOk={handleUnpublish} | |
| onCancel={() => setModalVisible(false)} | |
| okText={t('common.confirm')} | |
| cancelText={t('common.cancel')} | |
| okButtonProps={{ loading: isDeleting }} | |
| destroyOnHidden | |
| closeIcon={null} | |
| confirmLoading={isDeleting} | |
| > | |
| <Modal | |
| title={t('common.deleteConfirmMessage')} | |
| centered | |
| width={416} | |
| open={modalVisible} | |
| onOk={handleUnpublish} | |
| onCancel={() => setModalVisible(false)} | |
| okText={t('common.confirm')} | |
| cancelText={t('common.cancel')} | |
| okButtonProps={{ loading: isDeleting }} | |
| destroyOnClose | |
| closeIcon={null} | |
| confirmLoading={isDeleting} | |
| > |
🤖 Prompt for AI Agents
In packages/ai-workspace-common/src/components/app-manager/app-card.tsx around lines 94 to 107, the Modal uses the non-existent prop destroyOnHidden which causes compilation errors; replace destroyOnHidden with the supported Ant Design prop destroyOnClose (i.e., remove destroyOnHidden and add destroyOnClose) so the Modal is properly unmounted when closed and the component compiles. | const newMentionItem: MentionItem = { ...newItem, source: 'variables' } as MentionItem; | ||
| command(newMentionItem); | ||
| |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Rollback the inserted mention on failures.
We optimistically call command(newMentionItem) before the server round‑trip, but on failure we only restore the query cache. The mention already inserted into the editor now references a variable that was never persisted, leaving the document in an inconsistent state. Please defer the insert until after the updateWorkflowVariables call succeeds (or add explicit rollback logic for the editor state) so the UI never shows ghost variables when the API rejects the change.
- const newMentionItem: MentionItem = { ...newItem, source: 'variables' } as MentionItem; - command(newMentionItem); + const newMentionItem: MentionItem = { ...newItem, source: 'variables' } as MentionItem; @@ - if (data?.success) { + if (data?.success) { + command(newMentionItem); message.success(Also applies to: 145-169
🤖 Prompt for AI Agents
In packages/ai-workspace-common/src/components/canvas/launchpad/rich-chat-input/mentionList.tsx around lines 115-117 (and similarly at 145-169), the code calls command(newMentionItem) optimistically before the server update, which can leave a ghost mention if updateWorkflowVariables fails; change the flow to wait for the updateWorkflowVariables API call to succeed before calling command(newMentionItem), or if you must keep optimistic UI, implement explicit rollback by capturing the editor state/mention id before insertion and reverting that state (or removing the inserted mention) when the API returns an error; ensure errors are surfaced to the user and the query cache/update handlers remain consistent with the editor content. | title={t('common.deleteConfirmMessage')} | ||
| centered | ||
| width={416} | ||
| open={modalVisible && modalType === 'delete'} | ||
| onOk={handleDelete} | ||
| onCancel={() => reset()} | ||
| okText={t('common.confirm')} | ||
| cancelText={t('common.cancel')} | ||
| okButtonProps={{ danger: true, loading: isLoading }} | ||
| okButtonProps={{ loading: isLoading }} | ||
| destroyOnHidden |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Keep destructive affordance on delete confirmation.
Dropping the danger flag turns the delete confirm button back to the primary style, so the destructive action is no longer visually distinguished. Please reintroduce the danger styling while retaining the loading state.
Apply this diff to restore the styling:
- okButtonProps={{ loading: isLoading }} + okButtonProps={{ danger: true, loading: isLoading }}📝 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.
| title={t('common.deleteConfirmMessage')} | |
| centered | |
| width={416} | |
| open={modalVisible && modalType === 'delete'} | |
| onOk={handleDelete} | |
| onCancel={() => reset()} | |
| okText={t('common.confirm')} | |
| cancelText={t('common.cancel')} | |
| okButtonProps={{ danger: true, loading: isLoading }} | |
| okButtonProps={{ loading: isLoading }} | |
| destroyOnHidden | |
| title={t('common.deleteConfirmMessage')} | |
| centered | |
| width={416} | |
| open={modalVisible && modalType === 'delete'} | |
| onOk={handleDelete} | |
| onCancel={() => reset()} | |
| okText={t('common.confirm')} | |
| cancelText={t('common.cancel')} | |
| okButtonProps={{ danger: true, loading: isLoading }} | |
| destroyOnHidden |
🤖 Prompt for AI Agents
In packages/ai-workspace-common/src/components/canvas/modals/canvas-delete.tsx around lines 42 to 51, the delete confirmation lost its destructive styling when the danger flag was removed; restore the visual affordance by adding danger: true back into the okButtonProps while preserving the existing loading prop (e.g. okButtonProps={{ loading: isLoading, danger: true }}), ensuring the confirm button remains red and still shows the spinner when isLoading is true. | <div | ||
| className={`items-center gap-1 flex-shrik-0 ${ | ||
| modalVisible ? 'flex' : 'hidden group-hover:flex' | ||
| }`} | ||
| > |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fix typo in Tailwind utility class.
flex-shrik-0 is a misspelling, so the class never applies. Correct it to flex-shrink-0 to keep the action area from shrinking.
Apply this diff to fix the typo:
- className={`items-center gap-1 flex-shrik-0 ${ + className={`items-center gap-1 flex-shrink-0 ${📝 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.
| <div | |
| className={`items-center gap-1 flex-shrik-0 ${ | |
| modalVisible ? 'flex' : 'hidden group-hover:flex' | |
| }`} | |
| > | |
| <div | |
| className={`items-center gap-1 flex-shrink-0 ${ | |
| modalVisible ? 'flex' : 'hidden group-hover:flex' | |
| }`} | |
| > |
🤖 Prompt for AI Agents
In packages/ai-workspace-common/src/components/canvas/node-preview/start.tsx around lines 155 to 159, there's a typo in the Tailwind class name "flex-shrik-0" which prevents the intended no-shrink behavior; replace "flex-shrik-0" with the correct "flex-shrink-0" so the action area does not shrink (keep the rest of the class string and conditional logic unchanged). | /** | ||
| * Canvas workflow app | ||
| */ | ||
| workflowApp?: WorkflowApp; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
Optional fields should be omitted, not set to null.
Canvas.workflowApp is optional here. Please ensure API returns undefined/omits the key when absent rather than null to match the generated contract. Same note for Canvas.shareRecord.
Run to check DTOs/schemas and service mapping for null vs optional:
🏁 Script executed:
#!/bin/bash # Check CanvasDetailModel and schema nullability rg -nP "export\s+type\s+CanvasDetailModel|class\s+CanvasDetailModel" -C3 apps/api/src/modules/canvas rg -nP "workflowApp\??:\s*WorkflowApp" -n apps/api/src/modules/canvas -C2 rg -nP "shareRecord\??:\s*ShareRecord" -n apps/api/src/modules/canvas -C2 # OpenAPI schema for nullable flags rg -n "Canvas:" -n packages/openapi-schema/schema.yml -C5 rg -n "workflowApp:" packages/openapi-schema/schema.yml -n -C3 rg -n "shareRecord:" packages/openapi-schema/schema.yml -n -C3 # Service lines returning null rg -nP "workflowApp:\s+.*\|\|\s+null|shareRecord:\s+.*\|\|\s+null" apps/api/src/modules/canvas/canvas.service.ts -n -C2Length of output: 2495
🏁 Script executed:
#!/bin/bash # Find all Canvas object returns in canvas.service.ts with || null pattern rg -n "|| null" apps/api/src/modules/canvas/canvas.service.ts -C2 # Check if there are other methods returning Canvas objects rg -nP ":\s*Canvas|return.*\{" apps/api/src/modules/canvas/canvas.service.ts | head -30 # Verify DTO usage - check for class vs interface and if optional fields are marked nullable cat apps/api/src/modules/canvas/canvas.dto.ts | head -60Length of output: 53247
🏁 Script executed:
#!/bin/bash # Check NestJS serialization behavior for optional fields curl -s https://docs.nestjs.com/techniques/serialization 2>&1 | grep -i "undefined\|optional\|exclude" | head -5 || echo "Web search needed for NestJS serialization docs"Length of output: 0
🏁 Script executed:
#!/bin/bash # Find all methods in canvas.service.ts that return Canvas or Canvas[] rg -n "private|public|protected" apps/api/src/modules/canvas/canvas.service.ts | grep -E "\bgetCanvas|Canvas\b" -B1 -A15 | head -50Length of output: 0
Remove || null pattern for optional Canvas fields to match type contract.
The shareRecord and workflowApp fields in listCanvases() should omit from response when absent, not return null. Update lines 174–175 in apps/api/src/modules/canvas/canvas.service.ts:
shareRecord: shareRecordMap.get(canvas.canvasId), workflowApp: workflowAppMap.get(canvas.canvasId),This aligns with the DTO's optional field declarations and REST conventions, matching the pattern already used for minimapUrl (line 178). NestJS serialization will omit undefined fields automatically.
🤖 Prompt for AI Agents
packages/ai-workspace-common/src/requests/types.gen.ts around lines 606 to 609: the Canvas optional fields should not use a "|| null" pattern; update the code that builds canvas responses (specifically the assignments for shareRecord and workflowApp in apps/api/src/modules/canvas/canvas.service.ts lines ~174–175) to return the map.get(...) value directly (which yields undefined when absent) instead of falling back to null, so NestJS serialization omits the fields as the DTO declares. | shared: '已共享', | ||
| private: '私有', | ||
| published: '已发布', | ||
| unpublished: '未发布', | ||
| share: '分享', | ||
| unshare: '取消分享', | ||
| copyLink: '分享工作流', | ||
| copyLinkTooltip: '请先设置为公开可见后再分享', | ||
| templateLink: '查看模板详情', | ||
| templateLinkCopied: '模板链接复制成功,粘贴到浏览器即可查看', | ||
| templateNotPublishedTooltip: '模板未发布,发布后即可查看详情', | ||
| templateLinkFailed: '复制工作流 {{title}} 模板链接失败', | ||
| shareSuccess: '工作流 {{title}} 分享成功!链接已复制到剪贴板。', | ||
| shareFailed: '分享工作流 {{title}} 失败', | ||
| unshareSuccess: '{{title}} 已取消分享', | ||
| unshareFailed: '取消分享 {{title}} 失败', | ||
| copyLinkSuccess: '链接复制成功!分享你的工作流给好友试试吧', | ||
| copyLinkFailed: '复制工作流 {{title}} 链接失败', | ||
| usedToolsetsTitle: '工作流工具', | ||
| tableTitle: { | ||
| workflowName: '标题', | ||
| status: '状态', | ||
| publishStatus: '发布状态', | ||
| tools: '工具', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
copyLink label mismatch vs behavior — fix zh-Hans text.
In workflowList:
- en-US: copyLink = 'Copy Link'
- zh-Hans: copyLink = '分享工作流' (should denote copying)
Success/error strings already say “链接复制成功/失败”, so the button label should be “复制链接” for clarity and consistency.
Apply this diff:
- copyLink: '分享工作流', + copyLink: '复制链接',Optional follow-up: the new share/publish keys look consistent; consider centralizing repeated keys (copyLink, copyLinkTooltip, templateLink*) under a shared namespace if reused broadly. Based on learnings.
📝 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.
| shared: '已共享', | |
| private: '私有', | |
| published: '已发布', | |
| unpublished: '未发布', | |
| share: '分享', | |
| unshare: '取消分享', | |
| copyLink: '分享工作流', | |
| copyLinkTooltip: '请先设置为公开可见后再分享', | |
| templateLink: '查看模板详情', | |
| templateLinkCopied: '模板链接复制成功,粘贴到浏览器即可查看', | |
| templateNotPublishedTooltip: '模板未发布,发布后即可查看详情', | |
| templateLinkFailed: '复制工作流 {{title}} 模板链接失败', | |
| shareSuccess: '工作流 {{title}} 分享成功!链接已复制到剪贴板。', | |
| shareFailed: '分享工作流 {{title}} 失败', | |
| unshareSuccess: '{{title}} 已取消分享', | |
| unshareFailed: '取消分享 {{title}} 失败', | |
| copyLinkSuccess: '链接复制成功!分享你的工作流给好友试试吧', | |
| copyLinkFailed: '复制工作流 {{title}} 链接失败', | |
| usedToolsetsTitle: '工作流工具', | |
| tableTitle: { | |
| workflowName: '标题', | |
| status: '状态', | |
| publishStatus: '发布状态', | |
| tools: '工具', | |
| shared: '已共享', | |
| private: '私有', | |
| published: '已发布', | |
| unpublished: '未发布', | |
| share: '分享', | |
| unshare: '取消分享', | |
| copyLink: '复制链接', | |
| copyLinkTooltip: '请先设置为公开可见后再分享', | |
| templateLink: '查看模板详情', | |
| templateLinkCopied: '模板链接复制成功,粘贴到浏览器即可查看', | |
| templateNotPublishedTooltip: '模板未发布,发布后即可查看详情', | |
| templateLinkFailed: '复制工作流 {{title}} 模板链接失败', | |
| shareSuccess: '工作流 {{title}} 分享成功!链接已复制到剪贴板。', | |
| shareFailed: '分享工作流 {{title}} 失败', | |
| unshareSuccess: '{{title}} 已取消分享', | |
| unshareFailed: '取消分享 {{title}} 失败', | |
| copyLinkSuccess: '链接复制成功!分享你的工作流给好友试试吧', | |
| copyLinkFailed: '复制工作流 {{title}} 链接失败', | |
| usedToolsetsTitle: '工作流工具', | |
| tableTitle: { | |
| workflowName: '标题', | |
| status: '状态', | |
| publishStatus: '发布状态', | |
| tools: '工具', |
🤖 Prompt for AI Agents
In packages/i18n/src/zh-Hans/ui.ts around lines 3898 to 3921, the copyLink label currently reads '分享工作流' which mismatches the actual behavior (it copies a link); change the value for the copyLink key to '复制链接' to match success/error messages and the en-US label; leave other keys unchanged (optionally later consolidate repeated copy/share/template keys into a shared namespace if reused). | workflowApp: | ||
| description: Canvas workflow app | ||
| $ref: '#/components/schemas/WorkflowApp' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Invalid $ref usage in OAS 3.0.x: description sibling alongside $ref.
In OpenAPI 3.0.3, a schema object with $ref must not have sibling keys. Tools will ignore or fail on description next to $ref, risking codegen/validation breakage. Wrap with allOf (and optionally mark nullable/readOnly if applicable).
Apply:
workflowApp: - description: Canvas workflow app - $ref: '#/components/schemas/WorkflowApp' + allOf: + - $ref: '#/components/schemas/WorkflowApp' + description: Canvas workflow app + nullable: true + readOnly: trueNotes:
- nullable: true only if API may return
null; otherwise remove. - readOnly: true if clients never set this via UpsertCanvasRequest (server-populated).
📝 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.
| workflowApp: | |
| description: Canvas workflow app | |
| $ref: '#/components/schemas/WorkflowApp' | |
| workflowApp: | |
| allOf: | |
| - $ref: '#/components/schemas/WorkflowApp' | |
| description: Canvas workflow app | |
| nullable: true | |
| readOnly: true |
🤖 Prompt for AI Agents
In packages/openapi-schema/schema.yml around lines 4404 to 4406, the schema uses a $ref alongside a description which is invalid in OpenAPI 3.0.x; replace the direct $ref+description sibling with an allOf wrapper: use an allOf array whose first item is the $ref and add a second item containing the description (and add nullable: true or readOnly: true only if applicable per the API behavior). Ensure you remove the sibling description from the same object as the $ref so no non-$ref keys sit alongside the $ref. | workflowApp: { | ||
| description: 'Canvas workflow app', | ||
| $ref: '#/components/schemas/WorkflowApp', | ||
| }, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
workflowApp on Canvas: confirm nullability and downstream types
Looks good to expose WorkflowApp on Canvas. Quick check: will the API omit this field when absent, or return null? If null is possible, make the source OpenAPI add nullable (OAS 3.0) or type: ['object','null'] (OAS 3.1) for Canvas.properties.workflowApp in schema.yml so codegen and validators don’t break. Also verify client/server generated types now include it.
Run to verify types and usage across the repo:
🏁 Script executed:
#!/bin/bash set -euo pipefail echo "1) Check generated Canvas typing includes workflowApp" # Search likely generated type files first; fallback to repo-wide. targets=( "packages/openapi-schema/src/types.gen.ts" "packages/request/src/requests/types.gen.ts" ) found_any=false for f in "${targets[@]}"; do if [[ -f "$f" ]]; then echo "---- $f ----" rg -nP -C3 '(interface|type)\s+Canvas\b' "$f" || true rg -n "workflowApp" "$f" || true found_any=true fi done if ! $found_any; then echo "Falling back to repo-wide search for Canvas type and workflowApp" rg -n "workflowApp" -C2 rg -nP -C3 '(interface|type)\s+Canvas\b' fi echo echo "2) Check backend DTO/service include workflowApp serialization" rg -n "workflowApp" apps/api/src/modules/canvas/ -S -C2 || true echo echo "3) Inspect OpenAPI source to ensure desired nullability (if API returns null)" if [[ -f "packages/openapi-schema/schema.yml" ]]; then echo "Found schema.yml. Showing Canvas.workflowApp block:" rg -n "Canvas:" -n -C8 packages/openapi-schema/schema.yml || true rg -n "workflowApp:" -n -C5 packages/openapi-schema/schema.yml || true else echo "schema.yml not found at packages/openapi-schema/schema.yml" fi echo echo "Expected: - Canvas type contains 'workflowApp?: WorkflowApp' (or similar optional). - Backend DTO/service reference workflowApp. - If API returns null for absent app, schema.yml should mark workflowApp as nullable (OAS 3.0) or include null in type (OAS 3.1)."Length of output: 5532
OpenAPI schema source must mark workflowApp as nullable
The backend returns null for missing workflowApp (canvas.service.ts:175), but the OpenAPI schema source (schema.yml lines 4404–4406) doesn't declare it as nullable. Update schema.yml to add nullable: true (OAS 3.0) or include type: ['object', 'null'] (OAS 3.1) so codegen and validators handle the null case properly.
Lines 938–941 in schemas.gen.ts are generated correctly; the fix must be in schema.yml.
🤖 Prompt for AI Agents
In packages/openapi-schema/src/schemas.gen.ts around lines 938 to 941: the generated property workflowApp is returned as null by the backend but the source OpenAPI schema (schema.yml lines ~4404–4406) does not mark it nullable; edit schema.yml to declare workflowApp nullable by adding "nullable: true" (for OAS 3.0) or changing its type to ["object","null"] (for OAS 3.1), then re-run the OpenAPI codegen/generator to regenerate packages/openapi-schema/src/schemas.gen.ts so the generated schema reflects the nullable workflowApp. | const handleRemix = () => { | ||
| // Check if user is logged in | ||
| if (!isLogin) { | ||
| setLoginModalOpen(true); | ||
| return; | ||
| } | ||
| | ||
| // Call the original onCopyWorkflow function | ||
| onCopyWorkflow?.(); | ||
| }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion | 🟠 Major
Memoize handleRemix to follow our function-prop guideline.
handleRemix is passed straight into the Button on Line 705, so every render now creates a fresh function and breaks referential equality. Our coding guidelines call for wrapping such handlers in useCallback to contain re-renders and stay consistent.
- const handleRemix = () => { + const handleRemix = useCallback(() => { if (!isLogin) { setLoginModalOpen(true); return; } onCopyWorkflow?.(); - }; + }, [isLogin, onCopyWorkflow, setLoginModalOpen]);This keeps the behaviour identical while meeting the memoization requirement and avoiding unnecessary renders.
📝 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.
| const handleRemix = () => { | |
| // Check if user is logged in | |
| if (!isLogin) { | |
| setLoginModalOpen(true); | |
| return; | |
| } | |
| // Call the original onCopyWorkflow function | |
| onCopyWorkflow?.(); | |
| }; | |
| const handleRemix = useCallback(() => { | |
| // Check if user is logged in | |
| if (!isLogin) { | |
| setLoginModalOpen(true); | |
| return; | |
| } | |
| // Call the original onCopyWorkflow function | |
| onCopyWorkflow?.(); | |
| }, [isLogin, onCopyWorkflow, setLoginModalOpen]); |
🤖 Prompt for AI Agents
In packages/web-core/src/pages/workflow-app/workflow-app-form.tsx around lines 447 to 456, handleRemix is recreated on every render and should be memoized; wrap it in React.useCallback and return the same behavior, using isLogin, setLoginModalOpen, and onCopyWorkflow in the dependency array (or stable refs if appropriate) so the function identity is stable when passed to the Button.
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
Release Notes
New Features
Improvements
Deprecated