Browse Source

Feat: Use memo to wrap canvas nodes to improve fluency #3221 (#7929)

### What problem does this PR solve?

Feat: Use memo to wrap canvas nodes to improve fluency #3221

### Type of change


- [x] New Feature (non-breaking change which adds functionality)
tags/v0.19.1
balibabu 5 months ago
parent
commit
3f695a542c
No account linked to committer's email address

+ 2
- 1
web/src/components/llm-select/llm-label.tsx View File

import { getLLMIconName, getLlmNameAndFIdByLlmId } from '@/utils/llm-util'; import { getLLMIconName, getLlmNameAndFIdByLlmId } from '@/utils/llm-util';
import { memo } from 'react';
import { LlmIcon } from '../svg-icon'; import { LlmIcon } from '../svg-icon';


interface IProps { interface IProps {
); );
}; };


export default LLMLabel;
export default memo(LLMLabel);

+ 5
- 3
web/src/components/llm-select/next.tsx View File

import { LlmModelType } from '@/constants/knowledge'; import { LlmModelType } from '@/constants/knowledge';
import { useComposeLlmOptionsByModelTypes } from '@/hooks/llm-hooks'; import { useComposeLlmOptionsByModelTypes } from '@/hooks/llm-hooks';
import * as SelectPrimitive from '@radix-ui/react-select'; import * as SelectPrimitive from '@radix-ui/react-select';
import { forwardRef, useState } from 'react';
import { forwardRef, memo, useState } from 'react';
import { LlmSettingFieldItems } from '../llm-setting-items/next'; import { LlmSettingFieldItems } from '../llm-setting-items/next';
import { Popover, PopoverContent, PopoverTrigger } from '../ui/popover'; import { Popover, PopoverContent, PopoverTrigger } from '../ui/popover';
import { Select, SelectTrigger, SelectValue } from '../ui/select'; import { Select, SelectTrigger, SelectValue } from '../ui/select';
disabled?: boolean; disabled?: boolean;
} }


export const NextLLMSelect = forwardRef<
const NextInnerLLMSelect = forwardRef<
React.ElementRef<typeof SelectPrimitive.Trigger>, React.ElementRef<typeof SelectPrimitive.Trigger>,
IProps IProps
>(({ value, disabled }, ref) => { >(({ value, disabled }, ref) => {
); );
}); });


NextLLMSelect.displayName = 'LLMSelect';
NextInnerLLMSelect.displayName = 'LLMSelect';

export const NextLLMSelect = memo(NextInnerLLMSelect);

+ 4
- 2
web/src/pages/agent/agent-sidebar.tsx View File

SidebarHeader, SidebarHeader,
SidebarMenu, SidebarMenu,
} from '@/components/ui/sidebar'; } from '@/components/ui/sidebar';
import { useMemo } from 'react';
import { memo, useMemo } from 'react';
import { import {
AgentOperatorList, AgentOperatorList,
Operator, Operator,
); );
} }


export function AgentSidebar() {
function InnerAgentSidebar() {
const agentOperatorList = useMemo(() => { const agentOperatorList = useMemo(() => {
return componentMenuList.filter((x) => return componentMenuList.filter((x) =>
AgentOperatorList.some((y) => y === x.name), AgentOperatorList.some((y) => y === x.name),
</Sidebar> </Sidebar>
); );
} }

export const AgentSidebar = memo(InnerAgentSidebar);

+ 2
- 2
web/src/pages/agent/canvas/node/begin-node.tsx View File

import styles from './index.less'; import styles from './index.less';


// TODO: do not allow other nodes to connect to this node // TODO: do not allow other nodes to connect to this node
function Node({ selected, data }: NodeProps<IBeginNode>) {
function InnerBeginNode({ selected, data }: NodeProps<IBeginNode>) {
const { t } = useTranslation(); const { t } = useTranslation();
const query: BeginQuery[] = get(data, 'form.query', []); const query: BeginQuery[] = get(data, 'form.query', []);
const { theme } = useTheme(); const { theme } = useTheme();
); );
} }


export const BeginNode = memo(Node);
export const BeginNode = memo(InnerBeginNode);

+ 2
- 2
web/src/pages/agent/canvas/node/categorize-handle.tsx View File

import { Handle, Position } from '@xyflow/react'; import { Handle, Position } from '@xyflow/react';


import React from 'react';
import React, { memo } from 'react';
import styles from './index.less'; import styles from './index.less';


const DEFAULT_HANDLE_STYLE = { const DEFAULT_HANDLE_STYLE = {
); );
}; };


