@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.
Files changed (121) hide show
  1. package/.prettierrc +4 -4
  2. package/dist/AdminContext.d.ts.map +1 -1
  3. package/dist/components/MainCard.d.ts.map +1 -1
  4. package/dist/components/index.d.ts +1 -0
  5. package/dist/components/index.d.ts.map +1 -1
  6. package/dist/components/ra-forms/LongForm/{DispositionProps.d.ts → types.d.ts} +10 -4
  7. package/dist/components/ra-forms/LongForm/types.d.ts.map +1 -0
  8. package/dist/components/ra-forms/LongForm/useFormRootPath.d.ts +3 -3
  9. package/dist/components/ra-forms/LongForm/useFormRootPath.d.ts.map +1 -1
  10. package/dist/components/ra-forms/SimpleFormIterator.d.ts +5 -0
  11. package/dist/components/ra-forms/SimpleFormIterator.d.ts.map +1 -0
  12. package/dist/components/ra-forms/index.d.ts +2 -1
  13. package/dist/components/ra-forms/index.d.ts.map +1 -1
  14. package/dist/components/ra-inputs/AttachmentInput.d.ts +4 -1
  15. package/dist/components/ra-inputs/AttachmentInput.d.ts.map +1 -1
  16. package/dist/components/ra-inputs/AutocompleteInput.d.ts +1 -3
  17. package/dist/components/ra-inputs/AutocompleteInput.d.ts.map +1 -1
  18. package/dist/components/ra-inputs/LabeledInput.d.ts +2 -1
  19. package/dist/components/ra-inputs/LabeledInput.d.ts.map +1 -1
  20. package/dist/components/ra-inputs/SmartTextInput.d.ts.map +1 -1
  21. package/dist/contexts/ThemeConfigContext.d.ts.map +1 -1
  22. package/dist/hooks/useAppConfig.d.ts +3 -0
  23. package/dist/hooks/useAppConfig.d.ts.map +1 -1
  24. package/dist/index.d.ts +1 -1
  25. package/dist/react-admin.cjs.js +60 -57
  26. package/dist/react-admin.es.js +12795 -11451
  27. package/dist/react-admin.umd.js +60 -57
  28. package/dist/themes/overrides/Autocomplete.d.ts +4 -1
  29. package/dist/themes/overrides/Autocomplete.d.ts.map +1 -1
  30. package/package.json +1 -1
  31. package/playground/src/.prettierrc +8 -0
  32. package/playground/src/App.js +21 -21
  33. package/playground/src/components/pages/CustomPage.jsx +4 -4
  34. package/playground/src/components/pages/index.jsx +2 -2
  35. package/playground/src/components/ra-forms/DeviceForm.js +7 -14
  36. package/playground/src/components/ra-forms/UserForm.js +10 -24
  37. package/playground/src/components/ra-forms/index.js +4 -5
  38. package/playground/src/components/ra-lists/DeviceList.js +8 -16
  39. package/playground/src/components/ra-lists/UserList.js +17 -40
  40. package/playground/src/components/ra-lists/index.js +4 -4
  41. package/playground/src/contexts/index.js +1 -1
  42. package/playground/src/{resource → entities}/device.js +6 -6
  43. package/playground/src/{resource → entities}/i18n-message.js +1 -2
  44. package/playground/src/entities/index.js +4 -0
  45. package/playground/src/{resource → entities}/notification.js +0 -2
  46. package/playground/src/menu.js +18 -9
  47. package/playground/src/theme.js +10 -2
  48. package/react-admin.code-workspace +9 -0
  49. package/src/AdminContext.jsx +3 -5
  50. package/src/components/ActionsMenu.tsx +91 -0
  51. package/src/components/MainCard.jsx +29 -32
  52. package/src/components/index.jsx +21 -33
  53. package/src/components/ra-buttons/CreateInDialogButton.tsx +261 -0
  54. package/src/components/ra-custom/ListItem.tsx +147 -0
  55. package/src/components/ra-custom/index.tsx +2 -0
  56. package/src/components/ra-fields/AttachmentField.tsx +88 -0
  57. package/src/components/ra-fields/BaseAttachmentField.tsx +82 -0
  58. package/src/components/ra-forms/FormHeader.tsx +63 -0
  59. package/src/components/ra-forms/LongForm/LongForm.tsx +56 -0
  60. package/src/components/ra-forms/LongForm/LongFormSidebar.tsx +44 -0
  61. package/src/components/ra-forms/LongForm/{LongFormTab.jsx → LongFormTab.tsx} +47 -46
  62. package/src/components/ra-forms/LongForm/LongFormTabs.tsx +73 -0
  63. package/src/components/ra-forms/LongForm/LongFormView.tsx +129 -0
  64. package/{dist/components/ra-forms/LongForm/index.d.ts → src/components/ra-forms/LongForm/index.tsx} +1 -2
  65. package/src/components/ra-forms/LongForm/types.ts +15 -0
  66. package/src/components/ra-forms/LongForm/useFormRootPath.ts +26 -0
  67. package/src/components/ra-forms/SimpleFormIterator.jsx +14 -0
  68. package/src/components/ra-forms/index.jsx +2 -1
  69. package/src/components/ra-inputs/AttachmentInput.jsx +42 -25
  70. package/src/components/ra-inputs/AutocompleteInput.jsx +10 -5
  71. package/src/components/ra-inputs/LabeledInput.jsx +27 -32
  72. package/src/components/ra-inputs/SelectInput.jsx +11 -11
  73. package/src/components/ra-inputs/SmartTextInput.jsx +22 -26
  74. package/src/components/ra-inputs/TextInput.jsx +9 -9
  75. package/src/contexts/AppConfigContext.tsx +67 -0
  76. package/src/contexts/ThemeConfigContext.jsx +25 -29
  77. package/src/index.jsx +10 -8
  78. package/src/themes/overrides/Autocomplete.jsx +4 -1
  79. package/src/themes/overrides/index.jsx +1 -1
  80. package/src/utils/index.js +2 -2
  81. package/src/utils/lang.js +7 -7
  82. package/src/utils/time.js +7 -7
  83. package/dist/components/ActionsMenu.d.ts +0 -15
  84. package/dist/components/ActionsMenu.d.ts.map +0 -1
  85. package/dist/components/ra-buttons/CreateInDialogButton.d.ts +0 -37
  86. package/dist/components/ra-buttons/CreateInDialogButton.d.ts.map +0 -1
  87. package/dist/components/ra-fields/AttachmentField.d.ts +0 -28
  88. package/dist/components/ra-fields/AttachmentField.d.ts.map +0 -1
  89. package/dist/components/ra-fields/BaseAttachmentField.d.ts +0 -17
  90. package/dist/components/ra-fields/BaseAttachmentField.d.ts.map +0 -1
  91. package/dist/components/ra-forms/FormHeader.d.ts +0 -17
  92. package/dist/components/ra-forms/FormHeader.d.ts.map +0 -1
  93. package/dist/components/ra-forms/LongForm/DispositionProps.d.ts.map +0 -1
  94. package/dist/components/ra-forms/LongForm/LongForm.d.ts +0 -45
  95. package/dist/components/ra-forms/LongForm/LongForm.d.ts.map +0 -1
  96. package/dist/components/ra-forms/LongForm/LongFormHeader.d.ts +0 -20
  97. package/dist/components/ra-forms/LongForm/LongFormHeader.d.ts.map +0 -1
  98. package/dist/components/ra-forms/LongForm/LongFormTab.d.ts +0 -43
  99. package/dist/components/ra-forms/LongForm/LongFormTab.d.ts.map +0 -1
  100. package/dist/components/ra-forms/LongForm/LongFormTabs.d.ts +0 -21
  101. package/dist/components/ra-forms/LongForm/LongFormTabs.d.ts.map +0 -1
  102. package/dist/components/ra-forms/LongForm/LongFormView.d.ts +0 -29
  103. package/dist/components/ra-forms/LongForm/LongFormView.d.ts.map +0 -1
  104. package/dist/components/ra-forms/LongForm/index.d.ts.map +0 -1
  105. package/dist/contexts/AppConfigContext.d.ts +0 -22
  106. package/dist/contexts/AppConfigContext.d.ts.map +0 -1
  107. package/playground/src/resource/index.js +0 -4
  108. package/src/components/ActionsMenu.jsx +0 -77
  109. package/src/components/ra-buttons/CreateInDialogButton.jsx +0 -203
  110. package/src/components/ra-fields/AttachmentField.jsx +0 -82
  111. package/src/components/ra-fields/BaseAttachmentField.jsx +0 -72
  112. package/src/components/ra-forms/FormHeader.jsx +0 -42
  113. package/src/components/ra-forms/LongForm/DispositionProps.jsx +0 -10
  114. package/src/components/ra-forms/LongForm/LongForm.jsx +0 -38
  115. package/src/components/ra-forms/LongForm/LongFormHeader.jsx +0 -24
  116. package/src/components/ra-forms/LongForm/LongFormTabs.jsx +0 -63
  117. package/src/components/ra-forms/LongForm/LongFormView.jsx +0 -129
  118. package/src/components/ra-forms/LongForm/index.jsx +0 -2
  119. package/src/components/ra-forms/LongForm/useFormRootPath.jsx +0 -22
  120. package/src/contexts/AppConfigContext.jsx +0 -54
  121. /package/playground/src/{resource → entities}/user.js +0 -0
