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.
This commit is contained in:
Tom Butcher 2026-08-20 17:45:18 +01:00
parent 0b501a11c6
commit 76d00a8be1
2 changed files with 55 additions and 20 deletions

View File

@ -1337,6 +1337,29 @@ span.ant-skeleton-input.ant-skeleton-input-sm.text-skeleton {
vertical-align: middle; 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 { .permissions-matrix-table .permissions-matrix-group-row > .ant-table-cell {
font-weight: 600; font-weight: 600;
background-color: color-mix( background-color: color-mix(

View File

@ -3,7 +3,8 @@ import {
useCallback, useCallback,
useState, useState,
createElement, createElement,
useContext useContext,
useRef
} from 'react' } from 'react'
import PropTypes from 'prop-types' import PropTypes from 'prop-types'
import { Table, Flex, Tooltip, Button } from 'antd' 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 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 getPermissionState = (permissions, modelName, actionName) => {
const value = permissions?.[modelName]?.[actionName] const value = permissions?.[modelName]?.[actionName]
if (value === true) return true if (value === true) return true
@ -314,7 +320,21 @@ const PermissionsMatrix = ({
[models] [models]
) )
const [expandedRowKeys, setExpandedRowKeys] = useState(null) 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( const resolvedExpandedRowKeys = useMemo(
() => expandedRowKeys ?? dataSource.map((row) => row.key), () => expandedRowKeys ?? dataSource.map((row) => row.key),
@ -339,17 +359,6 @@ const PermissionsMatrix = ({
[dataSource] [dataSource]
) )
const getColumnHoverProps = useCallback(
(columnKey, isHeader = false) => ({
onMouseEnter: () => setHoveredColumnKey(columnKey),
className:
!isHeader && hoveredColumnKey === columnKey
? 'ant-table-cell-row-hover'
: undefined
}),
[hoveredColumnKey]
)
var adjustedScrollHeight = scrollHeight var adjustedScrollHeight = scrollHeight
if (isMobile) { if (isMobile) {
adjustedScrollHeight = 'calc(var(--unit-100vh) - 298px)' adjustedScrollHeight = 'calc(var(--unit-100vh) - 298px)'
@ -463,8 +472,8 @@ const PermissionsMatrix = ({
dataIndex: 'label', dataIndex: 'label',
fixed: isMobile ? undefined : 'left', fixed: isMobile ? undefined : 'left',
width: 280, width: 280,
onHeaderCell: () => getColumnHoverProps('model', true), onHeaderCell: () => getColumnIndexProps(1),
onCell: () => getColumnHoverProps('model'), onCell: () => getColumnIndexProps(1),
render: (label, record) => { render: (label, record) => {
const recordModels = getRecordModels(record) const recordModels = getRecordModels(record)
const aggregate = getAggregatePermissionState( const aggregate = getAggregatePermissionState(
@ -536,7 +545,7 @@ const PermissionsMatrix = ({
} }
} }
const actionColumns = actions.map((action) => { const actionColumns = actions.map((action, actionIndex) => {
const columnAggregate = getAggregatePermissionState( const columnAggregate = getAggregatePermissionState(
getColumnPermissionStates(permissions, models, action, inherit) getColumnPermissionStates(permissions, models, action, inherit)
) )
@ -561,8 +570,8 @@ const PermissionsMatrix = ({
key: action.name, key: action.name,
width: 48, width: 48,
align: 'center', align: 'center',
onHeaderCell: () => getColumnHoverProps(action.name, true), onHeaderCell: () => getColumnIndexProps(actionIndex + 2),
onCell: () => getColumnHoverProps(action.name), onCell: () => getColumnIndexProps(actionIndex + 2),
render: (_, record) => { render: (_, record) => {
const recordModels = getRecordModels(record) const recordModels = getRecordModels(record)
const applicable = recordModels.filter((model) => const applicable = recordModels.filter((model) =>
@ -594,7 +603,6 @@ const PermissionsMatrix = ({
return [modelColumn, ...actionColumns] return [modelColumn, ...actionColumns]
}, [ }, [
actions, actions,
getColumnHoverProps,
handleCycle, handleCycle,
handleCycleColumn, handleCycleColumn,
handleCycleModels, handleCycleModels,
@ -609,7 +617,11 @@ const PermissionsMatrix = ({
]) ])
return ( return (
<div onMouseLeave={() => setHoveredColumnKey(null)}> <div
className='permissions-matrix'
onMouseOver={handleMatrixMouseOver}
onMouseLeave={handleMatrixMouseLeave}
>
<Table <Table
className='dashboard-table permissions-matrix-table' className='dashboard-table permissions-matrix-table'
dataSource={dataSource} dataSource={dataSource}