- /console/settings#<section>[/<anchor>]; legacy ?tab= redirected in clientLoader - SETTINGS_SECTIONS in contracts with field-ownership test - Agent section: upstream list, create wizard (provider -> credentials/model -> login/test/default), edit drawer with OAuth browser/device login, test, set default, delete - sites section with site registration, snapshot/rate-limit drawer and account credentials - path mappings moved into downloader / media-server drawers; metadata and account sections Co-Authored-By: Claude Opus 5.5 <[email protected]>
38 lines
2.1 KiB
TypeScript
38 lines
2.1 KiB
TypeScript
import { SETTINGS_SECTIONS, type SettingsSectionDef, type SettingsSectionId } from "@umt/contracts";
|
|
import { Bot, FolderTree, KeyRound, type LucideIcon, Server, Shield, Tags, Tv, UserCog, Zap } from "lucide-react";
|
|
import type { ReactNode } from "react";
|
|
import { AccountSection } from "./account.tsx";
|
|
import { AgentSection } from "./agent.tsx";
|
|
import { ApiKeysSection } from "./api-keys.tsx";
|
|
import { AutomationSection } from "./automation.tsx";
|
|
import { DownloadersSection, MediaServersSection } from "./instances.tsx";
|
|
import { LibrarySection } from "./library.tsx";
|
|
import { MetadataSection } from "./metadata.tsx";
|
|
import { SitesSection } from "./sites.tsx";
|
|
|
|
// 设置分区:文案与字段归属在 contracts 的 SETTINGS_SECTIONS,这里只挂图标与渲染
|
|
|
|
const UI: Record<SettingsSectionId, { icon: LucideIcon; render: () => ReactNode }> = {
|
|
automation: { icon: Zap, render: () => <AutomationSection /> },
|
|
sites: { icon: UserCog, render: () => <SitesSection /> },
|
|
downloaders: { icon: Server, render: () => <DownloadersSection /> },
|
|
library: { icon: FolderTree, render: () => <LibrarySection /> },
|
|
"media-servers": { icon: Tv, render: () => <MediaServersSection /> },
|
|
metadata: { icon: Tags, render: () => <MetadataSection /> },
|
|
agent: { icon: Bot, render: () => <AgentSection /> },
|
|
"api-keys": { icon: KeyRound, render: () => <ApiKeysSection /> },
|
|
account: { icon: Shield, render: () => <AccountSection /> },
|
|
};
|
|
|
|
export type SectionView = SettingsSectionDef & { icon: LucideIcon; render: () => ReactNode };
|
|
export const SECTIONS: SectionView[] = SETTINGS_SECTIONS.map((s) => ({ ...s, ...UI[s.id] }));
|
|
|
|
/** URL hash:`#<分区>` 或 `#<分区>/<节>`;不认识的落到默认分区 */
|
|
export function parseSettingsHash(hash: string): { section: SectionView; anchor: string | null } {
|
|
const [id, anchor] = decodeURIComponent(hash.replace(/^#/, "")).split("/");
|
|
const section = SECTIONS.find((s) => s.id === id) ?? (SECTIONS[0] as SectionView);
|
|
return { section, anchor: section.id === id && anchor ? anchor : null };
|
|
}
|
|
|
|
export const settingsHash = (section: string, anchor?: string | null) => `#${section}${anchor ? `/${anchor}` : ""}`;
|