SettingsSection now carries titleKey/descriptionKey instead of title/description, and the sidebar and content pane resolve them. The section arrays are module-level consts holding JSX content, so they cannot call a hook — the data holds keys and the renderers translate. Sidebar search matches the RESOLVED words, so it works in the language on screen. Capital K in titleKey is load-bearing: docs-check-settings.ts greps key:\s*'…' for route segments, and a lowercase title_key would have fed it twenty bogus paths. Verified 0 bogus, 26 declared, 20 offered, 0 missing. Section titles now share one key with the Spotlight rows that name the same section, per 'one key per meaning'. Two casings had to converge, so Settings shows Spotlight's: 'Change Password' now reads 'Change password'. Settings sidebar search placeholder was 'Search...'; it is now 'Search settings…', which is what the skeleton catalog already said and what distinguishes it from the global Spotlight.
111 lines
3.5 KiB
TypeScript
111 lines
3.5 KiB
TypeScript
import { useMemo } from 'react';
|
|
import { Bot, Hammer, Mail, Mic, ScanText, Settings, Volume2 } from 'lucide-react';
|
|
import type { LayoutNode, PanelComponents } from 'officerdev';
|
|
import { WorkspaceLayout } from 'officerdev';
|
|
|
|
import { SettingsRoute, createSettingsPanelComponents, type SettingsSectionGroup } from './SettingsPanel';
|
|
import { SMTPSection } from './ServerSettings/SMTPSection';
|
|
import { MaintenanceSection } from './ServerSettings/MaintenanceSection';
|
|
import { TTSSection } from './ServerSettings/TTSSection';
|
|
import { STTSection } from './ServerSettings/STTSection';
|
|
import { OCRSection } from './ServerSettings/OCRSection';
|
|
|
|
const groups: SettingsSectionGroup[] = [
|
|
{
|
|
labelKey: 'settings.groups.ai',
|
|
icon: Bot,
|
|
sections: [
|
|
{
|
|
key: 'tts',
|
|
icon: Volume2,
|
|
titleKey: 'settings.sections.tts.label',
|
|
descriptionKey: 'settings.sections.tts.description',
|
|
content: <TTSSection />,
|
|
},
|
|
{
|
|
key: 'stt',
|
|
icon: Mic,
|
|
titleKey: 'settings.sections.stt.label',
|
|
descriptionKey: 'settings.sections.stt.description',
|
|
content: <STTSection />,
|
|
},
|
|
{
|
|
key: 'ocr',
|
|
icon: ScanText,
|
|
titleKey: 'settings.sections.ocr.label',
|
|
descriptionKey: 'settings.sections.ocr.description',
|
|
content: <OCRSection />,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
labelKey: 'settings.groups.maintenance',
|
|
icon: Hammer,
|
|
sections: [
|
|
{
|
|
key: 'maintenance',
|
|
icon: Hammer,
|
|
titleKey: 'settings.sections.maintenance.label',
|
|
descriptionKey: 'settings.sections.maintenance.description',
|
|
content: <MaintenanceSection />,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
labelKey: 'settings.groups.email',
|
|
icon: Mail,
|
|
sections: [
|
|
{
|
|
key: 'smtp',
|
|
icon: Mail,
|
|
titleKey: 'settings.sections.smtp.label',
|
|
descriptionKey: 'settings.sections.smtp.description',
|
|
content: <SMTPSection />,
|
|
},
|
|
],
|
|
},
|
|
];
|
|
|
|
const BASE_PATH = '/settings/system';
|
|
|
|
const { Sidebar, Content, allSections } = createSettingsPanelComponents({
|
|
basePath: BASE_PATH,
|
|
sidebarIcon: Settings,
|
|
sidebarLabelKey: 'settings.nav.system',
|
|
groups,
|
|
});
|
|
|
|
// There used to be a second layout here that split a terminal in below the settings content, driven by a
|
|
// `system-settings:run-command` channel: a section asked for a sudo command, this screen grew a pane, ran
|
|
// it, and invalidated the queries the section named. Its only writer was the AI harness installer, and
|
|
// that moved server-side to `POST /server-settings/chat-providers/install` — leaving a channel whose two
|
|
// remaining writes were both `setState(null)`, a pane nothing could ever open, and a layout nothing could
|
|
// ever select. Removed rather than rewired; the install path it existed for no longer wants a terminal.
|
|
const baseLayout: LayoutNode = {
|
|
type: 'group',
|
|
id: 'system-root',
|
|
direction: 'horizontal',
|
|
children: [
|
|
{ node: { type: 'panel', id: 'system-left', appType: null }, size: 20 },
|
|
{ node: { type: 'panel', id: 'system-right', appType: null }, size: 80 },
|
|
],
|
|
};
|
|
|
|
export const SystemSettings = () => {
|
|
const panelComponents: PanelComponents = useMemo(
|
|
() => ({
|
|
'system-left': Sidebar,
|
|
'system-right': Content,
|
|
}),
|
|
[],
|
|
);
|
|
|
|
return (
|
|
<SettingsRoute basePath={BASE_PATH} sections={allSections}>
|
|
<div className="h-full w-full pt-2">
|
|
<WorkspaceLayout layout={baseLayout} onLayoutChange={() => {}} components={panelComponents} />
|
|
</div>
|
|
</SettingsRoute>
|
|
);
|
|
};
|