From ee3e96647e24f204c149c238433903b2ac550a72 Mon Sep 17 00:00:00 2001 From: Denozordec Date: Tue, 4 Aug 2026 22:06:15 +0700 Subject: [PATCH] Refactor dropdown menu components in various files to prevent event propagation, enhancing user interaction. Update CountedLineTabs component documentation with preview links for better clarity. Improve styling and layout in resource page and user columns for consistency and visual appeal. --- apps/web/src/components/counted-line-tabs.tsx | 21 +++- .../src/components/errors/errors-columns.tsx | 46 ++++---- .../src/components/reui-kit/resource-page.tsx | 3 +- .../reui/data-grid/data-grid-table.tsx | 16 ++- .../src/components/users/users-columns.tsx | 104 +++++++++--------- 5 files changed, 115 insertions(+), 75 deletions(-) diff --git a/apps/web/src/components/counted-line-tabs.tsx b/apps/web/src/components/counted-line-tabs.tsx index 40bab99..1f003b8 100644 --- a/apps/web/src/components/counted-line-tabs.tsx +++ b/apps/web/src/components/counted-line-tabs.tsx @@ -17,7 +17,11 @@ interface CountedLineTabsProps { children?: ReactNode } -/** Line tabs with count pills (c-tabs-2 / data-grid-filtering-2). */ +/** + * Line tabs with count pills — ReUI PRO DNA. + * Preview: https://reui.io/preview/base/components/c-tabs-2 + * Lists: https://reui.io/preview/base/data-grid-filtering-2 + */ export function CountedLineTabs({ tabs, value, @@ -28,12 +32,23 @@ export function CountedLineTabs({ }: CountedLineTabsProps) { return ( - + {tabs.map((tab) => ( {tab.label} {tab.count !== undefined ? ( diff --git a/apps/web/src/components/errors/errors-columns.tsx b/apps/web/src/components/errors/errors-columns.tsx index d2ca76b..ecbc295 100644 --- a/apps/web/src/components/errors/errors-columns.tsx +++ b/apps/web/src/components/errors/errors-columns.tsx @@ -251,26 +251,32 @@ function RowActions({ onOpen: (row: TelemtErrorRow) => void }) { return ( - - - } - > - - - - onOpen(row.original)}> - - Открыть - - - +
event.stopPropagation()} + onPointerDown={(event) => event.stopPropagation()} + > + + + } + > + + + + onOpen(row.original)}> + + Открыть + + + +
) } diff --git a/apps/web/src/components/reui-kit/resource-page.tsx b/apps/web/src/components/reui-kit/resource-page.tsx index 1506f6f..aae9dd9 100644 --- a/apps/web/src/components/reui-kit/resource-page.tsx +++ b/apps/web/src/components/reui-kit/resource-page.tsx @@ -570,14 +570,13 @@ function ResourcePageFiltered({ {countedTabs.length > 0 ? ( <> -
+
- ) : null} diff --git a/apps/web/src/components/reui/data-grid/data-grid-table.tsx b/apps/web/src/components/reui/data-grid/data-grid-table.tsx index 4f21542..a68004a 100644 --- a/apps/web/src/components/reui/data-grid/data-grid-table.tsx +++ b/apps/web/src/components/reui/data-grid/data-grid-table.tsx @@ -1269,7 +1269,21 @@ function DataGridTableBodyRow({ data-depth={row.depth || undefined} data-row-pinned={isRowPinned || undefined} data-row-pinned-boundary={pinnedBoundary} - onClick={() => props.onRowClick && props.onRowClick(row.original)} + onClick={(event) => { + if (!props.onRowClick) return + // Interactive controls (actions menu, pin, checkbox, links) must not + // open the row detail — same contract as DataGridTableRowPin/Select. + const target = event.target + if ( + target instanceof Element && + target.closest( + 'button, a, input, textarea, select, [role="button"], [role="menuitem"], [role="checkbox"], [data-slot="dropdown-menu-trigger"], [data-slot="checkbox"]' + ) + ) { + return + } + props.onRowClick(row.original) + }} className={cn( "hover:bg-muted/40 data-[state=selected]:bg-muted/50", props.onRowClick && "cursor-pointer", diff --git a/apps/web/src/components/users/users-columns.tsx b/apps/web/src/components/users/users-columns.tsx index f24ff3f..5637854 100644 --- a/apps/web/src/components/users/users-columns.tsx +++ b/apps/web/src/components/users/users-columns.tsx @@ -199,55 +199,61 @@ export function ActionsCell({ return ( <> - - - } - > - - - - row.pin(isPinned ? false : 'top')}> - {isPinned ? ( - - onOpen(row.original)}> - - { - copyToClipboard(row.original.username) - toast.success('Имя скопировано', { - description: row.original.username, - }) - }} - > - - - setDeleteOpen(true)} - > - - - - +
event.stopPropagation()} + onPointerDown={(event) => event.stopPropagation()} + > + + + } + > + + + + row.pin(isPinned ? false : 'top')}> + {isPinned ? ( + + onOpen(row.original)}> + + { + copyToClipboard(row.original.username) + toast.success('Имя скопировано', { + description: row.original.username, + }) + }} + > + + + setDeleteOpen(true)} + > + + + + +