From 1e0fc4cd2d379fd4232cee2071e2fb3cc4a66dc0 Mon Sep 17 00:00:00 2001 From: Denozordec Date: Thu, 1 Oct 2026 10:35:34 +0700 Subject: [PATCH] =?UTF-8?q?fix(ui):=20=D0=B7=D0=B0=D0=B2=D0=B5=D1=80=D1=88?= =?UTF-8?q?=D0=B8=D1=82=D1=8C=20=D0=B4=D0=BE=D1=81=D1=82=D1=83=D0=BF=D0=BD?= =?UTF-8?q?=D0=BE=D1=81=D1=82=D1=8C=20=D1=84=D0=BE=D1=80=D0=BC=D1=8B=20?= =?UTF-8?q?=D0=BF=D0=BE=D0=BB=D1=8C=D0=B7=D0=BE=D0=B2=D0=B0=D1=82=D0=B5?= =?UTF-8?q?=D0=BB=D0=B5=D0=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/(main)/users/page.tsx | 23 +++- components/data-grids/users-data-grid.tsx | 20 ++-- components/users/user-sheet.tsx | 104 +++++++++++------- docs/ux-ui-progress.md | 11 +- docs/ux-ui-stage-11a.md | 10 ++ docs/ux-ui/screens/users-catalog-desktop.png | Bin 0 -> 184998 bytes docs/ux-ui/screens/users-catalog-mobile.png | Bin 0 -> 48965 bytes docs/ux-ui/screens/users-catalog-narrow.png | Bin 0 -> 46781 bytes docs/ux-ui/screens/users-error-desktop.png | Bin 0 -> 189087 bytes docs/ux-ui/screens/users-error-mobile.png | Bin 0 -> 50954 bytes docs/ux-ui/screens/users-error-narrow.png | Bin 0 -> 48745 bytes docs/ux-ui/screens/users-overview-desktop.png | Bin 0 -> 96475 bytes docs/ux-ui/screens/users-overview-mobile.png | Bin 0 -> 38041 bytes docs/ux-ui/screens/users-overview-narrow.png | Bin 0 -> 36555 bytes docs/ux-ui/screens/users-profile-desktop.png | Bin 0 -> 171223 bytes docs/ux-ui/screens/users-profile-mobile.png | Bin 0 -> 37825 bytes docs/ux-ui/screens/users-profile-narrow.png | Bin 0 -> 35759 bytes lib/users.ts | 6 +- tests/e2e/users-layout.spec.ts | 25 +++++ 19 files changed, 139 insertions(+), 60 deletions(-) create mode 100644 docs/ux-ui/screens/users-catalog-desktop.png create mode 100644 docs/ux-ui/screens/users-catalog-mobile.png create mode 100644 docs/ux-ui/screens/users-catalog-narrow.png create mode 100644 docs/ux-ui/screens/users-error-desktop.png create mode 100644 docs/ux-ui/screens/users-error-mobile.png create mode 100644 docs/ux-ui/screens/users-error-narrow.png create mode 100644 docs/ux-ui/screens/users-overview-desktop.png create mode 100644 docs/ux-ui/screens/users-overview-mobile.png create mode 100644 docs/ux-ui/screens/users-overview-narrow.png create mode 100644 docs/ux-ui/screens/users-profile-desktop.png create mode 100644 docs/ux-ui/screens/users-profile-mobile.png create mode 100644 docs/ux-ui/screens/users-profile-narrow.png create mode 100644 tests/e2e/users-layout.spec.ts diff --git a/app/(main)/users/page.tsx b/app/(main)/users/page.tsx index db80b89d..6bcc83a7 100644 --- a/app/(main)/users/page.tsx +++ b/app/(main)/users/page.tsx @@ -96,8 +96,18 @@ function UsersContent() { const mutationController = useRef(null) const alive = useRef(true) useEffect(() => { alive.current = true; return () => { alive.current = false; mutationController.current?.abort() } }, []) + const formReturnFocus = useRef(null) const [sheetOpen, setSheetOpen] = useState(false) const [editUser, setEditUser] = useState(null) + useEffect(() => { + if (sheetOpen || !formReturnFocus.current) return + const label = formReturnFocus.current.getAttribute("aria-label") + const frame = requestAnimationFrame(() => { + const target = Array.from(document.querySelectorAll("button[aria-label]")).find(button => button.getAttribute("aria-label") === label) + ;(target ?? document.querySelector('button[aria-label="Добавить пользователя"]'))?.focus() + }) + return () => cancelAnimationFrame(frame) + }, [sheetOpen]) const [deleteTarget, setDeleteTarget] = useState(null) const loadLive = useCallback(async () => { @@ -236,20 +246,20 @@ function UsersContent() { } return ( -
+
- {isLive && } - } + } /> -
+
{operationNotice &&

{operationNotice}

} {!isLive &&

Демо: изменения сохраняются только в текущем экране.

} {!canRead &&

Для чтения пользователей требуется mm:users:read.

} @@ -295,13 +305,14 @@ function UsersContent() { allSectionsCount={ALL_SECTIONS.length} isLoading={loading && !usersKnown} actionsDisabled={!writeReady || saving || deleting} - onEdit={(u) => { saveCheckpoint.current = null; setSaveError(null); setSaveBlocked(false); setSaveResume(false); setEditUser(u); setSheetOpen(true) }} + onEdit={(u) => { formReturnFocus.current = document.activeElement as HTMLElement; saveCheckpoint.current = null; setSaveError(null); setSaveBlocked(false); setSaveResume(false); setEditUser(u); setSheetOpen(true) }} onDelete={u => { setDeleteError(null); setDeleteTarget(u) }} /> }