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
This commit is contained in:
vvzvlad
2026-06-18 04:32:40 +03:00
parent 87d6bdfbd9
commit ea56985efd
7 changed files with 41 additions and 22 deletions

View File

@@ -68,7 +68,7 @@ every little fix. And it needs no enterprise license.
**Same server as standalone docmost-mcp — just bundled.** This is the exact
[docmost-mcp](https://github.com/vvzvlad/docmost-mcp) you can also run on its own; embedding
it doesn't make it more capable, you simply don't have to install and run a separate
process. An admin flips one toggle in **Workspace settings → AI & MCP** and any MCP client
process. An admin flips one toggle in **Workspace settings → AI** and any MCP client
points at `${APP_URL}/mcp`.
### AI agent chat
@@ -88,9 +88,9 @@ community feature, with no enterprise license. Open it from the page header; the
across pages.
- **Web access via external MCP.** Admins can connect external MCP servers (e.g. Tavily) to
give the agent web search / internet access.
- **Bring your own model.** Configure the provider (OpenAI, Gemini or Ollama), model and API
key in **Workspace settings → AI & MCP → AI / Models**. The key is encrypted and never
leaves the server.
- **Bring your own model.** Configure an OpenAI-compatible endpoint — OpenAI, OpenRouter, a
local Ollama, or any self-hosted server — plus the model and API key in
**Workspace settings → AI**. The key is encrypted and never leaves the server.
## Roadmap

View File

@@ -68,7 +68,7 @@ real-time-коллаборации Docmost, поэтому запись нико
**Это тот же сервер, что и отдельный docmost-mcp, — просто встроенный.** Это ровно тот самый
[docmost-mcp](https://github.com/vvzvlad/docmost-mcp), который можно запускать и отдельно;
от встраивания он не становится «мощнее» — просто не нужно ставить и держать отдельный
процесс. Админ включает его одним переключателем в **Настройки воркспейса → AI & MCP**, а
процесс. Админ включает его одним переключателем в **Настройки воркспейса → AI**, а
любой MCP-клиент указывает на `${APP_URL}/mcp`.
### Чат с AI-агентом
@@ -89,9 +89,9 @@ real-time-коллаборации Docmost, поэтому запись нико
семантический поиск по страницам.
- **Доступ в интернет через внешние MCP.** Админ может подключить внешние MCP-серверы
(например, Tavily), чтобы дать агенту веб-поиск / доступ в интернет.
- **Своя модель.** Провайдер (OpenAI, Gemini или Ollama), модель и API-ключ настраиваются
в **Настройки воркспейса → AI & MCP → AI / Модели**. Ключ шифруется и никогда не покидает
сервер.
- **Своя модель.** OpenAI-совместимый эндпоинт — OpenAI, OpenRouter, локальный Ollama или
любой self-hosted-сервер — плюс модель и API-ключ настраиваются в
**Настройки воркспейса → AI**. Ключ шифруется и никогда не покидает сервер.
## Дорожная карта

View File

@@ -6,6 +6,7 @@ import Page from "@/pages/page/page";
import AccountSettings from "@/pages/settings/account/account-settings";
import WorkspaceMembers from "@/pages/settings/workspace/workspace-members";
import WorkspaceSettings from "@/pages/settings/workspace/workspace-settings";
import AiSettings from "@/pages/settings/workspace/ai-settings";
import Groups from "@/pages/settings/group/groups";
import GroupInfo from "./pages/settings/group/group-info";
import Spaces from "@/pages/settings/space/spaces.tsx";
@@ -71,6 +72,7 @@ export default function App() {
element={<AccountPreferences />}
/>
<Route path={"workspace"} element={<WorkspaceSettings />} />
<Route path={"ai"} element={<AiSettings />} />
<Route path={"members"} element={<WorkspaceMembers />} />
<Route path={"groups"} element={<Groups />} />
<Route path={"groups/:groupId"} element={<GroupInfo />} />

View File

@@ -9,6 +9,7 @@ import {
IconSpaces,
IconBrush,
IconWorld,
IconSparkles,
} from "@tabler/icons-react";
import { Link, useLocation } from "react-router-dom";
import classes from "./settings.module.css";
@@ -52,6 +53,7 @@ const groupedData: DataGroup[] = [
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" },

View File

@@ -17,6 +17,7 @@ const APP_ROUTE = {
},
WORKSPACE: {
GENERAL: "/settings/workspace",
AI: "/settings/ai",
MEMBERS: "/settings/members",
GROUPS: "/settings/groups",
SPACES: "/settings/spaces",

View File

@@ -0,0 +1,28 @@
import SettingsTitle from "@/components/settings/settings-title.tsx";
import McpSettings from "@/features/workspace/components/settings/components/mcp-settings.tsx";
import AiProviderSettings from "@/features/workspace/components/settings/components/ai-provider-settings.tsx";
import { useTranslation } from "react-i18next";
import { getAppName } from "@/lib/config.ts";
import { Helmet } from "react-helmet-async";
import { Divider } from "@mantine/core";
import useUserRole from "@/hooks/use-user-role.tsx";
export default function AiSettings() {
const { t } = useTranslation();
const { isAdmin } = useUserRole();
return (
<>
<Helmet>
<title>
{t("AI")} - {getAppName()}
</title>
</Helmet>
<SettingsTitle title={t("AI")} />
{isAdmin && <AiProviderSettings />}
<Divider my="lg" />
<McpSettings />
</>
);
}

View File

@@ -1,17 +1,12 @@
import SettingsTitle from "@/components/settings/settings-title.tsx";
import WorkspaceNameForm from "@/features/workspace/components/settings/components/workspace-name-form";
import WorkspaceIcon from "@/features/workspace/components/settings/components/workspace-icon.tsx";
import McpSettings from "@/features/workspace/components/settings/components/mcp-settings.tsx";
import AiProviderSettings from "@/features/workspace/components/settings/components/ai-provider-settings.tsx";
import { useTranslation } from "react-i18next";
import { getAppName } from "@/lib/config.ts";
import { Helmet } from "react-helmet-async";
import { Divider } from "@mantine/core";
import useUserRole from "@/hooks/use-user-role.tsx";
export default function WorkspaceSettings() {
const { t } = useTranslation();
const { isAdmin } = useUserRole();
return (
<>
<Helmet>
@@ -20,15 +15,6 @@ export default function WorkspaceSettings() {
<SettingsTitle title={t("General")} />
<WorkspaceIcon />
<WorkspaceNameForm />
<Divider my="lg" />
<SettingsTitle title={t("AI")} />
{isAdmin && <AiProviderSettings />}
<Divider my="lg" />
<McpSettings />
</>
);
}