From 1152bb40f7400f42276db2127b1aa4410edfe43b Mon Sep 17 00:00:00 2001 From: Denozordec Date: Thu, 9 Jul 2026 20:54:35 +0700 Subject: [PATCH] feat: enhance BadgeTabs and Auth components with layout improvements and API integration Added layout metrics logging to the BadgeTabs component for better debugging and analysis. Updated the Auth route to include a reason for redirection when a token is required, improving user feedback. Enhanced the Settings component to display an alert when API token access is needed, ensuring clarity for users. Additionally, refined the Tabs component to improve responsiveness based on orientation, contributing to a more cohesive user experience. --- .cursor/debug-c10bcb.log | 11 ++++ apps/web/src/components/badge-tabs.tsx | 86 ++++++++++++++++++-------- apps/web/src/routes/_auth.tsx | 2 +- apps/web/src/routes/_auth/settings.tsx | 14 ++++- packages/ui/src/components/tabs.tsx | 8 +-- 5 files changed, 89 insertions(+), 32 deletions(-) create mode 100644 .cursor/debug-c10bcb.log diff --git a/.cursor/debug-c10bcb.log b/.cursor/debug-c10bcb.log new file mode 100644 index 0000000..21c07cc --- /dev/null +++ b/.cursor/debug-c10bcb.log @@ -0,0 +1,11 @@ +{"sessionId":"c10bcb","runId":"post-fix","hypothesisId":"H1","location":"badge-tabs.tsx:useEffect","message":"BadgeTabs layout metrics","data":{"flexDirection":"column","orientation":"horizontal","listLeft":280,"panelLeft":280,"stacked":true},"timestamp":1783605101206} +{"sessionId":"c10bcb","runId":"post-fix","hypothesisId":"H1","location":"badge-tabs.tsx:useEffect","message":"BadgeTabs layout metrics","data":{"flexDirection":"column","orientation":"horizontal","listLeft":280,"panelLeft":280,"stacked":true},"timestamp":1783605101204} +{"sessionId":"c10bcb","runId":"post-fix","hypothesisId":"H1","location":"badge-tabs.tsx:useEffect","message":"BadgeTabs layout metrics","data":{"flexDirection":"column","orientation":"horizontal","listLeft":280,"panelLeft":280,"stacked":true},"timestamp":1783605138640} +{"sessionId":"c10bcb","runId":"post-fix","hypothesisId":"H1","location":"badge-tabs.tsx:useEffect","message":"BadgeTabs layout metrics","data":{"flexDirection":"column","orientation":"horizontal","listLeft":280,"panelLeft":280,"stacked":true},"timestamp":1783605138642} +{"sessionId":"c10bcb","runId":"post-fix","hypothesisId":"H1","location":"badge-tabs.tsx:useEffect","message":"BadgeTabs layout metrics","data":{"flexDirection":"column","orientation":"horizontal","listLeft":280,"panelLeft":280,"stacked":true},"timestamp":1783605143758} +{"sessionId":"c10bcb","runId":"post-fix","hypothesisId":"H1","location":"badge-tabs.tsx:useEffect","message":"BadgeTabs layout metrics","data":{"flexDirection":"column","orientation":"horizontal","listLeft":280,"panelLeft":280,"stacked":true},"timestamp":1783605144457} +{"sessionId":"c10bcb","runId":"post-fix","hypothesisId":"H1","location":"badge-tabs.tsx:useEffect","message":"BadgeTabs layout metrics","data":{"flexDirection":"column","orientation":"horizontal","listLeft":280,"panelLeft":280,"stacked":true},"timestamp":1783605145907} +{"sessionId":"c10bcb","runId":"post-fix","hypothesisId":"H1","location":"badge-tabs.tsx:useEffect","message":"BadgeTabs layout metrics","data":{"flexDirection":"column","orientation":"horizontal","listLeft":280,"panelLeft":280,"stacked":true},"timestamp":1783605152669} +{"sessionId":"c10bcb","runId":"post-fix","hypothesisId":"H1","location":"badge-tabs.tsx:useEffect","message":"BadgeTabs layout metrics","data":{"flexDirection":"column","orientation":"horizontal","listLeft":280,"panelLeft":280,"stacked":true},"timestamp":1783605152671} +{"sessionId":"c10bcb","runId":"post-fix","hypothesisId":"H1","location":"badge-tabs.tsx:useEffect","message":"BadgeTabs layout metrics","data":{"flexDirection":"column","orientation":"horizontal","listLeft":280,"panelLeft":280,"stacked":true},"timestamp":1783605222064} +{"sessionId":"c10bcb","runId":"post-fix","hypothesisId":"H1","location":"badge-tabs.tsx:useEffect","message":"BadgeTabs layout metrics","data":{"flexDirection":"column","orientation":"horizontal","listLeft":280,"panelLeft":280,"stacked":true},"timestamp":1783605222067} diff --git a/apps/web/src/components/badge-tabs.tsx b/apps/web/src/components/badge-tabs.tsx index 208ef0e..cb0bbab 100644 --- a/apps/web/src/components/badge-tabs.tsx +++ b/apps/web/src/components/badge-tabs.tsx @@ -1,4 +1,5 @@ import type { ComponentProps, ReactNode } from 'react' +import { useEffect, useRef } from 'react' import { Tabs, TabsContent, TabsList, TabsTrigger } from '@evobgp/ui/components/tabs' import { cn } from '@evobgp/ui/lib/utils' @@ -35,34 +36,67 @@ export function BadgeTabs({ listClassName, contentClassName, }: BadgeTabsProps) { + const tabsRef = useRef(null) + + useEffect(() => { + const el = tabsRef.current?.querySelector('[data-slot=tabs]') + if (!el || !(el instanceof HTMLElement)) return + const flexDirection = getComputedStyle(el).flexDirection + const listRect = el.querySelector('[data-slot=tabs-list]')?.getBoundingClientRect() + const panelRect = el.querySelector('[data-slot=tabs-content]')?.getBoundingClientRect() + // #region agent log + fetch('http://127.0.0.1:7311/ingest/6b35c3ae-1bcd-4c9c-81eb-f157c9347393', { + method: 'POST', + headers: { 'Content-Type': 'application/json', 'X-Debug-Session-Id': 'c10bcb' }, + body: JSON.stringify({ + sessionId: 'c10bcb', + runId: 'post-fix', + hypothesisId: 'H1', + location: 'badge-tabs.tsx:useEffect', + message: 'BadgeTabs layout metrics', + data: { + flexDirection, + orientation: el.getAttribute('data-orientation'), + listLeft: listRect?.left, + panelLeft: panelRect?.left, + stacked: flexDirection === 'column', + }, + timestamp: Date.now(), + }), + }).catch(() => {}) + // #endregion + }, [value, defaultValue]) + return ( - - + - {items.map((item) => ( - - {item.icon} - {item.label} - {item.count !== undefined ? ( - - {item.count} - - ) : null} - - ))} - -
{children}
-
+ + {items.map((item) => ( + + {item.icon} + {item.label} + {item.count !== undefined ? ( + + {item.count} + + ) : null} + + ))} + +
{children}
+ + ) } diff --git a/apps/web/src/routes/_auth.tsx b/apps/web/src/routes/_auth.tsx index 4708472..91ab327 100644 --- a/apps/web/src/routes/_auth.tsx +++ b/apps/web/src/routes/_auth.tsx @@ -9,7 +9,7 @@ export const Route = createFileRoute('/_auth')({ const raw = typeof window !== 'undefined' ? window.localStorage.getItem(TOKEN_STORAGE_KEY) : null if (!raw || !normalizeApiToken(raw)) { - throw redirect({ to: '/settings' }) + throw redirect({ to: '/settings', search: { reason: 'token-required' } }) } }, component: AuthLayout, diff --git a/apps/web/src/routes/_auth/settings.tsx b/apps/web/src/routes/_auth/settings.tsx index 7c3470c..88c332c 100644 --- a/apps/web/src/routes/_auth/settings.tsx +++ b/apps/web/src/routes/_auth/settings.tsx @@ -1,7 +1,8 @@ -import { createFileRoute, useNavigate } from '@tanstack/react-router' +import { createFileRoute, useNavigate, useRouterState } from '@tanstack/react-router' import { useQuery, useQueryClient } from '@tanstack/react-query' import { Button } from '@evobgp/ui/components/button' +import { Alert, AlertDescription } from '@evobgp/ui/components/alert' import { PanelCard } from '@/components/panel-card' import { Input } from '@evobgp/ui/components/input' import { Label } from '@evobgp/ui/components/label' @@ -28,6 +29,9 @@ const THEME_SELECT_ITEMS = [ function SettingsComponent() { const navigate = useNavigate() + const tokenRequired = useRouterState({ + select: (s) => new URLSearchParams(s.location.search).get('reason') === 'token-required', + }) const qc = useQueryClient() const { data: session, isError: sessionError, error: sessionQueryError } = useQuery({ ...authSessionQueryOptions(), @@ -69,6 +73,14 @@ function SettingsComponent() { description="Параметры интерфейса и подключения браузера к API." /> + {tokenRequired ? ( + + + Для доступа к разделу нужен API-токен. Сохраните токен ниже или нажмите «Использовать dev». + + + ) : null} +