@dashadmin/dash-auto-admin 1.3.24 → 1.3.26

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 (176) hide show
  1. package/dist/DashAutoAdminComponentRegistry.js +64 -1
  2. package/dist/DashAutoAdminForm.js +137 -1
  3. package/dist/DashAutoAdminResizableDrawer.js +63 -1
  4. package/dist/DashAutoAdminSaveButton.js +57 -1
  5. package/dist/DashAutoCreate.js +102 -1
  6. package/dist/DashAutoDrawer.js +256 -1
  7. package/dist/DashAutoEdit.js +99 -1
  8. package/dist/DashAutoFiltersGenerator.js +193 -1
  9. package/dist/DashAutoFormGroups.js +118 -1
  10. package/dist/DashAutoFormLayout.js +68 -1
  11. package/dist/DashAutoFormMuiTabs.js +291 -1
  12. package/dist/DashAutoFormTabs.js +132 -1
  13. package/dist/DashAutoGroup.js +27 -1
  14. package/dist/DashAutoLayout.js +31 -1
  15. package/dist/DashAutoList.js +218 -1
  16. package/dist/DashAutoPostFilterForm.js +47 -1
  17. package/dist/DashAutoReferenceTab.js +10 -1
  18. package/dist/DashAutoResource.js +77 -1
  19. package/dist/DashAutoResourceLayout.js +16 -1
  20. package/dist/DashAutoShow.js +195 -1
  21. package/dist/DashAutoTabbedForm.js +244 -1
  22. package/dist/DashAutoTabbedForm.review.js +221 -1
  23. package/dist/DashAutoTabs.js +11 -1
  24. package/dist/DashFilterWrapper.js +62 -1
  25. package/dist/DashRedirect.js +56 -1
  26. package/dist/TabbedLayout.js +38 -1
  27. package/dist/common/DashAutoTitle.js +33 -1
  28. package/dist/common/components/FabButton.js +59 -1
  29. package/dist/common/components/TranslatedLabel.js +60 -1
  30. package/dist/common/settings/Settings.js +196 -1
  31. package/dist/common/settings/SettingsBarIcons.js +61 -1
  32. package/dist/context/DashAutoAdminFormContext.js +15 -1
  33. package/dist/hooks/useAutoAdminLoadingStateMediator.js +36 -1
  34. package/dist/hooks/useAutoAdminTranslate.js +61 -1
  35. package/dist/hooks/useHash.js +24 -1
  36. package/dist/hooks/useLogger.js +20 -1
  37. package/dist/hooks/useRoutePathPattern.js +20 -1
  38. package/dist/hooks/useVirtualHash.js +28 -1
  39. package/dist/index.js +77 -3406
  40. package/dist/list/DashAutoListActions.js +57 -1
  41. package/dist/list/DashAutoListDatagridWrapper.js +68 -1
  42. package/dist/list/DashAutoListDefaultActionsWrapper.js +14 -1
  43. package/dist/list/DashAutoListFilterFormWithButton.js +80 -1
  44. package/dist/list/DashAutoListTopToolbar.js +180 -1
  45. package/dist/mui/AttributeToField.js +576 -1
  46. package/dist/mui/AttributeToInput.js +630 -1
  47. package/dist/mui/AutoAdminResizableDrawer.js +63 -1
  48. package/dist/mui/AutoDataGrid.js +120 -1
  49. package/dist/mui/AutoReferenceFormTab.js +53 -1
  50. package/dist/mui/AutoReferenceTab.js +46 -1
  51. package/dist/mui/AutoTabs.js +19 -1
  52. package/dist/mui/components/ExtendedPagination.js +34 -1
  53. package/dist/mui/components/ListStringField.js +25 -1
  54. package/dist/providers/DashAuthProvider.js +215 -1
  55. package/dist/providers/DashDataProvider.js +310 -1
  56. package/dist/providers/index.js +10 -1
  57. package/dist/react-admin.d.js +0 -0
  58. package/dist/toolbar/buttons/BottomToolbarButtons.js +65 -1
  59. package/dist/toolbar/buttons/DashResourceButton.js +181 -1
  60. package/dist/toolbar/buttons/ListButtons.js +80 -1
  61. package/dist/toolbar/buttons/ToolbarButtons.js +135 -1
  62. package/dist/types/ActionCallback.d.js +0 -0
  63. package/dist/utils/SimpleLogger.js +52 -1
  64. package/dist/utils/enumToChoices.js +5 -1
  65. package/dist/utils/evalActionPermission.js +11 -1
  66. package/dist/utils/groupByTabs.js +21 -1
  67. package/dist/utils/hashedGroupByTabs.js +12 -1
  68. package/dist/utils/invertMap.js +12 -1
  69. package/dist/utils/isClassComponent.js +7 -1
  70. package/dist/utils/isComponent.js +29 -1
  71. package/dist/utils/isEnum.js +5 -1
  72. package/dist/utils/isFC.js +8 -1
  73. package/dist/utils/replaceParams.js +9 -1
  74. package/dist/utils/validate.js +19 -1
  75. package/dist/wrappers/UserAction.js +60 -1
  76. package/dist/wrappers/index.js +4 -1
  77. package/package.json +135 -120
  78. package/src/DashAutoAdminComponentRegistry.tsx +75 -0
  79. package/src/DashAutoAdminForm.tsx +155 -0
  80. package/src/DashAutoAdminResizableDrawer.tsx +69 -0
  81. package/src/DashAutoAdminSaveButton.tsx +116 -0
  82. package/src/DashAutoCreate.tsx +118 -0
  83. package/src/DashAutoDrawer.tsx +288 -0
  84. package/src/DashAutoEdit.tsx +109 -0
  85. package/src/DashAutoFiltersGenerator.tsx +208 -0
  86. package/src/DashAutoFormGroups.tsx +146 -0
  87. package/src/DashAutoFormLayout.tsx.review +113 -0
  88. package/src/DashAutoFormMuiTabs.tsx +368 -0
  89. package/src/DashAutoFormTabs.tsx +177 -0
  90. package/src/DashAutoGroup.tsx +42 -0
  91. package/src/DashAutoLayout.tsx +57 -0
  92. package/src/DashAutoList.tsx +237 -0
  93. package/src/DashAutoPostFilterForm.tsx +35 -0
  94. package/src/DashAutoReferenceTab.tsx +9 -0
  95. package/src/DashAutoResource.tsx +85 -0
  96. package/src/DashAutoResourceLayout.tsx +50 -0
  97. package/src/DashAutoShow.tsx +200 -0
  98. package/src/DashAutoTabbedForm.review.tsx +262 -0
  99. package/src/DashAutoTabbedForm.tsx +324 -0
  100. package/src/DashAutoTabs.tsx +19 -0
  101. package/src/DashFilterWrapper.tsx +43 -0
  102. package/src/DashRedirect.tsx +46 -0
  103. package/src/TabbedLayout.tsx +29 -0
  104. package/src/common/DashAutoTitle.tsx +24 -0
  105. package/src/common/components/FabButton.tsx +40 -0
  106. package/src/common/components/TranslatedLabel.tsx +81 -0
  107. package/src/common/settings/Settings.tsx +236 -0
  108. package/src/common/settings/SettingsBarIcons.tsx +72 -0
  109. package/src/context/DashAutoAdminFormContext.tsx +31 -0
  110. package/src/hooks/useAutoAdminLoadingStateMediator.tsx +42 -0
  111. package/src/hooks/useAutoAdminTranslate.tsx +106 -0
  112. package/src/hooks/useHash.tsx +27 -0
  113. package/src/hooks/useLogger.tsx +23 -0
  114. package/src/hooks/useRoutePathPattern.tsx +24 -0
  115. package/src/hooks/useVirtualHash.tsx +34 -0
  116. package/src/index.ts +85 -0
  117. package/src/interfaces/ICustomResourceSubComponent.ts +11 -0
  118. package/src/interfaces/IDashApplicationLayoutMainAction.ts +37 -0
  119. package/src/interfaces/IDashApplicationLayoutMenuItem.ts +24 -0
  120. package/src/interfaces/IDashAutoAdminAttribute.ts +104 -0
  121. package/src/interfaces/IDashAutoAdminCustomFieldComponent.ts +18 -0
  122. package/src/interfaces/IDashAutoAdminFormOptions.ts +22 -0
  123. package/src/interfaces/IDashAutoAdminListActions.ts +13 -0
  124. package/src/interfaces/IDashAutoAdminReference.ts +16 -0
  125. package/src/interfaces/IDashAutoAdminResourceConfig.ts +360 -0
  126. package/src/interfaces/IDashAutoForm.ts +24 -0
  127. package/src/interfaces/IDashAutoGridButton.ts +35 -0
  128. package/src/interfaces/IDashAutoShow.ts +12 -0
  129. package/src/interfaces/IGroupExtraData.ts +8 -0
  130. package/src/interfaces/IRecord.ts +7 -0
  131. package/src/interfaces/IReferenceFilter.ts +55 -0
  132. package/src/interfaces/IResourceComponent.ts +8 -0
  133. package/src/interfaces/IToolbarButton.ts +11 -0
  134. package/src/list/DashAutoListActions.tsx +88 -0
  135. package/src/list/DashAutoListDatagridWrapper.tsx +74 -0
  136. package/src/list/DashAutoListDefaultActionsWrapper.tsx +31 -0
  137. package/src/list/DashAutoListFilterFormWithButton.tsx +93 -0
  138. package/src/list/DashAutoListTopToolbar.tsx +240 -0
  139. package/src/mui/AttributeToField.tsx +657 -0
  140. package/src/mui/AttributeToInput.tsx +728 -0
  141. package/src/mui/AutoAdminResizableDrawer.tsx +69 -0
  142. package/src/mui/AutoDataGrid.tsx +127 -0
  143. package/src/mui/AutoReferenceFormTab.tsx +51 -0
  144. package/src/mui/AutoReferenceTab.tsx +45 -0
  145. package/src/mui/AutoTabs.tsx +32 -0
  146. package/src/mui/components/ExtendedPagination.tsx +23 -0
  147. package/src/mui/components/ListStringField.tsx +32 -0
  148. package/src/providers/DashAuthProvider.ts +341 -0
  149. package/src/providers/DashDataProvider.ts +466 -0
  150. package/src/providers/index.ts +17 -0
  151. package/src/toolbar/buttons/BottomToolbarButtons.tsx +59 -0
  152. package/src/toolbar/buttons/DashResourceButton.tsx +223 -0
  153. package/src/toolbar/buttons/ListButtons.tsx +137 -0
  154. package/src/toolbar/buttons/ToolbarButtons.tsx +186 -0
  155. package/src/utils/SimpleLogger.tsx +46 -0
  156. package/src/utils/enumToChoices.tsx +3 -0
  157. package/src/utils/evalActionPermission.tsx +14 -0
  158. package/src/utils/groupByTabs.tsx +23 -0
  159. package/src/utils/hashedGroupByTabs.tsx +16 -0
  160. package/src/utils/invertMap.tsx +10 -0
  161. package/src/utils/isClassComponent.tsx +9 -0
  162. package/src/utils/isComponent.tsx +45 -0
  163. package/src/utils/isEnum.tsx +3 -0
  164. package/src/utils/isFC.tsx +6 -0
  165. package/src/utils/replaceParams.tsx +6 -0
  166. package/src/utils/validate.tsx +24 -0
  167. package/src/wrappers/UserAction.tsx +67 -0
  168. package/src/wrappers/index.tsx +1 -0
  169. /package/{dist → src}/DashAutoAdminSaveButton.tsx.bkup +0 -0
  170. /package/{dist/DashAutoFormLayout.tsx.review → src/DashAutoFormLayout.tsx} +0 -0
  171. /package/{dist → src}/DashAutoFormTabs.review +0 -0
  172. /package/{dist → src}/DashAutoFormTabs.tsx.formcontext.wip +0 -0
  173. /package/{dist → src}/mui/AttributeToField.tsx.review +0 -0
  174. /package/{dist → src}/mui/AttributeToInput.tsx.review +0 -0
  175. /package/{dist → src}/react-admin.d.ts +0 -0
  176. /package/{dist → src}/types/ActionCallback.d.ts +0 -0