@@ -1,13 +1,13 @@
1
- import { Card, CardContent, CardHeader, Divider, Typography } from '@mui/material'
1
+ import { Card, CardContent, CardHeader, Divider, Typography } from '@mui/material';
2
+ import { lighten, useTheme } from '@mui/material/styles';
2
3
 
3
- import PropTypes from 'prop-types'
4
- import { forwardRef } from 'react'
5
- import { useTheme } from '@mui/material/styles'
4
+ import PropTypes from 'prop-types';
5
+ import { forwardRef } from 'react';
6
6
 
7
7
  const headerSX = {
8
8
  p: 2.5,
9
- '& .MuiCardHeader-action': { m: '0px auto', alignSelf: 'center' },
10
- }
9
+ '& .MuiCardHeader-action': { m: '0px auto', alignSelf: 'center' }
10
+ };
11
11
 
12
12
  const MainCard = forwardRef(
13
13
  (
@@ -26,13 +26,13 @@ const MainCard = forwardRef(
26
26
  sx = {},
27
27
  title,
28
28
  modal = false,
29
+ color = 'default',
29
30
  ...others
30
31
  },
31
- ref,
32
+ ref
32
33
  ) => {
33
- const theme = useTheme()
34
- boxShadow = theme.palette.mode === 'dark' ? boxShadow || true : boxShadow
35
-
34
+ const theme = useTheme();
35
+ boxShadow = theme.palette.mode === 'dark' ? boxShadow || true : boxShadow;
36
36
  return (
37
37
  <Card
38
38
  elevation={elevation || 0}
@@ -42,15 +42,17 @@ const MainCard = forwardRef(
42
42
  position: 'relative',
43
43
  border: border ? '1px solid' : 'none',
44
44
  borderRadius: 1,
45
- borderColor:
46
- theme.palette.mode === 'dark' ? theme.palette.divider : theme.palette.grey.A800,
47
- boxShadow:
48
- boxShadow && (!border || theme.palette.mode === 'dark')
49
- ? shadow || theme.customShadows.z1
50
- : 'inherit',
45
+ borderColor: theme.palette.mode === 'dark' ? theme.palette.divider : theme.palette.grey.A800,
46
+ boxShadow: boxShadow && (!border || theme.palette.mode === 'dark') ? shadow || theme.customShadows.z1 : 'inherit',
51
47
  ':hover': {
52
- boxShadow: boxShadow ? shadow || theme.customShadows.z1 : 'inherit',
48
+ boxShadow: boxShadow ? shadow || theme.customShadows.z1 : 'inherit'
53
49
  },
50
+ backgroundColor:
51
+ color === 'default'
52
+ ? theme.palette.background.paper
53
+ : color === 'primary'
54
+ ? lighten(theme.palette.primary[100], 0.5)
55
+ : lighten(theme.palette.secondary[100], 0.5),
54
56
  ...(modal && {
55
57
  position: 'absolute',
56
58
  top: '50%',
@@ -60,10 +62,10 @@ const MainCard = forwardRef(
60
62
  '& .MuiCardContent-root': {
61
63
  overflowY: 'auto',
62
64
  minHeight: 'auto',
63
- maxHeight: `calc(100vh - 200px)`,
64
- },
65
+ maxHeight: `calc(100vh - 200px)`
66
+ }
65
67
  }),
66
- ...sx,
68
+ ...sx
67
69
  }}
68
70
  >
69
71
  {!darkTitle && title && (
@@ -75,20 +77,14 @@ const MainCard = forwardRef(
75
77
  subheader={subheader}
76
78
  />
77
79
  )}
78
- {darkTitle && title && (
79
- <CardHeader
80
- sx={headerSX}
81
- title={<Typography variant="h4">{title}</Typography>}
82
- action={secondary}
83
- />
84
- )}
80
+ {darkTitle && title && <CardHeader sx={headerSX} title={<Typography variant="h4">{title}</Typography>} action={secondary} />}
85
81
  {title && divider && <Divider />}
86
82
  {content && <CardContent sx={contentSX}>{children}</CardContent>}
87
83
  {!content && children}
88
84
  </Card>
89
- )
90
- },
91
- )
85
+ );
86
+ }
87
+ );
92
88
 
