From 6898d2255d420afc638f82d2cfd2e8059af49ed3 Mon Sep 17 00:00:00 2001 From: Denozordec Date: Fri, 23 Oct 2026 13:53:59 +0700 Subject: [PATCH] =?UTF-8?q?refactor(web):=20=D0=B2=D1=8B=D0=BD=D0=B5=D1=81?= =?UTF-8?q?=D1=82=D0=B8=20=D0=BE=D0=B1=D1=89=D0=B8=D0=B5=20=D0=B1=D0=BB?= =?UTF-8?q?=D0=BE=D0=BA=D0=B8=20=D0=BC=D0=B0=D0=BA=D0=B5=D1=82=D0=B0=20?= =?UTF-8?q?=D0=B2=20components/portal?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Sonnet 5.5 --- .../portal}/bits.tsx | 4 ++-- .../portal}/canvas-blocks.tsx | 2 +- .../portal}/explain-banner.tsx | 6 +++--- .../portal}/kpi-strip.tsx | 0 .../portal}/kpi.tsx | 0 .../portal}/section-grid.tsx | 6 +++--- .../portal}/tone.ts | 6 +++++- apps/web/src/design-preview/access-editor.tsx | 2 +- apps/web/src/design-preview/access-matrix.tsx | 6 +++--- apps/web/src/design-preview/access-sheet.tsx | 6 +++--- apps/web/src/design-preview/create-sheets.tsx | 14 ++++++------- apps/web/src/design-preview/mock.ts | 3 ++- .../design-preview/pages/app-links-page.tsx | 16 +++++++-------- .../src/design-preview/pages/apps-page.tsx | 8 ++++---- .../src/design-preview/pages/audit-page.tsx | 16 +++++++-------- .../src/design-preview/pages/login-page.tsx | 2 +- .../src/design-preview/pages/logins-page.tsx | 18 ++++++++--------- .../src/design-preview/pages/oidc-page.tsx | 20 +++++++++---------- .../design-preview/pages/security-page.tsx | 20 +++++++++---------- .../src/design-preview/pages/users-page.tsx | 12 +++++------ .../web/src/design-preview/preview-chrome.tsx | 2 +- apps/web/src/design-preview/preview-store.ts | 3 ++- apps/web/src/design-preview/users-grid.tsx | 6 +++--- 23 files changed, 92 insertions(+), 86 deletions(-) rename apps/web/src/{design-preview => components/portal}/bits.tsx (99%) rename apps/web/src/{design-preview => components/portal}/canvas-blocks.tsx (99%) rename apps/web/src/{design-preview => components/portal}/explain-banner.tsx (96%) rename apps/web/src/{design-preview => components/portal}/kpi-strip.tsx (100%) rename apps/web/src/{design-preview => components/portal}/kpi.tsx (100%) rename apps/web/src/{design-preview => components/portal}/section-grid.tsx (99%) rename apps/web/src/{design-preview => components/portal}/tone.ts (71%) diff --git a/apps/web/src/design-preview/bits.tsx b/apps/web/src/components/portal/bits.tsx similarity index 99% rename from apps/web/src/design-preview/bits.tsx rename to apps/web/src/components/portal/bits.tsx index daa4fbf..0aafd38 100644 --- a/apps/web/src/design-preview/bits.tsx +++ b/apps/web/src/components/portal/bits.tsx @@ -33,7 +33,7 @@ import { SheetHeader, SheetTitle, } from '@authportal/ui/components/sheet' -import type { Tone } from './mock' +import type { Tone } from './tone' import { TONE_BADGE } from './tone' const TONE_GLYPH: Record = { ok: '●', wn: '▲', er: '✕', mu: '○', in: '' } @@ -104,7 +104,7 @@ export function SignalAlert({ } /** Боковое окно (как CreateUserSheet): заголовок, прокручиваемое тело, подвал. */ -export function PreviewSheet({ +export function PortalSheet({ open, onOpenChange, title, diff --git a/apps/web/src/design-preview/canvas-blocks.tsx b/apps/web/src/components/portal/canvas-blocks.tsx similarity index 99% rename from apps/web/src/design-preview/canvas-blocks.tsx rename to apps/web/src/components/portal/canvas-blocks.tsx index 83c13e8..9933f1c 100644 --- a/apps/web/src/design-preview/canvas-blocks.tsx +++ b/apps/web/src/components/portal/canvas-blocks.tsx @@ -3,7 +3,7 @@ import { Badge } from '@/components/reui/badge' import { Frame, FrameDescription, FrameHeader, FramePanel, FrameTitle } from '@/components/reui/frame' import { IconTile } from '@/components/reui/icon-tile' import { cn } from '@authportal/ui/lib/utils' -import type { Tone } from './mock' +import type { Tone } from './tone' import { StatusBadge } from './bits' export type AppCardItem = { diff --git a/apps/web/src/design-preview/explain-banner.tsx b/apps/web/src/components/portal/explain-banner.tsx similarity index 96% rename from apps/web/src/design-preview/explain-banner.tsx rename to apps/web/src/components/portal/explain-banner.tsx index a6ddc68..01307d5 100644 --- a/apps/web/src/design-preview/explain-banner.tsx +++ b/apps/web/src/components/portal/explain-banner.tsx @@ -2,7 +2,7 @@ import { useState, type ReactNode } from 'react' import { useNavigate } from '@tanstack/react-router' import { Button } from '@authportal/ui/components/button' import { cn } from '@authportal/ui/lib/utils' -import { CodeBlock, PreviewSheet, SignalAlert, StatusBadge } from './bits' +import { CodeBlock, PortalSheet, SignalAlert, StatusBadge } from './bits' /** * Баннер доски: заголовок и пояснение, справа «Объяснить» — открывает панель @@ -38,7 +38,7 @@ export function ExplainBanner({ Объяснить - Блокировка и сброс passkeys выполняются вручную с подтверждением и попадают в журнал «Изменения». - + ) } diff --git a/apps/web/src/design-preview/kpi-strip.tsx b/apps/web/src/components/portal/kpi-strip.tsx similarity index 100% rename from apps/web/src/design-preview/kpi-strip.tsx rename to apps/web/src/components/portal/kpi-strip.tsx diff --git a/apps/web/src/design-preview/kpi.tsx b/apps/web/src/components/portal/kpi.tsx similarity index 100% rename from apps/web/src/design-preview/kpi.tsx rename to apps/web/src/components/portal/kpi.tsx diff --git a/apps/web/src/design-preview/section-grid.tsx b/apps/web/src/components/portal/section-grid.tsx similarity index 99% rename from apps/web/src/design-preview/section-grid.tsx rename to apps/web/src/components/portal/section-grid.tsx index c1d5434..84bf282 100644 --- a/apps/web/src/design-preview/section-grid.tsx +++ b/apps/web/src/components/portal/section-grid.tsx @@ -32,8 +32,8 @@ import { Switch } from '@authportal/ui/components/switch' import { Tabs, TabsList, TabsTrigger } from '@authportal/ui/components/tabs' import { cn } from '@authportal/ui/lib/utils' import { StatusBadge } from './bits' -import type { Tone } from './mock' -import type { RowMark } from './preview-store' +import type { Tone } from './tone' +import type { RowMark } from './tone' import { TONE_DOT } from './tone' export type GridColumn = { @@ -83,7 +83,7 @@ const ACTIONS_COLUMN_SIZE = 120 * сохранённые виды линией со счётчиками, панель массовых действий, таблица со статусом и меню строки, * подвал «Показано N из M». Ширина таблицы не меньше суммы колонок — прокрутка внутри контейнера. */ -export function PreviewSectionGrid({ +export function SectionGrid({ title, description, rows, diff --git a/apps/web/src/design-preview/tone.ts b/apps/web/src/components/portal/tone.ts similarity index 71% rename from apps/web/src/design-preview/tone.ts rename to apps/web/src/components/portal/tone.ts index 5a13a3c..b45a9d4 100644 --- a/apps/web/src/design-preview/tone.ts +++ b/apps/web/src/components/portal/tone.ts @@ -1,4 +1,8 @@ -import type { Tone } from './mock' +export type Tone = 'ok' | 'wn' | 'er' | 'mu' | 'in' + +/** Пометка строки с накопленной правкой. */ +export type RowMark = 'new' | 'dirty' | 'deleted' + type BadgeVariant = | 'success-light' diff --git a/apps/web/src/design-preview/access-editor.tsx b/apps/web/src/design-preview/access-editor.tsx index b0ae75f..afb7e0c 100644 --- a/apps/web/src/design-preview/access-editor.tsx +++ b/apps/web/src/design-preview/access-editor.tsx @@ -10,7 +10,7 @@ import { } from '@authportal/ui/components/select' import { Switch } from '@authportal/ui/components/switch' import { Tabs, TabsContent, TabsList, TabsTrigger } from '@authportal/ui/components/tabs' -import { CodeBlock, SignalAlert } from './bits' +import { CodeBlock, SignalAlert } from '@/components/portal/bits' import { withLevel, levelOf, type AccessValue, type Level } from './access-model' import { APP_SHORT, USER_JOURNAL } from './mock' diff --git a/apps/web/src/design-preview/access-matrix.tsx b/apps/web/src/design-preview/access-matrix.tsx index 3d71e3a..ae6d79e 100644 --- a/apps/web/src/design-preview/access-matrix.tsx +++ b/apps/web/src/design-preview/access-matrix.tsx @@ -1,6 +1,6 @@ -import { StatusBadge } from './bits' +import { StatusBadge } from '@/components/portal/bits' import type { Tone } from './mock' -import { PreviewSectionGrid, TwoLineCell, type GridColumn } from './section-grid' +import { SectionGrid, TwoLineCell, type GridColumn } from '@/components/portal/section-grid' type MatrixRow = { id: string @@ -39,7 +39,7 @@ const COLUMNS: GridColumn[] = [ /** Матрица доступа по доске: сколько пользователей имеет доступ к каждому приложению и с каким уровнем. */ export function AccessMatrix() { return ( - diffAccess({ apps: user.apps, permissions: user.permissions }, value).length, [user, value]) return ( - !o && onClose()} size="lg" @@ -47,6 +47,6 @@ export function AccessSheet({ } > - + ) } diff --git a/apps/web/src/design-preview/create-sheets.tsx b/apps/web/src/design-preview/create-sheets.tsx index b86c015..4c5aa32 100644 --- a/apps/web/src/design-preview/create-sheets.tsx +++ b/apps/web/src/design-preview/create-sheets.tsx @@ -6,10 +6,10 @@ import { Field, FieldDescription, FieldError, FieldLabel } from '@authportal/ui/ import { Input } from '@authportal/ui/components/input' import { Switch } from '@authportal/ui/components/switch' import { Textarea } from '@authportal/ui/components/textarea' -import { PreviewSheet, SignalAlert } from './bits' +import { PortalSheet, SignalAlert } from '@/components/portal/bits' /** Окно «Создать пользователя» по доске: email, имя, временный пароль, администратор и заметка про журнал. */ -export function CreateUserPreviewSheet({ +export function CreateUserPortalSheet({ open, onOpenChange, onSubmit, @@ -37,7 +37,7 @@ export function CreateUserPreviewSheet({ } return ( - { if (!o) reset() @@ -93,12 +93,12 @@ export function CreateUserPreviewSheet({ Создание записывается в журнал «Изменения» с вашим именем и IP. - + ) } /** Окно «Создать OIDC-клиент» по доске: название, redirect URI, включён. */ -export function CreateOidcPreviewSheet({ +export function CreateOidcPortalSheet({ open, onOpenChange, onSubmit, @@ -128,7 +128,7 @@ export function CreateOidcPreviewSheet({ } return ( - { if (!o) reset() @@ -189,6 +189,6 @@ export function CreateOidcPreviewSheet({ Выключенный клиент не может получить токены - + ) } diff --git a/apps/web/src/design-preview/mock.ts b/apps/web/src/design-preview/mock.ts index af1e998..c26cf0f 100644 --- a/apps/web/src/design-preview/mock.ts +++ b/apps/web/src/design-preview/mock.ts @@ -21,7 +21,8 @@ import { type AuditLogEntry, } from '@authportal/shared' -export type Tone = 'ok' | 'wn' | 'er' | 'mu' | 'in' +import type { Tone } from '@/components/portal/tone' +export type { Tone } export type NavItem = { id: string diff --git a/apps/web/src/design-preview/pages/app-links-page.tsx b/apps/web/src/design-preview/pages/app-links-page.tsx index e1a6e74..9ce560d 100644 --- a/apps/web/src/design-preview/pages/app-links-page.tsx +++ b/apps/web/src/design-preview/pages/app-links-page.tsx @@ -15,13 +15,13 @@ import { } from '@authportal/ui/components/select' import { Switch } from '@authportal/ui/components/switch' import { Tabs, TabsContent } from '@authportal/ui/components/tabs' -import { KpiStrip } from '../kpi-strip' -import { PageHead, PreviewSheet, StatusBadge, PageTab, PageTabsList, FormFrame, SettingRow } from '../bits' -import { AppCards } from '../canvas-blocks' -import { kpi } from '../kpi' +import { KpiStrip } from '@/components/portal/kpi-strip' +import { PageHead, PortalSheet, StatusBadge, PageTab, PageTabsList, FormFrame, SettingRow } from '@/components/portal/bits' +import { AppCards } from '@/components/portal/canvas-blocks' +import { kpi } from '@/components/portal/kpi' import { MOCK_SWITCHER } from '../mock' import { usePreviewStore } from '../preview-store' -import { PreviewSectionGrid, TwoLineCell, type GridColumn } from '../section-grid' +import { SectionGrid, TwoLineCell, type GridColumn } from '@/components/portal/section-grid' type LinkRow = { id: AppId @@ -180,7 +180,7 @@ export function AppLinksPage() { - - !o && setEditing(null)} title="Приложение" @@ -323,7 +323,7 @@ export function AppLinksPage() { ) : null} - + ) } diff --git a/apps/web/src/design-preview/pages/apps-page.tsx b/apps/web/src/design-preview/pages/apps-page.tsx index d63dc51..7603fd3 100644 --- a/apps/web/src/design-preview/pages/apps-page.tsx +++ b/apps/web/src/design-preview/pages/apps-page.tsx @@ -2,12 +2,12 @@ import { Link } from '@tanstack/react-router' import { BadgeCheckIcon, CloudIcon, GlobeIcon, KeyRoundIcon, LayoutDashboardIcon, LayoutGridIcon, ServerIcon, ShieldIcon } from 'lucide-react' import { toast } from 'sonner' import { APPS, type AppId } from '@authportal/shared' -import { KpiStrip } from '../kpi-strip' +import { KpiStrip } from '@/components/portal/kpi-strip' import { Button } from '@authportal/ui/components/button' import { Tabs, TabsContent } from '@authportal/ui/components/tabs' -import { PageHead, PageTab, PageTabsList } from '../bits' -import { AppCards, type AppCardItem } from '../canvas-blocks' -import { kpi } from '../kpi' +import { PageHead, PageTab, PageTabsList } from '@/components/portal/bits' +import { AppCards, type AppCardItem } from '@/components/portal/canvas-blocks' +import { kpi } from '@/components/portal/kpi' const ICONS: Record = { cfdm: CloudIcon, diff --git a/apps/web/src/design-preview/pages/audit-page.tsx b/apps/web/src/design-preview/pages/audit-page.tsx index 0b27549..fb60db3 100644 --- a/apps/web/src/design-preview/pages/audit-page.tsx +++ b/apps/web/src/design-preview/pages/audit-page.tsx @@ -1,16 +1,16 @@ import { HistoryIcon, NetworkIcon, OctagonAlertIcon, UserCogIcon } from 'lucide-react' import { useState } from 'react' import { toast } from 'sonner' -import { KpiStrip } from '../kpi-strip' +import { KpiStrip } from '@/components/portal/kpi-strip' import { Button } from '@authportal/ui/components/button' import { Input } from '@authportal/ui/components/input' import { Switch } from '@authportal/ui/components/switch' import { Tabs, TabsContent } from '@authportal/ui/components/tabs' -import { CodeBlock, FormFrame, KvList, PageHead, PageTab, PageTabsList, PreviewSheet, SettingRow, StatusBadge, TypedConfirm } from '../bits' -import { ActivityFeed } from '../canvas-blocks' -import { kpi } from '../kpi' +import { CodeBlock, FormFrame, KvList, PageHead, PageTab, PageTabsList, PortalSheet, SettingRow, StatusBadge, TypedConfirm } from '@/components/portal/bits' +import { ActivityFeed } from '@/components/portal/canvas-blocks' +import { kpi } from '@/components/portal/kpi' import { AUDIT_FEED, AUDIT_ROWS, type AuditRow } from '../mock' -import { PreviewSectionGrid, TwoLineCell, type GridColumn } from '../section-grid' +import { SectionGrid, TwoLineCell, type GridColumn } from '@/components/portal/section-grid' const mono = (v: string) => {v} @@ -74,7 +74,7 @@ export function AuditPage() { /> - - !o && setEntry(null)} title="Событие журнала" @@ -137,7 +137,7 @@ export function AuditPage() { ) : null} - + - - - !o && setEvent(null)} title="Событие входа" @@ -148,7 +148,7 @@ export function LoginsPage() { {`action: ${event.tone === 'er' ? 'auth.login_failed' : 'auth.login'}\nsource_app: portal\nseverity: ${event.tone === 'er' ? 'warning' : 'info'}\nip: ${event.ip}`} ) : null} - + ) } diff --git a/apps/web/src/design-preview/pages/oidc-page.tsx b/apps/web/src/design-preview/pages/oidc-page.tsx index 1d509ef..93907e0 100644 --- a/apps/web/src/design-preview/pages/oidc-page.tsx +++ b/apps/web/src/design-preview/pages/oidc-page.tsx @@ -2,8 +2,8 @@ import { useMemo, useState } from 'react' import { CircleCheckIcon, CopyIcon, KeyRoundIcon, LockKeyholeIcon, TicketIcon } from 'lucide-react' import { toast } from 'sonner' import type { CreateOidcClientValues } from '@/components/reui-kit/create-oidc-client-sheet' -import { CreateOidcPreviewSheet } from '../create-sheets' -import { KpiStrip } from '../kpi-strip' +import { CreateOidcPortalSheet } from '../create-sheets' +import { KpiStrip } from '@/components/portal/kpi-strip' import { Button } from '@authportal/ui/components/button' import { AlertDialog, @@ -18,9 +18,9 @@ import { Input } from '@authportal/ui/components/input' import { Switch } from '@authportal/ui/components/switch' import { Tabs, TabsContent } from '@authportal/ui/components/tabs' import { Textarea } from '@authportal/ui/components/textarea' -import { ExplainBanner } from '../explain-banner' -import { CopyList, KvFrame, PageHead, PreviewSheet, StatusBadge, TypedConfirm, PageTab, PageTabsList } from '../bits' -import { kpi } from '../kpi' +import { ExplainBanner } from '@/components/portal/explain-banner' +import { CopyList, KvFrame, PageHead, PortalSheet, StatusBadge, TypedConfirm, PageTab, PageTabsList } from '@/components/portal/bits' +import { kpi } from '@/components/portal/kpi' import { MOCK_CLIENT_SECRET, MOCK_OIDC_CLIENTS, @@ -29,7 +29,7 @@ import { type OidcClientRow, type Tone } from '../mock' -import { PreviewSectionGrid, TwoLineCell, type GridColumn } from '../section-grid' +import { SectionGrid, TwoLineCell, type GridColumn } from '@/components/portal/section-grid' function tone(c: OidcClientRow): Tone { return !c.enabled ? 'mu' : c.stale ? 'wn' : 'ok' @@ -111,7 +111,7 @@ export function OidcPage() { - - + - !o && setEditing(null)} title="OIDC-клиент" @@ -193,7 +193,7 @@ export function OidcPage() { ) : null} - + (MOCK_PASSKEYS) @@ -72,7 +72,7 @@ export function SecurityPage() { - - Откроется системный диалог: подтвердите отпечатком, Face ID, PIN или ключом безопасности. Закрытый ключ не покидает устройство. - + - !o && setSelected(null)} title="Passkey" @@ -213,7 +213,7 @@ export function SecurityPage() { ['Последний вход', `${selected?.lastUsed ?? ''} · 203.0.113.10`], ]} /> - + - + {accessFor ? (