feat(design-preview): упростить страницы — без технической строки источника, дублей и лишних KPI
Убрана строка «Получено… GET /api/…» из шапок страниц (свежесть в кнопке i), дублирующий баннер на «Пользователях», KPI на «Приложениях». Контент ограничен шириной 1480px. Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
This commit is contained in:
1 parent
f486b72884
commit
5de88e18c8
9 files changed
+3
-42
No files matched your search
@@ -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>
|
||||
|
||||
Reference in new issue
Block a user