feat: consolidate AI settings into one page with tabs
- New SettingsAI page with 3 tabs: KI Assistent, Proaktive KI, MCP - Remove individual AI/proactive/mcp from settings nav - Settings nav now 6 items: Stammdaten, Nutzerverwaltung, System, Mail, KI Einstellungen, Benachrichtigungen
This commit is contained in:
@@ -19,10 +19,8 @@ export function SettingsPage() {
|
|||||||
{ to: '/settings/user-management', label: 'Nutzerverwaltung', icon: '\ud83d\udc65' },
|
{ to: '/settings/user-management', label: 'Nutzerverwaltung', icon: '\ud83d\udc65' },
|
||||||
{ to: '/settings/system', label: 'System', icon: '\u2699\ufe0f' },
|
{ to: '/settings/system', label: 'System', icon: '\u2699\ufe0f' },
|
||||||
{ to: '/settings/mail', label: t('mail.settings'), icon: '\ud83d\udce7' },
|
{ to: '/settings/mail', label: t('mail.settings'), icon: '\ud83d\udce7' },
|
||||||
{ to: '/settings/ai', label: t('nav.aiAssistant'), icon: '\ud83e\udde0' },
|
{ to: '/settings/ai-settings', label: 'KI Einstellungen', icon: '\ud83e\udde0' },
|
||||||
{ to: '/settings/ai-proactive', label: 'Proaktive KI', icon: '\ud83e\udd16' },
|
|
||||||
{ to: '/settings/notifications', label: t('settings.notifications'), icon: '\ud83d\udd14' },
|
{ to: '/settings/notifications', label: t('settings.notifications'), icon: '\ud83d\udd14' },
|
||||||
{ to: '/settings/mcp', label: t('settings.mcp', 'MCP'), icon: '\ud83d\udd27' },
|
|
||||||
];
|
];
|
||||||
|
|
||||||
const existingPaths = new Set(hardcodedNavItems.map(item => item.to));
|
const existingPaths = new Set(hardcodedNavItems.map(item => item.to));
|
||||||
|
|||||||
@@ -0,0 +1,46 @@
|
|||||||
|
import React, { useState } from 'react';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
import { AISettingsPage } from './AISettings';
|
||||||
|
import { ProactiveAISettings } from './ProactiveAISettings';
|
||||||
|
import { SettingsMcpPage } from './SettingsMcp';
|
||||||
|
|
||||||
|
export function SettingsAIPage() {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
const [activeTab, setActiveTab] = useState<'assistant' | 'proactive' | 'mcp'>('assistant');
|
||||||
|
|
||||||
|
const tabs = [
|
||||||
|
{ key: 'assistant' as const, label: t('nav.aiAssistant', 'KI Assistent') },
|
||||||
|
{ key: 'proactive' as const, label: t('settings.aiProactive', 'Proaktive KI') },
|
||||||
|
{ key: 'mcp' as const, label: t('settings.mcp', 'MCP') },
|
||||||
|
];
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div data-testid="settings-ai-page">
|
||||||
|
<h1 className="text-2xl font-bold text-secondary-900 mb-6">{t('settings.aiTitle', 'KI Einstellungen')}</h1>
|
||||||
|
<div className="border-b border-secondary-200 mb-6">
|
||||||
|
<nav className="flex gap-1" role="tablist">
|
||||||
|
{tabs.map((tab) => (
|
||||||
|
<button
|
||||||
|
key={tab.key}
|
||||||
|
onClick={() => setActiveTab(tab.key)}
|
||||||
|
className={`px-4 py-2 text-sm font-medium border-b-2 transition-colors ${
|
||||||
|
activeTab === tab.key
|
||||||
|
? 'border-primary-600 text-primary-600'
|
||||||
|
: 'border-transparent text-secondary-500 hover:text-secondary-700 hover:border-secondary-300'
|
||||||
|
}`}
|
||||||
|
role="tab"
|
||||||
|
aria-selected={activeTab === tab.key}
|
||||||
|
>
|
||||||
|
{tab.label}
|
||||||
|
</button>
|
||||||
|
))}
|
||||||
|
</nav>
|
||||||
|
</div>
|
||||||
|
<div className="mt-4">
|
||||||
|
{activeTab === 'assistant' && <AISettingsPage />}
|
||||||
|
{activeTab === 'proactive' && <ProactiveAISettings />}
|
||||||
|
{activeTab === 'mcp' && <SettingsMcpPage />}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -36,6 +36,7 @@ const AISettingsPage = React.lazy(() => import('@/pages/AISettings').then(m => (
|
|||||||
const ProactiveAISettings = React.lazy(() => import('@/pages/ProactiveAISettings').then(m => ({ default: m.ProactiveAISettings })));
|
const ProactiveAISettings = React.lazy(() => import('@/pages/ProactiveAISettings').then(m => ({ default: m.ProactiveAISettings })));
|
||||||
const SettingsThemePage = React.lazy(() => import('@/pages/SettingsTheme').then(m => ({ default: m.SettingsThemePage })));
|
const SettingsThemePage = React.lazy(() => import('@/pages/SettingsTheme').then(m => ({ default: m.SettingsThemePage })));
|
||||||
const SettingsMcpPage = React.lazy(() => import('@/pages/SettingsMcp').then(m => ({ default: m.SettingsMcpPage })));
|
const SettingsMcpPage = React.lazy(() => import('@/pages/SettingsMcp').then(m => ({ default: m.SettingsMcpPage })));
|
||||||
|
const SettingsAIPage = React.lazy(() => import('@/pages/SettingsAI').then(m => ({ default: m.SettingsAIPage })));
|
||||||
const SettingsMenuOrderPage = React.lazy(() => import('@/pages/SettingsMenuOrder').then(m => ({ default: m.SettingsMenuOrderPage })));
|
const SettingsMenuOrderPage = React.lazy(() => import('@/pages/SettingsMenuOrder').then(m => ({ default: m.SettingsMenuOrderPage })));
|
||||||
const SettingsStammdatenPage = React.lazy(() => import('@/pages/SettingsStammdaten').then(m => ({ default: m.SettingsStammdatenPage })));
|
const SettingsStammdatenPage = React.lazy(() => import('@/pages/SettingsStammdaten').then(m => ({ default: m.SettingsStammdatenPage })));
|
||||||
const SettingsUserManagementPage = React.lazy(() => import('@/pages/SettingsUserManagement').then(m => ({ default: m.SettingsUserManagementPage })));
|
const SettingsUserManagementPage = React.lazy(() => import('@/pages/SettingsUserManagement').then(m => ({ default: m.SettingsUserManagementPage })));
|
||||||
@@ -118,6 +119,7 @@ const router = createBrowserRouter([
|
|||||||
{ path: 'theme', element: withSuspense(<SettingsThemePage />) },
|
{ path: 'theme', element: withSuspense(<SettingsThemePage />) },
|
||||||
{ path: 'automation', element: withSuspense(<AutomationSettingsPage />) },
|
{ path: 'automation', element: withSuspense(<AutomationSettingsPage />) },
|
||||||
{ path: 'mcp', element: withSuspense(<SettingsMcpPage />) },
|
{ path: 'mcp', element: withSuspense(<SettingsMcpPage />) },
|
||||||
|
{ path: 'ai-settings', element: withSuspense(<SettingsAIPage />) },
|
||||||
{ path: 'menu', element: withSuspense(<SettingsMenuOrderPage />) },
|
{ path: 'menu', element: withSuspense(<SettingsMenuOrderPage />) },
|
||||||
{ path: '*', element: <PluginRouteRenderer /> },
|
{ path: '*', element: <PluginRouteRenderer /> },
|
||||||
],
|
],
|
||||||
|
|||||||
Reference in New Issue
Block a user