185 lines
4.8 KiB
JavaScript
185 lines
4.8 KiB
JavaScript
import { createElement } from 'react'
|
|
import { Dropdown, Button } from 'antd'
|
|
import { getModelByName } from '../../../database/ObjectModels'
|
|
import PropTypes from 'prop-types'
|
|
import { useNavigate, useLocation } from 'react-router-dom'
|
|
import { useActionsModal } from '../context/ActionsModalContext'
|
|
import KeyboardShortcut from './KeyboardShortcut'
|
|
|
|
// Recursively filter actions based on visibleActions
|
|
function filterActionsByVisibility(actions, visibleActions) {
|
|
if (!visibleActions) return actions
|
|
|
|
return actions.filter((action) => {
|
|
if (action.type === 'divider') {
|
|
return true // Always show dividers
|
|
}
|
|
|
|
const actionKey = action.key || action.name
|
|
const isVisible = visibleActions[actionKey] !== false
|
|
|
|
// If this action has children, filter them recursively
|
|
if (action.children && Array.isArray(action.children)) {
|
|
const filteredChildren = filterActionsByVisibility(
|
|
action.children,
|
|
visibleActions
|
|
)
|
|
action.children = filteredChildren
|
|
// Show parent if it has visible children or if it's explicitly visible
|
|
return (
|
|
isVisible &&
|
|
(filteredChildren.length > 0 || visibleActions[actionKey] === true)
|
|
)
|
|
}
|
|
|
|
return isVisible
|
|
})
|
|
}
|
|
|
|
// Recursively map actions to AntD Dropdown items
|
|
function mapActionsToMenuItems(actions, currentUrlWithActions, id, objectData) {
|
|
return actions.map((action) => {
|
|
if (action.type === 'divider') {
|
|
return { type: 'divider' }
|
|
}
|
|
const actionUrl = action.url ? action.url(id) : undefined
|
|
|
|
var disabled = actionUrl && actionUrl === currentUrlWithActions
|
|
var visible = true
|
|
|
|
if (action.disabled) {
|
|
if (typeof action.disabled === 'function') {
|
|
disabled = action.disabled(objectData)
|
|
} else {
|
|
disabled = action.disabled
|
|
}
|
|
}
|
|
|
|
if (action.visible) {
|
|
if (typeof action.visible === 'function') {
|
|
visible = action.visible(objectData)
|
|
} else {
|
|
visible = action.visible
|
|
}
|
|
}
|
|
|
|
const item = {
|
|
key: action.key || action.name,
|
|
label: action.label,
|
|
danger: action?.danger || false,
|
|
icon: action.icon ? createElement(action.icon) : undefined,
|
|
disabled
|
|
}
|
|
if (action.children && Array.isArray(action.children)) {
|
|
item.children = mapActionsToMenuItems(
|
|
action.children,
|
|
currentUrlWithActions,
|
|
id,
|
|
objectData
|
|
)
|
|
}
|
|
if (visible == true) {
|
|
return item
|
|
}
|
|
})
|
|
}
|
|
|
|
const stripActionParam = (pathname, search) => {
|
|
const params = new URLSearchParams(search)
|
|
params.delete('action')
|
|
const query = params.toString()
|
|
return pathname + (query ? `?${query}` : '')
|
|
}
|
|
|
|
const ObjectActions = ({
|
|
type,
|
|
id,
|
|
objectData,
|
|
disabled = false,
|
|
buttonProps = {},
|
|
visibleActions = {},
|
|
...dropdownProps
|
|
}) => {
|
|
const model = getModelByName(type)
|
|
const actions = model.actions || []
|
|
const navigate = useNavigate()
|
|
const location = useLocation()
|
|
const { showActionsModal } = useActionsModal()
|
|
|
|
// Get current url without 'action' param
|
|
const currentUrlWithoutActions = stripActionParam(
|
|
location.pathname,
|
|
location.search
|
|
)
|
|
|
|
// First filter by visibility, then by current URL
|
|
const visibilityFilteredActions = filterActionsByVisibility(
|
|
actions,
|
|
visibleActions
|
|
)
|
|
|
|
const filteredActions = visibilityFilteredActions.filter(
|
|
(action) =>
|
|
typeof action.url !== 'function' ||
|
|
action.url(id) !== currentUrlWithoutActions
|
|
)
|
|
|
|
const currentUrlWithActions = location.pathname + location.search
|
|
|
|
// Compose AntD Dropdown menu items
|
|
const menu = {
|
|
items: mapActionsToMenuItems(
|
|
filteredActions,
|
|
currentUrlWithActions,
|
|
id,
|
|
objectData
|
|
),
|
|
onClick: (info) => {
|
|
// Find the action by key
|
|
const findAction = (acts, key) => {
|
|
for (const act of acts) {
|
|
if ((act.key || act.name) === key) return act
|
|
if (act.children) {
|
|
const found = findAction(act.children, key)
|
|
if (found) return found
|
|
}
|
|
}
|
|
return null
|
|
}
|
|
const action = findAction(filteredActions, info.key)
|
|
if (action && action.url) {
|
|
navigate(action.url(id))
|
|
}
|
|
}
|
|
}
|
|
|
|
return (
|
|
<KeyboardShortcut
|
|
shortcut='alt+a'
|
|
onTrigger={() => showActionsModal(id, type, objectData)}
|
|
>
|
|
<Dropdown menu={menu} {...dropdownProps}>
|
|
<Button
|
|
{...buttonProps}
|
|
disabled={disabled}
|
|
onClick={() => showActionsModal(id, type, objectData)}
|
|
>
|
|
Actions
|
|
</Button>
|
|
</Dropdown>
|
|
</KeyboardShortcut>
|
|
)
|
|
}
|
|
|
|
ObjectActions.propTypes = {
|
|
type: PropTypes.string.isRequired,
|
|
objectData: PropTypes.object.isRequired,
|
|
id: PropTypes.string.isRequired,
|
|
disabled: PropTypes.bool,
|
|
buttonProps: PropTypes.object,
|
|
buttonLabel: PropTypes.string,
|
|
visibleActions: PropTypes.object
|
|
}
|
|
|
|
export default ObjectActions
|