export default CategorizeHandle;
export default memo(CategorizeHandle);

+ 4
- 1
web/src/pages/agent/canvas/node/categorize-node.tsx View File

import { Flex } from 'antd'; import { Flex } from 'antd';
import classNames from 'classnames'; import classNames from 'classnames';
import { get } from 'lodash'; import { get } from 'lodash';
import { memo } from 'react';
import { RightHandleStyle } from './handle-icon'; import { RightHandleStyle } from './handle-icon';
import { useBuildCategorizeHandlePositions } from './hooks'; import { useBuildCategorizeHandlePositions } from './hooks';
import styles from './index.less'; import styles from './index.less';
import NodeHeader from './node-header'; import NodeHeader from './node-header';


export function CategorizeNode({
export function InnerCategorizeNode({
id, id,
data, data,
selected, selected,
</section> </section>
); );
} }

export const CategorizeNode = memo(InnerCategorizeNode);

+ 4
- 2
web/src/pages/agent/canvas/node/email-node.tsx View File

import { Handle, NodeProps, Position } from '@xyflow/react'; import { Handle, NodeProps, Position } from '@xyflow/react';
import { Flex } from 'antd'; import { Flex } from 'antd';
import classNames from 'classnames'; import classNames from 'classnames';
import { useState } from 'react';
import { memo, useState } from 'react';
import { LeftHandleStyle, RightHandleStyle } from './handle-icon'; import { LeftHandleStyle, RightHandleStyle } from './handle-icon';
import styles from './index.less'; import styles from './index.less';
import NodeHeader from './node-header'; import NodeHeader from './node-header';


export function EmailNode({
export function InnerEmailNode({
id, id,
data, data,
isConnectable = true, isConnectable = true,
</section> </section>
); );
} }

export const EmailNode = memo(InnerEmailNode);

+ 4
- 1
web/src/pages/agent/canvas/node/generate-node.tsx View File

import { Handle, NodeProps, Position } from '@xyflow/react'; import { Handle, NodeProps, Position } from '@xyflow/react';
import classNames from 'classnames'; import classNames from 'classnames';
import { get } from 'lodash'; import { get } from 'lodash';
import { memo } from 'react';
import { LeftHandleStyle, RightHandleStyle } from './handle-icon'; import { LeftHandleStyle, RightHandleStyle } from './handle-icon';
import styles from './index.less'; import styles from './index.less';
import NodeHeader from './node-header'; import NodeHeader from './node-header';


export function GenerateNode({
export function InnerGenerateNode({
id, id,
data, data,
isConnectable = true, isConnectable = true,
</section> </section>
); );
} }

export const GenerateNode = memo(InnerGenerateNode);

+ 4
- 1
web/src/pages/agent/canvas/node/index.tsx View File

import { IRagNode } from '@/interfaces/database/flow'; import { IRagNode } from '@/interfaces/database/flow';
import { Handle, NodeProps, Position } from '@xyflow/react'; import { Handle, NodeProps, Position } from '@xyflow/react';
import classNames from 'classnames'; import classNames from 'classnames';
import { memo } from 'react';
import { LeftHandleStyle, RightHandleStyle } from './handle-icon'; import { LeftHandleStyle, RightHandleStyle } from './handle-icon';
import styles from './index.less'; import styles from './index.less';
import NodeHeader from './node-header'; import NodeHeader from './node-header';


export function RagNode({
function InnerRagNode({
id, id,
data, data,
isConnectable = true, isConnectable = true,
</section> </section>
); );
} }

export const RagNode = memo(InnerRagNode);

+ 4
- 1
web/src/pages/agent/canvas/node/invoke-node.tsx View File

import { Flex } from 'antd'; import { Flex } from 'antd';
import classNames from 'classnames'; import classNames from 'classnames';
import { get } from 'lodash'; import { get } from 'lodash';
import { memo } from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { LeftHandleStyle, RightHandleStyle } from './handle-icon'; import { LeftHandleStyle, RightHandleStyle } from './handle-icon';
import styles from './index.less'; import styles from './index.less';
import NodeHeader from './node-header'; import NodeHeader from './node-header';


export function InvokeNode({
function InnerInvokeNode({
id, id,
data, data,
isConnectable = true, isConnectable = true,
</section> </section>
); );
} }

export const InvokeNode = memo(InnerInvokeNode);

+ 7
- 2
web/src/pages/agent/canvas/node/iteration-node.tsx View File

