@dashadmin/dash-components 1.3.72 → 1.3.74-srcfree.1

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 (60) hide show
  1. package/package.json +24 -21
  2. package/src/components/AuditLog/AuditLog.tsx +0 -490
  3. package/src/components/AuditLog/index.ts +0 -2
  4. package/src/components/AutoCompleteArrayInput/AutoCompleteCheckBoxInput.tsx +0 -917
  5. package/src/components/AutoCompleteArrayInput/AutocompleteCheckBoxArrayInput.tsx +0 -39
  6. package/src/components/AutoCompleteArrayInputAutoSearch/AutoCompleteCheckBoxInput.tsx +0 -916
  7. package/src/components/AutoCompleteArrayInputAutoSearch/AutocompleteCheckBoxArrayAutoSearch.tsx.wip +0 -42
  8. package/src/components/AutoCompleteArrayInputAutoSearch/AutocompleteCheckBoxArrayInput.tsx +0 -44
  9. package/src/components/Json/Json.tsx +0 -312
  10. package/src/components/JsonColorSelector/JsonColorSelector.tsx +0 -1443
  11. package/src/components/JsonColorSelector/JsonColorSelector.tsx.bkup +0 -746
  12. package/src/components/JsonColorSelector/JsonColorSelectorEnhanced.tsx +0 -1135
  13. package/src/components/JsonColorSelector/JsonCssVarValues.tsx +0 -867
  14. package/src/components/JsonColorSelector/components/BasicColorSelector.tsx +0 -333
  15. package/src/components/JsonColorSelector/components/ColorEditDialog.tsx +0 -495
  16. package/src/components/JsonColorSelector/components/ColorPaletteItem.tsx +0 -80
  17. package/src/components/JsonColorSelector/components/ImageColorExtractor.tsx +0 -420
  18. package/src/components/JsonColorSelector/helpers/functions.tsx +0 -123
  19. package/src/components/JsonColorSelector/helpers/paletteDerivation.ts +0 -367
  20. package/src/components/JsonColorSelector/interfaces/interfaces.tsx +0 -22
  21. package/src/components/JsonColorSelector/useAsyncColorThief.tsx +0 -97
  22. package/src/components/ListActive/ListActive.tsx +0 -106
  23. package/src/components/ListActive/ListBoolean.tsx +0 -96
  24. package/src/components/NotificationPreferences/NotificationPreferences.tsx +0 -480
  25. package/src/components/NotificationPreferences/index.tsx +0 -2
  26. package/src/components/SearchableSelects/RASearchableSelect.tsx +0 -303
  27. package/src/components/SearchableSelects/RASearchableSelectCheckboxes.tsx +0 -617
  28. package/src/components/SearchableSelects/RASearchableSelectChips.tsx +0 -561
  29. package/src/components/SearchableSelects/RASearchableSelectChipsRecordContext.tsx +0 -366
  30. package/src/components/SearchableSelects/SearchableSelect.tsx +0 -323
  31. package/src/components/SearchableSelects/SearchableSelectCheckboxes.tsx +0 -358
  32. package/src/components/SortableDataGrid/README.md +0 -1
  33. package/src/components/SortableDataGrid/SortableDataGrid.tsx +0 -56
  34. package/src/components/SortableDataGrid/SortableDataGridBody.tsx +0 -175
  35. package/src/components/SortableDataGrid/SortableDataGridHeader.tsx +0 -171
  36. package/src/components/SortableDataGrid/SortableDataGridRow.tsx +0 -247
  37. package/src/components/Upload/SingleImageUploader.tsx +0 -55
  38. package/src/components/custom/PackageCopyMethod.tsx +0 -109
  39. package/src/components/custom/PackageRadioButtonGroup.tsx +0 -49
  40. package/src/components/dialog/Basic.tsx +0 -11
  41. package/src/components/dialog/Correct.tsx +0 -16
  42. package/src/components/dialog/Error.tsx +0 -15
  43. package/src/components/dialog/Info.tsx +0 -15
  44. package/src/components/dialog/InfoV2.tsx +0 -35
  45. package/src/components/dialog/NotFound.tsx +0 -18
  46. package/src/components/dialog/QuickSearch.tsx +0 -115
  47. package/src/components/notifications/NotificationsCenter.tsx +0 -743
  48. package/src/components/notifications/index.ts +0 -42
  49. package/src/components/tables/PaginationComponent.tsx +0 -17
  50. package/src/components/theme/AppLoadingFallback.tsx +0 -42
  51. package/src/components/theme/ErrorBoundary.tsx +0 -57
  52. package/src/components/theme/InitialLoader.tsx +0 -16
  53. package/src/components/theme/NotFound.tsx +0 -124
  54. package/src/components/theme/NotResults.tsx +0 -56
  55. package/src/hooks/useDraggable.ts +0 -11
  56. package/src/hooks/useNotifications.ts +0 -14
  57. package/src/hooks/useQuickSearch.tsx +0 -29
  58. package/src/index.tsx +0 -77
  59. package/src/styles/index.less +0 -0
  60. package/src/utils/setNativeValue.tsx +0 -23
