Skip to content

Commit e818b82

Browse files
authored
πŸ› When the list of agents is empty, the column width will shrink
2 parents fa1f5f4 + 17e778d commit e818b82

File tree

10 files changed

+269
-95
lines changed

10 files changed

+269
-95
lines changed

β€Žfrontend/app/[locale]/agents/AgentsContent.tsxβ€Ž

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

3-
import React, {useState, useEffect, useRef} from "react";
3+
import React, {useState, useEffect, useRef, forwardRef, useImperativeHandle} from "react";
44
import {motion} from "framer-motion";
55

66
import {useSetupFlow} from "@/hooks/useSetupFlow";
@@ -30,14 +30,14 @@ interface AgentsContentProps {
3030
* AgentsContent - Main component for agent configuration
3131
* Can be used in setup flow or as standalone page
3232
*/
33-
export default function AgentsContent({
33+
export default forwardRef<AgentConfigHandle, AgentsContentProps>(function AgentsContent({
3434
isSaving: externalIsSaving,
3535
connectionStatus: externalConnectionStatus,
3636
isCheckingConnection: externalIsCheckingConnection,
3737
onCheckConnection: externalOnCheckConnection,
3838
onConnectionStatusChange,
3939
onSavingStateChange,
40-
}: AgentsContentProps) {
40+
}: AgentsContentProps, ref) {
4141
const agentConfigRef = useRef<AgentConfigHandle | null>(null);
4242
const [showSaveConfirm, setShowSaveConfirm] = useState(false);
4343
const pendingNavRef = useRef<null | (() => void)>(null);
@@ -59,6 +59,21 @@ export default function AgentsContent({
5959
const [internalIsSaving, setInternalIsSaving] = useState(false);
6060
const isSaving = externalIsSaving ?? internalIsSaving;
6161

62+
// Expose AgentConfigHandle methods to parent
63+
useImperativeHandle(ref, () => ({
64+
hasUnsavedChanges: () => agentConfigRef.current?.hasUnsavedChanges?.() ?? false,
65+
saveAllChanges: async () => {
66+
if (agentConfigRef.current?.saveAllChanges) {
67+
await agentConfigRef.current.saveAllChanges();
68+
}
69+
},
70+
reloadCurrentAgentData: async () => {
71+
if (agentConfigRef.current?.reloadCurrentAgentData) {
72+
await agentConfigRef.current.reloadCurrentAgentData();
73+
}
74+
},
75+
}), []);
76+
6277
// Update external saving state
6378
useEffect(() => {
6479
onSavingStateChange?.(isSaving);
@@ -74,7 +89,7 @@ export default function AgentsContent({
7489
transition={pageTransition}
7590
style={{width: "100%", height: "100%"}}
7691
>
77-
<div className="w-full h-full flex items-center justify-center">
92+
<div className="w-full h-full">
7893
{canAccessProtectedData ? (
7994
<AgentConfig ref={agentConfigRef} canAccessProtectedData={canAccessProtectedData} />
8095
) : null}
@@ -108,5 +123,5 @@ export default function AgentsContent({
108123
/>
109124
</>
110125
);
111-
}
126+
});
112127

β€Žfrontend/app/[locale]/agents/components/AgentSetupOrchestrator.tsxβ€Ž

Lines changed: 18 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { useState, useEffect, useCallback, useRef, useMemo } from "react";
44
import { useTranslation } from "react-i18next";
55
import { TFunction } from "i18next";
66

7-
import { App, Modal, Button, Tooltip } from "antd";
7+
import { App, Modal, Button, Tooltip, Row, Col } from "antd";
88
import { WarningFilled } from "@ant-design/icons";
99

1010
import { TooltipProvider } from "@/components/ui/tooltip";
@@ -1961,11 +1961,11 @@ export default function AgentSetupOrchestrator({
19611961

19621962
return (
19631963
<TooltipProvider>
1964-
<div className="flex flex-col h-full gap-0 justify-between relative ml-2 mr-2">
1965-
{/* Lower part: Agent pool + Agent capability configuration + System Prompt */}
1966-
<div className="flex flex-col lg:flex-row gap-4 flex-1 min-h-0 max-w-full">
1967-
{/* Left column: Always show SubAgentPool - Equal flex width */}
1968-
<div className="w-full lg:w-auto lg:flex-1 h-full overflow-hidden">
1964+
<div className="h-full relative px-2">
1965+
{/* Three-column layout using Ant Design Grid */}
1966+
<Row gutter={[16, 16]} className="h-full">
1967+
{/* Left column: SubAgentPool */}
1968+
<Col xs={24} sm={24} md={24} lg={24} xl={8} className="flex flex-col" style={{ minHeight: '400px' }}>
19691969
<SubAgentPool
19701970
onEditAgent={(agent) => handleEditAgent(agent, t)}
19711971
onCreateNewAgent={() => confirmOrRun(handleCreateNewAgent)}
@@ -1985,29 +1985,28 @@ export default function AgentSetupOrchestrator({
19851985
: null
19861986
}
19871987
/>
1988-
</div>
1988+
</Col>
19891989

1990-
{/* Middle column: Agent capability configuration - Equal flex width */}
1991-
<div className="w-full lg:w-auto lg:flex-1 h-full flex flex-col overflow-hidden">
1990+
{/* Middle column: Agent capability configuration */}
1991+
<Col xs={24} sm={24} md={24} lg={24} xl={8} className="flex flex-col" style={{ minHeight: '400px' }}>
19921992
{/* Header: Configure Agent Capabilities */}
19931993
<div className="flex justify-between items-center mb-2">
19941994
<div className="flex items-center">
19951995
<div className="flex items-center justify-center w-6 h-6 rounded-full bg-blue-500 text-white text-sm font-medium mr-2">
19961996
2
19971997
</div>
1998-
<h2 className="text-lg font-medium">
1998+
<h2 className="text-lg font-medium m-0">
19991999
{t("businessLogic.config.title")}
20002000
</h2>
20012001
</div>
20022002
</div>
20032003

2004-
{/* Content: ScrollArea with two sections */}
2005-
<div className="flex-1 overflow-hidden border-t pt-2">
2004+
{/* Content: Two sections */}
2005+
<div className="flex-1 overflow-hidden border-t border-gray-200 pt-2">
20062006
<div className="flex flex-col h-full gap-4">
20072007
{/* Upper section: Collaborative Agent Display - fixed area */}
20082008
<CollaborativeAgentDisplay
2009-
className="h-[128px] lg:h-[128px]"
2010-
style={{ flexShrink: 0 }}
2009+
className="h-[128px] flex-shrink-0"
20112010
availableAgents={subAgentList}
20122011
selectedAgentIds={enabledAgentIds}
20132012
parentAgentId={
@@ -2070,10 +2069,10 @@ export default function AgentSetupOrchestrator({
20702069
</div>
20712070
</div>
20722071
</div>
2073-
</div>
2072+
</Col>
20742073

2075-
{/* Right column: System Prompt Display - Equal flex width */}
2076-
<div className="w-full lg:w-auto lg:flex-1 h-full overflow-hidden">
2074+
{/* Right column: System Prompt Display */}
2075+
<Col xs={24} sm={24} md={24} lg={24} xl={8} className="flex flex-col" style={{ minHeight: '400px' }}>
20772076
<PromptManager
20782077
onDebug={onDebug ? () => confirmOrRun(() => onDebug()) : () => {}}
20792078
agentId={
@@ -2123,8 +2122,8 @@ export default function AgentSetupOrchestrator({
21232122
editingAgent={editingAgentFromParent || editingAgent}
21242123
onViewCallRelationship={handleViewCallRelationship}
21252124
/>
2126-
</div>
2127-
</div>
2125+
</Col>
2126+
</Row>
21282127

21292128
{/* Delete confirmation popup */}
21302129
<Modal

β€Žfrontend/app/[locale]/agents/components/agent/SubAgentPool.tsxβ€Ž

Lines changed: 39 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
import { useState } from "react";
44
import { useTranslation } from "react-i18next";
55

6-
import { Button } from "antd";
6+
import { Button, Row, Col } from "antd";
77
import { ExclamationCircleOutlined } from "@ant-design/icons";
88
import { FileOutput, Network, FileInput, Trash2, Plus, X } from "lucide-react";
99

@@ -162,15 +162,16 @@ export default function SubAgentPool({
162162
<div className="flex flex-col pr-2">
163163
{/* Function operation block */}
164164
<div className="mb-4">
165-
<div className="flex gap-3">
166-
<Tooltip>
167-
<TooltipTrigger asChild>
168-
<div
169-
className={`flex-1 rounded-md p-2 flex items-center cursor-pointer transition-all duration-200 min-h-[70px] ${
170-
isCreatingNewAgent
171-
? "bg-blue-100 border border-blue-200 shadow-sm" // Highlight in creation mode
172-
: "bg-white hover:bg-blue-50 hover:shadow-sm"
173-
}`}
165+
<Row gutter={12}>
166+
<Col xs={24} sm={12}>
167+
<Tooltip>
168+
<TooltipTrigger asChild>
169+
<div
170+
className={`rounded-md p-2 flex items-center cursor-pointer transition-all duration-200 min-h-[70px] ${
171+
isCreatingNewAgent
172+
? "bg-blue-100 border border-blue-200 shadow-sm" // Highlight in creation mode
173+
: "bg-white hover:bg-blue-50 hover:shadow-sm"
174+
}`}
174175
onClick={() => {
175176
if (isCreatingNewAgent) {
176177
// If currently in creation mode, click to exit creation mode
@@ -217,24 +218,26 @@ export default function SubAgentPool({
217218
: t("subAgentPool.description.createAgent")}
218219
</div>
219220
</div>
221+
</div>
220222
</div>
221-
</div>
222-
</TooltipTrigger>
223-
<TooltipContent>
224-
{isCreatingNewAgent
225-
? t("subAgentPool.tooltip.exitCreateMode")
226-
: t("subAgentPool.tooltip.createNewAgent")}
227-
</TooltipContent>
228-
</Tooltip>
223+
</TooltipTrigger>
224+
<TooltipContent>
225+
{isCreatingNewAgent
226+
? t("subAgentPool.tooltip.exitCreateMode")
227+
: t("subAgentPool.tooltip.createNewAgent")}
228+
</TooltipContent>
229+
</Tooltip>
230+
</Col>
229231

230-
<Tooltip>
231-
<TooltipTrigger asChild>
232-
<div
233-
className={`flex-1 rounded-md p-2 flex items-center transition-all duration-200 min-h-[70px] ${
234-
isImporting
235-
? "bg-gray-100 cursor-not-allowed" // Importing: disabled state
236-
: "bg-white cursor-pointer hover:bg-green-50 hover:shadow-sm" // Normal state: clickable
237-
}`}
232+
<Col xs={24} sm={12}>
233+
<Tooltip>
234+
<TooltipTrigger asChild>
235+
<div
236+
className={`rounded-md p-2 flex items-center transition-all duration-200 min-h-[70px] ${
237+
isImporting
238+
? "bg-gray-100 cursor-not-allowed" // Importing: disabled state
239+
: "bg-white cursor-pointer hover:bg-green-50 hover:shadow-sm" // Normal state: clickable
240+
}`}
238241
onClick={isImporting ? undefined : onImportAgent}
239242
>
240243
<div
@@ -265,16 +268,17 @@ export default function SubAgentPool({
265268
: t("subAgentPool.description.importAgent")}
266269
</div>
267270
</div>
271+
</div>
268272
</div>
269-
</div>
270-
</TooltipTrigger>
271-
<TooltipContent>
272-
{isImporting
273-
? t("subAgentPool.description.importing")
274-
: t("subAgentPool.description.importAgent")}
275-
</TooltipContent>
276-
</Tooltip>
277-
</div>
273+
</TooltipTrigger>
274+
<TooltipContent>
275+
{isImporting
276+
? t("subAgentPool.description.importing")
277+
: t("subAgentPool.description.importAgent")}
278+
</TooltipContent>
279+
</Tooltip>
280+
</Col>
281+
</Row>
278282
</div>
279283

280284
{/* Agent list block */}

β€Žfrontend/app/[locale]/chat/streaming/chatStreamMain.tsxβ€Ž

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,9 +59,11 @@ export function ChatStreamMain({
5959
damping: 80,
6060
};
6161
const scrollAreaRef = useRef<HTMLDivElement>(null);
62+
const chatInputRef = useRef<HTMLDivElement>(null);
6263
const [showScrollButton, setShowScrollButton] = useState(false);
6364
const [showTopFade, setShowTopFade] = useState(false);
6465
const [autoScroll, setAutoScroll] = useState(true);
66+
const [chatInputHeight, setChatInputHeight] = useState(130); // Default ChatInput height
6567
const [processedMessages, setProcessedMessages] = useState<ProcessedMessages>(
6668
{
6769
finalMessages: [],
@@ -72,6 +74,28 @@ export function ChatStreamMain({
7274
const lastUserMessageIdRef = useRef<string | null>(null);
7375
const messagesEndRef = useRef<HTMLDivElement>(null);
7476

77+
// Monitor ChatInput height changes
78+
useEffect(() => {
79+
const chatInputElement = chatInputRef.current;
80+
if (!chatInputElement) return;
81+
82+
const resizeObserver = new ResizeObserver((entries) => {
83+
for (const entry of entries) {
84+
const height = entry.contentRect.height;
85+
setChatInputHeight(height);
86+
}
87+
});
88+
89+
resizeObserver.observe(chatInputElement);
90+
91+
// Set initial height
92+
setChatInputHeight(chatInputElement.getBoundingClientRect().height);
93+
94+
return () => {
95+
resizeObserver.disconnect();
96+
};
97+
}, [processedMessages.finalMessages.length]); // Re-observe when messages change (initial vs regular mode)
98+
7599
// Handle message classification
76100
useEffect(() => {
77101
const finalMsgs: ChatMessageType[] = [];
@@ -515,6 +539,7 @@ export function ChatStreamMain({
515539
animate="animate"
516540
variants={chatInputVariants}
517541
transition={chatInputTransition}
542+
ref={chatInputRef}
518543
>
519544
<ChatInput
520545
input={input}
@@ -582,12 +607,17 @@ export function ChatStreamMain({
582607
<div className="absolute top-0 left-0 right-0 h-16 pointer-events-none z-10 bg-gradient-to-b from-background to-transparent"></div>
583608
)}
584609

585-
{/* Scroll to bottom button */}
610+
{/* Scroll to bottom button - dynamically positioned based on ChatInput height */}
586611
{showScrollButton && (
587612
<Button
588613
variant="outline"
589614
size="icon"
590-
className="absolute bottom-[130px] left-1/2 transform -translate-x-1/2 z-20 rounded-full shadow-md bg-background hover:bg-background/90 border border-border h-8 w-8"
615+
className="absolute left-1/2 transform -translate-x-1/2 z-20 rounded-full shadow-md bg-background hover:bg-background/90 border border-border h-8 w-8"
616+
style={{
617+
// Position the button above the ChatInput with some margin
618+
// The ChatInput height changes from 130px (default) to up to 200px+ when textarea expands
619+
bottom: `${chatInputHeight-15}px`
620+
}}
591621
onClick={(e) => {
592622
e.preventDefault();
593623
e.stopPropagation();
@@ -607,6 +637,7 @@ export function ChatStreamMain({
607637
animate="animate"
608638
variants={chatInputVariants}
609639
transition={chatInputTransition}
640+
ref={chatInputRef}
610641
>
611642
<ChatInput
612643
input={input}

β€Žfrontend/app/[locale]/models/components/model/ModelAddDialog.tsxβ€Ž

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -290,6 +290,10 @@ export const ModelAddDialog = ({
290290
) {
291291
setConnectivityStatus({ status: null, message: "" });
292292
}
293+
// Clear model search term when model type changes
294+
if (field === "type") {
295+
setModelSearchTerm("");
296+
}
293297
};
294298

295299
// Verify if the vector dimension is valid
@@ -1177,7 +1181,7 @@ export const ModelAddDialog = ({
11771181
onCancel={() => setSettingsModalVisible(false)}
11781182
onOk={handleSettingsSave}
11791183
cancelText={t("common.cancel")}
1180-
okText={t("common.ok")}
1184+
okText={t("common.confirm")}
11811185
destroyOnClose
11821186
>
11831187
<div className="space-y-3">

0 commit comments

Comments
Β (0)