Enhance PermissionsMatrix with session storage for expanded rows and scroll position
- Implemented session storage functionality to persist expanded row keys and scroll position in the PermissionsMatrix, improving user experience during navigation. - Refactored state management to utilize hooks for handling expanded rows and scroll restoration. - Added utility functions for reading and writing to session storage, ensuring data integrity and availability across user sessions. - Updated event handling for scroll events to maintain the user's scroll position, enhancing usability in the permissions matrix.
This commit is contained in:
parent
24c06c25d3
commit
0a09905f9f
@ -4,7 +4,9 @@ import {
|
|||||||
useState,
|
useState,
|
||||||
createElement,
|
createElement,
|
||||||
useContext,
|
useContext,
|
||||||
useRef
|
useRef,
|
||||||
|
useEffect,
|
||||||
|
useLayoutEffect
|
||||||
} 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 +23,30 @@ import PermissionCheckbox from './PermissionCheckbox'
|
|||||||
import { CaretRightOutlined } from '@ant-design/icons'
|
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 PERMISSIONS_MATRIX_SESSION_KEY = 'permissionsMatrix:ui'
|
||||||
|
|
||||||
|
const readPermissionsMatrixSession = () => {
|
||||||
|
try {
|
||||||
|
const parsed = JSON.parse(
|
||||||
|
sessionStorage.getItem(PERMISSIONS_MATRIX_SESSION_KEY)
|
||||||
|
)
|
||||||
|
if (!parsed || typeof parsed !== 'object') return {}
|
||||||
|
return parsed
|
||||||
|
} catch {
|
||||||
|
return {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const writePermissionsMatrixSession = (patch) => {
|
||||||
|
try {
|
||||||
|
sessionStorage.setItem(
|
||||||
|
PERMISSIONS_MATRIX_SESSION_KEY,
|
||||||
|
JSON.stringify({ ...readPermissionsMatrixSession(), ...patch })
|
||||||
|
)
|
||||||
|
} catch {
|
||||||
|
// sessionStorage may be unavailable
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const getColumnIndexProps = (columnIndex) => ({
|
const getColumnIndexProps = (columnIndex) => ({
|
||||||
'data-col': String(columnIndex),
|
'data-col': String(columnIndex),
|
||||||
@ -328,9 +354,26 @@ const PermissionsMatrix = ({
|
|||||||
() => buildPermissionMatrixDataSource(models),
|
() => buildPermissionMatrixDataSource(models),
|
||||||
[models]
|
[models]
|
||||||
)
|
)
|
||||||
const [expandedRowKeys, setExpandedRowKeys] = useState(null)
|
const [expandedRowKeys, setExpandedRowKeys] = useState(() => {
|
||||||
|
const stored = readPermissionsMatrixSession().expandedRowKeys
|
||||||
|
return Array.isArray(stored) ? stored : []
|
||||||
|
})
|
||||||
|
const matrixRef = useRef(null)
|
||||||
|
const scrollPositionRef = useRef(null)
|
||||||
|
if (scrollPositionRef.current === null) {
|
||||||
|
const storedScroll = readPermissionsMatrixSession().scroll
|
||||||
|
scrollPositionRef.current = {
|
||||||
|
left: Number(storedScroll?.left) || 0,
|
||||||
|
top: Number(storedScroll?.top) || 0
|
||||||
|
}
|
||||||
|
}
|
||||||
const hoveredColumnIndexRef = useRef(null)
|
const hoveredColumnIndexRef = useRef(null)
|
||||||
|
|
||||||
|
const persistExpandedRowKeys = useCallback((keys) => {
|
||||||
|
setExpandedRowKeys(keys)
|
||||||
|
writePermissionsMatrixSession({ expandedRowKeys: keys })
|
||||||
|
}, [])
|
||||||
|
|
||||||
const handleMatrixMouseOver = useCallback((event) => {
|
const handleMatrixMouseOver = useCallback((event) => {
|
||||||
const cell = event.target.closest('.ant-table-cell')
|
const cell = event.target.closest('.ant-table-cell')
|
||||||
if (!cell || !event.currentTarget.contains(cell)) return
|
if (!cell || !event.currentTarget.contains(cell)) return
|
||||||
@ -345,11 +388,44 @@ const PermissionsMatrix = ({
|
|||||||
event.currentTarget.style.removeProperty('--permissions-hovered-col')
|
event.currentTarget.style.removeProperty('--permissions-hovered-col')
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
const resolvedExpandedRowKeys = useMemo(
|
const resolvedExpandedRowKeys = useMemo(() => {
|
||||||
() => expandedRowKeys ?? dataSource.map((row) => row.key),
|
const sectionKeys = new Set(dataSource.map((row) => row.key))
|
||||||
[dataSource, expandedRowKeys]
|
return expandedRowKeys.filter((key) => sectionKeys.has(key))
|
||||||
|
}, [dataSource, expandedRowKeys])
|
||||||
|
|
||||||
|
const getTableBody = useCallback(
|
||||||
|
() => matrixRef.current?.querySelector('.ant-table-body') || null,
|
||||||
|
[]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const restoreTableScroll = useCallback(() => {
|
||||||
|
const body = getTableBody()
|
||||||
|
if (!body) return
|
||||||
|
body.scrollLeft = scrollPositionRef.current.left
|
||||||
|
body.scrollTop = scrollPositionRef.current.top
|
||||||
|
}, [getTableBody])
|
||||||
|
|
||||||
|
useLayoutEffect(() => {
|
||||||
|
restoreTableScroll()
|
||||||
|
}, [restoreTableScroll, resolvedExpandedRowKeys])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const body = getTableBody()
|
||||||
|
if (!body) return
|
||||||
|
|
||||||
|
const handleScroll = (event) => {
|
||||||
|
const next = {
|
||||||
|
left: event.currentTarget.scrollLeft,
|
||||||
|
top: event.currentTarget.scrollTop
|
||||||
|
}
|
||||||
|
scrollPositionRef.current = next
|
||||||
|
writePermissionsMatrixSession({ scroll: next })
|
||||||
|
}
|
||||||
|
|
||||||
|
body.addEventListener('scroll', handleScroll, { passive: true })
|
||||||
|
return () => body.removeEventListener('scroll', handleScroll)
|
||||||
|
}, [getTableBody, resolvedExpandedRowKeys])
|
||||||
|
|
||||||
const isSectionExpanded = useCallback(
|
const isSectionExpanded = useCallback(
|
||||||
(record) => resolvedExpandedRowKeys.includes(record.key),
|
(record) => resolvedExpandedRowKeys.includes(record.key),
|
||||||
[resolvedExpandedRowKeys]
|
[resolvedExpandedRowKeys]
|
||||||
@ -358,14 +434,20 @@ const PermissionsMatrix = ({
|
|||||||
const handleToggleSection = useCallback(
|
const handleToggleSection = useCallback(
|
||||||
(record) => {
|
(record) => {
|
||||||
if (!record.isGroup) return
|
if (!record.isGroup) return
|
||||||
setExpandedRowKeys((current) => {
|
persistExpandedRowKeys(
|
||||||
const keys = current ?? dataSource.map((row) => row.key)
|
expandedRowKeys.includes(record.key)
|
||||||
return keys.includes(record.key)
|
? expandedRowKeys.filter((key) => key !== record.key)
|
||||||
? keys.filter((key) => key !== record.key)
|
: [...expandedRowKeys, record.key]
|
||||||
: [...keys, record.key]
|
)
|
||||||
})
|
|
||||||
},
|
},
|
||||||
[dataSource]
|
[expandedRowKeys, persistExpandedRowKeys]
|
||||||
|
)
|
||||||
|
|
||||||
|
const handleExpandedRowsChange = useCallback(
|
||||||
|
(keys) => {
|
||||||
|
persistExpandedRowKeys(keys)
|
||||||
|
},
|
||||||
|
[persistExpandedRowKeys]
|
||||||
)
|
)
|
||||||
|
|
||||||
var adjustedScrollHeight = scrollHeight
|
var adjustedScrollHeight = scrollHeight
|
||||||
@ -627,6 +709,7 @@ const PermissionsMatrix = ({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
|
ref={matrixRef}
|
||||||
className='permissions-matrix'
|
className='permissions-matrix'
|
||||||
onMouseOver={handleMatrixMouseOver}
|
onMouseOver={handleMatrixMouseOver}
|
||||||
onMouseLeave={handleMatrixMouseLeave}
|
onMouseLeave={handleMatrixMouseLeave}
|
||||||
@ -645,7 +728,7 @@ const PermissionsMatrix = ({
|
|||||||
}
|
}
|
||||||
expandable={{
|
expandable={{
|
||||||
expandedRowKeys: resolvedExpandedRowKeys,
|
expandedRowKeys: resolvedExpandedRowKeys,
|
||||||
onExpandedRowsChange: setExpandedRowKeys,
|
onExpandedRowsChange: handleExpandedRowsChange,
|
||||||
indentSize: 0,
|
indentSize: 0,
|
||||||
expandIcon: () => null
|
expandIcon: () => null
|
||||||
}}
|
}}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user