feat(design-preview): упростить страницы — без технической строки источника, дублей и лишних KPI

Убрана строка «Получено… GET /api/…» из шапок страниц (свежесть в кнопке i), дублирующий
баннер на «Пользователях», KPI на «Приложениях». Контент ограничен шириной 1480px.

Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
This commit is contained in:
DenozordecandClaude Sonnet 5.5 committed 2026-10-18 01:35:17 +07:00
1 parent f486b72884
commit 5de88e18c8
9 files changed
+3 -42

No files matched your search

-9
View File
@@ -52,12 +52,10 @@ export function StatusBadge({ tone, children }: { tone: Tone; children: ReactNod
export function PageHead({
title,
sub,
source,
actions,
}: {
title: string
sub: string
source: string
actions?: ReactNode
}) {
return (
@@ -65,13 +63,6 @@ export function PageHead({
<div className="flex min-w-0 flex-col gap-1">
<h1 className="text-2xl font-semibold tracking-tight text-balance">{title}</h1>
<p className="text-muted-foreground max-w-prose text-sm text-pretty">{sub}</p>
<p
role="status"
className="text-muted-foreground flex flex-wrap items-center gap-1.5 text-xs"
>
<span className="bg-success size-1.5 rounded-full" aria-hidden />
<span>Получено 14:02:11 · {source}</span>
</p>
</div>
{actions ? <div className="flex flex-wrap items-center gap-2">{actions}</div> : null}
</header>
@@ -110,7 +110,6 @@ export function AppLinksPage() {
<PageHead
title="Ссылки приложений"
sub="Каталог приложений и переключатель в шапке · общий для всех сервисов семейства"
source="portal_settings.app_switcher_json · публичный GET /api/v1/app-switcher"
actions={
<Button variant="outline" onClick={() => toast('Добавление приложения недоступно в макете', { description: 'Каталог фиксирован контрактом: cfdm · vps · bgp · fw · dns · cdn · mm.' })}>
<PlusIcon aria-hidden />
@@ -1,13 +1,11 @@
import { Link } from '@tanstack/react-router'
import { CloudIcon, GlobeIcon, LayoutDashboardIcon, ServerIcon, ShieldIcon, LayoutGridIcon, KeyRoundIcon, FingerprintIcon, ShieldCheckIcon } from 'lucide-react'
import { CloudIcon, GlobeIcon, LayoutDashboardIcon, ServerIcon, ShieldIcon } from 'lucide-react'
import { toast } from 'sonner'
import { APPS, type AppId } from '@authportal/shared'
import { KpiStatGrid } from '@/components/reui-kit/kpi-stat-grid'
import { QuickActionGrid } from '@/components/reui-kit/quick-action-grid'
import { Button } from '@authportal/ui/components/button'
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@authportal/ui/components/tabs'
import { PageHead } from '../bits'
import { kpi } from '../kpi'
const ICONS: Record<AppId, typeof CloudIcon> = {
cfdm: CloudIcon,
@@ -30,22 +28,12 @@ export function AppsPage() {
<PageHead
title="Приложения"
sub="Открыть приложение с текущей сессией · SSO handoff без повторного ввода пароля"
source="сессия действует до 22:02 · права из базы портала, не из токена"
actions={
<Button variant="outline" size="sm" render={<Link to="/design-preview/app-links" />} nativeButton={false}>
Ссылки приложений
</Button>
}
/>
<KpiStatGrid
aria-label="Показатели"
items={[
kpi('avail', 'Доступно приложений', String(allowed.length), { icon: LayoutGridIcon, tone: 'ok', badge: 'доступ есть', sub: `из ${APPS.length}` }),
kpi('jwt', 'JWT SSO', String(allowed.filter((a) => a.authMode === 'jwt').length), { icon: KeyRoundIcon, tone: 'in', badge: 'fragment-токен', sub: 'вход без пароля' }),
kpi('oidc', 'OIDC', String(allowed.filter((a) => a.authMode === 'oidc').length), { icon: FingerprintIcon, tone: 'in', badge: 'Technitium DNS', sub: 'внешний RP' }),
kpi('role', 'Роль', 'Админ', { icon: ShieldCheckIcon, tone: 'wn', badge: 'is_admin', sub: 'полный доступ' }),
]}
/>
<Tabs defaultValue="all" className="min-w-0">
<TabsList>
<TabsTrigger value="all">Доступные · {allowed.length}</TabsTrigger>
@@ -72,7 +72,6 @@ export function AuditPage() {
<PageHead
title="Изменения"
sub="Журнал действий администраторов и приложений · портал, EvoFirewall, EvoBGP, MikrotikManager и другие через ingest"
source="GET /api/v1/admin/audit?kind=changes · ingest от 5 приложений"
actions={
<>
<Button variant="outline" onClick={() => toast.success('CSV сформирован (макет)')}>
@@ -65,7 +65,6 @@ export function LoginsPage() {
<PageHead
title="Входы"
sub="Журнал входов и активные сессии · портал и SSO в приложения"
source="GET /api/v1/admin/audit?kind=logins · хранение 90 дней"
actions={
<Button variant="outline" onClick={() => toast.success('CSV сформирован (макет)')}>
<DownloadIcon aria-hidden />
@@ -98,7 +98,6 @@ export function OidcPage() {
<PageHead
title="OIDC-клиенты"
sub="Портал как провайдер OpenID Connect · внешние приложения входят через auth.shnt.top"
source="discovery и JWKS доступны · подпись RS256"
actions={
<Button onClick={() => setCreateOpen(true)}>
<PlusIcon aria-hidden />
@@ -37,7 +37,6 @@ export function SecurityPage() {
<PageHead
title="Безопасность"
sub="Passkey как альтернатива паролю · пароль остаётся запасным входом"
source="WebAuthn · домен auth.shnt.top"
actions={
<Button onClick={() => setAddOpen(true)}>
<PlusIcon aria-hidden />
@@ -1,6 +1,5 @@
import { UsersIcon, ShieldCheckIcon, FingerprintIcon, UserXIcon } from 'lucide-react'
import { useCallback, useEffect, useRef, useState } from 'react'
import { Link } from '@tanstack/react-router'
import { toast } from 'sonner'
import type { AdminUser, CreateUserRequest } from '@authportal/shared'
import { CreateUserSheet } from '@/components/reui-kit/create-user-sheet'
@@ -10,7 +9,7 @@ import { Tabs, TabsContent, TabsList, TabsTrigger } from '@authportal/ui/compone
import { UserPlusIcon } from 'lucide-react'
import { AccessDialog } from '../access-dialog'
import { diffAccess, type AccessValue } from '../access-model'
import { CodeBlock, KvList, PageHead, PreviewSheet, SignalAlert, TypedConfirm } from '../bits'
import { CodeBlock, KvList, PageHead, PreviewSheet, TypedConfirm } from '../bits'
import { kpi } from '../kpi'
import { ALL_APP_IDS, APP_SHORT, MOCK_USERS, USER_JOURNAL, type Tone } from '../mock'
import { PreviewSectionGrid, TwoLineCell, type GridColumn } from '../section-grid'
@@ -121,7 +120,6 @@ export function UsersPage() {
<PageHead
title="Пользователи"
sub="Каталог учётных записей · роли, приложения, passkeys · изменения прав записываются в журнал"
source={`GET /api/v1/admin/users · ${users.length} учётных записей`}
actions={
<Button onClick={() => setCreateOpen(true)}>
<UserPlusIcon aria-hidden />
@@ -129,17 +127,6 @@ export function UsersPage() {
</Button>
}
/>
<SignalAlert
tone="er"
title="Подозрительная активность: [email protected]."
action={
<Button variant="outline" size="sm" render={<Link to="/design-preview/logins" />} nativeButton={false}>
Показать
</Button>
}
>
6 неудачных входов с 203.0.113.58 за 10 минут. Проверьте журнал входов и при необходимости отключите учётную запись.
</SignalAlert>
<KpiStatGrid
aria-label="Показатели"
items={[
@@ -41,7 +41,7 @@ export function PreviewShell({ children }: { children: ReactNode }) {
<PreviewSidebar />
<SidebarInset id="main-content" className="min-w-0">
<PreviewHeader />
<div className="flex min-w-0 flex-1 flex-col gap-4 px-4 py-4 pb-24 md:gap-6 md:px-6 md:py-5 md:pb-24">
<div className="mx-auto flex w-full min-w-0 max-w-[1480px] flex-1 flex-col gap-4 px-4 py-4 pb-24 md:gap-6 md:px-6 md:py-5 md:pb-24">
{children}
</div>
</SidebarInset>