93
89
  MainCard.propTypes = {
94
90
  border: PropTypes.bool,
@@ -106,6 +102,7 @@ MainCard.propTypes = {
106
102
  sx: PropTypes.object,
107
103
  title: PropTypes.oneOfType([PropTypes.node, PropTypes.string, PropTypes.object]),
108
104
  modal: PropTypes.bool,
109
- }
105
+ color: PropTypes.oneOf(['default', 'primary', 'secondary'])
106
+ };
110
107
 
111
- export default MainCard
108
+ export default MainCard;
@@ -1,36 +1,24 @@
1
- import ActionsMenu from './ActionsMenu'
2
- import Layout from './Layout'
3
- import Loadable from './Loadable'
4
- import Loader from './Loader'
5
- import Logo from './Logo'
6
- import MainCard from './MainCard'
7
- import MainIcon from './MainIcon'
8
- import { MenuPopover } from './MenuPopover'
9
- import Notification from './Notification'
10
- import ScrollTop from './ScrollTop'
11
- import ScrollX from './ScrollX'
12
- import SmallIcon from './SmallIcon'
13
- export {
14
- MainIcon,
15
- ActionsMenu,
16
- Loadable,
17
- Loader,
18
- Layout,
19
- Logo,
20
- MainCard,
21
- ScrollTop,
22
- ScrollX,
23
- MenuPopover,
24
- Notification,
25
- SmallIcon,
26
- }
1
+ import ActionsMenu from './ActionsMenu';
2
+ import Layout from './Layout';
3
+ import Loadable from './Loadable';
4
+ import Loader from './Loader';
5
+ import Logo from './Logo';
6
+ import MainCard from './MainCard';
7
+ import MainIcon from './MainIcon';
8
+ import { MenuPopover } from './MenuPopover';
9
+ import Notification from './Notification';
10
+ import ScrollTop from './ScrollTop';
11
+ import ScrollX from './ScrollX';
12
+ import SmallIcon from './SmallIcon';
13
+ export { MainIcon, ActionsMenu, Loadable, Loader, Layout, Logo, MainCard, ScrollTop, ScrollX, MenuPopover, Notification, SmallIcon };
27
14
 
