Files
gitmost/apps/client/src/components/settings/settings-sidebar.tsx
vvzvlad ea56985efd refactor(ai): move AI settings to a dedicated /settings/ai page
Extract the AI provider/endpoints settings and the MCP server section out
of the Workspace "General" settings page into their own "AI" settings page,
reachable from a new sidebar entry.

- add page apps/client/.../settings/workspace/ai-settings.tsx (AiProviderSettings
  admin-gated + McpSettings), with its own Helmet title
- register the /settings/ai route in App.tsx and add SETTINGS.WORKSPACE.AI
  to app-route.ts
- add an "AI" item (IconSparkles) to the Workspace group in settings-sidebar
- trim workspace-settings.tsx back to the General section and drop the
  now-unused imports
2026-06-18 04:34:57 +03:00

149 lines
4.1 KiB
TypeScript

import React, { useEffect, useState } from "react";
import { Group, Text, ScrollArea, ActionIcon } from "@mantine/core";
import {
IconUser,
IconSettings,
IconUsers,
IconArrowLeft,
IconUsersGroup,
IconSpaces,
IconBrush,
IconWorld,
IconSparkles,
} from "@tabler/icons-react";
import { Link, useLocation } from "react-router-dom";
import classes from "./settings.module.css";
import { useTranslation } from "react-i18next";
import {
prefetchGroups,
prefetchShares,
prefetchSpaces,
prefetchWorkspaceMembers,
} from "@/components/settings/settings-queries.tsx";
import AppVersion from "@/components/settings/app-version.tsx";
import { mobileSidebarAtom } from "@/components/layouts/global/hooks/atoms/sidebar-atom.ts";
import { useToggleSidebar } from "@/components/layouts/global/hooks/hooks/use-toggle-sidebar.ts";
import { useSettingsNavigation } from "@/hooks/use-settings-navigation";
import { useAtom } from "jotai";
type DataItem = {
label: string;
icon: React.ElementType;
path: string;
};
type DataGroup = {
heading: string;
items: DataItem[];
};
const groupedData: DataGroup[] = [
{
heading: "Account",
items: [
{ label: "Profile", icon: IconUser, path: "/settings/account/profile" },
{
label: "Preferences",
icon: IconBrush,
path: "/settings/account/preferences",
},
],
},
{
heading: "Workspace",
items: [
{ label: "General", icon: IconSettings, path: "/settings/workspace" },
{ label: "AI", icon: IconSparkles, path: "/settings/ai" },
{ label: "Members", icon: IconUsers, path: "/settings/members" },
{ label: "Groups", icon: IconUsersGroup, path: "/settings/groups" },
{ label: "Spaces", icon: IconSpaces, path: "/settings/spaces" },
{ label: "Public sharing", icon: IconWorld, path: "/settings/sharing" },
],
},
];
export default function SettingsSidebar() {
const { t } = useTranslation();
const location = useLocation();
const [active, setActive] = useState(location.pathname);
const { goBack } = useSettingsNavigation();
const [mobileSidebarOpened] = useAtom(mobileSidebarAtom);
const toggleMobileSidebar = useToggleSidebar(mobileSidebarAtom);
useEffect(() => {
setActive(location.pathname);
}, [location.pathname]);
const menuItems = groupedData.map((group) => {
return (
<div key={group.heading}>
<Text c="dimmed" className={classes.linkHeader}>
{t(group.heading)}
</Text>
{group.items.map((item) => {
let prefetchHandler: any;
switch (item.label) {
case "Members":
prefetchHandler = prefetchWorkspaceMembers;
break;
case "Spaces":
prefetchHandler = prefetchSpaces;
break;
case "Groups":
prefetchHandler = prefetchGroups;
break;
case "Public sharing":
prefetchHandler = prefetchShares;
break;
default:
break;
}
return (
<Link
onMouseEnter={prefetchHandler}
className={classes.link}
data-active={active.startsWith(item.path) || undefined}
key={item.label}
to={item.path}
onClick={() => {
if (mobileSidebarOpened) {
toggleMobileSidebar();
}
}}
>
<item.icon className={classes.linkIcon} stroke={2} />
<span>{t(item.label)}</span>
</Link>
);
})}
</div>
);
});
return (
<div className={classes.navbar}>
<Group className={classes.title} justify="flex-start">
<ActionIcon
onClick={() => {
goBack();
if (mobileSidebarOpened) {
toggleMobileSidebar();
}
}}
variant="transparent"
c="gray"
aria-label={t("Back")}
>
<IconArrowLeft stroke={2} />
</ActionIcon>
<Text fw={500}>{t("Settings")}</Text>
</Group>
<ScrollArea w="100%">{menuItems}</ScrollArea>
<AppVersion />
</div>
);
}