@applica-software-guru/react-admin 1.0.35 → 1.0.37
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.prettierrc +4 -4
- package/dist/AdminContext.d.ts.map +1 -1
- package/dist/components/MainCard.d.ts.map +1 -1
- package/dist/components/index.d.ts +1 -0
- package/dist/components/index.d.ts.map +1 -1
- package/dist/components/ra-forms/LongForm/{DispositionProps.d.ts → types.d.ts} +10 -4
- package/dist/components/ra-forms/LongForm/types.d.ts.map +1 -0
- package/dist/components/ra-forms/LongForm/useFormRootPath.d.ts +3 -3
- package/dist/components/ra-forms/LongForm/useFormRootPath.d.ts.map +1 -1
- package/dist/components/ra-forms/SimpleFormIterator.d.ts +5 -0
- package/dist/components/ra-forms/SimpleFormIterator.d.ts.map +1 -0
- package/dist/components/ra-forms/index.d.ts +2 -1
- package/dist/components/ra-forms/index.d.ts.map +1 -1
- package/dist/components/ra-inputs/AttachmentInput.d.ts +4 -1
- package/dist/components/ra-inputs/AttachmentInput.d.ts.map +1 -1
- package/dist/components/ra-inputs/AutocompleteInput.d.ts +1 -3
- package/dist/components/ra-inputs/AutocompleteInput.d.ts.map +1 -1
- package/dist/components/ra-inputs/LabeledInput.d.ts +2 -1
- package/dist/components/ra-inputs/LabeledInput.d.ts.map +1 -1
- package/dist/components/ra-inputs/SmartTextInput.d.ts.map +1 -1
- package/dist/contexts/ThemeConfigContext.d.ts.map +1 -1
- package/dist/hooks/useAppConfig.d.ts +3 -0
- package/dist/hooks/useAppConfig.d.ts.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/react-admin.cjs.js +60 -57
- package/dist/react-admin.es.js +12795 -11451
- package/dist/react-admin.umd.js +60 -57
- package/dist/themes/overrides/Autocomplete.d.ts +4 -1
- package/dist/themes/overrides/Autocomplete.d.ts.map +1 -1
- package/package.json +1 -1
- package/playground/src/.prettierrc +8 -0
- package/playground/src/App.js +21 -21
- package/playground/src/components/pages/CustomPage.jsx +4 -4
- package/playground/src/components/pages/index.jsx +2 -2
- package/playground/src/components/ra-forms/DeviceForm.js +7 -14
- package/playground/src/components/ra-forms/UserForm.js +10 -24
- package/playground/src/components/ra-forms/index.js +4 -5
- package/playground/src/components/ra-lists/DeviceList.js +8 -16
- package/playground/src/components/ra-lists/UserList.js +17 -40
- package/playground/src/components/ra-lists/index.js +4 -4
- package/playground/src/contexts/index.js +1 -1
- package/playground/src/{resource → entities}/device.js +6 -6
- package/playground/src/{resource → entities}/i18n-message.js +1 -2
- package/playground/src/entities/index.js +4 -0
- package/playground/src/{resource → entities}/notification.js +0 -2
- package/playground/src/menu.js +18 -9
- package/playground/src/theme.js +10 -2
- package/react-admin.code-workspace +9 -0
- package/src/AdminContext.jsx +3 -5
- package/src/components/ActionsMenu.tsx +91 -0
- package/src/components/MainCard.jsx +29 -32
- package/src/components/index.jsx +21 -33
- package/src/components/ra-buttons/CreateInDialogButton.tsx +261 -0
- package/src/components/ra-custom/ListItem.tsx +147 -0
- package/src/components/ra-custom/index.tsx +2 -0
- package/src/components/ra-fields/AttachmentField.tsx +88 -0
- package/src/components/ra-fields/BaseAttachmentField.tsx +82 -0
- package/src/components/ra-forms/FormHeader.tsx +63 -0
- package/src/components/ra-forms/LongForm/LongForm.tsx +56 -0
- package/src/components/ra-forms/LongForm/LongFormSidebar.tsx +44 -0
- package/src/components/ra-forms/LongForm/{LongFormTab.jsx → LongFormTab.tsx} +47 -46
- package/src/components/ra-forms/LongForm/LongFormTabs.tsx +73 -0
- package/src/components/ra-forms/LongForm/LongFormView.tsx +129 -0
- package/{dist/components/ra-forms/LongForm/index.d.ts → src/components/ra-forms/LongForm/index.tsx} +1 -2
- package/src/components/ra-forms/LongForm/types.ts +15 -0
- package/src/components/ra-forms/LongForm/useFormRootPath.ts +26 -0
- package/src/components/ra-forms/SimpleFormIterator.jsx +14 -0
- package/src/components/ra-forms/index.jsx +2 -1
- package/src/components/ra-inputs/AttachmentInput.jsx +42 -25
- package/src/components/ra-inputs/AutocompleteInput.jsx +10 -5
- package/src/components/ra-inputs/LabeledInput.jsx +27 -32
- package/src/components/ra-inputs/SelectInput.jsx +11 -11
- package/src/components/ra-inputs/SmartTextInput.jsx +22 -26
- package/src/components/ra-inputs/TextInput.jsx +9 -9
- package/src/contexts/AppConfigContext.tsx +67 -0
- package/src/contexts/ThemeConfigContext.jsx +25 -29
- package/src/index.jsx +10 -8
- package/src/themes/overrides/Autocomplete.jsx +4 -1
- package/src/themes/overrides/index.jsx +1 -1
- package/src/utils/index.js +2 -2
- package/src/utils/lang.js +7 -7
- package/src/utils/time.js +7 -7
- package/dist/components/ActionsMenu.d.ts +0 -15
- package/dist/components/ActionsMenu.d.ts.map +0 -1
- package/dist/components/ra-buttons/CreateInDialogButton.d.ts +0 -37
- package/dist/components/ra-buttons/CreateInDialogButton.d.ts.map +0 -1
- package/dist/components/ra-fields/AttachmentField.d.ts +0 -28
- package/dist/components/ra-fields/AttachmentField.d.ts.map +0 -1
- package/dist/components/ra-fields/BaseAttachmentField.d.ts +0 -17
- package/dist/components/ra-fields/BaseAttachmentField.d.ts.map +0 -1
- package/dist/components/ra-forms/FormHeader.d.ts +0 -17
- package/dist/components/ra-forms/FormHeader.d.ts.map +0 -1
- package/dist/components/ra-forms/LongForm/DispositionProps.d.ts.map +0 -1
- package/dist/components/ra-forms/LongForm/LongForm.d.ts +0 -45
- package/dist/components/ra-forms/LongForm/LongForm.d.ts.map +0 -1
- package/dist/components/ra-forms/LongForm/LongFormHeader.d.ts +0 -20
- package/dist/components/ra-forms/LongForm/LongFormHeader.d.ts.map +0 -1
- package/dist/components/ra-forms/LongForm/LongFormTab.d.ts +0 -43
- package/dist/components/ra-forms/LongForm/LongFormTab.d.ts.map +0 -1
- package/dist/components/ra-forms/LongForm/LongFormTabs.d.ts +0 -21
- package/dist/components/ra-forms/LongForm/LongFormTabs.d.ts.map +0 -1
- package/dist/components/ra-forms/LongForm/LongFormView.d.ts +0 -29
- package/dist/components/ra-forms/LongForm/LongFormView.d.ts.map +0 -1
- package/dist/components/ra-forms/LongForm/index.d.ts.map +0 -1
- package/dist/contexts/AppConfigContext.d.ts +0 -22
- package/dist/contexts/AppConfigContext.d.ts.map +0 -1
- package/playground/src/resource/index.js +0 -4
- package/src/components/ActionsMenu.jsx +0 -77
- package/src/components/ra-buttons/CreateInDialogButton.jsx +0 -203
- package/src/components/ra-fields/AttachmentField.jsx +0 -82
- package/src/components/ra-fields/BaseAttachmentField.jsx +0 -72
- package/src/components/ra-forms/FormHeader.jsx +0 -42
- package/src/components/ra-forms/LongForm/DispositionProps.jsx +0 -10
- package/src/components/ra-forms/LongForm/LongForm.jsx +0 -38
- package/src/components/ra-forms/LongForm/LongFormHeader.jsx +0 -24
- package/src/components/ra-forms/LongForm/LongFormTabs.jsx +0 -63
- package/src/components/ra-forms/LongForm/LongFormView.jsx +0 -129
- package/src/components/ra-forms/LongForm/index.jsx +0 -2
- package/src/components/ra-forms/LongForm/useFormRootPath.jsx +0 -22
- package/src/contexts/AppConfigContext.jsx +0 -54
- /package/playground/src/{resource → entities}/user.js +0 -0
|
@@ -1,82 +0,0 @@
|
|
|
1
|
-
import { Box, Typography } from '@mui/material'
|
|
2
|
-
import {
|
|
3
|
-
FileField as RaFileField,
|
|
4
|
-
useDataProvider,
|
|
5
|
-
useRecordContext,
|
|
6
|
-
useResourceContext,
|
|
7
|
-
useTranslate
|
|
8
|
-
} from 'react-admin'
|
|
9
|
-
import { useCallback, useEffect, useMemo, useState } from 'react'
|
|
10
|
-
|
|
11
|
-
import BaseAttachmentField from './BaseAttachmentField'
|
|
12
|
-
import PropTypes from 'prop-types'
|
|
13
|
-
import dayjs from 'dayjs'
|
|
14
|
-
import { get } from 'lodash'
|
|
15
|
-
|
|
16
|
-
const AttachmentField = ({ entityId, property, ...props }) => {
|
|
17
|
-
const [user, setUser] = useState(null)
|
|
18
|
-
const record = useRecordContext(props)
|
|
19
|
-
const dataProvider = useDataProvider()
|
|
20
|
-
const resource = useResourceContext()
|
|
21
|
-
const handleClick = useCallback(
|
|
22
|
-
async (e) => {
|
|
23
|
-
e.preventDefault()
|
|
24
|
-
e.stopPropagation()
|
|
25
|
-
const item = get(record, props?.source)
|
|
26
|
-
const entity = resource.replace('entities/', '')
|
|
27
|
-
const attachment = await dataProvider.getFile(
|
|
28
|
-
`/attachments/${entity}/${entityId || record?.id}/${property || props?.source}/${
|
|
29
|
-
item?.id || record?.id
|
|
30
|
-
}`
|
|
31
|
-
)
|
|
32
|
-
const link = document.createElement('a')
|
|
33
|
-
link.href = attachment
|
|
34
|
-
link.download = get(record, props?.title || props?.source)
|
|
35
|
-
link.click()
|
|
36
|
-
},
|
|
37
|
-
[dataProvider, record, entityId, resource, property, props?.source, props?.title]
|
|
38
|
-
)
|
|
39
|
-
const _record = useMemo(
|
|
40
|
-
() => ({
|
|
41
|
-
...record,
|
|
42
|
-
[props?.source]: record?.src || get(record, props?.source),
|
|
43
|
-
[props?.title]: record?.title || get(record, props?.title || props?.source)
|
|
44
|
-
}),
|
|
45
|
-
[record, props?.source, props?.title]
|
|
46
|
-
)
|
|
47
|
-
const translate = useTranslate()
|
|
48
|
-
useEffect(() => {
|
|
49
|
-
if (!record || !record?.userId) return
|
|
50
|
-
dataProvider.getOne('entities/user', { id: record?.userId }).then(({ data }) => setUser(data))
|
|
51
|
-
}, [record, dataProvider])
|
|
52
|
-
|
|
53
|
-
return (
|
|
54
|
-
<BaseAttachmentField
|
|
55
|
-
{...props}
|
|
56
|
-
record={_record}
|
|
57
|
-
onClick={handleClick}
|
|
58
|
-
title={
|
|
59
|
-
<Box sx={{ cursor: 'pointer' }}>
|
|
60
|
-
<Typography variant="subtitle1">{get(_record, props?.title || props?.source)}</Typography>
|
|
61
|
-
<Typography variant="caption" color="secondary">
|
|
62
|
-
{get(_record, 'sizeDescription')}
|
|
63
|
-
{user && ` | `}
|
|
64
|
-
{user &&
|
|
65
|
-
translate('ra.attachment.info', {
|
|
66
|
-
user: user?.name,
|
|
67
|
-
created: dayjs(_record?.createdAt).format('DD/MM/YYYY HH:mm')
|
|
68
|
-
})}
|
|
69
|
-
</Typography>
|
|
70
|
-
</Box>
|
|
71
|
-
}
|
|
72
|
-
/>
|
|
73
|
-
)
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
AttachmentField.propTypes = {
|
|
77
|
-
...RaFileField.propTypes,
|
|
78
|
-
source: PropTypes.string,
|
|
79
|
-
title: PropTypes.string
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
export default AttachmentField
|
|
@@ -1,72 +0,0 @@
|
|
|
1
|
-
import * as React from 'react'
|
|
2
|
-
|
|
3
|
-
import { useRecordContext, useTranslate } from 'ra-core'
|
|
4
|
-
|
|
5
|
-
import PropTypes from 'prop-types'
|
|
6
|
-
import Typography from '@mui/material/Typography'
|
|
7
|
-
import get from 'lodash/get'
|
|
8
|
-
import { styled } from '@mui/material/styles'
|
|
9
|
-
|
|
10
|
-
export const BaseAttachmentField = (props) => {
|
|
11
|
-
const { className, emptyText, source, title, ...rest } = props
|
|
12
|
-
const record = useRecordContext(props)
|
|
13
|
-
const sourceValue = get(record, source)
|
|
14
|
-
const translate = useTranslate()
|
|
15
|
-
|
|
16
|
-
if (!sourceValue) {
|
|
17
|
-
return emptyText ? (
|
|
18
|
-
<Typography component="span" variant="body2" className={className} {...rest}>
|
|
19
|
-
{emptyText && translate(emptyText, { _: emptyText })}
|
|
20
|
-
</Typography>
|
|
21
|
-
) : (
|
|
22
|
-
<Root className={className} {...rest} />
|
|
23
|
-
)
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
if (Array.isArray(sourceValue)) {
|
|
27
|
-
return (
|
|
28
|
-
<StyledList className={className} {...rest}>
|
|
29
|
-
{sourceValue.map((file, index) => {
|
|
30
|
-
const fileTitleValue = get(file, title) || title
|
|
31
|
-
|
|
32
|
-
return <li key={index}>{fileTitleValue}</li>
|
|
33
|
-
})}
|
|
34
|
-
</StyledList>
|
|
35
|
-
)
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
const titleValue = get(record, title) || title
|
|
39
|
-
|
|
40
|
-
return (
|
|
41
|
-
<Root className={className} {...rest}>
|
|
42
|
-
{titleValue}
|
|
43
|
-
</Root>
|
|
44
|
-
)
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
BaseAttachmentField.propTypes = {
|
|
48
|
-
src: PropTypes.string,
|
|
49
|
-
title: PropTypes.oneOfType([PropTypes.string, PropTypes.func, PropTypes.element]),
|
|
50
|
-
target: PropTypes.string,
|
|
51
|
-
download: PropTypes.oneOfType([PropTypes.bool, PropTypes.string]),
|
|
52
|
-
ping: PropTypes.string,
|
|
53
|
-
rel: PropTypes.string,
|
|
54
|
-
emptyText: PropTypes.string,
|
|
55
|
-
source: PropTypes.string.isRequired,
|
|
56
|
-
className: PropTypes.string,
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
const PREFIX = 'RaApplicaBaseAttachmentField'
|
|
60
|
-
|
|
61
|
-
const Root = styled('div', {
|
|
62
|
-
name: PREFIX,
|
|
63
|
-
overridesResolver: (props, styles) => styles.root,
|
|
64
|
-
})({
|
|
65
|
-
display: 'inline-block',
|
|
66
|
-
})
|
|
67
|
-
|
|
68
|
-
const StyledList = styled('ul')({
|
|
69
|
-
display: 'inline-block',
|
|
70
|
-
})
|
|
71
|
-
|
|
72
|
-
export default BaseAttachmentField
|
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
import { CardHeader, Divider } from '@mui/material'
|
|
2
|
-
|
|
3
|
-
import { Fragment } from 'react'
|
|
4
|
-
import PropTypes from 'prop-types'
|
|
5
|
-
import { styled } from '@mui/material/styles'
|
|
6
|
-
import { useTranslate } from 'react-admin'
|
|
7
|
-
|
|
8
|
-
const StyledCardHeader = styled(CardHeader)(({ theme }) => ({
|
|
9
|
-
marginTop: theme.spacing(4),
|
|
10
|
-
marginLeft: 0,
|
|
11
|
-
marginRight: 0,
|
|
12
|
-
paddingLeft: 0,
|
|
13
|
-
paddingRight: 0,
|
|
14
|
-
}))
|
|
15
|
-
|
|
16
|
-
const StyledDivider = styled(Divider)(({ theme }) => ({
|
|
17
|
-
marginLeft: `-${theme.spacing(2.5)}`,
|
|
18
|
-
marginRight: `-${theme.spacing(2.5)}`,
|
|
19
|
-
marginBottom: theme.spacing(2),
|
|
20
|
-
width: `calc(100% + ${theme.spacing(5)})`,
|
|
21
|
-
}))
|
|
22
|
-
|
|
23
|
-
const FormHeader = ({ title, divider }) => {
|
|
24
|
-
const translate = useTranslate()
|
|
25
|
-
return (
|
|
26
|
-
<Fragment>
|
|
27
|
-
<StyledCardHeader title={translate(title, { _: title })} />
|
|
28
|
-
{divider && <StyledDivider />}
|
|
29
|
-
</Fragment>
|
|
30
|
-
)
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
FormHeader.propTypes = {
|
|
34
|
-
title: PropTypes.string.isRequired,
|
|
35
|
-
divider: PropTypes.bool,
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
FormHeader.defaultProps = {
|
|
39
|
-
divider: true,
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
export default FormHeader
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
import DispositionProps from './DispositionProps'
|
|
2
|
-
import { Form } from 'react-admin'
|
|
3
|
-
import LongFormTab from './LongFormTab'
|
|
4
|
-
import LongFormTabHeader from './LongFormHeader'
|
|
5
|
-
import LongFormView from './LongFormView'
|
|
6
|
-
import PropTypes from 'prop-types'
|
|
7
|
-
import useFormRootPath from './useFormRootPath'
|
|
8
|
-
import { useThemeConfig } from '../../../hooks'
|
|
9
|
-
|
|
10
|
-
const LongForm = ({ spacing: _spacing, ...props }) => {
|
|
11
|
-
const formRootPathname = useFormRootPath()
|
|
12
|
-
const { spacing: _themeSpacing } = useThemeConfig()
|
|
13
|
-
const spacing = _spacing || _themeSpacing
|
|
14
|
-
return (
|
|
15
|
-
<Form formRootPathname={formRootPathname} {...props}>
|
|
16
|
-
<LongFormView formRootPathname={formRootPathname} {...props} spacing={spacing} />
|
|
17
|
-
</Form>
|
|
18
|
-
)
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
LongForm.propTypes = {
|
|
22
|
-
syncWithLocation: PropTypes.bool,
|
|
23
|
-
spacing: PropTypes.number,
|
|
24
|
-
tabsDisposition: DispositionProps,
|
|
25
|
-
contentDisposition: DispositionProps,
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
LongForm.defaultProps = {
|
|
29
|
-
syncWithLocation: false,
|
|
30
|
-
spacing: 2,
|
|
31
|
-
tabsDisposition: { xl: 3, lg: 3, md: 4, sm: 4, xs: 12 },
|
|
32
|
-
contentDisposition: { xl: 9, lg: 9, md: 8, sm: 8, xs: 12 },
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
LongForm.Tab = LongFormTab
|
|
36
|
-
LongForm.Header = LongFormTabHeader
|
|
37
|
-
|
|
38
|
-
export default LongForm
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import PropTypes from 'prop-types'
|
|
2
|
-
import { styled } from '@mui/material/styles'
|
|
3
|
-
import { useMediaQuery } from '@mui/material'
|
|
4
|
-
const StyledSidebar = styled('div')(({ theme }) => ({
|
|
5
|
-
marginBottom: theme.spacing(2),
|
|
6
|
-
}))
|
|
7
|
-
|
|
8
|
-
const LongFormTabHeader = ({ children, visibility }) => {
|
|
9
|
-
const isVisible = useMediaQuery((theme) => theme.breakpoints.up(visibility))
|
|
10
|
-
return isVisible ? <StyledSidebar>{children}</StyledSidebar> : null
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
LongFormTabHeader.propTypes = {
|
|
14
|
-
visibility: PropTypes.oneOf(['xl', 'lg', 'md', 'sm', 'xs']),
|
|
15
|
-
position: PropTypes.oneOf(['top', 'bottom']).isRequired,
|
|
16
|
-
children: PropTypes.node.isRequired,
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
LongFormTabHeader.defaultProps = {
|
|
20
|
-
position: 'top',
|
|
21
|
-
visibility: 'md',
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
export default LongFormTabHeader
|
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
import { matchPath, useLocation } from 'react-router'
|
|
2
|
-
|
|
3
|
-
import { List } from '@mui/material'
|
|
4
|
-
import MainCard from '../../MainCard'
|
|
5
|
-
import PropTypes from 'prop-types'
|
|
6
|
-
import React from 'react'
|
|
7
|
-
import { styled } from '@mui/system'
|
|
8
|
-
|
|
9
|
-
const StyledList = styled(List, {
|
|
10
|
-
name: 'RaLongFormTabs',
|
|
11
|
-
slot: 'Root',
|
|
12
|
-
})(({ theme }) => ({
|
|
13
|
-
p: 0,
|
|
14
|
-
|
|
15
|
-
'& .MuiListItemIcon-root': {
|
|
16
|
-
minWidth: 32,
|
|
17
|
-
color: theme.palette.grey[500],
|
|
18
|
-
},
|
|
19
|
-
'& .MuiListItemButton-root.Mui-selected': {
|
|
20
|
-
borderRight: `2px solid ${theme.palette.primary.main}`,
|
|
21
|
-
marginRight: `-2px`,
|
|
22
|
-
},
|
|
23
|
-
}))
|
|
24
|
-
|
|
25
|
-
const LongFormTabs = ({ children, syncWithLocation, value, url, onChange }) => {
|
|
26
|
-
const location = useLocation()
|
|
27
|
-
return (
|
|
28
|
-
<MainCard>
|
|
29
|
-
<StyledList component="nav">
|
|
30
|
-
{React.Children.map(children, (tab, index) => {
|
|
31
|
-
if (!React.isValidElement(tab)) return null
|
|
32
|
-
const tabPath = getTabbedFormTabFullPath(tab, index)
|
|
33
|
-
const selected = syncWithLocation
|
|
34
|
-
? !!matchPath(`${url}/${tabPath}`, location.pathname)
|
|
35
|
-
: index === value
|
|
36
|
-
|
|
37
|
-
return React.cloneElement(tab, {
|
|
38
|
-
intent: 'header',
|
|
39
|
-
value: syncWithLocation ? tabPath : index,
|
|
40
|
-
syncWithLocation,
|
|
41
|
-
onChange,
|
|
42
|
-
url,
|
|
43
|
-
selected,
|
|
44
|
-
})
|
|
45
|
-
})}
|
|
46
|
-
</StyledList>
|
|
47
|
-
</MainCard>
|
|
48
|
-
)
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
export const getTabbedFormTabFullPath = (tab, index) =>
|
|
52
|
-
tab.props.path != null ? tab.props.path : index > 0 ? index.toString() : ''
|
|
53
|
-
|
|
54
|
-
LongFormTabs.propTypes = {
|
|
55
|
-
children: PropTypes.node,
|
|
56
|
-
url: PropTypes.string,
|
|
57
|
-
tabsWithErrors: PropTypes.arrayOf(PropTypes.string),
|
|
58
|
-
syncWithLocation: PropTypes.bool,
|
|
59
|
-
onChange: PropTypes.func,
|
|
60
|
-
value: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
export default LongFormTabs
|
|
@@ -1,129 +0,0 @@
|
|
|
1
|
-
import React, { useMemo, useState } from 'react'
|
|
2
|
-
import { Route, Routes, matchPath, useLocation, useResolvedPath } from 'react-router'
|
|
3
|
-
import { getTabbedFormTabFullPath, useResourceContext } from 'react-admin'
|
|
4
|
-
|
|
5
|
-
import DispositionProps from './DispositionProps'
|
|
6
|
-
import { Grid } from '@mui/material'
|
|
7
|
-
import LongFormCard from './LongFormHeader'
|
|
8
|
-
import LongFormTab from './LongFormTab'
|
|
9
|
-
import LongFormTabs from './LongFormTabs'
|
|
10
|
-
import PropTypes from 'prop-types'
|
|
11
|
-
import { styled } from '@mui/material/styles'
|
|
12
|
-
|
|
13
|
-
const StyledGrid = styled(Grid, {
|
|
14
|
-
name: 'RaLongFormView',
|
|
15
|
-
slot: 'Root',
|
|
16
|
-
})(({ theme }) => ({
|
|
17
|
-
'& .MuiToolbar-root': {
|
|
18
|
-
marginTop: theme.spacing(2),
|
|
19
|
-
marginLeft: `-${theme.spacing(3)}`,
|
|
20
|
-
marginRight: `-${theme.spacing(3)}`,
|
|
21
|
-
marginBottom: `-${theme.spacing(2)}`,
|
|
22
|
-
borderTop: `1px solid ${theme.palette.divider}`,
|
|
23
|
-
},
|
|
24
|
-
}))
|
|
25
|
-
|
|
26
|
-
const isSidebar = (child, position) =>
|
|
27
|
-
child && child.type === LongFormCard && child.props.position === position
|
|
28
|
-
const isTab = (child) => child && child.type === LongFormTab
|
|
29
|
-
|
|
30
|
-
const LongFormView = ({
|
|
31
|
-
children,
|
|
32
|
-
formRootPathname,
|
|
33
|
-
syncWithLocation,
|
|
34
|
-
spacing,
|
|
35
|
-
tabs,
|
|
36
|
-
tabsDisposition,
|
|
37
|
-
contentDisposition,
|
|
38
|
-
...props
|
|
39
|
-
}) => {
|
|
40
|
-
const [tabValue, setTabValue] = useState(0)
|
|
41
|
-
const resolvedPath = useResolvedPath('')
|
|
42
|
-
const resource = useResourceContext(props)
|
|
43
|
-
const location = useLocation()
|
|
44
|
-
const topSidebars = useMemo(
|
|
45
|
-
() => React.Children.toArray(children).find((child) => isSidebar(child, 'top')),
|
|
46
|
-
[children],
|
|
47
|
-
)
|
|
48
|
-
const bottomSidebars = useMemo(
|
|
49
|
-
() => React.Children.toArray(children).find((child) => isSidebar(child, 'bottom')),
|
|
50
|
-
[children],
|
|
51
|
-
)
|
|
52
|
-
const tabChildrens = useMemo(
|
|
53
|
-
() => React.Children.toArray(children).filter((child) => isTab(child)),
|
|
54
|
-
[children],
|
|
55
|
-
)
|
|
56
|
-
|
|
57
|
-
const handleTabChange = (value) => {
|
|
58
|
-
if (!syncWithLocation) {
|
|
59
|
-
setTabValue(value)
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
const renderTabs = () =>
|
|
63
|
-
React.cloneElement(
|
|
64
|
-
tabs,
|
|
65
|
-
{
|
|
66
|
-
onChange: handleTabChange,
|
|
67
|
-
syncWithLocation,
|
|
68
|
-
url: formRootPathname,
|
|
69
|
-
value: tabValue,
|
|
70
|
-
intent: 'header',
|
|
71
|
-
},
|
|
72
|
-
tabChildrens,
|
|
73
|
-
)
|
|
74
|
-
return (
|
|
75
|
-
<StyledGrid container spacing={spacing * 2}>
|
|
76
|
-
<Grid item {...tabsDisposition}>
|
|
77
|
-
{topSidebars}
|
|
78
|
-
{syncWithLocation ? (
|
|
79
|
-
<Routes>
|
|
80
|
-
<Route path="/*" element={renderTabs()} />
|
|
81
|
-
</Routes>
|
|
82
|
-
) : (
|
|
83
|
-
renderTabs()
|
|
84
|
-
)}
|
|
85
|
-
{bottomSidebars}
|
|
86
|
-
</Grid>
|
|
87
|
-
<Grid item {...contentDisposition}>
|
|
88
|
-
{/* All tabs are rendered (not only the one in focus), to allow validation
|
|
89
|
-
on tabs not in focus. The tabs receive a `hidden` property, which they'll
|
|
90
|
-
use to hide the tab using CSS if it's not the one in focus.
|
|
91
|
-
See https://github.com/marmelab/react-admin/issues/1866 */}
|
|
92
|
-
{React.Children.map(tabChildrens, (tab, index) => {
|
|
93
|
-
if (!tab) {
|
|
94
|
-
return null
|
|
95
|
-
}
|
|
96
|
-
const tabPath = getTabbedFormTabFullPath(tab, index)
|
|
97
|
-
const hidden = syncWithLocation
|
|
98
|
-
? !matchPath(`${resolvedPath.pathname}/${tabPath}`, location.pathname)
|
|
99
|
-
: tabValue !== index
|
|
100
|
-
|
|
101
|
-
return React.isValidElement(tab)
|
|
102
|
-
? React.cloneElement(tab, {
|
|
103
|
-
intent: 'content',
|
|
104
|
-
resource,
|
|
105
|
-
hidden,
|
|
106
|
-
value: syncWithLocation ? tabPath : index,
|
|
107
|
-
})
|
|
108
|
-
: null
|
|
109
|
-
})}
|
|
110
|
-
</Grid>
|
|
111
|
-
</StyledGrid>
|
|
112
|
-
)
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
LongFormView.propTypes = {
|
|
116
|
-
children: PropTypes.node,
|
|
117
|
-
spacing: PropTypes.number,
|
|
118
|
-
syncWithLocation: PropTypes.bool,
|
|
119
|
-
tabs: PropTypes.element,
|
|
120
|
-
formRootPathname: PropTypes.string,
|
|
121
|
-
tabsDisposition: DispositionProps,
|
|
122
|
-
contentDisposition: DispositionProps,
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
LongFormView.defaultProps = {
|
|
126
|
-
tabs: <LongFormTabs />,
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
export default LongFormView
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
import { matchPath, useLocation } from 'react-router-dom'
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* This hook infers the tabbed form root path from the current location.
|
|
5
|
-
*/
|
|
6
|
-
const useFormRootPath = () => {
|
|
7
|
-
const location = useLocation()
|
|
8
|
-
const createMatch = matchPath(':resource/create/*', location.pathname)
|
|
9
|
-
const editMatch = matchPath(':resource/:id/*', location.pathname)
|
|
10
|
-
|
|
11
|
-
if (createMatch) {
|
|
12
|
-
return createMatch.pathnameBase
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
if (editMatch) {
|
|
16
|
-
return editMatch.pathnameBase
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
return ''
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
export default useFormRootPath
|
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
import React, { createContext, useState } from 'react'
|
|
2
|
-
|
|
3
|
-
import PropTypes from 'prop-types'
|
|
4
|
-
|
|
5
|
-
const initialState = {
|
|
6
|
-
/**
|
|
7
|
-
* This context is necessary to work with react-admin standard forms when executed
|
|
8
|
-
* inside a dialog and deeper in another resource handled inside a primary form.
|
|
9
|
-
*
|
|
10
|
-
* In this case, when using "EditInDialogButton" or "CreateInDialogButton" components,
|
|
11
|
-
* the dialog is opened and the form is rendered inside it. If the form has a subform
|
|
12
|
-
* and needs to know the associated resource.
|
|
13
|
-
*/
|
|
14
|
-
openDialogs: [],
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
const AppConfigContext = createContext(initialState)
|
|
18
|
-
|
|
19
|
-
const AppConfigProvider = ({ children }) => {
|
|
20
|
-
const [config, setConfig] = useState(initialState)
|
|
21
|
-
const openDialog = (id, callback) => {
|
|
22
|
-
setConfig((config) => ({ ...config, openDialogs: [...config.openDialogs, id] }))
|
|
23
|
-
if (callback) callback()
|
|
24
|
-
}
|
|
25
|
-
const closeDialog = (id, callback) => {
|
|
26
|
-
setConfig((config) => ({
|
|
27
|
-
...config,
|
|
28
|
-
openDialogs: config.openDialogs.filter((modalId) => modalId !== id),
|
|
29
|
-
}))
|
|
30
|
-
if (callback) callback()
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
const getCurrentDialog = () =>
|
|
34
|
-
config.openDialogs.length > 0 ? config.openDialogs[config.openDialogs.length - 1] : null
|
|
35
|
-
|
|
36
|
-
return (
|
|
37
|
-
<AppConfigContext.Provider
|
|
38
|
-
value={{
|
|
39
|
-
...config,
|
|
40
|
-
openDialog,
|
|
41
|
-
closeDialog,
|
|
42
|
-
getCurrentDialog,
|
|
43
|
-
}}
|
|
44
|
-
>
|
|
45
|
-
{children}
|
|
46
|
-
</AppConfigContext.Provider>
|
|
47
|
-
)
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
AppConfigProvider.propTypes = {
|
|
51
|
-
children: PropTypes.node,
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
export { AppConfigProvider, AppConfigContext }
|
|
File without changes
|