@dashadmin/dash-admin 1.3.44 → 1.3.46
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/dist/components/i18n/BridgedLocalesMenuButton.js +1 -2
- package/dist/components/menu/DarkToggleMode.js +1 -1
- package/dist/components/serviceAccount/ApiKeyRevealDialog.js +110 -0
- package/dist/components/serviceAccount/ServiceAccountStatusSwitch.js +94 -0
- package/dist/components/subscription/PlanPricesSettings.js +4 -2
- package/dist/components/tenancy/GlobalTenantWrapper.js +64 -0
- package/dist/components/tenancy/TenantSwitcher.js +389 -0
- package/dist/contexts/com/components/EchoNotificationsCenter.js +40 -0
- package/dist/default-theme/menu/AppMenuComponents/expanded/SidebarItem.js +1 -0
- package/dist/index.js +60 -40
- package/dist/pages/Profile.js +32 -38
- package/dist/providers/i18n/en.js +108 -0
- package/dist/providers/i18n/es.js +108 -0
- package/dist/providers/i18n/languages.js +3 -1
- package/dist/providers/i18n/mergeTranslations.js +18 -0
- package/dist/resources/User/components/AvatarUploadField.js +61 -0
- package/dist/resources/User/components/PasswordFields.js +67 -0
- package/dist/resources/User/getProfileMenu.js +36 -0
- package/dist/resources/User/profileResource.js +33 -0
- package/dist/resources/User/userLayout.js +58 -0
- package/dist/resources/User/userResource.js +90 -0
- package/dist/resources/User/userSchema.js +206 -0
- package/dist/resources/User/usersFilters.js +22 -0
- package/dist/systemResources.js +30 -19
- package/dist/templates/ResourceTemplateCreate.js +5 -2
- package/package.json +4 -1
- package/src/components/i18n/BridgedLocalesMenuButton.tsx +1 -2
- package/src/components/menu/DarkToggleMode.tsx +1 -1
- package/src/components/serviceAccount/ApiKeyRevealDialog.tsx +129 -0
- package/src/components/serviceAccount/ServiceAccountStatusSwitch.tsx +99 -0
- package/src/components/subscription/PlanPricesSettings.tsx +2 -2
- package/src/components/tenancy/GlobalTenantWrapper.tsx +84 -0
- package/src/components/tenancy/TenantSwitcher.tsx +485 -0
- package/src/contexts/com/components/EchoNotificationsCenter.tsx +65 -0
- package/src/default-theme/menu/AppMaterialMenu.tsx +1 -1
- package/src/default-theme/menu/AppMenuComponents/expanded/SidebarItem.tsx +1 -0
- package/src/default-theme/menu/SidebarActions.tsx +1 -1
- package/src/index.tsx +15 -0
- package/src/pages/Profile.tsx +69 -107
- package/src/providers/i18n/en.ts +113 -0
- package/src/providers/i18n/es.ts +113 -0
- package/src/providers/i18n/languages.tsx +3 -0
- package/src/providers/i18n/mergeTranslations.ts +53 -0
- package/src/resources/User/components/AvatarUploadField.tsx +57 -0
- package/src/resources/User/components/PasswordFields.tsx +73 -0
- package/src/resources/User/getProfileMenu.ts +57 -0
- package/src/resources/User/profileResource.tsx +51 -0
- package/src/resources/User/userLayout.tsx +62 -0
- package/src/resources/User/userResource.tsx +111 -0
- package/src/resources/User/userSchema.tsx +213 -0
- package/src/resources/User/usersFilters.tsx +21 -0
- package/src/systemResources.tsx +31 -20
- package/src/templates/ResourceTemplateCreate.tsx +17 -2
package/src/providers/i18n/es.ts
CHANGED
|
@@ -318,8 +318,57 @@ const dashSpanish = {
|
|
|
318
318
|
auto_reset_notice: 'Esta pantalla se reiniciará automáticamente en 30 segundos',
|
|
319
319
|
loading: 'Cargando...',
|
|
320
320
|
},
|
|
321
|
+
// Service account API keys
|
|
322
|
+
serviceAccount: {
|
|
323
|
+
reveal: {
|
|
324
|
+
title: 'Copia tu API Key ahora',
|
|
325
|
+
warning:
|
|
326
|
+
'Esta es la única vez que se mostrará esta clave. No se puede recuperar más adelante — si la pierdes, tendrás que emitir una nueva.',
|
|
327
|
+
forKey: 'Clave',
|
|
328
|
+
copy: 'Copiar',
|
|
329
|
+
copied: 'Copiado',
|
|
330
|
+
dismiss: 'La he guardado',
|
|
331
|
+
},
|
|
332
|
+
status: {
|
|
333
|
+
active: 'Activa',
|
|
334
|
+
disabled: 'Deshabilitada',
|
|
335
|
+
},
|
|
336
|
+
expiration: {
|
|
337
|
+
'1': '1 día',
|
|
338
|
+
'7': '7 días',
|
|
339
|
+
'30': '30 días',
|
|
340
|
+
never: 'Nunca',
|
|
341
|
+
},
|
|
342
|
+
notify: {
|
|
343
|
+
enabled: 'API Key habilitada',
|
|
344
|
+
disabled: 'API Key deshabilitada',
|
|
345
|
+
toggle_error: 'No se pudo cambiar el estado de la API Key',
|
|
346
|
+
},
|
|
347
|
+
action: {
|
|
348
|
+
enable: 'Habilitar',
|
|
349
|
+
disable: 'Deshabilitar',
|
|
350
|
+
},
|
|
351
|
+
// Shown when a tenancy-level role is selected: such a key reaches every
|
|
352
|
+
// tenant in the account, so the tenant field stops being a boundary.
|
|
353
|
+
tenancy_role_warning:
|
|
354
|
+
'Este rol otorga acceso a todos los locales de la cuenta. El local seleccionado es informativo, no un límite de seguridad.',
|
|
355
|
+
},
|
|
321
356
|
// Resource labels for admin panel
|
|
322
357
|
resource: {
|
|
358
|
+
tenancy: {
|
|
359
|
+
serviceAccounts: {
|
|
360
|
+
label: 'Cuentas de Servicio',
|
|
361
|
+
name: 'Nombre',
|
|
362
|
+
tenant: 'Local',
|
|
363
|
+
roles: 'Roles',
|
|
364
|
+
expiration: 'Expiración',
|
|
365
|
+
status: 'Estado',
|
|
366
|
+
token: 'Clave',
|
|
367
|
+
expires_at: 'Expira',
|
|
368
|
+
last_used_at: 'Último uso',
|
|
369
|
+
created_at: 'Creado',
|
|
370
|
+
},
|
|
371
|
+
},
|
|
323
372
|
// Groups
|
|
324
373
|
groups: {
|
|
325
374
|
system_resources: 'Recursos de Sistema',
|
|
@@ -531,6 +580,70 @@ const dashSpanish = {
|
|
|
531
580
|
has_modifiers: 'Personalizable',
|
|
532
581
|
no_more_products: 'No hay más productos',
|
|
533
582
|
},
|
|
583
|
+
// JSON Color Selector - extracción de tema desde imagen
|
|
584
|
+
colorSelector: {
|
|
585
|
+
imageExtractor: {
|
|
586
|
+
title_ai: 'Generador de Tema con IA',
|
|
587
|
+
title_local: 'Tema desde Imagen',
|
|
588
|
+
upload_prompt: 'Sube una Imagen para Extraer Colores',
|
|
589
|
+
upload_hint: 'Selecciona un archivo de imagen y extraeremos automáticamente una paleta de colores',
|
|
590
|
+
upload_button: 'Elegir Imagen',
|
|
591
|
+
drop_hint: 'o arrástrala aquí',
|
|
592
|
+
invalid_file_type: 'Por favor selecciona un archivo de imagen válido',
|
|
593
|
+
file_too_large: 'El archivo debe pesar menos de %{limit}MB',
|
|
594
|
+
extracting: 'Extrayendo colores de la imagen...',
|
|
595
|
+
extracted_colors: 'Colores Extraídos (%{count} colores encontrados)',
|
|
596
|
+
dominant_label: 'Dominante',
|
|
597
|
+
uploaded_image_alt: 'Imagen subida',
|
|
598
|
+
no_palette_error: 'Primero extrae los colores de una imagen',
|
|
599
|
+
theme_generation_failed: 'No se pudo generar el tema',
|
|
600
|
+
theme_description_label: 'Descripción del Tema (Opcional)',
|
|
601
|
+
theme_description_placeholder:
|
|
602
|
+
"Opcional: Describe el estilo de tema que deseas (ej: 'moderno y minimalista', 'cálido y acogedor', 'corporativo profesional')",
|
|
603
|
+
apply_colors_button: 'Aplicar Colores',
|
|
604
|
+
generate_button: 'Generar Tema con IA',
|
|
605
|
+
generating_button: 'Generando...',
|
|
606
|
+
apply_colors_help_label: 'Aplicar Colores:',
|
|
607
|
+
apply_colors_help_desc:
|
|
608
|
+
'Aplica la paleta extraída a los colores base de tu tema localmente — sin usar IA',
|
|
609
|
+
generate_help_label: 'Generar Tema con IA:',
|
|
610
|
+
generate_help_desc:
|
|
611
|
+
'Usa IA para crear un esquema de color completo basado en los colores extraídos y tu descripción',
|
|
612
|
+
},
|
|
613
|
+
},
|
|
614
|
+
// Profile page
|
|
615
|
+
profile: {
|
|
616
|
+
title: 'Perfil',
|
|
617
|
+
subtitle: 'Configuración de perfil',
|
|
618
|
+
info: {
|
|
619
|
+
title: 'Info',
|
|
620
|
+
name: 'Nombre',
|
|
621
|
+
lastname: 'Apellido',
|
|
622
|
+
email: 'Email',
|
|
623
|
+
save: 'Guardar',
|
|
624
|
+
saving: 'Guardando...',
|
|
625
|
+
},
|
|
626
|
+
password: {
|
|
627
|
+
title: 'Contraseñas',
|
|
628
|
+
current: 'Contraseña actual',
|
|
629
|
+
new: 'Nueva contraseña',
|
|
630
|
+
confirm: 'Repita nueva contraseña',
|
|
631
|
+
save: 'Guardar Contraseñas',
|
|
632
|
+
saving: 'Guardando Contraseñas...',
|
|
633
|
+
},
|
|
634
|
+
preferences: {
|
|
635
|
+
title: 'Preferencias',
|
|
636
|
+
},
|
|
637
|
+
validation: {
|
|
638
|
+
required: 'El campo es requerido',
|
|
639
|
+
password_mismatch: 'Las contraseñas no coinciden',
|
|
640
|
+
},
|
|
641
|
+
notify: {
|
|
642
|
+
success: 'Usuario actualizado correctamente',
|
|
643
|
+
error: 'Error al actualizar el usuario',
|
|
644
|
+
error_with_message: 'Error al actualizar el usuario, %{message}',
|
|
645
|
+
},
|
|
646
|
+
},
|
|
534
647
|
};
|
|
535
648
|
|
|
536
649
|
export default {
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Deep-merge translation message trees.
|
|
3
|
+
*
|
|
4
|
+
* Apps compose their messages as `{ ...dashAdminEs, ...customSpanish }`. That
|
|
5
|
+
* spread is shallow, so any top-level key defined on BOTH sides is replaced
|
|
6
|
+
* wholesale by the app's version - every core key underneath it is silently
|
|
7
|
+
* dropped. Apps worked around this by hand-merging one extra level for
|
|
8
|
+
* `resource`, but that only moved the problem down a level: core's
|
|
9
|
+
* `resource.tenancy.*` is still erased by an app that defines any
|
|
10
|
+
* `resource.tenancy` key of its own.
|
|
11
|
+
*
|
|
12
|
+
* This merges recursively instead, so core can ship translations for a subtree
|
|
13
|
+
* an app also contributes to. App values still win on leaf collisions.
|
|
14
|
+
*
|
|
15
|
+
* Arrays are replaced, not concatenated - a translation array is a complete
|
|
16
|
+
* value (e.g. a list of month names), never something to append to.
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* mergeTranslations(dashAdminEs, customSpanish)
|
|
20
|
+
* // core: resource.tenancy.serviceAccounts.label
|
|
21
|
+
* // app: resource.tenancy.tenants.label
|
|
22
|
+
* // -> both survive
|
|
23
|
+
*/
|
|
24
|
+
export type TranslationMessages = Record<string, any>;
|
|
25
|
+
|
|
26
|
+
const isPlainObject = (value: unknown): value is TranslationMessages =>
|
|
27
|
+
typeof value === 'object' &&
|
|
28
|
+
value !== null &&
|
|
29
|
+
!Array.isArray(value);
|
|
30
|
+
|
|
31
|
+
export const mergeTranslations = (
|
|
32
|
+
...sources: (TranslationMessages | undefined | null)[]
|
|
33
|
+
): TranslationMessages => {
|
|
34
|
+
const result: TranslationMessages = {};
|
|
35
|
+
|
|
36
|
+
for (const source of sources) {
|
|
37
|
+
if (!isPlainObject(source)) continue;
|
|
38
|
+
|
|
39
|
+
for (const key of Object.keys(source)) {
|
|
40
|
+
const incoming = source[key];
|
|
41
|
+
const existing = result[key];
|
|
42
|
+
|
|
43
|
+
result[key] =
|
|
44
|
+
isPlainObject(existing) && isPlainObject(incoming)
|
|
45
|
+
? mergeTranslations(existing, incoming)
|
|
46
|
+
: incoming;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
return result;
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
export default mergeTranslations;
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { IDashAutoAdminCustomFieldComponent } from 'dash-auto-admin';
|
|
3
|
+
import { useRecordContext } from 'react-admin';
|
|
4
|
+
import { SingleImageUploader } from 'dash-components';
|
|
5
|
+
import { useFormContext } from 'react-hook-form';
|
|
6
|
+
|
|
7
|
+
export type AvatarComponent = IDashAutoAdminCustomFieldComponent;
|
|
8
|
+
|
|
9
|
+
export const AvatarHandler: React.FC<AvatarComponent> = (props) => {
|
|
10
|
+
const { method, attribute } = props;
|
|
11
|
+
const record = useRecordContext();
|
|
12
|
+
const {
|
|
13
|
+
setValue,
|
|
14
|
+
formState: { errors },
|
|
15
|
+
} = useFormContext();
|
|
16
|
+
|
|
17
|
+
const onChange = (file: File) => {
|
|
18
|
+
setValue(attribute.attribute, file, { shouldDirty: true });
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
return (
|
|
22
|
+
<>
|
|
23
|
+
<SingleImageUploader
|
|
24
|
+
classNamePrefix='dash-profile'
|
|
25
|
+
{...method === "edit" && { currentUrl: `${record.image_path}`} }
|
|
26
|
+
onChange={onChange}
|
|
27
|
+
/>
|
|
28
|
+
{errors[attribute.attribute] && (
|
|
29
|
+
<span style={{ color: 'red' }}>
|
|
30
|
+
{errors[attribute.attribute]?.message?.toString() || 'Error'}
|
|
31
|
+
</span>
|
|
32
|
+
)}
|
|
33
|
+
</>
|
|
34
|
+
);
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Generic user-avatar upload field for the shared user resource schema.
|
|
39
|
+
*
|
|
40
|
+
* Moved from kt-ecommerce (components/User/Avatar.tsx) - purely generic
|
|
41
|
+
* (dash-auto-admin/dash-components/react-hook-form only, no kitchntabs- or
|
|
42
|
+
* vanexa-specific logic), so it belongs alongside userSchema.tsx here rather
|
|
43
|
+
* than duplicated per domain. Renamed from "Avatar" to avoid colliding with
|
|
44
|
+
* dash-admin's unrelated components/user/AvatarComponent.tsx (the topbar
|
|
45
|
+
* user-menu avatar widget - a different component for a different purpose).
|
|
46
|
+
*/
|
|
47
|
+
const AvatarUploadField = ({ method, attribute, resourceConfig }: IDashAutoAdminCustomFieldComponent) => {
|
|
48
|
+
switch (method) {
|
|
49
|
+
case 'edit':
|
|
50
|
+
return <AvatarHandler attribute={attribute} method={method} resourceConfig={resourceConfig} />;
|
|
51
|
+
case 'create':
|
|
52
|
+
return <AvatarHandler attribute={attribute} method={method} resourceConfig={resourceConfig} />;
|
|
53
|
+
case 'view':
|
|
54
|
+
return <></>;
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
export default AvatarUploadField;
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { IDashAutoAdminCustomFieldComponent } from 'dash-auto-admin';
|
|
3
|
+
import {
|
|
4
|
+
PasswordInput,
|
|
5
|
+
} from 'react-admin';
|
|
6
|
+
import { Box } from '@mui/material';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Generic password + confirm-password field pair for the shared user
|
|
10
|
+
* resource schema. Moved from kt-ecommerce (components/User/Password.tsx) -
|
|
11
|
+
* no kitchntabs- or vanexa-specific logic. Renamed from "Password" to avoid
|
|
12
|
+
* ambiguity with other password-related components in this package.
|
|
13
|
+
*/
|
|
14
|
+
export type PasswordComponent = IDashAutoAdminCustomFieldComponent;
|
|
15
|
+
export const PasswordShow: React.FC<PasswordComponent> = (_props) => {
|
|
16
|
+
return <></>;
|
|
17
|
+
};
|
|
18
|
+
export const PasswordEdit: React.FC<PasswordComponent> = (_props) => {
|
|
19
|
+
|
|
20
|
+
return (
|
|
21
|
+
<>
|
|
22
|
+
<Box>
|
|
23
|
+
<PasswordInput
|
|
24
|
+
sx={{ width: '100%' }}
|
|
25
|
+
autoComplete='off'
|
|
26
|
+
source='Contraseña'
|
|
27
|
+
name='password'
|
|
28
|
+
/>
|
|
29
|
+
</Box>
|
|
30
|
+
<Box>
|
|
31
|
+
<PasswordInput
|
|
32
|
+
sx={{ width: '100%' }}
|
|
33
|
+
autoComplete='off'
|
|
34
|
+
source='Confirmar Contraseña'
|
|
35
|
+
name='password_confirmation'
|
|
36
|
+
/>
|
|
37
|
+
</Box>
|
|
38
|
+
</>
|
|
39
|
+
);
|
|
40
|
+
};
|
|
41
|
+
export const PasswordCreate: React.FC<PasswordComponent> = (_props) => {
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
return (
|
|
45
|
+
<>
|
|
46
|
+
<Box>
|
|
47
|
+
<PasswordInput
|
|
48
|
+
sx={{ width: '100%' }}
|
|
49
|
+
source='Contraseña'
|
|
50
|
+
name='password'
|
|
51
|
+
/>
|
|
52
|
+
</Box>
|
|
53
|
+
<Box>
|
|
54
|
+
<PasswordInput
|
|
55
|
+
sx={{ width: '100%' }}
|
|
56
|
+
source='Confirmar Contraseña'
|
|
57
|
+
name='password_confirmation'
|
|
58
|
+
/>
|
|
59
|
+
</Box>
|
|
60
|
+
</>
|
|
61
|
+
);
|
|
62
|
+
};
|
|
63
|
+
const PasswordFields = ({ method, attribute, resourceConfig }: IDashAutoAdminCustomFieldComponent) => {
|
|
64
|
+
switch (method) {
|
|
65
|
+
case 'edit':
|
|
66
|
+
return <PasswordEdit attribute={attribute} method={method} resourceConfig={resourceConfig} />;
|
|
67
|
+
case 'create':
|
|
68
|
+
return <PasswordCreate attribute={attribute} method={method} resourceConfig={resourceConfig} />;
|
|
69
|
+
case 'view':
|
|
70
|
+
return <PasswordShow attribute={attribute} method={method} resourceConfig={resourceConfig} />;
|
|
71
|
+
}
|
|
72
|
+
};
|
|
73
|
+
export default PasswordFields;
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Profile menu generator for user navigation.
|
|
3
|
+
*
|
|
4
|
+
* Moved here from kt-utils (getProfileMenu.ts) per the profile/user resource
|
|
5
|
+
* refactor - it is consumed by resources/User/profileResource.tsx, which now
|
|
6
|
+
* also lives in this package, and doesn't depend on anything kitchntabs- or
|
|
7
|
+
* vanexa-specific beyond the 'Cliente' role check below (kept verbatim - both
|
|
8
|
+
* domains currently use it identically; a domain that needs a different
|
|
9
|
+
* profile menu can still override profileResource.menu after importing it).
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import { dashStorage } from 'dash-utils';
|
|
13
|
+
import type IApplicationLayoutMenuItem from 'dash-auto-admin/src/interfaces/IDashApplicationLayoutMenuItem';
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Generates the profile menu based on user roles
|
|
17
|
+
*/
|
|
18
|
+
const getProfileMenu = (resourceConfig?: any): IApplicationLayoutMenuItem[] => {
|
|
19
|
+
const userStr = dashStorage.getItem('user');
|
|
20
|
+
const rolesStr = dashStorage.getItem('roles');
|
|
21
|
+
|
|
22
|
+
const user = userStr ? JSON.parse(userStr) : null;
|
|
23
|
+
const roles: any[] = rolesStr ? JSON.parse(rolesStr) : [];
|
|
24
|
+
|
|
25
|
+
const profileMenu: IApplicationLayoutMenuItem[] = [
|
|
26
|
+
{
|
|
27
|
+
title: 'Perfil',
|
|
28
|
+
redirect: '/profile',
|
|
29
|
+
},
|
|
30
|
+
];
|
|
31
|
+
|
|
32
|
+
const isCliente = roles
|
|
33
|
+
? roles.map((role) => role.name).includes('Cliente')
|
|
34
|
+
: false;
|
|
35
|
+
|
|
36
|
+
if (isCliente) {
|
|
37
|
+
profileMenu.push(
|
|
38
|
+
{
|
|
39
|
+
title: 'Comunas',
|
|
40
|
+
redirect: '/profile/commune',
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
title: 'Centros Logísticos',
|
|
44
|
+
redirect: '/profile/logistic-center',
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
title: 'Notificaciones',
|
|
48
|
+
redirect: '/profile/notification',
|
|
49
|
+
},
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
return profileMenu;
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
export default getProfileMenu;
|
|
57
|
+
export { getProfileMenu };
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { IDashAutoAdminResourceConfig } from 'dash-auto-admin';
|
|
2
|
+
import ResourceTemplate from '../../templates/ResourceTemplate';
|
|
3
|
+
import Dashboard from '@mui/icons-material/Dashboard';
|
|
4
|
+
import {DASHAdminSystemConstants} from 'dash-constants';
|
|
5
|
+
|
|
6
|
+
import getProfileMenu from './getProfileMenu';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Shared "/profile" resource shell.
|
|
10
|
+
*
|
|
11
|
+
* Moved here from kt-ecommerce (resources/user/profileResource.tsx) - the
|
|
12
|
+
* config itself is generic. `listComponent` is intentionally left unset: the
|
|
13
|
+
* kt-ecommerce original hardcoded kt-pages' CustomProfile page, which would
|
|
14
|
+
* have made this package depend on a kitchntabs-flavored consumer package
|
|
15
|
+
* (backwards - dash-admin is core, kt-pages/kt-ecommerce are domain layers
|
|
16
|
+
* built on top of it). Each app supplies its own profile page component by
|
|
17
|
+
* overriding `listComponent` after importing this base config, e.g.:
|
|
18
|
+
*
|
|
19
|
+
* import profileResource from 'dash-admin/src/resources/User/profileResource';
|
|
20
|
+
* import CustomProfile from 'kt-pages/src/pages/Account/CustomProfile';
|
|
21
|
+
*
|
|
22
|
+
* export default {
|
|
23
|
+
* ...profileResource,
|
|
24
|
+
* listComponent: (_resourceConfig) => <CustomProfile />,
|
|
25
|
+
* };
|
|
26
|
+
*/
|
|
27
|
+
const profileResource: IDashAutoAdminResourceConfig = {
|
|
28
|
+
filterWithSubmit: true,
|
|
29
|
+
roles: ["*"
|
|
30
|
+
/*
|
|
31
|
+
DASHAdminSystemConstants.system.DASH_SYSTEM_ROLE,
|
|
32
|
+
DASHAppConstants.system.TENANT_ROLE,
|
|
33
|
+
DASHAppConstants.system.USER_ROLE,
|
|
34
|
+
DASHAppConstants.system.CREATOR_ROLE,
|
|
35
|
+
DASHAppConstants.system.CLOSING_ROLE,
|
|
36
|
+
DASHAppConstants.system.GUNNER_ROLE,
|
|
37
|
+
DASHAppConstants.system.DRIVER_ROLE
|
|
38
|
+
*/
|
|
39
|
+
],
|
|
40
|
+
component: ResourceTemplate,
|
|
41
|
+
hidden: true,
|
|
42
|
+
model: 'profile',
|
|
43
|
+
group: 'Perfil',
|
|
44
|
+
label: 'Perfil',
|
|
45
|
+
icon: <Dashboard />,
|
|
46
|
+
schema: null,
|
|
47
|
+
menu: getProfileMenu,
|
|
48
|
+
listProps : { perPage: DASHAdminSystemConstants.system.DEFAULT_PER_PAGE || 50}
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
export default profileResource;
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { Box, Card, Grid } from '@mui/material';
|
|
2
|
+
|
|
3
|
+
const userLayout = (render) => {
|
|
4
|
+
return (
|
|
5
|
+
<Grid container spacing={1}>
|
|
6
|
+
<Grid size={{ xs: 12, md: 4 }}>
|
|
7
|
+
<Grid container>
|
|
8
|
+
<Grid size={12}>
|
|
9
|
+
<Card sx={{ mb: 1 }} className='dash-widget'>
|
|
10
|
+
<Box
|
|
11
|
+
sx={{ p: 1 }}
|
|
12
|
+
style={{ display: 'flex', alignItems: 'center' }}
|
|
13
|
+
>
|
|
14
|
+
<span className='card-title'>Avatar</span>
|
|
15
|
+
</Box>
|
|
16
|
+
<Box sx={{ p: 1 }}>{render('Avatar')}</Box>
|
|
17
|
+
</Card>
|
|
18
|
+
</Grid>
|
|
19
|
+
<Grid size={12}>
|
|
20
|
+
<Card sx={{ mb: 1 }} className='dash-widget'>
|
|
21
|
+
<Box
|
|
22
|
+
sx={{ p: 1 }}
|
|
23
|
+
style={{ display: 'flex', alignItems: 'center' }}
|
|
24
|
+
>
|
|
25
|
+
<span className='card-title'>Credenciales</span>
|
|
26
|
+
</Box>
|
|
27
|
+
<Box sx={{ p: 1 }}>{render('Credenciales')}</Box>
|
|
28
|
+
</Card>
|
|
29
|
+
</Grid>
|
|
30
|
+
</Grid>
|
|
31
|
+
</Grid>
|
|
32
|
+
<Grid size={{ xs: 12, md: 8 }}>
|
|
33
|
+
<Grid container >
|
|
34
|
+
<Grid size={12}>
|
|
35
|
+
<Card sx={{ mb: 1 }} className='dash-widget'>
|
|
36
|
+
<Box
|
|
37
|
+
sx={{ p: 1 }}
|
|
38
|
+
style={{ display: 'flex', alignItems: 'center' }}
|
|
39
|
+
>
|
|
40
|
+
<span className='card-title'>Datos del usuario</span>
|
|
41
|
+
</Box>
|
|
42
|
+
<Box sx={{ p: 1 }}>{render('Datos del usuario')}</Box>
|
|
43
|
+
</Card>
|
|
44
|
+
</Grid>
|
|
45
|
+
<Grid size={12}>
|
|
46
|
+
<Card sx={{ mb: 1 }} className='dash-widget'>
|
|
47
|
+
<Box
|
|
48
|
+
sx={{ p: 1 }}
|
|
49
|
+
style={{ display: 'flex', alignItems: 'center' }}
|
|
50
|
+
>
|
|
51
|
+
<span className='card-title'>Configuración</span>
|
|
52
|
+
</Box>
|
|
53
|
+
<Box sx={{ p: 1 }}>{render('Configuración')}</Box>
|
|
54
|
+
</Card>
|
|
55
|
+
</Grid>
|
|
56
|
+
</Grid>
|
|
57
|
+
</Grid>
|
|
58
|
+
</Grid>
|
|
59
|
+
|
|
60
|
+
);};
|
|
61
|
+
|
|
62
|
+
export default userLayout;
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import { IDashAutoAdminResourceConfig } from 'dash-auto-admin';
|
|
2
|
+
import ResourceTemplate from '../../templates/ResourceTemplate';
|
|
3
|
+
import Settings from '@mui/icons-material/Settings';
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
import { PaginationComponent } from 'dash-components';
|
|
7
|
+
|
|
8
|
+
import { Card } from '@mui/material';
|
|
9
|
+
import { downloadCSV } from 'react-admin';
|
|
10
|
+
import {DASHAppConstants} from 'dash-constants';
|
|
11
|
+
import jsonExport from 'jsonexport/dist';
|
|
12
|
+
import {DASHAdminSystemConstants} from 'dash-constants';
|
|
13
|
+
import userLayout from './userLayout';
|
|
14
|
+
import userSchema from './userSchema';
|
|
15
|
+
import { NoResults } from '../../components/misc/NoResults';
|
|
16
|
+
import usersFilters from './usersFilters';
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Shared tenant-user CRUD resource (list/create/edit/trash for `tenant/user`).
|
|
20
|
+
*
|
|
21
|
+
* Moved here from kt-ecommerce (resources/user/userResource.tsx) - nothing in
|
|
22
|
+
* this config is kitchntabs- or vanexa-specific (model, schema, layout and
|
|
23
|
+
* filters were all already generic; the only reason it lived in kt-ecommerce
|
|
24
|
+
* was history), so every app - kitchntabs-* and vanexa-* alike - should
|
|
25
|
+
* consume this single copy instead of each domain package carrying its own.
|
|
26
|
+
*/
|
|
27
|
+
const userResource: IDashAutoAdminResourceConfig = {
|
|
28
|
+
filterWithSubmit: true,
|
|
29
|
+
roles: [
|
|
30
|
+
DASHAdminSystemConstants.system.DASH_SYSTEM_ROLE,
|
|
31
|
+
DASHAppConstants.system.TENANT_ROLE,
|
|
32
|
+
],
|
|
33
|
+
component: ResourceTemplate,
|
|
34
|
+
trash: true,
|
|
35
|
+
model: 'tenant/user',
|
|
36
|
+
|
|
37
|
+
schema: userSchema,
|
|
38
|
+
icon: <Settings />,
|
|
39
|
+
|
|
40
|
+
group: "resource.groups.configuration",
|
|
41
|
+
label: "resource.ecommerce.users.label",
|
|
42
|
+
|
|
43
|
+
menu: [
|
|
44
|
+
{
|
|
45
|
+
title: 'Usuarios',
|
|
46
|
+
redirect: '/tenant/user',
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
title: "🗑",
|
|
50
|
+
redirect: "/tenant/user/trash",
|
|
51
|
+
}
|
|
52
|
+
],
|
|
53
|
+
resourceMenuDisabled: false,
|
|
54
|
+
refreshAfter:true,
|
|
55
|
+
/*customListActions: (props) => {
|
|
56
|
+
const { children } = props;
|
|
57
|
+
return <Card sx={{ mb: 2 }} className='dash-card-content dash-module top-toolbar'>{children}</Card>;
|
|
58
|
+
},*/
|
|
59
|
+
isFormData: true,
|
|
60
|
+
/** @deprecated TODO: side effects? seems is not implemented anywhere */
|
|
61
|
+
listEditButton: { enabled: true },
|
|
62
|
+
|
|
63
|
+
postFormatter: (params, _method) => {
|
|
64
|
+
if (!params.avatar) {
|
|
65
|
+
// delete the param if value is falsy, undefined, null, etc..
|
|
66
|
+
delete params.avatar;
|
|
67
|
+
}
|
|
68
|
+
return params;
|
|
69
|
+
},
|
|
70
|
+
dataGridProps: { stickyHeader: true, empty: <NoResults />, bulkActionButtons: false },
|
|
71
|
+
listProps: { perPage: DASHAdminSystemConstants.system.DEFAULT_PER_PAGE || 50, empty: false },
|
|
72
|
+
dataGridWrapper: (props) => {
|
|
73
|
+
const { children } = props;
|
|
74
|
+
return <div className='sticky-header-wrapper'>{children}</div>;
|
|
75
|
+
},
|
|
76
|
+
redirectAfterUpdate: false,
|
|
77
|
+
createLayout: userLayout,
|
|
78
|
+
editLayout: userLayout,
|
|
79
|
+
formGroupMode: 'layout',
|
|
80
|
+
/*exporter: (clients) => {
|
|
81
|
+
const clientsForExport = clients.map((client) => {
|
|
82
|
+
return client;
|
|
83
|
+
});
|
|
84
|
+
jsonExport(
|
|
85
|
+
clientsForExport,
|
|
86
|
+
{
|
|
87
|
+
//headers: ['id', 'title', 'author_name', 'body'] // order fields in the export
|
|
88
|
+
},
|
|
89
|
+
(err, csv) => {
|
|
90
|
+
downloadCSV(csv, 'clientes');
|
|
91
|
+
},
|
|
92
|
+
);
|
|
93
|
+
},*/
|
|
94
|
+
create: true,
|
|
95
|
+
edit: true,
|
|
96
|
+
view: false,
|
|
97
|
+
listViewButton: { enabled: false },
|
|
98
|
+
toolbarCreateButton: { enabled: true },
|
|
99
|
+
toolbarEditButton: { enabled: false },
|
|
100
|
+
toolbarExportButton: { enabled: false },
|
|
101
|
+
toolbarListButton: { enabled: true },
|
|
102
|
+
listDeleteButton: { enabled: true, props: { confirm: true } },
|
|
103
|
+
Pagination: PaginationComponent,
|
|
104
|
+
drawer: false,
|
|
105
|
+
|
|
106
|
+
mutationMode: 'pessimistic',
|
|
107
|
+
referenceFilters: usersFilters,
|
|
108
|
+
|
|
109
|
+
};
|
|
110
|
+
|
|
111
|
+
export default userResource;
|