Skip to content

Commit b84e702

Browse files
authored
♻️ Reactoring agent is new diplay logic
♻️ Reactoring agent is new diplay logic
2 parents a98345b + 8b786e8 commit b84e702

11 files changed

Lines changed: 124 additions & 364 deletions

File tree

frontend/app/[locale]/agents/components/AgentManageComp.tsx

Lines changed: 6 additions & 113 deletions
Original file line numberDiff line numberDiff line change
@@ -4,74 +4,34 @@ import { useTranslation } from "react-i18next";
44
import { App, Row, Col, Flex, Tooltip, Badge, Divider } from "antd";
55
import { FileInput, Plus, X } from "lucide-react";
66

7-
import { Agent } from "@/types/agentConfig";
87
import AgentList from "./agentManage/AgentList";
9-
import { useSaveGuard } from "@/hooks/agent/useSaveGuard";
10-
import { useCallback } from "react";
8+
119
import { useAgentConfigStore } from "@/stores/agentConfigStore";
1210
import { importAgent } from "@/services/agentConfigService";
1311
import { useMutation, useQueryClient } from "@tanstack/react-query";
1412
import { useAgentList } from "@/hooks/agent/useAgentList";
15-
import { useAgentInfo } from "@/hooks/agent/useAgentInfo";
1613
import log from "@/lib/logger";
17-
import { useState, useEffect } from "react";
14+
import { useState } from "react";
1815
import { ImportAgentData } from "@/hooks/useAgentImport";
1916
import AgentImportWizard from "@/components/agent/AgentImportWizard";
20-
import { clearAgentNewMark } from "@/services/agentConfigService";
21-
import { clearAgentAndSync } from "@/lib/agentNewUtils";
17+
2218

