From 76d00a8be1eecd331f71c32f4aa0560e404a80cd Mon Sep 17 00:00:00 2001 From: Tom Butcher Date: Thu, 20 Aug 2026 17:45:18 +0100 Subject: [PATCH] Enhance PermissionsMatrix with hover effects and refactor column handling - Added hover effect to the permissions matrix table cells, improving visual feedback for user interactions. - Refactored column handling by introducing a new utility function for setting column index properties. - Replaced state management for hovered columns with a ref to optimize performance and reduce unnecessary re-renders. - Updated event handling for mouse over and leave actions to enhance user experience in the permissions matrix. --- assets/stylesheets/App.css | 23 ++++++++ .../Dashboard/common/PermissionsMatrix.jsx | 52 ++++++++++++------- 2 files changed, 55 insertions(+), 20 deletions(-) diff --git a/assets/stylesheets/App.css b/assets/stylesheets/App.css index eba69484..2da2489a 100644 --- a/assets/stylesheets/App.css +++ b/assets/stylesheets/App.css @@ -1337,6 +1337,29 @@ span.ant-skeleton-input.ant-skeleton-input-sm.text-skeleton { vertical-align: middle; } +.permissions-matrix:hover .ant-table-tbody > tr > .ant-table-cell { + box-shadow: inset 0 0 0 100vmax + color-mix( + in srgb, + var(--color-text) + calc( + 4% * + ( + 1 - + min( + 1, + abs( + calc( + var(--permissions-col, 0) - var(--permissions-hovered-col, -1) + ) + ) + ) + ) + ), + transparent + ); +} + .permissions-matrix-table .permissions-matrix-group-row > .ant-table-cell { font-weight: 600; background-color: color-mix( diff --git a/src/components/Dashboard/common/PermissionsMatrix.jsx b/src/components/Dashboard/common/PermissionsMatrix.jsx index 29fcfa10..20eb676f 100644 --- a/src/components/Dashboard/common/PermissionsMatrix.jsx +++ b/src/components/Dashboard/common/PermissionsMatrix.jsx @@ -3,7 +3,8 @@ import { useCallback, useState, createElement, - useContext + useContext, + useRef } from 'react' import PropTypes from 'prop-types' import { Table, Flex, Tooltip, Button } from 'antd' @@ -21,6 +22,11 @@ import { CaretRightOutlined } from '@ant-design/icons' const DEFAULT_SCROLL_HEIGHT = 'calc(var(--unit-100vh) - 258px)' +const getColumnIndexProps = (columnIndex) => ({ + 'data-col': String(columnIndex), + style: { '--permissions-col': String(columnIndex) } +}) + const getPermissionState = (permissions, modelName, actionName) => { const value = permissions?.[modelName]?.[actionName] if (value === true) return true @@ -314,7 +320,21 @@ const PermissionsMatrix = ({ [models] ) const [expandedRowKeys, setExpandedRowKeys] = useState(null) - const [hoveredColumnKey, setHoveredColumnKey] = useState(null) + const hoveredColumnIndexRef = useRef(null) + + const handleMatrixMouseOver = useCallback((event) => { + const cell = event.target.closest('.ant-table-cell') + if (!cell || !event.currentTarget.contains(cell)) return + const next = cell.getAttribute('data-col') + if (!next || hoveredColumnIndexRef.current === next) return + hoveredColumnIndexRef.current = next + event.currentTarget.style.setProperty('--permissions-hovered-col', next) + }, []) + + const handleMatrixMouseLeave = useCallback((event) => { + hoveredColumnIndexRef.current = null + event.currentTarget.style.removeProperty('--permissions-hovered-col') + }, []) const resolvedExpandedRowKeys = useMemo( () => expandedRowKeys ?? dataSource.map((row) => row.key), @@ -339,17 +359,6 @@ const PermissionsMatrix = ({ [dataSource] ) - const getColumnHoverProps = useCallback( - (columnKey, isHeader = false) => ({ - onMouseEnter: () => setHoveredColumnKey(columnKey), - className: - !isHeader && hoveredColumnKey === columnKey - ? 'ant-table-cell-row-hover' - : undefined - }), - [hoveredColumnKey] - ) - var adjustedScrollHeight = scrollHeight if (isMobile) { adjustedScrollHeight = 'calc(var(--unit-100vh) - 298px)' @@ -463,8 +472,8 @@ const PermissionsMatrix = ({ dataIndex: 'label', fixed: isMobile ? undefined : 'left', width: 280, - onHeaderCell: () => getColumnHoverProps('model', true), - onCell: () => getColumnHoverProps('model'), + onHeaderCell: () => getColumnIndexProps(1), + onCell: () => getColumnIndexProps(1), render: (label, record) => { const recordModels = getRecordModels(record) const aggregate = getAggregatePermissionState( @@ -536,7 +545,7 @@ const PermissionsMatrix = ({ } } - const actionColumns = actions.map((action) => { + const actionColumns = actions.map((action, actionIndex) => { const columnAggregate = getAggregatePermissionState( getColumnPermissionStates(permissions, models, action, inherit) ) @@ -561,8 +570,8 @@ const PermissionsMatrix = ({ key: action.name, width: 48, align: 'center', - onHeaderCell: () => getColumnHoverProps(action.name, true), - onCell: () => getColumnHoverProps(action.name), + onHeaderCell: () => getColumnIndexProps(actionIndex + 2), + onCell: () => getColumnIndexProps(actionIndex + 2), render: (_, record) => { const recordModels = getRecordModels(record) const applicable = recordModels.filter((model) => @@ -594,7 +603,6 @@ const PermissionsMatrix = ({ return [modelColumn, ...actionColumns] }, [ actions, - getColumnHoverProps, handleCycle, handleCycleColumn, handleCycleModels, @@ -609,7 +617,11 @@ const PermissionsMatrix = ({ ]) return ( -
setHoveredColumnKey(null)}> +