@@ -1,480 +0,0 @@
1
- import React, { useMemo } from 'react';
2
- import {
3
- Box,
4
- Card,
5
- CardContent,
6
- Typography,
7
- Switch,
8
- FormControlLabel,
9
- Alert,
10
- TextField,
11
- InputAdornment,
12
- IconButton,
13
- Chip,
14
- } from '@mui/material';
15
- import { Search as SearchIcon, Clear as ClearIcon, Email as EmailIcon, Notifications as PushIcon } from '@mui/icons-material';
16
- import { useRecordContext } from 'react-admin';
17
- import { useFormContext } from 'react-hook-form';
18
- import { AuthPersistenceService } from 'dash-auth';
19
- import { IDashAutoAdminCustomFieldComponent } from 'dash-auto-admin';
20
-
21
- interface NotificationConfig {
22
- id: string;
23
- name: string;
24
- className: string;
25
- hasEmail: boolean;
26
- hasPush: boolean;
27
- hasSocket: boolean;
28
- hasDatabase: boolean;
29
- }
30
-
31
- interface NotificationPreference {
32
- id: string;
33
- name: string;
34
- email: boolean;
35
- push: boolean;
36
- }
37
-
38
- // Helper functions - moved outside component
39
- const getNestedValue = (obj: any, path: string): any => {
40
- if (!path || !obj) return [];
41
- const keys = path.split('.');
42
- return keys.reduce((o, key) => (o && o[key] !== undefined ? o[key] : []), obj);
43
- };
44
-
45
- const setNestedValue = (obj: any, path: string, value: any): any => {
46
- if (!path) return value;
47
- const keys = path.split('.');
48
- const lastKey = keys.pop();
49
- const result = { ...obj };
50
- let current = result;
51
-
52
- for (const key of keys) {
53
- if (!current[key]) current[key] = {};
54
- current = current[key];
55
- }
56
-
57
- if (lastKey) {
58
- current[lastKey] = value;
59
- }
60
- return result;
61
- };
62
-
63
- /**
64
- * NotificationPreferencesEdit - Edit mode component
65
- * All hooks are called unconditionally at the top level
66
- */
67
- export const NotificationPreferencesEdit: React.FC<IDashAutoAdminCustomFieldComponent> = (props) => {
68
- const { attribute } = props;
69
-
70
- // ALL HOOKS CALLED UNCONDITIONALLY AT TOP LEVEL
71
- const record = useRecordContext();
72
- const formContext = useFormContext();
73
- const [searchTerm, setSearchTerm] = React.useState<string>('');
74
- const [localPreferences, setLocalPreferences] = React.useState<NotificationPreference[] | null>(null);
75
-
76
- // Get form methods safely
77
- const setValue = formContext?.setValue;
78
- const getValues = formContext?.getValues;
79
-
80
- // Calculate attribute paths
81
- const attributePath = attribute?.attribute || '';
82
- const isNestedSetting = attributePath.startsWith('preferences.');
83
- const preferencesPath = isNestedSetting ? attributePath.split('.').slice(1).join('.') : attributePath;
84
-
85
- // Get available notifications from systemValues (memoized)
86
- const availableNotifications = useMemo<NotificationConfig[]>(() => {
87
- const systemValues = AuthPersistenceService.getSystemValues();
88
- console.log('🔔 NotificationPreferencesEdit - systemValues:', systemValues);
89
- const notifications = systemValues?.user_notifications || [];
90
- console.log('🔔 NotificationPreferencesEdit - user_notifications:', notifications);
91
- return notifications;
92
- }, []);
93
-
94
- // Get current preferences from record/form (memoized)
95
- const initialPreferences = useMemo<NotificationPreference[]>(() => {
96
- let currentPrefs: NotificationPreference[] = [];
97
-
98
- if (record) {
99
- const recordValue = isNestedSetting
100
- ? getNestedValue(record, preferencesPath)
101
- : record[attributePath];
102
- currentPrefs = Array.isArray(recordValue) ? recordValue : [];
103
- console.log('🔔 NotificationPreferencesEdit - preferences from record:', currentPrefs);
104
- } else if (getValues) {
105
- const formValues = getValues();
106
- const formValue = isNestedSetting
107
- ? getNestedValue(formValues, preferencesPath)
108
- : formValues[attributePath];
109
- currentPrefs = Array.isArray(formValue) ? formValue : [];
110
- console.log('🔔 NotificationPreferencesEdit - preferences from form:', currentPrefs);
111
- }
112
-
113
- // Map available notifications to preferences with defaults
114
- return availableNotifications.map(notification => {
115
- const existing = currentPrefs.find(p => p.id === notification.className);
116
- return existing || {
117
- id: notification.className,
118
- name: notification.name,
119
- email: notification.hasEmail,
120
- push: notification.hasPush,
121
- };
122
- });
123
- }, [availableNotifications, record, attributePath, isNestedSetting, preferencesPath, getValues]);
124
-
125
- // Use local state if modified, otherwise use initial
126
- const preferences = localPreferences ?? initialPreferences;
127
-
128
- // Filter preferences based on search term
129
- const filteredPreferences = useMemo(() => {
130
- if (!searchTerm.trim()) return preferences;
131
- return preferences.filter(pref =>
132
- pref.name.toLowerCase().includes(searchTerm.toLowerCase())
133
- );
134
- }, [preferences, searchTerm]);
135
-
136
- // Update form value when preferences change
137
- const updateFormValue = (newPreferences: NotificationPreference[]) => {
138
- if (!setValue) return;
139
-
140
- if (isNestedSetting) {
141
- const formValues = getValues?.() || {};
142
- const updatedValues = setNestedValue({ ...formValues }, preferencesPath, newPreferences);
143
- setValue(attributePath, getNestedValue(updatedValues, preferencesPath), { shouldDirty: true });
144
- } else {
145
- setValue(attributePath, newPreferences, { shouldDirty: true });
146
- }
147
- };
148
-
149
- // Handle toggle
150
- const handleToggle = (notificationId: string, channel: 'email' | 'push') => {
151
- const updatedPreferences = preferences.map(pref =>
152
- pref.id === notificationId
153
- ? { ...pref, [channel]: !pref[channel] }
154
- : pref
155
- );
156
- setLocalPreferences(updatedPreferences);
157
- updateFormValue(updatedPreferences);
158
- };
159
-
160
- // Early return if no form context
161
- if (!formContext) {
162
- return (
163
- <Alert severity="warning">
164
- Form context not available. This component must be used within a form.
165
- </Alert>
166
- );
167
- }
168
-
169
- // Early return if no notifications
170
- if (availableNotifications.length === 0) {
171
- return (
172
- <Alert severity="info">No notifications available to configure.
173
- <Typography
174
- variant="caption"
175
- sx={{
176
- display: "block",
177
- mt: 1
178
- }}>
179
- Debug: No user_notifications found in systemValues.
180
- Try logging out and logging back in to refresh auth data.
181
- </Typography>
182
- </Alert>
183
- );
184
- }
185
-
186
- return (
187
- <Box sx={{ mt: 1, mb: 2 }}>
188
- <Typography variant="h6" gutterBottom>
189
- Notification Preferences
190
- </Typography>
191
- <Typography
192
- variant="body2"
193
- sx={{
194
- color: "text.secondary",
195
- mb: 2
196
- }}>
197
- Configure which notifications you want to receive via email and push notifications
198
- </Typography>
199
-
200
- {/* Search Box */}
201
- {preferences.length > 5 && (
202
- <TextField
203
- fullWidth
204
- variant="outlined"
205
- placeholder="Search notifications..."
206
- value={searchTerm}
207
- onChange={(e) => setSearchTerm(e.target.value)}
208
- sx={{ mb: 2 }}
209
- slotProps={{
210
- input: {
211
- startAdornment: (
212
- <InputAdornment position="start">
213
- <SearchIcon />
214
- </InputAdornment>
215
- ),
216
- endAdornment: searchTerm && (
217
- <InputAdornment position="end">
218
- <IconButton onClick={() => setSearchTerm('')} edge="end" size="small">
219
- <ClearIcon />
220
- </IconButton>
221
- </InputAdornment>
222
- ),
223
- }
224
- }}
225
- />
226
- )}
227
-
228
- {/* No results message */}
229
- {searchTerm && filteredPreferences.length === 0 && (
230
- <Alert severity="info" sx={{ mb: 2 }}>
231
- No notifications found matching "{searchTerm}"
232
- </Alert>
233
- )}
234
-
235
- {/* Notification list */}
236
- {filteredPreferences.map((preference) => {
237
- const notification = availableNotifications.find(n => n.className === preference.id);
238
- if (!notification) return null;
239
-
240
- return (
241
- <Card
242
- key={preference.id}
243
- variant="outlined"
244
- sx={{
245
- mb: 1,
246
- '&:hover': {
247
- boxShadow: 2,
248
- },
249
- }}
250
- >
251
- <CardContent sx={{ p: 2, '&:last-child': { pb: 2 } }}>
252
- <Box sx={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
253
- <Box sx={{ flex: 1 }}>
254
- <Typography variant="subtitle1" sx={{
255
- fontWeight: "bold"
256
- }}>
257
- {preference.name}
258
- </Typography>
259
- <Box sx={{ display: 'flex', gap: 1, mt: 0.5 }}>
260
- {notification.hasSocket && (
261
- <Chip label="Real-time" size="small" color="info" />
262
- )}
263
- {notification.hasDatabase && (
264
- <Chip label="Stored" size="small" color="default" />
265
- )}
266
- </Box>
267
- </Box>
268
- <Box sx={{ display: 'flex', gap: 2, alignItems: 'center' }}>
269
- {notification.hasEmail && (
270
- <FormControlLabel
271
- control={
272
- <Switch
273
- checked={preference.email}
274
- onChange={() => handleToggle(preference.id, 'email')}
275
- color="primary"
276
- />
277
- }
278
- label={
279
- <Box sx={{ display: 'flex', alignItems: 'center', gap: 0.5 }}>
280
- <EmailIcon fontSize="small" />
281
- <Typography variant="body2">Email</Typography>
282
- </Box>
283
- }
284
- />
285
- )}
286
- {notification.hasPush && (
287
- <FormControlLabel
288
- control={
289
- <Switch
290
- checked={preference.push}
291
- onChange={() => handleToggle(preference.id, 'push')}
292
- color="secondary"
293
- />
294
- }
295
- label={
296
- <Box sx={{ display: 'flex', alignItems: 'center', gap: 0.5 }}>
297
- <PushIcon fontSize="small" />
298
- <Typography variant="body2">Push</Typography>
299
- </Box>
300
- }
301
- />
302
- )}
303
- </Box>
304
- </Box>
305
- </CardContent>
306
- </Card>
307
- );
308
- })}
309
- </Box>
310
- );
311
- };
312
-
313
- /**
314
- * NotificationPreferencesView - View mode component
315
- * All hooks are called unconditionally at the top level
316
- */
317
- export const NotificationPreferencesView: React.FC<IDashAutoAdminCustomFieldComponent> = (props) => {
318
- const { attribute } = props;
319
-
320
- // ALL HOOKS CALLED UNCONDITIONALLY AT TOP LEVEL
321
- const record = useRecordContext();
322
- const [searchTerm, setSearchTerm] = React.useState<string>('');
323
-
324
- // Calculate attribute paths
325
- const attributePath = attribute?.attribute || '';
326
- const isNestedSetting = attributePath.startsWith('preferences.');
327
- const preferencesPath = isNestedSetting ? attributePath.split('.').slice(1).join('.') : attributePath;
328
-
329
- // Get available notifications from systemValues (memoized)
330
- const availableNotifications = useMemo<NotificationConfig[]>(() => {
331
- const systemValues = AuthPersistenceService.getSystemValues();
332
- return systemValues?.user_notifications || [];
333
- }, []);
334
-
335
- // Get current preferences from record (memoized)
336
- const preferences = useMemo<NotificationPreference[]>(() => {
337
- if (!record) return [];
338
- const recordValue = isNestedSetting
339
- ? getNestedValue(record, preferencesPath)
340
- : record[attributePath];
341
- return Array.isArray(recordValue) ? recordValue : [];
342
- }, [record, attributePath, isNestedSetting, preferencesPath]);
343
-
344
- // Filter preferences based on search term
345
- const filteredPreferences = useMemo(() => {
346
- if (!searchTerm.trim()) return preferences;
347
- return preferences.filter(pref =>
348
- pref.name.toLowerCase().includes(searchTerm.toLowerCase())
349
- );
350
- }, [preferences, searchTerm]);
351
-
352
- // Early return if no notifications
353
- if (availableNotifications.length === 0) {
354
- return (
355
- <Alert severity="info">
356
- No notification preferences configured.
357
- </Alert>
358
- );
359
- }
360
-
361
- return (
362
- <Box sx={{ mt: 1, mb: 2 }}>
363
- <Typography variant="h6" gutterBottom>
364
- Notification Preferences
365
- </Typography>
366
-
367
- {/* Search Box */}
368
- {preferences.length > 5 && (
369
- <TextField
370
- fullWidth
371
- variant="outlined"
372
- placeholder="Search notifications..."
373
- value={searchTerm}
374
- onChange={(e) => setSearchTerm(e.target.value)}
375
- sx={{ mb: 2 }}
376
- slotProps={{
377
- input: {
378
- startAdornment: (
379
- <InputAdornment position="start">
380
- <SearchIcon />
381
- </InputAdornment>
382
- ),
383
- endAdornment: searchTerm && (
384
- <InputAdornment position="end">
385
- <IconButton onClick={() => setSearchTerm('')} edge="end" size="small">
386
- <ClearIcon />
387
- </IconButton>
388
- </InputAdornment>
389
- ),
390
- }
391
- }}
392
- />
393
- )}
394
-
395
- {/* Notification list */}
396
- {filteredPreferences.map((preference) => {
397
- const notification = availableNotifications.find(n => n.className === preference.id);
398
- if (!notification) return null;
399
-
400
- return (
401
- <Card key={preference.id} variant="outlined" sx={{ mb: 1 }}>
402
- <CardContent sx={{ p: 2, '&:last-child': { pb: 2 } }}>
403
- <Box sx={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
404
- <Box sx={{ flex: 1 }}>
405
- <Typography variant="subtitle1" sx={{
406
- fontWeight: "bold"
407
- }}>
408
- {preference.name}
409
- </Typography>
410
- <Box sx={{ display: 'flex', gap: 1, mt: 0.5 }}>
411
- {notification.hasSocket && (
412
- <Chip label="Real-time" size="small" color="info" />
413
- )}
414
- {notification.hasDatabase && (
415
- <Chip label="Stored" size="small" color="default" />
416
- )}
417
- </Box>
418
- </Box>
419
- <Box sx={{ display: 'flex', gap: 2 }}>
420
- {notification.hasEmail && (
421
- <Chip
422
- icon={<EmailIcon />}
423
- label="Email"
424
- color={preference.email ? 'primary' : 'default'}
425
- variant={preference.email ? 'filled' : 'outlined'}
426
- />
427
- )}
428
- {notification.hasPush && (
429
- <Chip
430
- icon={<PushIcon />}
431
- label="Push"
432
- color={preference.push ? 'secondary' : 'default'}
433
- variant={preference.push ? 'filled' : 'outlined'}
434
- />
435
- )}
436
- </Box>
437
- </Box>
438
- </CardContent>
439
- </Card>
440
- );
441
- })}
442
-
443
- {preferences.length === 0 && (
444
- <Alert severity="info">
445
- No notification preferences configured
446
- </Alert>
447
- )}
448
- </Box>
449
- );
450
- };
451
-
452
- /**
453
- * NotificationPreferences - Main component
454
- * NO CONDITIONAL HOOKS - All hooks called at top level
455
- * Renders appropriate view based on method prop
456
- */
457
- const NotificationPreferences: React.FC<IDashAutoAdminCustomFieldComponent> = (props) => {
458
-
459
-
460
-
461
- const { method="edit", attribute=null, resourceConfig=null } = props;
462
-
463
- console.log('🔔 NotificationPreferences - method:', method);
464
- console.log('🔔 NotificationPreferences - attribute:', attribute);
465
-
466
- // Determine which component to render based on method
467
- // No hooks, no conditional logic, just a simple switch
468
- switch (method) {
469
- case 'edit':
470
- case 'create':
471
- return <><NotificationPreferencesEdit method={method} attribute={attribute} resourceConfig={resourceConfig} /></>;
472
- case 'view':
473
- return <><NotificationPreferencesView method={method} attribute={attribute} resourceConfig={resourceConfig} /></>;
474
- default:
475
- console.log('🔔 NotificationPreferences - unsupported method:', method);
476
- return null;
477
- }
478
- };
479
-
480
- export default NotificationPreferences;
@@ -1,2 +0,0 @@
1
- export { default as NotificationPreferences } from './NotificationPreferences';
2
- export { NotificationPreferencesEdit, NotificationPreferencesView } from './NotificationPreferences';