2319
export default function AgentManageComp() {
2420
const { t } = useTranslation("common");
2521
const { message } = App.useApp();
2622

2723
// Get state from store
28-
const currentAgentId = useAgentConfigStore((state) => state.currentAgentId);
29-
const hasUnsavedChanges = useAgentConfigStore(
30-
(state) => state.hasUnsavedChanges
31-
);
3224
const isCreatingMode = useAgentConfigStore((state) => state.isCreatingMode);
33-
const setCurrentAgent = useAgentConfigStore((state) => state.setCurrentAgent);
3425
const enterCreateMode = useAgentConfigStore((state) => state.enterCreateMode);
3526
const reset = useAgentConfigStore((state) => state.reset);
3627

37-
// Unsaved changes guard
38-
const checkUnsavedChanges = useSaveGuard();
39-
40-
// Handle unsaved changes check and agent switching
41-
const handleAgentSwitch = useCallback(
42-
async (agentDetail: any) => {
43-
const canSwitch = await checkUnsavedChanges.saveWithModal();
44-
if (canSwitch) {
45-
setCurrentAgent(agentDetail);
46-
}
47-
},
48-
[checkUnsavedChanges]
49-
);
50-
51-
const editable = currentAgentId || isCreatingMode;
52-
53-
// Shared agent list via React Query
54-
const { agents: agentList, isLoading: loading, refetch } = useAgentList();
55-
const queryClient = useQueryClient();
56-
57-
// State for selected agent info loading
58-
const [selectedAgentId, setSelectedAgentId] = useState<number | null>(null);
59-
6028
// Import wizard state
6129
const [importWizardVisible, setImportWizardVisible] = useState(false);
6230
const [importWizardData, setImportWizardData] =
6331
useState<ImportAgentData | null>(null);
6432

65-
const {
66-
data: agentDetail,
67-
isLoading: agentInfoLoading,
68-
error: agentInfoError,
69-
} = useAgentInfo(selectedAgentId);
70-
71-
const importAgentMutation = useMutation({
72-
mutationFn: (agentData: any) => importAgent(agentData),
73-
onSuccess: () => queryClient.invalidateQueries({ queryKey: ["agents"] }),
74-
});
33+
// Shared agent list via React Query
34+
const { agents: agentList, isLoading: loading, refetch } = useAgentList();
7535

7636
// Handle import agent for space view - open wizard instead of direct import
7737
const handleImportAgent = () => {
@@ -117,63 +77,6 @@ export default function AgentManageComp() {
11777
fileInput.click();
11878
};
11979

120-
// Handle agent detail loading completion
121-
useEffect(() => {
122-
if (
123-
selectedAgentId &&
124-
agentDetail &&
125-
!agentInfoLoading &&
126-
!agentInfoError
127-
) {
128-
// Handle agent switch with unsaved changes check
129-
handleAgentSwitch(agentDetail);
130-
setSelectedAgentId(null);
131-
} else if (selectedAgentId && agentInfoError && !agentInfoLoading) {
132-
// Handle error
133-
log.error("Failed to load agent detail:", agentInfoError);
134-
message.error(t("agentConfig.agents.detailsLoadFailed"));
135-
setSelectedAgentId(null);
136-
}
137-
}, [
138-
selectedAgentId,
139-
agentDetail,
140-
agentInfoLoading,
141-
agentInfoError,
142-
handleAgentSwitch,
143-
message,
144-
t,
145-
]);
146-
147-
// Handle select agent
148-
const handleSelectAgent = async (agent: Agent) => {
149-
// If already selected, deselect it
150-
if (
151-
currentAgentId !== null &&
152-
String(currentAgentId) === String(agent.id)
153-
) {
154-
const canDeselect = await checkUnsavedChanges.saveWithModal();
155-
if (canDeselect) {
156-
setCurrentAgent(null);
157-
}
158-
return;
159-
}
160-
161-
// Clear NEW mark when agent is selected for editing (only if marked as new)
162-
if (agent.is_new === true) {
163-
try {
164-
const res = await clearAgentAndSync(agent.id, queryClient);
165-
if (!res?.success) {
166-
log.warn("Failed to clear NEW mark on select:", res);
167-
}
168-
} catch (err) {
169-
log.error("Failed to clear NEW mark on select:", err);
170-
}
171-
}
172-
173-
// Set selected agent id to trigger the hook
174-
setSelectedAgentId(Number(agent.id));
175-
};
176-
17780
return (
17881
<>
17982
{/* Import handled by Ant Design Upload (no hidden input required) */}
@@ -283,17 +186,7 @@ export default function AgentManageComp() {
283186
</Row>
284187

285188
<div className="flex-1 min-h-0">
286-
<AgentList
287-
agentList={agentList}
288-
currentAgentId={currentAgentId}
289-
hasUnsavedChanges={hasUnsavedChanges}
290-
onSelectAgent={handleSelectAgent}
291-
onAgentDeleted={(agentId) => {
292-
if (currentAgentId === agentId) {
293-
setCurrentAgent(null);
294-
}
295-
}}
296-
/>
189+
<AgentList agentList={agentList} />
297190
</div>
298191
</Flex>
299192

frontend/app/[locale]/agents/components/agentManage/AgentList.tsx

Lines changed: 66 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
"use client";
22

3-
import React, { useState, useEffect } from "react";
3+
import React from "react";
4+
import { useState } from "react";
45
import { useTranslation } from "react-i18next";
56
import { Button, Col, Flex, Tooltip, Divider, Table, theme, App } from "antd";
67
import { ExclamationCircleOutlined } from "@ant-design/icons";
@@ -17,58 +18,35 @@ import {
1718
exportAgent,
1819
updateToolConfig,
1920
} from "@/services/agentConfigService";
21+
import { useAgentConfigStore } from "@/stores/agentConfigStore";
22+
import { useSaveGuard } from "@/hooks/agent/useSaveGuard";
2023
import { clearAgentNewMark } from "@/services/agentConfigService";
2124
import log from "@/lib/logger";
22-
import { clearAgentAndSync } from "@/lib/agentNewUtils";
2325

2426
interface AgentListProps {
2527
agentList: Agent[];
26-
currentAgentId: number | null;
27-
hasUnsavedChanges: boolean;
28-
onSelectAgent: (agent: Agent) => void;
29-
onAgentDeleted?: (agentId: number) => void;
3028
}
3129

3230
export default function AgentList({
3331
agentList,
34-
currentAgentId,
35-
hasUnsavedChanges,
36-
onSelectAgent,
37-
onAgentDeleted,
3832
}: AgentListProps) {
3933
const { t } = useTranslation();
4034
const { token } = theme.useToken();
4135
const { message } = App.useApp();
4236
const confirm = useConfirmModal();
4337
const queryClient = useQueryClient();
4438

45-
// Note: rely on agent.is_new from agentList (single source of truth).
46-
// Clear NEW mark when agent is selected (sync with selection visual feedback)
47-
useEffect(() => {
48-
if (currentAgentId) {
49-
const agentId = String(currentAgentId);
50-
const agent = agentList.find(a => String(a.id) === agentId);
51-
if (agent?.is_new === true) {
52-
(async () => {
53-
try {
54-
const res = await clearAgentAndSync(agentId, queryClient);
55-
if (!res?.success) {
56-
log.warn("Failed to clear NEW mark for agent:", agentId, res);
57-
}
58-
} catch (err) {
59-
log.error("Error clearing NEW mark:", err);
60-
}
61-
})();
62-
}
63-
}
64-
}, [currentAgentId, agentList]);
65-
6639
// Call relationship modal state
6740
const [callRelationshipModalVisible, setCallRelationshipModalVisible] =
6841
useState(false);
6942
const [selectedAgentForRelationship, setSelectedAgentForRelationship] =
7043
useState<Agent | null>(null);
7144

45+
// Get state from store
46+
const currentAgentId = useAgentConfigStore((state) => state.currentAgentId);
47+
const setCurrentAgent = useAgentConfigStore((state) => state.setCurrentAgent);
48+
const hasUnsavedChanges = useAgentConfigStore((state) => state.hasUnsavedChanges);
49+
7250
// Mutations
7351
const updateAgentMutation = useMutation({
7452
mutationFn: (payload: any) => updateAgentInfo(payload),
@@ -78,6 +56,9 @@ export default function AgentList({
7856
mutationFn: (agentId: number) => deleteAgent(agentId),
7957
});
8058

59+
// Unsaved changes guard
60+
const checkUnsavedChanges = useSaveGuard();
61+
8162
// Handle view call relationship
8263
const handleViewCallRelationship = (agent: Agent) => {
8364
setSelectedAgentForRelationship(agent);
@@ -89,6 +70,53 @@ export default function AgentList({
8970
setSelectedAgentForRelationship(null);
9071
};
9172

73+
// Handle select agent
74+
const handleSelectAgent = async (agent: Agent) => {
75+
// Clear NEW mark when agent is selected for editing (only if marked as new)
76+
if (agent.is_new === true) {
77+
try {
78+
const res = await clearAgentNewMark(agent.id);
79+
if (res?.success) {
80+
log.warn("Failed to clear NEW mark on select:", res);
81+
queryClient.invalidateQueries({ queryKey: ["agents"] });
82+
}
83+
} catch (err) {
84+
log.error("Failed to clear NEW mark on select:", err);
85+
}
86+
}
87+
88+
// If already selected, deselect it
89+
if (
90+
currentAgentId !== null &&
91+
String(currentAgentId) === String(agent.id)
92+
) {
93+
const canDeselect = await checkUnsavedChanges.saveWithModal();
94+
if (canDeselect) {
95+
setCurrentAgent(null);
96+
}
97+
return;
98+
}
99+
100+
// Check if can switch (has unsaved changes)
101+
const canSwitch = await checkUnsavedChanges.saveWithModal();
102+
if (!canSwitch) {
103+
return;
104+
}
105+
106+
// Load agent detail and set as current
107+
try {
108+
const result = await searchAgentInfo(Number(agent.id));
109+
if (result.success && result.data) {
110+
setCurrentAgent(result.data);
111+
} else {
112+
message.error(result.message || t("agentConfig.agents.detailsLoadFailed"));
113+
}
114+
} catch (error) {
115+
log.error("Failed to load agent detail:", error);
116+
message.error(t("agentConfig.agents.detailsLoadFailed"));
117+
}
118+
};
119+
92120
// Handle export agent
93121
const handleExportAgent = async (agent: Agent) => {
94122
try {
@@ -244,12 +272,12 @@ export default function AgentList({
244272
})
245273
);
246274

247-
// Notify parent component if this was the current agent
275+
// Clear current agent if this was the selected agent
248276
if (
249277
currentAgentId !== null &&
250278
String(currentAgentId) === String(agent.id)
251279
) {
252-
onAgentDeleted?.(Number(agent.id));
280+
setCurrentAgent(null);
253281
}
254282

255283
// Refresh agent list
@@ -287,22 +315,23 @@ export default function AgentList({
287315
pagination={false}
288316
showHeader={false}
289317
rowClassName={(agent: any) => {
318+
const isSelected =
319+
currentAgentId !== null &&
320+
String(currentAgentId) === String(agent.id);
290321
return `py-3 px-4 transition-colors border-gray-200 h-[80px] ${
291322
agent.is_available === false
292323
? "opacity-60 cursor-not-allowed"
293324
: "hover:bg-gray-50 cursor-pointer"
294325
} ${
295-
currentAgentId !== null &&
296-
String(currentAgentId) === String(agent.id)
297-
? "bg-blue-50 selected-row pl-3"
326+
isSelected ? "bg-blue-50 selected-row pl-3"
298327
: ""
299328
}`;
300329
}}
301330
onRow={(agent: any) => ({
302331
onClick: (e: any) => {
303332
e.preventDefault();
304333
e.stopPropagation();
305-
onSelectAgent(agent);
334+
handleSelectAgent(agent);
306335
},
307336
})}
308337
columns={[

0 commit comments

Comments
 (0)