feat: improve admin experience and ignore local data

This commit is contained in:
2026-04-14 19:12:20 +08:00
parent 6378ab4994
commit 2e3eb4b8f8
10 changed files with 1132 additions and 119 deletions
+17 -59
View File
@@ -6,11 +6,8 @@ import {
listSubscriptionNodes,
} from "@/lib/store";
import {
deleteProxyGroupAction,
saveProxyGroupAction,
saveSubscriptionSettingsAction,
} from "./actions";
import { saveSubscriptionSettingsAction } from "./actions";
import { ProxyGroupEditor } from "./proxy-group-editor";
export default async function AdminSubscriptionsPage() {
const [settings, adminUser, nodes, origin] = await Promise.all([
@@ -19,6 +16,14 @@ export default async function AdminSubscriptionsPage() {
listSubscriptionNodes(),
getRequestOrigin(),
]);
const proxyGroupNodes = nodes.map((node) => ({
slug: node.slug,
label: node.client_name || node.name,
meta:
node.client_name && node.client_name !== node.name
? `${node.name} / ${node.slug}`
: node.slug,
}));
return (
<main className="page-stack">
@@ -62,65 +67,18 @@ export default async function AdminSubscriptionsPage() {
</section>
<section className="panel-card">
<div className="section-title">
<h3>Proxy Groups</h3>
<div className="section-title section-title--top">
<div className="stack-tight">
<h3>Proxy Groups</h3>
<p className="muted">已选列表从上到下的顺序,就是写入 Clash 配置时的节点顺序。</p>
</div>
</div>
<div className="stack-lg">
{settings.proxyGroups.map((group) => (
<article key={group.id} className="instruction-block">
<form action={saveProxyGroupAction} className="stack-md">
<input type="hidden" name="id" value={group.id} />
<label className="field">
<span>组名</span>
<input name="name" defaultValue={group.name} required />
</label>
<div className="checkbox-grid">
{nodes.map((node) => (
<label key={`${group.id}-${node.slug}`} className="checkbox">
<input
type="checkbox"
name="member_slugs"
value={node.slug}
defaultChecked={group.memberSlugs.includes(node.slug)}
/>
<span>{node.client_name || node.name}</span>
</label>
))}
</div>
<div className="action-row">
<button className="ghost-button" type="submit">
保存分组
</button>
</div>
</form>
<form action={deleteProxyGroupAction}>
<input type="hidden" name="id" value={group.id} />
<button className="danger-button" type="submit">
删除分组
</button>
</form>
</article>
<ProxyGroupEditor key={group.id} group={group} nodes={proxyGroupNodes} />
))}
<article className="instruction-block">
<form action={saveProxyGroupAction} className="stack-md">
<label className="field">
<span>新建分组名</span>
<input name="name" placeholder="ChatGPT" required />
</label>
<div className="checkbox-grid">
{nodes.map((node) => (
<label key={`new-${node.slug}`} className="checkbox">
<input type="checkbox" name="member_slugs" value={node.slug} />
<span>{node.client_name || node.name}</span>
</label>
))}
</div>
<button className="primary-button" type="submit">
新建分组
</button>
</form>
</article>
<ProxyGroupEditor key={`new-${settings.proxyGroups.length}`} nodes={proxyGroupNodes} />
</div>
</section>