Source

adminjs/src/frontend/components/app/action-header/action-header.tsx

  1. /* eslint-disable jsx-a11y/anchor-is-valid */
  2. import React from 'react'
  3. import { Box, Badge, H3, H2, ButtonGroup, cssClass } from '@adminjs/design-system'
  4. import { useHistory } from 'react-router'
  5. import Breadcrumbs from '../breadcrumbs'
  6. import { ActionHeaderProps } from './action-header-props'
  7. import { actionsToButtonGroup } from './actions-to-button-group'
  8. import { StyledBackButton } from './styled-back-button'
  9. import { useActionResponseHandler, useTranslation } from '../../../hooks'
  10. import { ActionJSON, buildActionClickHandler } from '../../../interfaces/action'
  11. /**
  12. * Header of an action. It renders Action name with buttons for all the actions.
  13. *
  14. * ### Usage
  15. *
  16. * ```
  17. * import { ActionHeader } from 'adminjs'
  18. * ```
  19. *
  20. * @component
  21. * @subcategory Application
  22. */
  23. export const ActionHeader: React.FC<ActionHeaderProps> = (props) => {
  24. const {
  25. resource, toggleFilter, actionPerformed, record, action, tag, omitActions,
  26. } = props
  27. const { translateButton } = useTranslation()
  28. const history = useHistory()
  29. const actionResponseHandler = useActionResponseHandler(actionPerformed)
  30. if (action.hideActionHeader) {
  31. return null
  32. }
  33. const resourceId = resource.id
  34. const params = { resourceId, recordId: record?.id }
  35. const handleActionClick = (event, sourceAction: ActionJSON): any | Promise<any> => (
  36. buildActionClickHandler({
  37. action: sourceAction,
  38. params,
  39. actionResponseHandler,
  40. push: history.push,
  41. })(event)
  42. )
  43. const actionButtons = actionsToButtonGroup({
  44. actions: record
  45. ? record.recordActions.filter(ra => !action || action.name !== ra.name)
  46. // only new action should be seen in regular "Big" actions place
  47. : resource.resourceActions.filter(ra => ra.name === 'new' && (!action || action.name !== ra.name)),
  48. params,
  49. handleClick: handleActionClick,
  50. })
  51. if (toggleFilter) {
  52. actionButtons.push({
  53. label: translateButton('filter', resource.id),
  54. onClick: toggleFilter,
  55. icon: 'SettingsAdjust',
  56. })
  57. }
  58. // list and new actions are special and are are always
  59. const customResourceButtons = actionsToButtonGroup({
  60. actions: action.showResourceActions
  61. ? resource.resourceActions.filter(ra => !['list', 'new'].includes(ra.name))
  62. : [],
  63. params: { resourceId },
  64. handleClick: handleActionClick,
  65. })
  66. const title = action ? action.label : resource.name
  67. const isList = action && action.name === 'list'
  68. const listAction = resource.resourceActions.find(ra => ra.name === 'list')
  69. // styled which differs if action header is in the drawer or not
  70. const cssIsRootFlex = !action.showInDrawer
  71. const cssHeaderMT = action.showInDrawer ? '' : 'lg'
  72. const cssActionsMB = action.showInDrawer ? 'xl' : 'default'
  73. const CssHComponent = action.showInDrawer ? H3 : H2
  74. return (
  75. <Box className={cssClass('ActionHeader')}>
  76. {action.showInDrawer ? '' : (
  77. <Box flex flexDirection="row" px={['default', 0]}>
  78. <Breadcrumbs resource={resource} actionName={action.name} record={record} />
  79. <Box flexShrink={0}>
  80. <ButtonGroup size="sm" rounded buttons={customResourceButtons} />
  81. </Box>
  82. </Box>
  83. )}
  84. <Box display={['block', cssIsRootFlex ? 'flex' : 'block']}>
  85. <Box mt={cssHeaderMT} flexGrow={1} px={['default', 0]}>
  86. <CssHComponent mb="lg">
  87. {!isList && listAction ? (
  88. <StyledBackButton resourceId={resourceId} showInDrawer={action.showInDrawer} />
  89. ) : ''}
  90. {title}
  91. {tag ? (<Badge variant="primary" ml="default">{tag}</Badge>) : ''}
  92. </CssHComponent>
  93. </Box>
  94. {omitActions ? '' : (
  95. <Box mt="xl" mb={cssActionsMB} flexShrink={0}>
  96. <ButtonGroup buttons={actionButtons} />
  97. </Box>
  98. )}
  99. </Box>
  100. </Box>
  101. )
  102. }
  103. export default ActionHeader