Files
smart-org/apps/web/src/app/(app)/admin/layout.tsx
T
mjalmoudy94 3d1e98f4fb افزودن ارائه‌دهندهٔ agy (Google Antigravity) با لاگین headless و پول چرخشی اکانت
- Adapter اکانت‌محور با چرخش round-robin و بنچ‌شدن خودکار روی ۴۲۹/۴۰۱
- ورود ادمین از طریق URL بازگشتی گوگل (PKCE) و ذخیرهٔ رمزنگاری‌شدهٔ refresh token
- صفحهٔ مدیریت اکانت‌های agy در پنل ادمین به همراه تست و فعال/غیرفعال‌سازی
- مهاجرت Alembic b1c2d3e4f5a6 برای ستون‌های اکانت agy
- seed همیشه کاتالوگ agy را می‌سازد و فقط با AI_DEFAULT_PROVIDER=agy مسیریابی می‌شود
2026-10-13 08:20:27 +03:30

72 lines
2.3 KiB
TypeScript

"use client";
import Link from "next/link";
import { usePathname } from "next/navigation";
import * as React from "react";
import { EmptyState, LoadingState } from "@agy/ui";
import { useSession } from "@/lib/session";
/**
* Guard + chrome for the platform-owner console.
*
* The API enforces ownership on every endpoint; this layout only avoids
* rendering a console that would 401 on every request. It is a convenience,
* never the security boundary.
*/
const SECTIONS = [
{ href: "/admin", label: "نمای کلی" },
{ href: "/admin/agy-accounts", label: "اکانت‌های agy" },
{ href: "/admin/providers", label: "ارائه‌دهنده‌ها" },
{ href: "/admin/models", label: "مدل‌ها" },
{ href: "/admin/routing", label: "مسیریابی" },
{ href: "/admin/rate-cards", label: "تعرفه‌ها" },
{ href: "/admin/usage", label: "مصرف سراسری" },
{ href: "/admin/organizations", label: "سازمان‌ها" },
{ href: "/admin/errors", label: "کنسول خطا" },
] as const;
export default function AdminLayout({ children }: { children: React.ReactNode }) {
const { user, ready } = useSession();
const pathname = usePathname();
if (!ready) return <LoadingState label="در حال بررسی دسترسی…" />;
if (!user?.is_platform_owner) {
return (
<EmptyState
title="دسترسی محدود"
description="این بخش فقط برای مالک سامانه قابل دسترسی است."
/>
);
}
return (
<div className="anim-stagger flex flex-col gap-5">
<nav className="flex flex-wrap gap-1 border-b border-surface-border">
{SECTIONS.map((section) => {
const active =
section.href === "/admin"
? pathname === "/admin"
: pathname.startsWith(section.href);
return (
<Link
key={section.href}
href={section.href}
className={
"border-b-2 px-3 py-2 text-sm transition-colors " +
(active
? "border-accent text-slate-100"
: "border-transparent text-slate-400 hover:text-slate-200")
}
>
{section.label}
</Link>
);
})}
</nav>
{children}
</div>
);
}