28
- export * from './@extended'
29
- export * from './third-party'
15
+ export * from './@extended';
16
+ export * from './third-party';
30
17
 
31
18
  // Ra-Applica
32
- export * from './ra-buttons'
33
- export * from './ra-fields'
34
- export * from './ra-inputs'
35
- export * from './ra-lists'
36
- export * from './ra-forms'
19
+ export * from './ra-buttons';
20
+ export * from './ra-fields';
21
+ export * from './ra-inputs';
22
+ export * from './ra-lists';
23
+ export * from './ra-forms';
24
+ export * from './ra-custom';
@@ -0,0 +1,261 @@
1
+ import {
2
+ Button,
3
+ CreateButtonClasses,
4
+ CreateContextProvider,
5
+ CreateControllerResult,
6
+ RedirectionSideEffect,
7
+ SaveButton,
8
+ useCreateController,
9
+ useNotify,
10
+ useRedirect,
11
+ useResourceContext,
12
+ useTranslate
13
+ } from 'react-admin';
14
+ import { Dialog, Fab, useMediaQuery } from '@mui/material';
15
+ import React, { useCallback, useState } from 'react';
16
+ import { SxProps, Theme, styled } from '@mui/material/styles';
17
+
18
+ import { Add } from '@mui/icons-material';
19
+ import PropTypes from 'prop-types';
20
+ import { Toolbar } from '../ra-forms';
21
+ import clsx from 'clsx';
22
+ import { useAppConfig } from '../../hooks';
23
+ import { useQueryClient } from 'react-query';
24
+
25
+ const updateColl = (old: any, data: any) => {
26
+ const id = data.id;
27
+ if (!old) return [data];
28
+ const index = old.findIndex((record: any) => record.id === id);
29
+ if (index === -1) {
30
+ return [...old, data];
31
+ }
32
+
33
+ return [...old.slice(0, index), { ...old[index], ...data }, ...old.slice(index + 1)];
34
+ };
35
+ const setManyReferenceQueryData = (res: any, data: any) => {
36
+ const result = res && res.data ? { data: updateColl(res.data, data), total: res.total + 1 } : res;
37
+ return result;
38
+ };
39
+ const setManyQueryData = (coll: any, data: any) => (coll && coll.length > 0 ? updateColl(coll, data) : coll);
40
+ const setListQueryData = (res: any, data: any) =>
41
+ res && res.data ? { ...res, data: updateColl(res.data, data), total: res.total + 1 } : res;
42
+
43
+ export type CreateInDialogContentProps = {
44
+ onClose: () => void;
45
+ record?: any;
46
+ redirect: RedirectionSideEffect;
47
+ children: React.ReactElement;
48
+ onSubmit?: (record: any, close: () => void) => void;
49
+ onSuccess?: (data: any) => void;
50
+ onError?: (error: any) => void;
51
+ };
52
+
53
+ const CreateInDialogContent = ({
54
+ onClose,
55
+ record,
56
+ children,
57
+ redirect: _redirect,
58
+ onSubmit,
59
+ onSuccess,
60
+ onError
61
+ }: CreateInDialogContentProps) => {
62
+ const queryClient = useQueryClient();
63
+ const resource = useResourceContext();
64
+ const redirect = useRedirect();
65
+ const notify = useNotify();
66
+ const handleSuccess = useCallback(
67
+ (data: any) => {
68
+ const now = Date.now();
69
+ const updatedAt = now;
70
+
71
+ queryClient.setQueryData([resource, 'getOne', { id: data.id }], data);
72
+ queryClient.setQueriesData([resource, 'getList'], (res: any) => setListQueryData(res, data), {
73
+ updatedAt
74
+ });
75
+ queryClient.setQueriesData([resource, 'getMany'], (coll: any) => setManyQueryData(coll, data), {
76
+ updatedAt
77
+ });
78
+ queryClient.setQueriesData([resource, 'getManyReference'], (res: any) => setManyReferenceQueryData(res, data), { updatedAt });
79
+
80
+ onClose();
81
+ notify('ra.notification.created');
82
+ if (_redirect !== undefined) {
83
+ redirect(_redirect, resource, data.id, data);
84
+ }
85
+ if (onSuccess) {
86
+ onSuccess(data);
87
+ }
88
+ },
89
+ [onClose, onSuccess, queryClient, resource, notify, redirect, _redirect]
90
+ );
91
+ const { save, isLoading } = useCreateController({
92
+ mutationOptions: {
93
+ onSuccess: handleSuccess,
94
+ onError: onError
95
+ }
96
+ });
97
+ const handleSave = useCallback(
98
+ (record: any) => {
99
+ if (onSubmit) {
100
+ onSubmit(record, onClose);
101
+ } else if (save) {
102
+ save(record);
103
+ }
104
+ },
105
+ [onSubmit, save, onClose]
106
+ );
107
+ return (
108
+ <CreateContextProvider
109
+ value={
110
+ {
111
+ record: record,
112
+ save: handleSave,
113
+ saving: isLoading,
114
+ redirect: _redirect
115
+ } as CreateControllerResult
116
+ }
117
+ >
118
+ {React.cloneElement(children, {
119
+ ...children.props,
120
+ toolbar: (
121
+ <Toolbar>
122
+ <Button variant="text" size="medium" label="ra.action.cancel" onClick={onClose} />
123
+ <SaveButton />
124
+ </Toolbar>
125
+ )
126
+ })}
127
+ </CreateContextProvider>
128
+ );
129
+ };
130
+
131
+ CreateInDialogContent.propTypes = {
132
+ children: PropTypes.node,
133
+ onClose: PropTypes.func,
134
+ record: PropTypes.object,
135
+ redirect: PropTypes.oneOf(['list', 'edit', 'show', false])
136
+ };
137
+ CreateInDialogContent.defaultProps = {
138
+ redirect: false
139
+ };
140
+ const scrollStates = {
141
+ true: { _scrollToTop: true },
142
+ false: {}
143
+ } as any;
144
+
145
+ const StyledFab = styled(Fab, {
146
+ name: 'RaApplicaCreateInDialogButton',
147
+ overridesResolver: (_props, styles) => styles.root
148
+ })(({ theme }) => ({
149
+ [`&.${CreateButtonClasses.floating}`]: {
150
+ color: theme.palette.getContrastText(theme.palette.primary.main),
151
+ margin: 0,
152
+ top: 'auto',
153
+ right: 20,
154
+ bottom: 60,
155
+ left: 'auto',
156
+ position: 'fixed',
157
+ zIndex: 1000
158
+ }
159
+ }));
160
+
161
+ export type CreateInDialogButtonProps = {
162
+ fullWidth?: boolean;
163
+ maxWidth?: 'xs' | 'sm' | 'md' | 'lg' | 'xl' | false;
164
+ label?: string;
165
+ record?: any;
166
+ redirect?: RedirectionSideEffect;
167
+ scrollToTop?: boolean;
168
+ className?: string;
169
+ sx?: SxProps;
170
+ children: React.ReactElement;
171
+ onSubmit?: (record: any, close: () => void) => void;
172
+ onSuccess?: (data: any) => void;
173
+ onError?: (error: any) => void;
174
+ };
175
+
176
+ /**
177
+ * Consente di gestire la creazione di un record, per una specifica entità, o in modalità completamente personalizzata, all'interno di una dialog.
178
+ *
179
+ * @param {CreateInDialogButtonProps}
180
+ * @returns {React.ReactElement}
181
+ */
182
+ const CreateInDialogButton = ({
183
+ fullWidth,
184
+ maxWidth,
185
+ label,
186
+ record,
187
+ redirect,
188
+ scrollToTop,
189
+ className,
190
+ sx,
191
+ onSubmit,
192
+ onSuccess,
193
+ onError,
194
+ ...props
195
+ }: CreateInDialogButtonProps): React.ReactElement => {
196
+ const [open, setOpen] = useState(false);
197
+ const translate = useTranslate();
198
+ const resource = useResourceContext();
199
+ const { openDialog, closeDialog } = useAppConfig();
200
+
201
+ const handleOpen = useCallback(() => openDialog(resource, () => setOpen(true)), [openDialog, resource]);
202
+ const handleClose = useCallback(() => closeDialog(resource, () => setOpen(false)), [closeDialog, resource]);
203
+ const isSmall = useMediaQuery((theme: Theme) => theme.breakpoints.down('md'));
204
+ return (
205
+ <>
206
+ {isSmall ? (
207
+ <StyledFab
208
+ {...props}
209
+ // @ts-ignore
210
+ state={scrollStates[String(scrollToTop)]}
211
+ color="primary"
212
+ className={clsx(CreateButtonClasses.floating, className)}
213
+ aria-label={label && translate(label)}
214
+ onClick={handleOpen}
215
+ >
216
+ <Add />
217
+ </StyledFab>
218
+ ) : (
219
+ <Button {...props} sx={sx} label={label} onClick={handleOpen}>
220
+ <Add />
221
+ </Button>
222
+ )}
223
+ <Dialog open={open} onClose={handleClose} fullWidth={fullWidth} maxWidth={maxWidth}>
224
+ <CreateInDialogContent
225
+ {...props}
226
+ redirect={redirect}
227
+ record={record}
228
+ onClose={handleClose}
229
+ onSubmit={onSubmit}
230
+ onSuccess={onSuccess}
231
+ onError={onError}
232
+ />
233
+ </Dialog>
234
+ </>
235
+ );
236
+ };
237
+
238
+ CreateInDialogButton.defaultProps = {
239
+ fullWidth: true,
240
+ maxWidth: 'md',
241
+ label: 'ra.action.create',
242
+ scrollToTop: true
243
+ };
244
+
245
+ CreateInDialogButton.propTypes = {
246
+ ...Button.propTypes,
247
+ redirect: PropTypes.oneOf(['list', 'edit', 'show', false]),
248
+ fullWidth: PropTypes.bool,
249
+ maxWidth: PropTypes.oneOf(['xs', 'sm', 'md', 'lg', 'xl', false]),
250
+ label: PropTypes.string,
251
+ record: PropTypes.object,
252
+ scrollToTop: PropTypes.bool,
253
+ className: PropTypes.string,
254
+ sx: PropTypes.object,
255
+ children: PropTypes.node,
256
+ onSubmit: PropTypes.func,
257
+ onSuccess: PropTypes.func,
258
+ onError: PropTypes.func
259
+ };
260
+
261
+ export default CreateInDialogButton;
@@ -0,0 +1,147 @@
1
+ import { Button, ButtonProps, Stack, Typography } from '@mui/material';
2
+ import { FieldTitle, useRecordContext, useResourceContext } from 'ra-core';
3
+ import React, { ElementType } from 'react';
4
+
5
+ import PropTypes from 'prop-types';
6
+ import { get } from 'lodash';
7
+ import { useAppConfig } from '../../hooks';
8
+
9
+ export type ListItemProps = {
10
+ source?: string;
11
+ label?: string;
12
+ record?: any;
13
+ variant?:
14
+ | 'body1'
15
+ | 'body2'
16
+ | 'caption'
17
+ | 'button'
18
+ | 'h1'
19
+ | 'h2'
20
+ | 'h3'
21
+ | 'h4'
22
+ | 'h5'
23
+ | 'h6'
24
+ | 'inherit'
25
+ | 'overline'
26
+ | 'subtitle1'
27
+ | 'subtitle2';
28
+ spaceTop?: boolean;
29
+ spaceBottom?: boolean;
30
+ leftIcon?: ElementType<any>;
31
+ rightIcon?: ElementType<any>;
32
+ component?: ElementType<any>;
33
+ button?: string;
34
+ buttonProps?: ButtonProps;
35
+ };
36
+
37
+ const defaultIconStyle = {
38
+ width: '1.5rem',
39
+ alignSelf: 'center'
40
+ };
41
+
42
+ /**
43
+ * Implementa il componente ListItem progettato e disegnato da Applica.
44
+ * Questo componente può essere utilizzato in diverse combinazioni di proprietà e consente di visualizzare e/o modificare dati
45
+ * aggiungendo elementi decorativi di dettagli e personalizzazioni nella formattazione dei dati.
46
+ *
47
+ * @param {ListItemProps} props
48
+ * @returns {JSX.Element}
49
+ */
50
+ const ListItem = ({
51
+ source,
52
+ label,
53
+ variant,
54
+ record: providedRecord,
55
+ spaceBottom,
56
+ spaceTop,
57
+ component,
58
+ leftIcon,
59
+ rightIcon,
60
+ button,
61
+ buttonProps,
62
+ ...props
63
+ }: ListItemProps): JSX.Element => {
64
+ const { getCurrentDialog } = useAppConfig();
65
+ const resource = useResourceContext(props as any);
66
+ const dialogResource = getCurrentDialog();
67
+ const _record = useRecordContext();
68
+ const record = providedRecord || _record;
69
+ const value = get(record, (source as string) || '');
70
+ return (
71
+ <Stack
72
+ direction="row"
73
+ alignItems="center"
74
+ justifyContent="space-between"
75
+ sx={(theme) => ({
76
+ pt: 1,
77
+ pb: 1,
78
+ borderBottom: `1px solid ${theme.palette.divider}`,
79
+ ...(spaceBottom && { mb: 2 }),
80
+ ...(spaceTop && { mt: 2 })
81
+ })}
82
+ >
83
+ <Stack direction="row" alignItems="start">
84
+ {leftIcon &&
85
+ (React.isValidElement(leftIcon)
86
+ ? React.cloneElement(leftIcon, { style: defaultIconStyle } as any)
87
+ : React.createElement(leftIcon as ElementType<any>, { style: defaultIconStyle }))}
88
+ <FieldTitle label={label} source={source} resource={dialogResource || resource} />
89
+ </Stack>
90
+ <Stack direction="row" alignItems="center">
91
+ {component ? (
92
+ React.isValidElement(component) ? (
93
+ React.cloneElement(component, { record, resource, value } as any)
94
+ ) : (
95
+ React.createElement(component as ElementType<any>, { source, record, resource, value })
96
+ )
97
+ ) : (
98
+ <Typography variant={variant}>{value}</Typography>
99
+ )}
100
+ {rightIcon &&
101
+ (React.isValidElement(rightIcon)
102
+ ? React.cloneElement(rightIcon, { style: defaultIconStyle } as any)
103
+ : React.createElement(rightIcon as ElementType<any>, { style: defaultIconStyle }))}
104
+ {button && (
105
+ <Button size="small" variant="outlined" sx={{ ml: 1, p: 0 }} {...buttonProps}>
106
+ {button}
107
+ </Button>
108
+ )}
109
+ </Stack>
110
+ </Stack>
111
+ );
112
+ };
113
+
114
+ ListItem.propTypes = {
115
+ source: PropTypes.string,
116
+ label: PropTypes.string,
117
+ record: PropTypes.object,
118
+ variant: PropTypes.oneOf([
119
+ 'body1',
120
+ 'body2',
121
+ 'caption',
122
+ 'button',
123
+ 'h1',
124
+ 'h2',
125
+ 'h3',
126
+ 'h4',
127
+ 'h5',
128
+ 'h6',
129
+ 'inherit',
130
+ 'overline',
131
+ 'subtitle1',
132
+ 'subtitle2'
133
+ ]),
134
+ spaceTop: PropTypes.bool,
135
+ spaceBottom: PropTypes.bool,
136
+ leftIcon: PropTypes.oneOfType([PropTypes.elementType, PropTypes.element, PropTypes.func]),
137
+ rightIcon: PropTypes.oneOfType([PropTypes.elementType, PropTypes.element, PropTypes.func]),
138
+ component: PropTypes.oneOfType([PropTypes.elementType, PropTypes.element, PropTypes.func]),
139
+ buttonProps: PropTypes.object,
140
+ button: PropTypes.string
141
+ };
142
+
143
+ ListItem.defaultProps = {
144
+ variant: 'body1'
145
+ };
146
+
147
+ export default ListItem;
@@ -0,0 +1,2 @@
1
+ import ListItem from './ListItem';
2
+ export { ListItem };
@@ -0,0 +1,88 @@
1
+ import BaseAttachmentField, { BaseAttachmentFieldProps } from './BaseAttachmentField';
2
+ import { Box, Typography } from '@mui/material';
3
+ import { FileField as RaFileField, useDataProvider, useRecordContext, useResourceContext, useTranslate } from 'react-admin';
4
+ import { useCallback, useEffect, useMemo, useState } from 'react';
5
+
6
+ import PropTypes from 'prop-types';
7
+ import dayjs from 'dayjs';
8
+ import { get } from 'lodash';
9
+
10
+ export type AttachmentFieldProps = BaseAttachmentFieldProps & {
11
+ title: string;
12
+ entityId?: string;
13
+ property?: string;
14
+ disabled?: boolean;
15
+ /**
16
+ * Consente di definire la risorsa base da utilizzare, per le chiamate REST, per recuperare i dati dell'utente associato al singolo allegato.
17
+ */
18
+ userResource?: string;
19
+ };
20
+
21
+ const AttachmentField = ({ entityId, property, disabled, userResource = 'entities/user', ...props }: AttachmentFieldProps) => {
22
+ const [user, setUser] = useState<any>(null);
23
+ const record = useRecordContext(props);
24
+ const dataProvider = useDataProvider();
25
+ const resource = useResourceContext();
26
+ const handleClick = useCallback(
27
+ async (e: any) => {
28
+ e.preventDefault();
29
+ e.stopPropagation();
30
+ const item = get(record, props?.source);
31
+ const entity = resource.replace('entities/', '');
32
+ const attachment = await dataProvider.getFile(
33
+ `/attachments/${entity}/${entityId || record?.id}/${property || props?.source}/${item?.id || record?.id}`
34
+ );
35
+ const link = document.createElement('a');
36
+ link.href = attachment;
37
+ link.download = get(record, props?.title || props?.source);
38
+ link.click();
39
+ },
40
+ [dataProvider, record, entityId, resource, property, props?.source, props?.title]
41
+ );
42
+ const _record = useMemo(
43
+ () => ({
44
+ ...record,
45
+ [props?.source]: record?.src || get(record, props?.source),
46
+ [props?.title]: record?.title || get(record, props?.title || props?.source)
47
+ }),
48
+ [record, props?.source, props?.title]
49
+ );
50
+ const translate = useTranslate();
51
+ useEffect(() => {
52
+ if (!record || !record?.userId) return;
53
+ dataProvider.getOne(userResource, { id: record?.userId }).then(({ data }) => setUser(data));
54
+ }, [record, dataProvider, userResource]);
55
+
56
+ return (
57
+ <BaseAttachmentField
58
+ {...props}
59
+ disabled={disabled}
60
+ record={_record}
61
+ onClick={handleClick}
62
+ title={
63
+ <Box sx={{ cursor: 'pointer' }}>
64
+ <Typography variant="subtitle1">{get(_record, props?.title || props?.source)}</Typography>
65
+ <Typography variant="caption" color="secondary">
66
+ {get(_record, 'sizeDescription')}
67
+ {user && ` | `}
68
+ {user &&
69
+ translate('ra.attachment.info', {
70
+ user: user?.name,
71
+ created: dayjs(_record?.createdAt).format('DD/MM/YYYY HH:mm')
72
+ })}
73
+ </Typography>
74
+ </Box>
75
+ }
76
+ />
77
+ );
78
+ };
79
+
80
+ AttachmentField.propTypes = {
81
+ // @ts-ignore
82
+ ...RaFileField.propTypes,
83
+ source: PropTypes.string,
84
+ title: PropTypes.string,
85
+ disabled: PropTypes.bool
86
+ };
87
+
88
+ export default AttachmentField;