@@ -0,0 +1,29 @@
1
+ import { TabbedShowLayout } from 'react-admin';
2
+ import IDashAutoAdminAttribute from './interfaces/IDashAutoAdminAttribute';
3
+ import { IDashAutoAdminReference } from './interfaces/IDashAutoAdminReference';
4
+ import AutoReferenceTab from './DashAutoReferenceTab';
5
+ import AutoTabs from './DashAutoTabs';
6
+ import IDashAutoAdminResourceConfig from './interfaces/IDashAutoAdminResourceConfig';
7
+
8
+ export interface ITabbedLayout {
9
+ resourceConfig: IDashAutoAdminResourceConfig;
10
+ schema: IDashAutoAdminAttribute[];
11
+ references?: IDashAutoAdminReference[];
12
+ }
13
+
14
+ const TabbedLayout: React.FC<ITabbedLayout> = ({
15
+ resourceConfig,
16
+ schema,
17
+ references,
18
+ ..._props
19
+ }) => {
20
+ // console.log("references",references);
21
+ return (
22
+ <TabbedShowLayout >
23
+ {AutoTabs(resourceConfig)}
24
+ {references && references.map((reference) => AutoReferenceTab(reference))}
25
+ </TabbedShowLayout>
26
+ );
27
+ };
28
+
29
+ export default TabbedLayout;
@@ -0,0 +1,24 @@
1
+ import { useTranslate } from 'react-admin';
2
+ import IDashAutoAdminResourceConfig from '../interfaces/IDashAutoAdminResourceConfig';
3
+
4
+ export interface IAutoTitle {
5
+ record?: any;
6
+ resourceConfig: IDashAutoAdminResourceConfig;
7
+ }
8
+
9
+ const DashAutoTitle: React.FC<IAutoTitle> = ({
10
+ resourceConfig,
11
+ record,
12
+ ..._props
13
+ }) => {
14
+ const translate = useTranslate();
15
+ const translatedLabel = translate(resourceConfig.label, { _: resourceConfig.label });
16
+
17
+ return (
18
+ <span>
19
+ {record ? `${translate('dash.action.edit')} "${record[resourceConfig.schema[0].attribute]}"` : translatedLabel}
20
+ </span>
21
+ );
22
+ };
23
+
24
+ export default DashAutoTitle;
@@ -0,0 +1,40 @@
1
+ import { FC, JSX, cloneElement } from 'react';
2
+ import Settings from '@mui/icons-material/Settings';
3
+ import { Fab, FabProps, Tooltip } from '@mui/material';
4
+
5
+ export interface IFabButton extends FabProps {
6
+ onClick: (_e: any) => any;
7
+ tooltip: React.ReactNode;
8
+ icon?: JSX.Element;
9
+ }
10
+
11
+ export const FabButton: FC<IFabButton> = (props) => {
12
+ const { icon, onClick, tooltip, children, ...rest } = props;
13
+
14
+ const _icon = icon ? (
15
+ cloneElement(props.icon, { sx: { fontSize: 16 }, fontSize: 'small' })
16
+ ) : (
17
+ <Settings sx={{ fontSize: 16 }} fontSize={'small'} />
18
+ );
19
+ return (
20
+ <Tooltip title={tooltip}>
21
+ <Fab
22
+ size='small'
23
+ aria-label='settings'
24
+ color='primary'
25
+ onClick={onClick}
26
+ style={{
27
+ position: 'absolute',
28
+ }}
29
+ className={'toolbar-settings-button'}
30
+
31
+ {...rest}
32
+ >
33
+
34
+ {_icon}
35
+ </Fab>
36
+ </Tooltip>
37
+ );
38
+ };
39
+
40
+ export default FabButton;
@@ -0,0 +1,81 @@
1
+ /**
2
+ * TranslatedLabel Component
3
+ *
4
+ * A component that automatically translates labels using react-admin's i18n system.
5
+ * Useful for rendering translated labels in legends, titles, and other places
6
+ * where raw text is displayed.
7
+ */
8
+
9
+ import React from 'react';
10
+ import { useTranslate } from 'react-admin';
11
+ import { isTranslationKey } from '../../hooks/useAutoAdminTranslate';
12
+
13
+ export interface TranslatedLabelProps {
14
+ /** The label to translate (can be a translation key or plain text) */
15
+ label: string | undefined;
16
+ /** Optional fallback if translation is not found */
17
+ fallback?: string;
18
+ /** Optional className for styling */
19
+ className?: string;
20
+ /** Optional component to wrap the text (default: span) */
21
+ component?: React.ElementType;
22
+ /** Optional props to pass to the wrapper component */
23
+ componentProps?: Record<string, any>;
24
+ }
25
+
26
+ /**
27
+ * Component that renders a translated label
28
+ * If the label looks like a translation key (contains dots), it will be translated
29
+ * Otherwise, it renders the label as-is
30
+ */
31
+ export const TranslatedLabel: React.FC<TranslatedLabelProps> = ({
32
+ label,
33
+ fallback = '',
34
+ className,
35
+ component: Component = 'span',
36
+ componentProps = {},
37
+ }) => {
38
+ const translate = useTranslate();
39
+
40
+ if (!label) {
41
+ return fallback ? <Component className={className} {...componentProps}>{fallback}</Component> : null;
42
+ }
43
+
44
+ let displayText = label;
45
+
46
+ if (isTranslationKey(label)) {
47
+ const translated = translate(label, { _: label });
48
+ // If translation returns the key itself and we have a fallback, use it
49
+ if (translated === label && fallback) {
50
+ displayText = fallback;
51
+ } else {
52
+ displayText = translated;
53
+ }
54
+ }
55
+
56
+ return (
57
+ <Component className={className} {...componentProps}>
58
+ {displayText}
59
+ </Component>
60
+ );
61
+ };
62
+
63
+ /**
64
+ * Higher-order component that provides translation to a component
65
+ */
66
+ export const withTranslatedLabel = <P extends { label?: string }>(
67
+ WrappedComponent: React.ComponentType<P>
68
+ ): React.FC<P> => {
69
+ return (props: P) => {
70
+ const translate = useTranslate();
71
+
72
+ let translatedLabel = props.label;
73
+ if (props.label && isTranslationKey(props.label)) {
74
+ translatedLabel = translate(props.label, { _: props.label });
75
+ }
76
+
77
+ return <WrappedComponent {...props} label={translatedLabel} />;
78
+ };
79
+ };
80
+
81
+ export default TranslatedLabel;
@@ -0,0 +1,236 @@
1
+ import {
2
+ Dialog,
3
+ DialogContent,
4
+ Drawer,
5
+ Fade,
6
+ Popover,
7
+ Tooltip,
8
+ } from '@mui/material';
9
+
10
+ import React, { FC, memo } from 'react';
11
+ import { GearBadge, AlertBadge, ErrorBadge } from './SettingsBarIcons';
12
+
13
+ export interface ISettings {
14
+ /** Type. */
15
+ type?: 'drawer' | 'dialog' | 'tooltip';
16
+ /** Memoization data to compare. */
17
+ data?: any;
18
+ /** Warning. */
19
+ warning?: { active: boolean; message: string };
20
+ /** Error. */
21
+ error?: { active: boolean; message: string };
22
+ /** Optional ClassName. */
23
+ className?: string;
24
+ /** Optional GearIcon. */
25
+ gearIcon?: JSX.Element;
26
+ /** Children Required. */
27
+ children: React.ReactNode;
28
+ }
29
+
30
+ const SettingsTooltip: FC<ISettings> = ({
31
+ type,
32
+ className,
33
+ children,
34
+ warning,
35
+ error,
36
+ gearIcon,
37
+ ..._props
38
+ }) => {
39
+ if (!warning) warning = { active: false, message: '' };
40
+ if (!error) error = { active: false, message: '' };
41
+
42
+ const [anchorEl, setAnchorEl] = React.useState<null | HTMLElement>(null);
43
+ const open = Boolean(anchorEl);
44
+
45
+ const openSettings = (event: React.MouseEvent<HTMLElement>) => {
46
+ setAnchorEl(event.currentTarget);
47
+ };
48
+
49
+ const closeSettings = () => {
50
+ setAnchorEl(null);
51
+ };
52
+
53
+ return (
54
+ <div {...(className && { className })}>
55
+ <div className='settings-widget-actions'>
56
+ {error.active && (
57
+ <div className='settings-widget-action'>
58
+ <ErrorBadge onClick={() => {}}>
59
+ <></>
60
+ </ErrorBadge>
61
+ </div>
62
+ )}
63
+ {warning.active && (
64
+ <Tooltip title={warning.message}>
65
+ <div className='settings-widget-action'>
66
+ <AlertBadge onClick={() => {}}>
67
+ <></>
68
+ </AlertBadge>
69
+ </div>
70
+ </Tooltip>
71
+ )}
72
+ <div className='settings-widget-action'>
73
+ <GearBadge icon={gearIcon} onClick={openSettings}>
74
+ <></>
75
+ </GearBadge>
76
+ </div>
77
+ </div>
78
+
79
+ <Popover
80
+ anchorOrigin={{
81
+ vertical: 'bottom',
82
+ horizontal: 'right',
83
+ }}
84
+ transformOrigin={{
85
+ vertical: 'top',
86
+ horizontal: 'left',
87
+ }}
88
+ id='fade-menu'
89
+ anchorEl={anchorEl}
90
+ open={open}
91
+ onClose={closeSettings}
92
+ TransitionComponent={Fade}
93
+ >
94
+ <div style={{ padding: 8 }}>{children}</div>
95
+ </Popover>
96
+ </div>
97
+ );
98
+ };
99
+
100
+ const SettingsDialog: FC<ISettings> = ({
101
+ type,
102
+ className,
103
+ children,
104
+ warning,
105
+ error,
106
+ ..._props
107
+ }) => {
108
+ if (!warning) warning = { active: false, message: '' };
109
+ if (!error) error = { active: false, message: '' };
110
+
111
+ const [open, setOpen] = React.useState(false);
112
+
113
+ const openSettings = (_event: React.MouseEvent<HTMLElement>) => {
114
+ setOpen(true);
115
+ };
116
+
117
+ const closeSettings = () => {
118
+ setOpen(false);
119
+ };
120
+
121
+ return (
122
+ <div>
123
+ <div className='settings-widget-actions'>
124
+ {error.active && (
125
+ <div className='settings-widget-action'>
126
+ <ErrorBadge onClick={() => {}}>
127
+ <></>
128
+ </ErrorBadge>
129
+ </div>
130
+ )}
131
+ {warning.active && (
132
+ <Tooltip title={warning.message}>
133
+ <div className='settings-widget-action'>
134
+ <AlertBadge onClick={() => {}}>
135
+ <></>
136
+ </AlertBadge>
137
+ </div>
138
+ </Tooltip>
139
+ )}
140
+ <div className='settings-widget-action'>
141
+ <GearBadge onClick={openSettings}>
142
+ <></>
143
+ </GearBadge>
144
+ </div>
145
+ </div>
146
+
147
+ <Dialog open={open} onClose={closeSettings}>
148
+ {/* @ts-ignore Expected mismatch ReactNode. */}
149
+ <DialogContent>{children}</DialogContent>
150
+ </Dialog>
151
+ </div>
152
+ );
153
+ };
154
+
155
+ const SettingsDrawer: FC<ISettings> = ({
156
+ type,
157
+ className,
158
+ children,
159
+ warning,
160
+ error,
161
+ ..._props
162
+ }) => {
163
+ if (!warning) warning = { active: false, message: '' };
164
+ if (!error) error = { active: false, message: '' };
165
+
166
+ const [open, setOpen] = React.useState(false);
167
+
168
+ const openSettings = (_event: React.MouseEvent<HTMLElement>) => {
169
+ setOpen(true);
170
+ };
171
+
172
+ const closeSettings = () => {
173
+ setOpen(false);
174
+ };
175
+
176
+ return (
177
+ <div>
178
+ <div className='settings-widget-actions'>
179
+ {error.active && (
180
+ <div className='settings-widget-action'>
181
+ <ErrorBadge onClick={() => {}}>
182
+ <></>
183
+ </ErrorBadge>
184
+ </div>
185
+ )}
186
+ {warning.active && (
187
+ <Tooltip title={warning.message}>
188
+ <div className='settings-widget-action'>
189
+ <AlertBadge onClick={() => {}}>
190
+ <></>
191
+ </AlertBadge>
192
+ </div>
193
+ </Tooltip>
194
+ )}
195
+ <div className='settings-widget-action'>
196
+ <GearBadge onClick={openSettings}>
197
+ <></>
198
+ </GearBadge>
199
+ </div>
200
+ </div>
201
+
202
+ <Drawer
203
+ open={open}
204
+ onClose={closeSettings}
205
+ anchor={'right'}
206
+ PaperProps={{
207
+ sx: { width: '20%' },
208
+ }}
209
+ >
210
+ {/* @ts-ignore Expected mismatch ReactNode. */}
211
+ {children}
212
+ </Drawer>
213
+ </div>
214
+ );
215
+ };
216
+
217
+ const propsAreEqual = (oldProps, newProps) => {
218
+ return oldProps.data === newProps.data;
219
+ };
220
+
221
+
222
+ const Settings: FC<ISettings> = ({ type = 'dialog', ...props }) => {
223
+ switch (type) {
224
+ case 'tooltip':
225
+ return <SettingsTooltip type={type} {...props} />;
226
+ case 'drawer':
227
+ return <SettingsDrawer type={type} {...props} />;
228
+ case 'dialog':
229
+ default:
230
+ return <SettingsDialog type={type} {...props} />;
231
+ }
232
+ };
233
+
234
+ const MemoizedSettings = memo(Settings, propsAreEqual);
235
+
236
+ export default MemoizedSettings;
@@ -0,0 +1,72 @@
1
+ import Badge, { BadgeProps } from '@mui/material/Badge';
2
+ import styled from '@emotion/styled';
3
+ import {Settings, Error, Warning }from '@mui/icons-material';
4
+
5
+ import { FC, JSX, cloneElement } from 'react';
6
+ import { Fab } from '@mui/material';
7
+
8
+ const StyledBadge = styled(Badge)<BadgeProps>(({ theme: _theme }) => ({
9
+ '& .MuiBadge-badge': {
10
+ padding: 0,
11
+ },
12
+ }));
13
+
14
+ export interface ISettingsBadge {
15
+ onClick: (e: any) => any;
16
+ icon?: JSX.Element;
17
+ children: React.ReactNode;
18
+ }
19
+
20
+ export const GearBadge: FC<ISettingsBadge> = (props) => {
21
+ const icon = props.icon ? (
22
+ cloneElement(props.icon, { sx: { fontSize: 16 }, fontSize: 'small' })
23
+ ) : (
24
+ <Settings sx={{ fontSize: 16 }} fontSize={'small'} />
25
+ );
26
+
27
+ return (
28
+ <Fab
29
+ size='small'
30
+ aria-label='settings'
31
+ color='primary'
32
+ onClick={props.onClick}
33
+ style={{
34
+ position: 'absolute',
35
+ }}
36
+ className={'toolbar-settings-button'}
37
+ >
38
+ {icon}
39
+ </Fab>
40
+ );
41
+ };
42
+
43
+ export const AlertBadge: FC<ISettingsBadge> = (props) => {
44
+ return (
45
+ <StyledBadge
46
+ onClick={props.onClick}
47
+ badgeContent={
48
+ <Warning
49
+ sx={{ fontSize: 16, color: 'orange' }}
50
+ fontSize={'small'}
51
+ />
52
+ }
53
+ color='default'
54
+ >
55
+ {props.children}
56
+ </StyledBadge>
57
+ );
58
+ };
59
+
60
+ export const ErrorBadge: FC<ISettingsBadge> = (props) => {
61
+ return (
62
+ <StyledBadge
63
+ onClick={props.onClick}
64
+ badgeContent={
65
+ <Error sx={{ fontSize: 16, color: 'red' }} fontSize={'small'} />
66
+ }
67
+ color='default'
68
+ >
69
+ {props.children}
70
+ </StyledBadge>
71
+ );
72
+ };
@@ -0,0 +1,31 @@
1
+ import React, { createContext, useContext } from 'react';
2
+
3
+ export interface IDashAutoAdminFormContext {
4
+ /**
5
+ * The save handler that wraps form submission with validation.
6
+ * This is exposed so child components (like SaveButton) can trigger it manually.
7
+ */
8
+ onSave?: (values: any) => Promise<void> | void;
9
+ /**
10
+ * The current form mode
11
+ */
12
+ mode: 'create' | 'edit';
13
+ }
14
+
15
+ const DashAutoAdminFormContext = createContext<IDashAutoAdminFormContext>({
16
+ mode: 'create',
17
+ });
18
+
19
+ export const DashAutoAdminFormProvider = DashAutoAdminFormContext.Provider;
20
+
21
+ /**
22
+ * Hook to access the DashAutoAdminForm context.
23
+ * This is useful for child components that need to trigger form submission manually,
24
+ * such as when using SaveButton with type="button".
25
+ */
26
+ export const useDashAutoAdminForm = () => {
27
+ const context = useContext(DashAutoAdminFormContext);
28
+ return context;
29
+ };
30
+
31
+ export default DashAutoAdminFormContext;
@@ -0,0 +1,42 @@
1
+ import React, { useEffect, useState } from 'react';
2
+
3
+ const useAutoAdminLoadingStateMediator = (origin?: string) => {
4
+ const useAutoAdminLoadingState = useState<boolean>(false);
5
+
6
+ const localState = useState<MessageEvent>(null);
7
+
8
+ useEffect(() => {
9
+ if (!localState[0]) return;
10
+
11
+ if (origin && localState[0]?.origin) {
12
+
13
+ if ( /* @ts-ignore : An expression of type 'void' cannot be tested for truthiness.ts(1345). */
14
+ localState[0].origin === origin &&
15
+ useAutoAdminLoadingState[1](localState[0].data)
16
+ ) {
17
+ // eslint-disable-line no-debugger
18
+ return;
19
+ }
20
+ }
21
+
22
+ useAutoAdminLoadingState[1](localState[0]?.data);
23
+
24
+ return;
25
+ }, [localState[0]]);
26
+
27
+ React.useEffect(() => {
28
+ window.addEventListener('auto-admin-loading-state', (e: any) =>
29
+ localState[1](e),
30
+ );
31
+
32
+ return () => {
33
+ window.removeEventListener('auto-admin-loading-state', (e: any) =>
34
+ localState[1](e),
35
+ );
36
+ };
37
+ }, []);
38
+
39
+ return useAutoAdminLoadingState;
40
+ };
41
+
42
+ export default useAutoAdminLoadingStateMediator;
@@ -0,0 +1,106 @@
1
+ /**
2
+ * useAutoAdminTranslate Hook
3
+ *
4
+ * Provides translation functionality for dash-auto-admin components.
5
+ * Uses react-admin's useTranslate hook internally.
6
+ *
7
+ * This hook handles:
8
+ * - Translating labels that are translation keys
9
+ * - Fallback to original label if no translation found
10
+ * - Checking if a string looks like a translation key (contains dots)
11
+ */
12
+
13
+ import { useTranslate } from 'react-admin';
14
+ import { useCallback, useMemo } from 'react';
15
+
16
+ /**
17
+ * Check if a string looks like a translation key (contains dots like 'tab.resource.tabs')
18
+ */
19
+ export const isTranslationKey = (value: string): boolean => {
20
+ if (!value || typeof value !== 'string') return false;
21
+ // Translation keys typically contain dots and are lowercase/snake_case
22
+ // Examples: 'tab.resource.tabs', 'common.save', 'resources.users.name'
23
+ return /^[a-z][a-z0-9_.]*[a-z0-9]$/i.test(value) && value.includes('.');
24
+ };
25
+
26
+ /**
27
+ * Hook that provides translation utilities for dash-auto-admin
28
+ */
29
+ export const useAutoAdminTranslate = () => {
30
+ const translate = useTranslate();
31
+
32
+ /**
33
+ * Translate a label if it's a translation key, otherwise return as-is
34
+ */
35
+ const translateLabel = useCallback((label: string | undefined, fallback?: string): string => {
36
+ if (!label) return fallback || '';
37
+
38
+ if (isTranslationKey(label)) {
39
+ const translated = translate(label, { _: label });
40
+ // If translation returns the same key, it means no translation was found
41
+ // In that case, check if we should return the label or a fallback
42
+ if (translated === label && fallback) {
43
+ return fallback;
44
+ }
45
+ return translated;
46
+ }
47
+
48
+ return label;
49
+ }, [translate]);
50
+
51
+ /**
52
+ * Translate a value only if it looks like a translation key
53
+ */
54
+ const translateIfKey = useCallback((value: string | undefined): string => {
55
+ if (!value) return '';
56
+ if (isTranslationKey(value)) {
57
+ return translate(value, { _: value });
58
+ }
59
+ return value;
60
+ }, [translate]);
61
+
62
+ /**
63
+ * Translate with parameters
64
+ */
65
+ const translateWithParams = useCallback((key: string, params?: Record<string, any>): string => {
66
+ return translate(key, params);
67
+ }, [translate]);
68
+
69
+ /**
70
+ * Check if a translation exists for a key
71
+ */
72
+ const hasTranslation = useCallback((key: string): boolean => {
73
+ if (!isTranslationKey(key)) return false;
74
+ const translated = translate(key, { _: key });
75
+ return translated !== key;
76
+ }, [translate]);
77
+
78
+ return useMemo(() => ({
79
+ translate,
80
+ translateLabel,
81
+ translateIfKey,
82
+ translateWithParams,
83
+ hasTranslation,
84
+ isTranslationKey,
85
+ }), [translate, translateLabel, translateIfKey, translateWithParams, hasTranslation]);
86
+ };
87
+
88
+ /**
89
+ * Standalone translation function for use outside of React components
90
+ * Uses the translate function from React Admin context if available
91
+ */
92
+ export const translateLabelSync = (label: string | undefined, translate: (key: string, options?: any) => string, fallback?: string): string => {
93
+ if (!label) return fallback || '';
94
+
95
+ if (isTranslationKey(label)) {
96
+ const translated = translate(label, { _: label });
97
+ if (translated === label && fallback) {
98
+ return fallback;
99
+ }
100
+ return translated;
101
+ }
102
+
103
+ return label;
104
+ };
105
+
106
+ export default useAutoAdminTranslate;
@@ -0,0 +1,27 @@
1
+ import React from 'react';
2
+
3
+ const useHash = () => {
4
+ const [hash, setHash] = React.useState(() => window.location.hash);
5
+
6
+ const hashChangeHandler = React.useCallback(() => {
7
+ setHash(window.location.hash);
8
+ }, []);
9
+
10
+ React.useEffect(() => {
11
+ window.addEventListener('hashchange', hashChangeHandler);
12
+ return () => {
13
+ window.removeEventListener('hashchange', hashChangeHandler);
14
+ };
15
+ }, []);
16
+
17
+ const updateHash = React.useCallback(
18
+ (newHash) => {
19
+ if (newHash !== hash) window.location.hash = newHash;
20
+ },
21
+ [hash],
22
+ );
23
+
24
+ return [hash, updateHash];
25
+ };
26
+
27
+ export default useHash;