Feat: Delete the operator node and hide the corresponding sheet #3221 (#9142)

### What problem does this PR solve?

Feat: Delete the operator node and hide the corresponding sheet #3221
### Type of change


- [x] New Feature (non-breaking change which adds functionality)
This commit is contained in:
balibabu
2025-08-01 09:38:48 +08:00
committed by GitHub
parent 89c2067a16
commit 0aa160a990
8 changed files with 55 additions and 19 deletions

View File

@ -1,3 +1,4 @@
import message from '@/components/ui/message';
import { Authorization } from '@/constants/authorization'; import { Authorization } from '@/constants/authorization';
import { IReferenceObject } from '@/interfaces/database/chat'; import { IReferenceObject } from '@/interfaces/database/chat';
import { BeginQuery } from '@/pages/agent/interface'; import { BeginQuery } from '@/pages/agent/interface';
@ -136,6 +137,9 @@ export const useSendMessageBySSE = (url: string = api.completeConversation) => {
const val = JSON.parse(value?.data || ''); const val = JSON.parse(value?.data || '');
console.info('data:', val); console.info('data:', val);
if (val.code === 500) {
message.error(val.message);
}
setAnswerList((list) => { setAnswerList((list) => {
const nextList = [...list]; const nextList = [...list];

View File

@ -32,7 +32,11 @@ import { useAddNode } from '../hooks/use-add-node';
import { useBeforeDelete } from '../hooks/use-before-delete'; import { useBeforeDelete } from '../hooks/use-before-delete';
import { useCacheChatLog } from '../hooks/use-cache-chat-log'; import { useCacheChatLog } from '../hooks/use-cache-chat-log';
import { useMoveNote } from '../hooks/use-move-note'; import { useMoveNote } from '../hooks/use-move-note';
import { useShowDrawer, useShowLogSheet } from '../hooks/use-show-drawer'; import {
useHideFormSheetOnNodeDeletion,
useShowDrawer,
useShowLogSheet,
} from '../hooks/use-show-drawer';
import { LogSheet } from '../log-sheet'; import { LogSheet } from '../log-sheet';
import RunSheet from '../run-sheet'; import RunSheet from '../run-sheet';
import { ButtonEdge } from './edge'; import { ButtonEdge } from './edge';
@ -160,6 +164,9 @@ function AgentCanvas({ drawerVisible, hideDrawer }: IProps) {
setLastSendLoading(false); setLastSendLoading(false);
} }
}; };
useHideFormSheetOnNodeDeletion({ hideFormDrawer });
return ( return (
<div className={styles.canvasWrapper}> <div className={styles.canvasWrapper}>
<svg <svg

View File

@ -33,7 +33,7 @@ function InnerBeginNode({ data, id, selected }: NodeProps<IBeginNode>) {
id={NodeHandleId.Start} id={NodeHandleId.Start}
></CommonHandle> ></CommonHandle>
<section className="flex items-center justify-center gap-2"> <section className="flex items-center gap-2">
<OperatorIcon name={data.label as Operator}></OperatorIcon> <OperatorIcon name={data.label as Operator}></OperatorIcon>
<div className="truncate text-center font-semibold text-sm"> <div className="truncate text-center font-semibold text-sm">
{t(`flow.begin`)} {t(`flow.begin`)}

View File

@ -56,7 +56,7 @@ function NoteNode({ data, id, selected }: NodeProps<INoteNode>) {
<section className="px-1 py-2 flex gap-2 bg-background-highlight items-center note-drag-handle rounded-s-md"> <section className="px-1 py-2 flex gap-2 bg-background-highlight items-center note-drag-handle rounded-s-md">
<NotebookPen className="size-4" /> <NotebookPen className="size-4" />
<Form {...nameForm}> <Form {...nameForm}>
<form> <form className="flex-1">
<FormField <FormField
control={nameForm.control} control={nameForm.control}
name="name" name="name"

View File

@ -16,13 +16,13 @@ import { useFetchUserInfo } from '@/hooks/user-setting-hooks';
import { Message } from '@/interfaces/database/chat'; import { Message } from '@/interfaces/database/chat';
import { buildMessageUuidWithRole } from '@/utils/chat'; import { buildMessageUuidWithRole } from '@/utils/chat';
import { get } from 'lodash'; import { get } from 'lodash';
import { useCallback } from 'react'; import { memo, useCallback } from 'react';
import { useParams } from 'umi'; import { useParams } from 'umi';
import DebugContent from '../debug-content'; import DebugContent from '../debug-content';
import { BeginQuery } from '../interface'; import { BeginQuery } from '../interface';
import { buildBeginQueryWithObject } from '../utils'; import { buildBeginQueryWithObject } from '../utils';
const AgentChatBox = () => { function AgentChatBox() {
const { const {
value, value,
ref, ref,
@ -117,7 +117,7 @@ const AgentChatBox = () => {
})} })}
{/* </Spin> */} {/* </Spin> */}
</div> </div>
<div ref={ref} /> <div ref={ref.scrollRef} />
</div> </div>
<NextMessageInput <NextMessageInput
value={value} value={value}
@ -140,6 +140,6 @@ const AgentChatBox = () => {
></PdfDrawer> ></PdfDrawer>
</> </>
); );
}; }
export default AgentChatBox; export default memo(AgentChatBox);

View File

@ -235,18 +235,23 @@ export const useSendAgentMessage = (
params.session_id = sessionId; params.session_id = sessionId;
} }
const res = await send(params);
clearUploadResponseList(); try {
const res = await send(params);
if (receiveMessageError(res)) { clearUploadResponseList();
sonnerMessage.error(res?.data?.message);
// cancel loading if (receiveMessageError(res)) {
setValue(message.content); sonnerMessage.error(res?.data?.message);
removeLatestMessage();
} else { // cancel loading
// refetch(); // pull the message list after sending the message successfully setValue(message.content);
removeLatestMessage();
} else {
// refetch(); // pull the message list after sending the message successfully
}
} catch (error) {
console.log('🚀 ~ useSendAgentMessage ~ error:', error);
} }
}, },
[ [

View File

@ -167,3 +167,15 @@ export function useShowLogSheet({
showLogSheet: handleShow, showLogSheet: handleShow,
}; };
} }
export function useHideFormSheetOnNodeDeletion({
hideFormDrawer,
}: Pick<ReturnType<typeof useShowFormDrawer>, 'hideFormDrawer'>) {
const { nodes, clickedNodeId } = useGraphStore((state) => state);
useEffect(() => {
if (!nodes.some((x) => x.id === clickedNodeId)) {
hideFormDrawer();
}
}, [clickedNodeId, hideFormDrawer, nodes]);
}