import { cn } from '@/lib/utils'; import { cn } from '@/lib/utils';
import { Handle, NodeProps, NodeResizeControl, Position } from '@xyflow/react'; import { Handle, NodeProps, NodeResizeControl, Position } from '@xyflow/react';
import { ListRestart } from 'lucide-react'; import { ListRestart } from 'lucide-react';
import { memo } from 'react';
import { LeftHandleStyle, RightHandleStyle } from './handle-icon'; import { LeftHandleStyle, RightHandleStyle } from './handle-icon';
import styles from './index.less'; import styles from './index.less';
import NodeHeader from './node-header'; import NodeHeader from './node-header';
cursor: 'nwse-resize', cursor: 'nwse-resize',
}; };


export function IterationNode({
export function InnerIterationNode({
id, id,
data, data,
isConnectable = true, isConnectable = true,
); );
} }


export function IterationStartNode({
function InnerIterationStartNode({
isConnectable = true, isConnectable = true,
selected, selected,
}: NodeProps<IIterationStartNode>) { }: NodeProps<IIterationStartNode>) {
</section> </section>
); );
} }

export const IterationStartNode = memo(InnerIterationStartNode);

export const IterationNode = memo(InnerIterationNode);

+ 4
- 1
web/src/pages/agent/canvas/node/keyword-node.tsx View File

import { Handle, NodeProps, Position } from '@xyflow/react'; import { Handle, NodeProps, Position } from '@xyflow/react';
import classNames from 'classnames'; import classNames from 'classnames';
import { get } from 'lodash'; import { get } from 'lodash';
import { memo } from 'react';
import { LeftHandleStyle, RightHandleStyle } from './handle-icon'; import { LeftHandleStyle, RightHandleStyle } from './handle-icon';
import styles from './index.less'; import styles from './index.less';
import NodeHeader from './node-header'; import NodeHeader from './node-header';


export function KeywordNode({
export function InnerKeywordNode({
id, id,
data, data,
isConnectable = true, isConnectable = true,
</section> </section>
); );
} }

export const KeywordNode = memo(InnerKeywordNode);

+ 4
- 1
web/src/pages/agent/canvas/node/logic-node.tsx View File

import { ILogicNode } from '@/interfaces/database/flow'; import { ILogicNode } from '@/interfaces/database/flow';
import { Handle, NodeProps, Position } from '@xyflow/react'; import { Handle, NodeProps, Position } from '@xyflow/react';
import classNames from 'classnames'; import classNames from 'classnames';
import { memo } from 'react';
import { LeftHandleStyle, RightHandleStyle } from './handle-icon'; import { LeftHandleStyle, RightHandleStyle } from './handle-icon';
import styles from './index.less'; import styles from './index.less';
import NodeHeader from './node-header'; import NodeHeader from './node-header';


export function LogicNode({
export function InnerLogicNode({
id, id,
data, data,
isConnectable = true, isConnectable = true,
</section> </section>
); );
} }

export const LogicNode = memo(InnerLogicNode);

+ 4
- 1
web/src/pages/agent/canvas/node/message-node.tsx View File

import { Flex } from 'antd'; import { Flex } from 'antd';
import classNames from 'classnames'; import classNames from 'classnames';
import { get } from 'lodash'; import { get } from 'lodash';
import { memo } from 'react';
import { LeftHandleStyle, RightHandleStyle } from './handle-icon'; import { LeftHandleStyle, RightHandleStyle } from './handle-icon';
import styles from './index.less'; import styles from './index.less';
import NodeHeader from './node-header'; import NodeHeader from './node-header';


export function MessageNode({
function InnerMessageNode({
id, id,
data, data,
isConnectable = true, isConnectable = true,
</section> </section>
); );
} }

export const MessageNode = memo(InnerMessageNode);

+ 4
- 1
web/src/pages/agent/canvas/node/node-header.tsx View File

import NodeDropdown from './dropdown'; import NodeDropdown from './dropdown';
import { NextNodePopover } from './popover'; import { NextNodePopover } from './popover';


import { memo } from 'react';
import { RunTooltip } from '../../flow-tooltip'; import { RunTooltip } from '../../flow-tooltip';
interface IProps { interface IProps {
id: string; id: string;
); );
} }


const NodeHeader = ({
const InnerNodeHeader = ({
label, label,
id, id,
name, name,
); );
}; };


const NodeHeader = memo(InnerNodeHeader);

export default NodeHeader; export default NodeHeader;

+ 4
- 1
web/src/pages/agent/canvas/node/relevant-node.tsx View File

