Skip to content

Commit 406cf99

Browse files
committed
🐛 [Request] Administrator can go to any configuration page #1346
1 parent 5b66185 commit 406cf99

File tree

5 files changed

+162
-35
lines changed

5 files changed

+162
-35
lines changed

frontend/app/[locale]/chat/components/chatLeftSidebar.tsx

Lines changed: 104 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@ import {
99
ChevronLeft,
1010
ChevronRight,
1111
User,
12+
Database,
13+
Box,
14+
Bot,
1215
} from "lucide-react";
1316

1417
import { Button } from "@/components/ui/button";
@@ -37,7 +40,8 @@ import { StaticScrollArea } from "@/components/ui/scrollArea";
3740
import { USER_ROLES } from "@/const/modelConfig";
3841
import { useConfig } from "@/hooks/useConfig";
3942
import { useResponsiveTextSize } from "@/hooks/useResponsiveTextSize";
40-
import { Spin, Tag, ConfigProvider } from "antd";
43+
import { Spin, Tag, ConfigProvider, Dropdown, Menu } from "antd";
44+
import type { MenuProps } from "antd";
4145
import { getRoleColor } from "@/lib/auth";
4246
import { useAuth } from "@/hooks/useAuth";
4347
import { extractColorsFromUri } from "@/lib/avatar";
@@ -120,6 +124,7 @@ export function ChatSidebar({
120124
onRename,
121125
onDelete,
122126
onSettingsClick,
127+
settingsMenuItems,
123128
onDropdownOpenChange,
124129
onToggleSidebar,
125130
expanded,
@@ -237,6 +242,102 @@ export function ChatSidebar({
237242
);
238243
};
239244

245+
// Get icon for menu item based on key
246+
const getMenuIcon = (key: string) => {
247+
switch (key) {
248+
case "models":
249+
return <Box className="h-4 w-4" />;
250+
case "knowledges":
251+
return <Database className="h-4 w-4" />;
252+
case "agents":
253+
return <Bot className="h-4 w-4" />;
254+
default:
255+
return null;
256+
}
257+
};
258+
259+
// Render settings button (with dropdown for admin, plain button for regular users)
260+
const renderSettingsButton = (isCollapsed: boolean = false) => {
261+
const buttonContent = (
262+
<Button
263+
variant="ghost"
264+
size="icon"
265+
className={isCollapsed ? "h-10 w-10 rounded-full hover:bg-slate-100" : "size-10 rounded-full hover:bg-slate-100"}
266+
onClick={settingsMenuItems ? undefined : onSettingsClick}
267+
>
268+
<Settings className={isCollapsed ? "h-6 w-6" : "size-5"} />
269+
</Button>
270+
);
271+
272+
// If settingsMenuItems is provided, show dropdown with icons
273+
if (settingsMenuItems && settingsMenuItems.length > 0) {
274+
const menuProps: MenuProps = {
275+
items: settingsMenuItems.map((item, index) => ({
276+
key: item.key,
277+
label: (
278+
<div className="flex items-center gap-3 py-1">
279+
<span className="text-gray-600">{getMenuIcon(item.key)}</span>
280+
<span className="text-sm font-medium">{item.label}</span>
281+
</div>
282+
),
283+
onClick: item.onClick,
284+
style: {
285+
padding: "8px 16px",
286+
},
287+
})),
288+
style: {
289+
minWidth: "240px",
290+
borderRadius: "8px",
291+
boxShadow: "0 4px 12px rgba(0, 0, 0, 0.15)",
292+
},
293+
};
294+
295+
return (
296+
<TooltipProvider>
297+
<Tooltip>
298+
<TooltipTrigger asChild>
299+
<ConfigProvider
300+
getPopupContainer={() => document.body}
301+
theme={{
302+
components: {
303+
Dropdown: {
304+
paddingBlock: 4,
305+
},
306+
},
307+
}}
308+
>
309+
<Dropdown menu={menuProps} placement="topRight" trigger={["click"]}>
310+
<div className={isCollapsed ? "flex justify-center" : ""}>
311+
{buttonContent}
312+
</div>
313+
</Dropdown>
314+
</ConfigProvider>
315+
</TooltipTrigger>
316+
<TooltipContent side={isCollapsed ? "right" : "top"}>
317+
{t("chatLeftSidebar.settings")}
318+
</TooltipContent>
319+
</Tooltip>
320+
</TooltipProvider>
321+
);
322+
}
323+
324+
// Otherwise, show plain button for regular users (shouldn't reach here anymore)
325+
return (
326+
<TooltipProvider>
327+
<Tooltip>
328+
<TooltipTrigger asChild>
329+
<div className={isCollapsed ? "flex justify-center" : ""}>
330+
{buttonContent}
331+
</div>
332+
</TooltipTrigger>
333+
<TooltipContent side={isCollapsed ? "right" : "top"}>
334+
{t("chatLeftSidebar.settings")}
335+
</TooltipContent>
336+
</Tooltip>
337+
</TooltipProvider>
338+
);
339+
};
340+
240341
// Render dialog list items
241342
const renderDialogList = (dialogs: ConversationListItem[], title: string) => {
242343
if (dialogs.length === 0) return null;
@@ -461,25 +562,7 @@ export function ChatSidebar({
461562
) : null}
462563

463564
{/* Settings button */}
464-
<TooltipProvider>
465-
<Tooltip>
466-
<TooltipTrigger asChild>
467-
<div className="flex justify-center">
468-
<Button
469-
variant="ghost"
470-
size="icon"
471-
className="h-10 w-10 rounded-full hover:bg-slate-100"
472-
onClick={onSettingsClick}
473-
>
474-
<Settings className="h-6 w-6" />
475-
</Button>
476-
</div>
477-
</TooltipTrigger>
478-
<TooltipContent side="right">
479-
{t("chatLeftSidebar.settings")}
480-
</TooltipContent>
481-
</Tooltip>
482-
</TooltipProvider>
565+
{renderSettingsButton(true)}
483566
</>
484567
);
485568
};
@@ -628,14 +711,7 @@ export function ChatSidebar({
628711
</div>
629712
</ConfigProvider>
630713
) : null}
631-
<Button
632-
variant="ghost"
633-
size="icon"
634-
className="size-10 rounded-full hover:bg-slate-100"
635-
onClick={onSettingsClick}
636-
>
637-
<Settings className="size-5" />
638-
</Button>
714+
{renderSettingsButton(false)}
639715
</div>
640716
</div>
641717
) : (

frontend/app/[locale]/chat/internal/chatInterface.tsx

Lines changed: 44 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1533,6 +1533,48 @@ export function ChatInterface() {
15331533
};
15341534
}, []);
15351535