View File

@ -1,7 +1,7 @@
import { IconFont } from '@/components/icon-font'; import { IconFont } from '@/components/icon-font';
import SvgIcon from '@/components/svg-icon'; import SvgIcon from '@/components/svg-icon';
import { cn } from '@/lib/utils'; import { cn } from '@/lib/utils';
import { CirclePlay } from 'lucide-react'; import { HousePlus } from 'lucide-react';
import { Operator } from './constant'; import { Operator } from './constant';
interface IProps { interface IProps {
@ -11,7 +11,7 @@ interface IProps {
export const OperatorIconMap = { export const OperatorIconMap = {
[Operator.Retrieval]: 'KR', [Operator.Retrieval]: 'KR',
[Operator.Begin]: CirclePlay, [Operator.Begin]: 'house-plus',
[Operator.Categorize]: 'a-QuestionClassification', [Operator.Categorize]: 'a-QuestionClassification',
[Operator.Message]: 'reply', [Operator.Message]: 'reply',
[Operator.Iteration]: 'loop', [Operator.Iteration]: 'loop',
@ -49,6 +49,14 @@ const Empty = () => {
const OperatorIcon = ({ name, className }: IProps) => { const OperatorIcon = ({ name, className }: IProps) => {
const Icon = OperatorIconMap[name as keyof typeof OperatorIconMap] || Empty; const Icon = OperatorIconMap[name as keyof typeof OperatorIconMap] || Empty;
if (name === Operator.Begin) {
return (
<div className="inline-block p-1 bg-background-checked rounded-sm">
<HousePlus className="rounded size-3" />
</div>
);
}
if (name in SVGIconMap) { if (name in SVGIconMap) {
return ( return (
<SvgIcon <SvgIcon