import { useTheme } from '@/components/theme-provider'; import { useTheme } from '@/components/theme-provider';
import { IRelevantNode } from '@/interfaces/database/flow'; import { IRelevantNode } from '@/interfaces/database/flow';
import { get } from 'lodash'; import { get } from 'lodash';
import { memo } from 'react';
import { useReplaceIdWithName } from '../../hooks'; import { useReplaceIdWithName } from '../../hooks';
import styles from './index.less'; import styles from './index.less';
import NodeHeader from './node-header'; import NodeHeader from './node-header';


export function RelevantNode({ id, data, selected }: NodeProps<IRelevantNode>) {
function InnerRelevantNode({ id, data, selected }: NodeProps<IRelevantNode>) {
const yes = get(data, 'form.yes'); const yes = get(data, 'form.yes');
const no = get(data, 'form.no'); const no = get(data, 'form.no');
const replaceIdWithName = useReplaceIdWithName(); const replaceIdWithName = useReplaceIdWithName();
</section> </section>
); );
} }

export const RelevantNode = memo(InnerRelevantNode);

+ 4
- 2
web/src/pages/agent/canvas/node/retrieval-node.tsx View File

import { Avatar, Flex } from 'antd'; import { Avatar, Flex } from 'antd';
import classNames from 'classnames'; import classNames from 'classnames';
import { get } from 'lodash'; import { get } from 'lodash';
import { useMemo } from 'react';
import { memo, useMemo } from 'react';
import { LeftHandleStyle, RightHandleStyle } from './handle-icon'; import { LeftHandleStyle, RightHandleStyle } from './handle-icon';
import styles from './index.less'; import styles from './index.less';
import NodeHeader from './node-header'; import NodeHeader from './node-header';


export function RetrievalNode({
function InnerRetrievalNode({
id, id,
data, data,
isConnectable = true, isConnectable = true,
</section> </section>
); );
} }

export const RetrievalNode = memo(InnerRetrievalNode);

+ 4
- 1
web/src/pages/agent/canvas/node/rewrite-node.tsx View File

import { Handle, NodeProps, Position } from '@xyflow/react'; import { Handle, NodeProps, Position } from '@xyflow/react';
import classNames from 'classnames'; import classNames from 'classnames';
import { get } from 'lodash'; import { get } from 'lodash';
import { memo } from 'react';
import { LeftHandleStyle, RightHandleStyle } from './handle-icon'; import { LeftHandleStyle, RightHandleStyle } from './handle-icon';
import styles from './index.less'; import styles from './index.less';
import NodeHeader from './node-header'; import NodeHeader from './node-header';


export function RewriteNode({
function InnerRewriteNode({
id, id,
data, data,
isConnectable = true, isConnectable = true,
</section> </section>
); );
} }

export const RewriteNode = memo(InnerRewriteNode);

+ 4
- 1
web/src/pages/agent/canvas/node/switch-node.tsx View File

import { Handle, NodeProps, Position } from '@xyflow/react'; import { Handle, NodeProps, Position } from '@xyflow/react';
import { Divider, Flex } from 'antd'; import { Divider, Flex } from 'antd';
import classNames from 'classnames'; import classNames from 'classnames';
import { memo } from 'react';
import { useGetComponentLabelByValue } from '../../hooks/use-get-begin-query'; import { useGetComponentLabelByValue } from '../../hooks/use-get-begin-query';
import { RightHandleStyle } from './handle-icon'; import { RightHandleStyle } from './handle-icon';
import { useBuildSwitchHandlePositions } from './hooks'; import { useBuildSwitchHandlePositions } from './hooks';
); );
}; };


export function SwitchNode({ id, data, selected }: NodeProps<ISwitchNode>) {
function InnerSwitchNode({ id, data, selected }: NodeProps<ISwitchNode>) {
const { positions } = useBuildSwitchHandlePositions({ data, id }); const { positions } = useBuildSwitchHandlePositions({ data, id });
const { theme } = useTheme(); const { theme } = useTheme();
return ( return (
</section> </section>
); );
} }

export const SwitchNode = memo(InnerSwitchNode);

+ 4
- 1
web/src/pages/agent/canvas/node/template-node.tsx View File

import NodeHeader from './node-header'; import NodeHeader from './node-header';


import { ITemplateNode } from '@/interfaces/database/flow'; import { ITemplateNode } from '@/interfaces/database/flow';
import { memo } from 'react';
import styles from './index.less'; import styles from './index.less';


export function TemplateNode({
function InnerTemplateNode({
id, id,
data, data,
isConnectable = true, isConnectable = true,
</section> </section>
); );
} }

export const TemplateNode = memo(InnerTemplateNode);

Loading…
Cancel
Save