Files
amania-jailbreak cfe5bfb788 feat: 設定画面を実装
Workspace・認証モード・保存容量・配布上限・API情報を一覧表示する
設定画面を追加した。OIDCモードではログインユーザー表示とログアウト
ボタンを表示し、demoモードではアカウント情報を固定表示する。
- settings用のグリッド/行/バッジ/クォータスタイルをglobals.cssに追加
- AdminShellの未使用変数警告を解消
2026-08-05 16:27:29 +09:00

87 lines
5.9 KiB
TypeScript

"use client";
import { useEffect, useState } from "react";
import { BookOpen, Database, HardDrive, KeyRound, LogOut, Server, ShieldCheck, SlidersHorizontal, User, Workflow } from "lucide-react";
import { API_BASE, AUTH_MODE, formatBytes } from "@/app/lib/dashboard";
import { useDashboard } from "@/components/altdock/dashboard-provider";
import { Button } from "@/components/ui/button";
import type { Identity } from "@/packages/core/src/index";
function SettingRow({ icon: Icon, label, value, hint }: { icon: typeof User; label: string; value: React.ReactNode; hint?: string }) {
return <div className="settings-row"><span className="settings-row-icon"><Icon size={16} strokeWidth={1.8} /></span><div className="settings-row-copy"><span>{label}</span><strong>{value}</strong>{hint && <small>{hint}</small>}</div></div>;
}
function Section({ title, description, children }: { title: string; description: string; children: React.ReactNode }) {
return <section className="admin-section-card settings-section"><div className="admin-section-card-header"><div><h2>{title}</h2><p>{description}</p></div></div>{children}</section>;
}
export default function SettingsPage() {
const { dashboard } = useDashboard();
const [identity, setIdentity] = useState<Identity | null>(null);
useEffect(() => {
if (AUTH_MODE !== "oidc") return;
let cancelled = false;
fetch(`${API_BASE}/api/v1/me`, { credentials: "include" })
.then((response) => response.ok ? response.json() : null)
.then((body) => { if (!cancelled && body?.identity) setIdentity(body.identity as Identity); })
.catch(() => {});
return () => { cancelled = true; };
}, []);
const storagePercent = dashboard ? Math.min(100, (dashboard.usage.storageBytes / Math.max(1, dashboard.limits.maxStorageBytes)) * 100) : 0;
return <>
<div className="admin-page-heading"><div><div className="admin-eyebrow">WORKSPACE SETTINGS</div><h1>設定</h1><p>Workspace・認証・配布上限の状態を確認できます。</p></div></div>
<div className="settings-grid">
<Section title="Workspace" description="AltDock上の配布単位となるWorkspace情報です。">
<div className="settings-rows">
<SettingRow icon={Workflow} label="Workspace名" value={dashboard?.workspace.name || "—"} />
<SettingRow icon={SlidersHorizontal} label="Workspace slug" value={<code>{dashboard?.workspace.slug || "—"}</code>} />
<SettingRow icon={User} label="ログインユーザー" value={AUTH_MODE === "oidc" ? (identity?.displayName || "—") : "Demo Developer"} hint={AUTH_MODE === "oidc" ? identity?.email : "demo@altdock.local"} />
</div>
</Section>
<Section title="認証" description="このAPIに接続している認証モードです。">
<div className="settings-rows">
<SettingRow icon={ShieldCheck} label="認証モード" value={AUTH_MODE === "oidc" ? <span className="settings-badge settings-badge-ok">OIDC SSO</span> : <span className="settings-badge">Demo mode</span>} hint={AUTH_MODE === "oidc" ? "汎用OIDCプロバイダでログインしています" : "開発用の簡易認証です。本番ではOIDCを推奨します"} />
{AUTH_MODE === "oidc" && <SettingRow icon={KeyRound} label="SSOセッション" value={identity ? <span className="settings-badge settings-badge-ok">ログイン中</span> : <span className="settings-badge">セッション確認中…</span>} />}
</div>
</Section>
<Section title="保存容量" description="Workspaceで使用しているストレージの割合です。">
<div className="settings-quota">
<div className="settings-quota-top"><span>{formatBytes(dashboard?.usage.storageBytes || 0)} / {formatBytes(dashboard?.limits.maxStorageBytes || 0)}</span><strong>{storagePercent.toFixed(1)}%</strong></div>
<div className="admin-progress"><span style={{ width: `${storagePercent}%` }} /></div>
<small>ADP ZIP本体と公開済みアセットの合計サイズ</small>
</div>
</Section>
<Section title="配布上限" description="環境変数で変更できる制限値です。">
<div className="settings-rows">
<SettingRow icon={HardDrive} label="ADP ZIP 1件の上限" value={formatBytes(dashboard?.limits.maxUploadBytes || 0)} />
<SettingRow icon={Database} label="WorkspaceあたりのSource数" value={dashboard?.limits.maxSources || "—"} />
<SettingRow icon={Workflow} label="Sourceあたりのアプリ数" value={dashboard?.limits.maxAppsPerSource || "—"} />
</div>
</Section>
<Section title="API" description="フロントエンドが利用しているAPIエンドポイントです。">
<div className="settings-rows">
<SettingRow icon={Server} label="API Base URL" value={<code>{API_BASE}</code>} />
<SettingRow icon={Server} label="ヘルスチェック" value={<a className="admin-link" href={`${API_BASE}/healthz`} target="_blank" rel="noreferrer">/healthz を開く</a>} />
<SettingRow icon={Server} label="バージョン" value={<a className="admin-link" href={`${API_BASE}/version`} target="_blank" rel="noreferrer">/version を開く</a>} />
</div>
</Section>
</div>
<section className="admin-section-card settings-footer">
<div><ShieldCheck size={17} /><span><strong>AltDock 管理画面</strong><small>Source・アプリ・リリースは左のナビゲーションから操作できます。</small></span></div>
<div className="settings-footer-actions">
<Button variant="outline" size="sm" onClick={() => window.open("https://faq.altstore.io/developers/distribute-with-altstore-pal", "_blank")}><BookOpen size={14} />PALドキュメント</Button>
{AUTH_MODE === "oidc" && <Button variant="ghost" size="sm" onClick={() => { window.location.href = `${API_BASE}/auth/logout`; }}><LogOut size={14} />ログアウト</Button>}
</div>
</section>
</>;
}