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 ( showActionsModal(id, type, objectData)} > ) } 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