diff --git a/app/dashboard/settings/page.tsx b/app/dashboard/settings/page.tsx index a8666c4..e90cbdd 100644 --- a/app/dashboard/settings/page.tsx +++ b/app/dashboard/settings/page.tsx @@ -1,7 +1,86 @@ -import Link from "next/link"; -import { ArrowUpRight, KeyRound, ShieldCheck, SlidersHorizontal } from "lucide-react"; +"use client"; -export default function SettingsPage() { - return <>
WORKSPACE SETTINGS

設定

認証と配布上限は環境設定で管理します。

設定画面は準備中です

SSO、ストレージ、アップロード上限は現在の環境変数と管理者設定で制御されています。

認証OIDC / demo mode
配布Workspace単位の認可
PALドキュメントを開く
; +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
{label}{value}{hint && {hint}}
; } +function Section({ title, description, children }: { title: string; description: string; children: React.ReactNode }) { + return

{title}

{description}

{children}
; +} + +export default function SettingsPage() { + const { dashboard } = useDashboard(); + const [identity, setIdentity] = useState(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 <> +
WORKSPACE SETTINGS

設定

Workspace・認証・配布上限の状態を確認できます。

+ +
+
+
+ + {dashboard?.workspace.slug || "—"}} /> + +
+
+ +
+
+ OIDC SSO : Demo mode} hint={AUTH_MODE === "oidc" ? "汎用OIDCプロバイダでログインしています" : "開発用の簡易認証です。本番ではOIDCを推奨します"} /> + {AUTH_MODE === "oidc" && ログイン中 : セッション確認中…} />} +
+
+ +
+
+
{formatBytes(dashboard?.usage.storageBytes || 0)} / {formatBytes(dashboard?.limits.maxStorageBytes || 0)}{storagePercent.toFixed(1)}%
+
+ ADP ZIP本体と公開済みアセットの合計サイズ +
+
+ +
+
+ + + +
+
+ +
+
+ {API_BASE}} /> + /healthz を開く} /> + /version を開く} /> +
+
+
+ +
+
AltDock 管理画面Source・アプリ・リリースは左のナビゲーションから操作できます。
+
+ + {AUTH_MODE === "oidc" && } +
+
+ ; +} diff --git a/app/globals.css b/app/globals.css index 06ac125..8dff989 100644 --- a/app/globals.css +++ b/app/globals.css @@ -92,6 +92,9 @@ button { cursor: pointer; } .admin-toast-viewport { position: fixed; z-index: 100; right: 18px; bottom: 18px; display: flex; width: 360px; max-width: calc(100vw - 36px); flex-direction: column; gap: 8px; outline: 0; }.admin-toast { position: relative; display: grid; grid-template-columns: 1fr auto; gap: 3px 12px; padding: 13px 14px; border: 1px solid var(--admin-line-strong); border-left: 3px solid var(--admin-green); border-radius: 7px; color: var(--admin-text); background: #fff; box-shadow: 0 10px 32px #17202c22; }.admin-toast.toast-error { border-left-color: var(--admin-red); }.admin-toast.toast-info { border-left-color: var(--admin-blue); }.admin-toast [data-radix-toast-title] { font-size: 11px; font-weight: 720; }.admin-toast [data-radix-toast-description] { color: var(--admin-muted); font-size: 10px; line-height: 1.45; }.admin-toast button { grid-column: 2; grid-row: 1 / span 2; align-self: center; border: 0; color: var(--admin-subtle); background: transparent; font-size: 16px; } .mobile-nav-dialog { top: 0; left: 0; width: min(290px, calc(100vw - 44px)); height: 100vh; max-height: none; padding: 0; border: 0; border-radius: 0 9px 9px 0; transform: none; }.mobile-nav-dialog .admin-sidebar-inner { padding: 16px 12px; }.mobile-nav-close { position: absolute; z-index: 2; top: 16px; right: 13px; display: inline-flex; width: 28px; height: 28px; align-items: center; justify-content: center; border: 0; border-radius: 5px; color: var(--admin-subtle); background: #f1f3f5; } .settings-placeholder { max-width: 620px; padding: 34px; text-align: center; }.settings-placeholder-icon { display: inline-flex; width: 42px; height: 42px; align-items: center; justify-content: center; border-radius: 8px; color: var(--admin-orange); background: #fff1ed; }.settings-placeholder h2 { margin: 14px 0 7px; color: var(--admin-text); font-size: 16px; }.settings-placeholder > p { max-width: 420px; margin: 0 auto 22px; color: var(--admin-muted); font-size: 11px; line-height: 1.6; }.settings-placeholder-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 9px; margin-bottom: 20px; }.settings-placeholder-grid > div { display: flex; align-items: center; gap: 8px; padding: 12px; border: 1px solid var(--admin-line); border-radius: 6px; text-align: left; }.settings-placeholder-grid svg { color: var(--admin-blue); }.settings-placeholder-grid strong, .settings-placeholder-grid span { display: block; }.settings-placeholder-grid strong { color: var(--admin-text); font-size: 10px; }.settings-placeholder-grid span { margin-top: 3px; color: var(--admin-subtle); font-size: 9px; } +.settings-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 15px; }.settings-section { margin-bottom: 0; }.settings-section .admin-section-card-header { padding-bottom: 11px; }.settings-rows { display: flex; flex-direction: column; padding: 0 19px 17px; }.settings-row { display: flex; align-items: center; gap: 11px; min-height: 44px; padding: 9px 0; border-top: 1px solid var(--admin-line); }.settings-row:first-child { border-top: 0; }.settings-row-icon { display: inline-flex; width: 28px; height: 28px; flex: 0 0 28px; align-items: center; justify-content: center; border-radius: 6px; color: var(--admin-muted); background: #f2f4f6; }.settings-row-icon svg { color: var(--admin-muted); }.settings-row-copy { min-width: 0; flex: 1; }.settings-row-copy span { display: block; color: var(--admin-subtle); font-size: 9px; font-weight: 700; letter-spacing: .05em; }.settings-row-copy strong { display: block; overflow: hidden; margin-top: 2px; color: var(--admin-text); font-size: 11px; font-weight: 620; text-overflow: ellipsis; white-space: nowrap; }.settings-row-copy code { color: var(--admin-muted); font-family: var(--font-geist-mono), monospace; font-size: 10px; }.settings-row-copy small { display: block; margin-top: 2px; color: var(--admin-subtle); font-size: 9px; }.settings-badge { display: inline-flex; align-items: center; min-height: 19px; padding: 0 8px; border: 1px solid var(--admin-line-strong); border-radius: 99px; color: var(--admin-muted); background: #f6f7f9; font-size: 9px; font-weight: 680; }.settings-badge-ok { border-color: #cfe5da; color: var(--admin-green); background: #edf7f2; }.settings-quota { padding: 2px 19px 18px; }.settings-quota-top { display: flex; align-items: baseline; justify-content: space-between; gap: 10px; margin-bottom: 9px; color: var(--admin-muted); font-size: 10px; }.settings-quota-top strong { color: var(--admin-text); font-family: var(--font-geist-mono), monospace; font-size: 13px; font-weight: 620; }.settings-quota small { display: block; margin-top: 8px; color: var(--admin-subtle); font-size: 9px; }.settings-footer { display: flex; align-items: center; justify-content: space-between; gap: 16px; padding: 15px 19px; }.settings-footer > div:first-child { display: flex; align-items: center; gap: 11px; }.settings-footer svg { color: var(--admin-orange); }.settings-footer strong, .settings-footer small { display: block; }.settings-footer strong { color: var(--admin-text); font-size: 11px; font-weight: 650; }.settings-footer small { margin-top: 2px; color: var(--admin-subtle); font-size: 9px; }.settings-footer-actions { display: flex; align-items: center; gap: 8px; } +@media (max-width: 880px) { .settings-grid { grid-template-columns: 1fr; } } +@media (max-width: 760px) { .settings-rows { padding-inline: 14px; }.settings-quota { padding-inline: 14px; }.settings-footer { align-items: start; flex-direction: column; } } @media (max-width: 1050px) { .admin-sidebar { width: 210px; flex-basis: 210px; }.admin-sidebar.is-collapsed { width: 64px; flex-basis: 64px; }.admin-collapse-toggle { left: 192px; }.admin-sidebar.is-collapsed ~ .admin-collapse-toggle { left: 50px; }.admin-metric-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }.admin-overview-grid { grid-template-columns: 1fr; }.admin-overview-grid .admin-section-card { margin-bottom: 0; }.admin-topbar { padding-inline: 24px; }.admin-content { padding-inline: 24px; } } @media (max-width: 760px) { .admin-sidebar, .admin-collapse-toggle { display: none; }.admin-topbar { height: 53px; padding: 0 15px; }.mobile-menu-button { display: inline-flex; margin-right: 5px; }.admin-topbar-actions { gap: 8px; }.admin-search-trigger { min-width: 31px; width: 31px; justify-content: center; padding: 0; }.admin-search-trigger span, .admin-search-trigger kbd, .admin-topbar-action span, .admin-auth-link { display: none; }.admin-topbar-action { width: 31px; height: 31px; justify-content: center; padding: 0; border: 1px solid var(--admin-line-strong); border-radius: 6px; }.admin-content { padding: 24px 15px 45px; }.admin-page-heading { align-items: start; flex-direction: column; gap: 15px; margin-bottom: 22px; }.admin-page-heading h1 { font-size: 24px; }.admin-page-actions { width: 100%; }.admin-page-actions .ui-button { flex: 1; }.admin-metric-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px; }.admin-metric-card { min-height: 102px; padding: 13px; }.admin-metric-card strong { margin-top: 13px; font-size: 21px; }.admin-section-card-header { padding-inline: 14px; }.health-list { grid-template-columns: repeat(2, 1fr); padding-inline: 14px; }.quota-summary { padding-inline: 14px; }.admin-table th, .admin-table td { padding-inline: 13px; }.admin-toolbar { flex-wrap: wrap; padding-inline: 13px; }.admin-search-field { min-width: 100%; max-width: none; }.admin-toolbar-note { margin-left: 0; }.admin-form-grid, .release-detail-grid, .json-summary-grid, .settings-placeholder-grid { grid-template-columns: 1fr; }.ui-dialog-content { width: min(100% - 22px, 520px); padding: 20px 17px; }.ui-dialog-content.wide-dialog { width: min(100% - 22px, 680px); }.admin-toast-viewport { right: 11px; bottom: 11px; max-width: calc(100vw - 22px); }.admin-toast { width: 100%; } } diff --git a/components/altdock/admin-shell.tsx b/components/altdock/admin-shell.tsx index 7bad128..6b31b09 100644 --- a/components/altdock/admin-shell.tsx +++ b/components/altdock/admin-shell.tsx @@ -86,7 +86,7 @@ export function AdminShell({ children }: PropsWithChildren) { const [mobileOpen, setMobileOpen] = useState(false); const [commandOpen, setCommandOpen] = useState(false); const pathname = usePathname(); - const { notice, dismissNotice, dashboard } = useDashboard(); + const { notice, dismissNotice } = useDashboard(); const { identity } = useIdentity(); useEffect(() => {