feat(web): settings with 9 sidebar sections and Agent upstream management
- /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]>
This commit is contained in:
1 parent
459991421e
commit
c67f6a9682
25 files changed
+3842
-942
No files matched your search
@@ -0,0 +1,37 @@
|
||||
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}` : ""}`;
|
||||
Reference in new issue
Block a user