1536+
// Handle settings click - not used when menu items are provided
1537+
const handleSettingsClick = () => {
1538+
// This function is kept for compatibility but not used
1539+
// Both admin and regular users now use dropdown menus
1540+
};
1541+
1542+
// Settings menu items based on user role
1543+
const settingsMenuItems = user?.role === "admin" ? [
1544+
// Admin has three options
1545+
{
1546+
key: "models",
1547+
label: t("chatLeftSidebar.settingsMenu.modelConfig"),
1548+
onClick: () => {
1549+
localStorage.setItem("show_page", "1");
1550+
router.push("/setup/models");
1551+
},
1552+
},
1553+
{
1554+
key: "knowledges",
1555+
label: t("chatLeftSidebar.settingsMenu.knowledgeConfig"),
1556+
onClick: () => {
1557+
router.push("/setup/knowledges");
1558+
},
1559+
},
1560+
{
1561+
key: "agents",
1562+
label: t("chatLeftSidebar.settingsMenu.agentConfig"),
1563+
onClick: () => {
1564+
router.push("/setup/agents");
1565+
},
1566+
},
1567+
] : [
1568+
// Regular user only has knowledge base configuration
1569+
{
1570+
key: "knowledges",
1571+
label: t("chatLeftSidebar.settingsMenu.knowledgeConfig"),
1572+
onClick: () => {
1573+
router.push("/setup/knowledges");
1574+
},
1575+
},
1576+
];
1577+
15361578
return (
15371579
<>
15381580
<div className="flex h-screen">
@@ -1546,13 +1588,8 @@ export function ChatInterface() {
15461588
onDialogClick={handleDialogClick}
15471589
onRename={handleConversationRename}
15481590
onDelete={handleConversationDeleteClick}
1549-
onSettingsClick={() => {
1550-
localStorage.setItem(
1551-
"show_page",
1552-
user?.role === "admin" ? "1" : "2"
1553-
);
1554-
router.push("/setup");
1555-
}}
1591+
onSettingsClick={handleSettingsClick}
1592+
settingsMenuItems={settingsMenuItems}
15561593
onDropdownOpenChange={(open: boolean, id: string | null) =>
15571594
setOpenDropdownId(open ? id : null)
15581595
}

frontend/public/locales/en/common.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,9 @@
100100
"chatLeftSidebar.noHistory": "No conversation history",
101101
"chatLeftSidebar.expandSidebar": "Expand Sidebar",
102102
"chatLeftSidebar.settings": "Settings",
103+
"chatLeftSidebar.settingsMenu.modelConfig": "Application and System Model Configuration",
104+
"chatLeftSidebar.settingsMenu.knowledgeConfig": "Knowledge Base Configuration",
105+
"chatLeftSidebar.settingsMenu.agentConfig": "Agent Configuration",
103106
"chatLeftSidebar.confirmDeletionTitle": "Delete Conversation",
104107
"chatLeftSidebar.confirmDeletionDescription": "Are you sure you want to delete this conversation? This action cannot be undone.",
105108
"chatLeftSidebar.cancel": "Cancel",

frontend/public/locales/zh/common.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,9 @@
100100
"chatLeftSidebar.noHistory": "无历史对话",
101101
"chatLeftSidebar.expandSidebar": "展开边栏",
102102
"chatLeftSidebar.settings": "设置",
103+
"chatLeftSidebar.settingsMenu.modelConfig": "应用程序和系统模型配置",
104+
"chatLeftSidebar.settingsMenu.knowledgeConfig": "知识库配置",
105+
"chatLeftSidebar.settingsMenu.agentConfig": "代理配置",
103106
"chatLeftSidebar.confirmDeletionTitle": "删除对话",
104107
"chatLeftSidebar.confirmDeletionDescription": "确定要删除这个对话吗?此操作无法撤销。",
105108
"chatLeftSidebar.cancel": "取消",

frontend/types/chat.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -249,6 +249,13 @@ export interface FilePreview {
249249
previewUrl?: string;
250250
}
251251

252+
// Settings menu item type for admin users
253+
export interface SettingsMenuItem {
254+
key: string;
255+
label: string;
256+
onClick: () => void;
257+
}
258+
252259
// Chat sidebar props type
253260
export interface ChatSidebarProps {
254261
conversationList: ConversationListItem[];
@@ -261,6 +268,7 @@ export interface ChatSidebarProps {
261268
onRename: (dialogId: number, title: string) => void;
262269
onDelete: (dialogId: number) => void;
263270
onSettingsClick: () => void;
271+
settingsMenuItems?: SettingsMenuItem[];
264272
onDropdownOpenChange: (open: boolean, id: string | null) => void;
265273
onToggleSidebar: () => void;
266274
expanded: boolean;

0 commit comments

Comments
 (0)