@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/dist/pages/Profile.js
CHANGED
|
@@ -26,12 +26,13 @@ import {
|
|
|
26
26
|
useRefresh,
|
|
27
27
|
Loading,
|
|
28
28
|
useNotify,
|
|
29
|
+
useTranslate,
|
|
29
30
|
TextInput
|
|
30
31
|
} from "react-admin";
|
|
31
32
|
import { useDispatch } from "react-redux";
|
|
32
33
|
import { DASH_REDUX_ACTIONS } from "dash-admin-state";
|
|
33
|
-
import useAxios from "
|
|
34
|
-
import SingleImageUploader from "
|
|
34
|
+
import { useAxios } from "dash-axios-hook";
|
|
35
|
+
import { SingleImageUploader } from "dash-components";
|
|
35
36
|
import { useAuthContext } from "../contexts/auth";
|
|
36
37
|
import UserPreferences from "../components/user/UserPreferences";
|
|
37
38
|
const Profile = (_props) => {
|
|
@@ -40,31 +41,35 @@ const Profile = (_props) => {
|
|
|
40
41
|
const { user, fetchAuth } = useAuthContext();
|
|
41
42
|
const [avatar, setAvatar] = useState({ rawFile: null, urlFile: "" });
|
|
42
43
|
const notify = useNotify();
|
|
43
|
-
const
|
|
44
|
+
const translate = useTranslate();
|
|
45
|
+
const axios = useAxios();
|
|
44
46
|
const refresh = useRefresh();
|
|
47
|
+
const { showPreferences = false } = _props;
|
|
45
48
|
const dispatch = useDispatch();
|
|
46
49
|
useEffect(() => {
|
|
47
50
|
dispatch(
|
|
48
51
|
DASH_REDUX_ACTIONS.updatePage({
|
|
49
|
-
title: "Perfil",
|
|
52
|
+
title: translate("profile.title", { _: "Perfil" }),
|
|
50
53
|
//icon:
|
|
51
|
-
subTitle: "Configuraci\xF3n de perfil"
|
|
54
|
+
subTitle: translate("profile.subtitle", { _: "Configuraci\xF3n de perfil" })
|
|
52
55
|
})
|
|
53
56
|
);
|
|
54
|
-
}, []);
|
|
57
|
+
}, [translate]);
|
|
55
58
|
const validateUserCreation = (values) => {
|
|
56
59
|
const errors = {};
|
|
57
60
|
if (currTab === "auth/update/password") {
|
|
61
|
+
const required = translate("profile.validation.required", { _: "El campo es requerido" });
|
|
62
|
+
const mismatch = translate("profile.validation.password_mismatch", { _: "Las contrase\xF1as no coinciden" });
|
|
58
63
|
if ((values.password || values.password_confirmation) && !values.current_password) {
|
|
59
|
-
errors.current_password =
|
|
64
|
+
errors.current_password = required;
|
|
60
65
|
}
|
|
61
66
|
if (values.current_password && (!values.password || !values.password_confirmation)) {
|
|
62
|
-
errors.password =
|
|
63
|
-
errors.password_confirmation =
|
|
67
|
+
errors.password = required;
|
|
68
|
+
errors.password_confirmation = required;
|
|
64
69
|
}
|
|
65
70
|
if (values.password_confirmation !== values.password) {
|
|
66
|
-
errors.password =
|
|
67
|
-
errors.password_confirmation =
|
|
71
|
+
errors.password = mismatch;
|
|
72
|
+
errors.password_confirmation = mismatch;
|
|
68
73
|
}
|
|
69
74
|
}
|
|
70
75
|
return errors;
|
|
@@ -103,17 +108,17 @@ const Profile = (_props) => {
|
|
|
103
108
|
yield fetchAuth();
|
|
104
109
|
console.log("Auth context refreshed after profile update");
|
|
105
110
|
} catch (authError) {
|
|
106
|
-
console.error("
|
|
111
|
+
console.error("Failed to refresh auth context:", authError);
|
|
107
112
|
}
|
|
108
|
-
notify("Usuario actualizado correctamente", { type: "success" });
|
|
113
|
+
notify(translate("profile.notify.success", { _: "Usuario actualizado correctamente" }), { type: "success" });
|
|
109
114
|
refresh();
|
|
110
115
|
} catch (error) {
|
|
111
116
|
let mainMessage = ((_b = (_a = error == null ? void 0 : error.response) == null ? void 0 : _a.data) == null ? void 0 : _b.message) || ((_c = error == null ? void 0 : error.body) == null ? void 0 : _c.message) || "";
|
|
112
117
|
let fieldErrors = ((_e = (_d = error == null ? void 0 : error.response) == null ? void 0 : _d.data) == null ? void 0 : _e.errors) || ((_f = error == null ? void 0 : error.body) == null ? void 0 : _f.errors) || error;
|
|
113
118
|
if (mainMessage) {
|
|
114
|
-
notify(`Error al actualizar el usuario, ${mainMessage}
|
|
119
|
+
notify(translate("profile.notify.error_with_message", { message: mainMessage, _: `Error al actualizar el usuario, ${mainMessage}` }), { type: "error" });
|
|
115
120
|
} else {
|
|
116
|
-
notify("Error al actualizar el usuario", { type: "error" });
|
|
121
|
+
notify(translate("profile.notify.error", { _: "Error al actualizar el usuario" }), { type: "error" });
|
|
117
122
|
}
|
|
118
123
|
if (fieldErrors && typeof fieldErrors === "object") {
|
|
119
124
|
const errors = {};
|
|
@@ -124,6 +129,7 @@ const Profile = (_props) => {
|
|
|
124
129
|
}
|
|
125
130
|
} finally {
|
|
126
131
|
setIsLoading(false);
|
|
132
|
+
window.location.reload();
|
|
127
133
|
}
|
|
128
134
|
});
|
|
129
135
|
const handleInfoSubmit = () => {
|
|
@@ -165,7 +171,6 @@ const Profile = (_props) => {
|
|
|
165
171
|
width: "100%"
|
|
166
172
|
},
|
|
167
173
|
children: [
|
|
168
|
-
"<!-- F -->",
|
|
169
174
|
/* @__PURE__ */ jsx(
|
|
170
175
|
SingleImageUploader,
|
|
171
176
|
{
|
|
@@ -211,7 +216,7 @@ const Profile = (_props) => {
|
|
|
211
216
|
CardHeader,
|
|
212
217
|
{
|
|
213
218
|
sx: { padding: "16px 25px 0" },
|
|
214
|
-
title: "Info"
|
|
219
|
+
title: translate("profile.info.title", { _: "Info" })
|
|
215
220
|
}
|
|
216
221
|
),
|
|
217
222
|
/* @__PURE__ */ jsx(CardContent, { sx: { padding: "25px" }, children: /* @__PURE__ */ jsxs(Grid, { container: true, spacing: 2, children: [
|
|
@@ -219,7 +224,7 @@ const Profile = (_props) => {
|
|
|
219
224
|
TextInput,
|
|
220
225
|
{
|
|
221
226
|
source: "name",
|
|
222
|
-
label: "Nombre",
|
|
227
|
+
label: translate("profile.info.name", { _: "Nombre" }),
|
|
223
228
|
variant: "outlined",
|
|
224
229
|
fullWidth: true
|
|
225
230
|
}
|
|
@@ -228,7 +233,7 @@ const Profile = (_props) => {
|
|
|
228
233
|
TextInput,
|
|
229
234
|
{
|
|
230
235
|
source: "lastname",
|
|
231
|
-
label: "Apellido",
|
|
236
|
+
label: translate("profile.info.lastname", { _: "Apellido" }),
|
|
232
237
|
variant: "outlined",
|
|
233
238
|
fullWidth: true
|
|
234
239
|
}
|
|
@@ -237,7 +242,7 @@ const Profile = (_props) => {
|
|
|
237
242
|
TextInput,
|
|
238
243
|
{
|
|
239
244
|
source: "email",
|
|
240
|
-
label: "Email",
|
|
245
|
+
label: translate("profile.info.email", { _: "Email" }),
|
|
241
246
|
variant: "outlined",
|
|
242
247
|
fullWidth: true
|
|
243
248
|
}
|
|
@@ -258,7 +263,7 @@ const Profile = (_props) => {
|
|
|
258
263
|
color: "white"
|
|
259
264
|
}
|
|
260
265
|
},
|
|
261
|
-
children: isLoading && currTab === "auth/update/info" ? "Guardando..." : "Guardar"
|
|
266
|
+
children: isLoading && currTab === "auth/update/info" ? translate("profile.info.saving", { _: "Guardando..." }) : translate("profile.info.save", { _: "Guardar" })
|
|
262
267
|
}
|
|
263
268
|
) })
|
|
264
269
|
] }) })
|
|
@@ -268,7 +273,7 @@ const Profile = (_props) => {
|
|
|
268
273
|
CardHeader,
|
|
269
274
|
{
|
|
270
275
|
sx: { padding: "16px 25px 0" },
|
|
271
|
-
title: "Contrase\xF1as"
|
|
276
|
+
title: translate("profile.password.title", { _: "Contrase\xF1as" })
|
|
272
277
|
}
|
|
273
278
|
),
|
|
274
279
|
/* @__PURE__ */ jsx(CardContent, { sx: { padding: "25px" }, children: /* @__PURE__ */ jsxs(Grid, { container: true, spacing: 2, children: [
|
|
@@ -277,7 +282,7 @@ const Profile = (_props) => {
|
|
|
277
282
|
{
|
|
278
283
|
type: "password",
|
|
279
284
|
source: "current_password",
|
|
280
|
-
label: "Contrase\xF1a actual",
|
|
285
|
+
label: translate("profile.password.current", { _: "Contrase\xF1a actual" }),
|
|
281
286
|
variant: "outlined",
|
|
282
287
|
fullWidth: true
|
|
283
288
|
}
|
|
@@ -287,7 +292,7 @@ const Profile = (_props) => {
|
|
|
287
292
|
{
|
|
288
293
|
type: "password",
|
|
289
294
|
source: "password",
|
|
290
|
-
label: "Nueva contrase\xF1a",
|
|
295
|
+
label: translate("profile.password.new", { _: "Nueva contrase\xF1a" }),
|
|
291
296
|
variant: "outlined",
|
|
292
297
|
fullWidth: true
|
|
293
298
|
}
|
|
@@ -295,7 +300,7 @@ const Profile = (_props) => {
|
|
|
295
300
|
/* @__PURE__ */ jsx(Grid, { size: 12, children: /* @__PURE__ */ jsx(
|
|
296
301
|
TextInput,
|
|
297
302
|
{
|
|
298
|
-
label: "Repita nueva contrase\xF1a",
|
|
303
|
+
label: translate("profile.password.confirm", { _: "Repita nueva contrase\xF1a" }),
|
|
299
304
|
type: "password",
|
|
300
305
|
source: "password_confirmation",
|
|
301
306
|
variant: "outlined",
|
|
@@ -318,23 +323,12 @@ const Profile = (_props) => {
|
|
|
318
323
|
color: "white"
|
|
319
324
|
}
|
|
320
325
|
},
|
|
321
|
-
children: isLoading && currTab === "auth/update/password" ? "Guardando Contrase\xF1as..." : "Guardar Contrase\xF1as"
|
|
326
|
+
children: isLoading && currTab === "auth/update/password" ? translate("profile.password.saving", { _: "Guardando Contrase\xF1as..." }) : translate("profile.password.save", { _: "Guardar Contrase\xF1as" })
|
|
322
327
|
}
|
|
323
328
|
) })
|
|
324
329
|
] }) })
|
|
325
330
|
] }),
|
|
326
|
-
/* @__PURE__ */
|
|
327
|
-
xs: 12
|
|
328
|
-
}, children: [
|
|
329
|
-
/* @__PURE__ */ jsx(
|
|
330
|
-
CardHeader,
|
|
331
|
-
{
|
|
332
|
-
sx: { padding: "16px 25px 0" },
|
|
333
|
-
title: "Preferencias"
|
|
334
|
-
}
|
|
335
|
-
),
|
|
336
|
-
/* @__PURE__ */ jsx(CardContent, { sx: { padding: "25px" }, children: /* @__PURE__ */ jsx(UserPreferences, {}) })
|
|
337
|
-
] })
|
|
331
|
+
showPreferences && /* @__PURE__ */ jsx(Grid, { size: { xs: 12 }, children: /* @__PURE__ */ jsx(CardContent, { sx: { padding: "25px" }, children: /* @__PURE__ */ jsx(UserPreferences, {}) }) })
|
|
338
332
|
]
|
|
339
333
|
}
|
|
340
334
|
) })
|
|
@@ -302,8 +302,55 @@ const dashEnglish = {
|
|
|
302
302
|
auto_reset_notice: "This screen will automatically reset in 30 seconds",
|
|
303
303
|
loading: "Loading..."
|
|
304
304
|
},
|
|
305
|
+
// Service account API keys
|
|
306
|
+
serviceAccount: {
|
|
307
|
+
reveal: {
|
|
308
|
+
title: "Copy your API key now",
|
|
309
|
+
warning: "This is the only time this key will be shown. It cannot be recovered later \u2014 if you lose it, you will have to issue a new one.",
|
|
310
|
+
forKey: "Key",
|
|
311
|
+
copy: "Copy",
|
|
312
|
+
copied: "Copied",
|
|
313
|
+
dismiss: "I have saved it"
|
|
314
|
+
},
|
|
315
|
+
status: {
|
|
316
|
+
active: "Active",
|
|
317
|
+
disabled: "Disabled"
|
|
318
|
+
},
|
|
319
|
+
expiration: {
|
|
320
|
+
"1": "1 day",
|
|
321
|
+
"7": "7 days",
|
|
322
|
+
"30": "30 days",
|
|
323
|
+
never: "Never"
|
|
324
|
+
},
|
|
325
|
+
notify: {
|
|
326
|
+
enabled: "API key enabled",
|
|
327
|
+
disabled: "API key disabled",
|
|
328
|
+
toggle_error: "Could not change the key status"
|
|
329
|
+
},
|
|
330
|
+
action: {
|
|
331
|
+
enable: "Enable",
|
|
332
|
+
disable: "Disable"
|
|
333
|
+
},
|
|
334
|
+
// Shown when a tenancy-level role is selected: such a key reaches every
|
|
335
|
+
// tenant in the account, so the tenant field stops being a boundary.
|
|
336
|
+
tenancy_role_warning: "This role grants access to every tenant in the account. The selected tenant is informational, not a security boundary."
|
|
337
|
+
},
|
|
305
338
|
// Resource labels for admin panel
|
|
306
339
|
resource: {
|
|
340
|
+
tenancy: {
|
|
341
|
+
serviceAccounts: {
|
|
342
|
+
label: "Service Accounts",
|
|
343
|
+
name: "Name",
|
|
344
|
+
tenant: "Tenant",
|
|
345
|
+
roles: "Roles",
|
|
346
|
+
expiration: "Expiration",
|
|
347
|
+
status: "Status",
|
|
348
|
+
token: "Key",
|
|
349
|
+
expires_at: "Expires",
|
|
350
|
+
last_used_at: "Last used",
|
|
351
|
+
created_at: "Created"
|
|
352
|
+
}
|
|
353
|
+
},
|
|
307
354
|
// Groups
|
|
308
355
|
groups: {
|
|
309
356
|
system_resources: "System Resources",
|
|
@@ -506,6 +553,67 @@ const dashEnglish = {
|
|
|
506
553
|
all_products: "All Products",
|
|
507
554
|
has_modifiers: "Customizable",
|
|
508
555
|
no_more_products: "No more products"
|
|
556
|
+
},
|
|
557
|
+
// JSON Color Selector - image-based theme extraction
|
|
558
|
+
colorSelector: {
|
|
559
|
+
imageExtractor: {
|
|
560
|
+
title_ai: "AI Theme Generator",
|
|
561
|
+
title_local: "Theme from Image",
|
|
562
|
+
upload_prompt: "Upload an Image to Extract Colors",
|
|
563
|
+
upload_hint: "Select an image file and we'll automatically extract a color palette",
|
|
564
|
+
upload_button: "Choose Image",
|
|
565
|
+
drop_hint: "or drag and drop it here",
|
|
566
|
+
invalid_file_type: "Please select a valid image file",
|
|
567
|
+
file_too_large: "File size must be less than %{limit}MB",
|
|
568
|
+
extracting: "Extracting colors from image...",
|
|
569
|
+
extracted_colors: "Extracted Colors (%{count} colors found)",
|
|
570
|
+
dominant_label: "Dominant",
|
|
571
|
+
uploaded_image_alt: "Uploaded image",
|
|
572
|
+
no_palette_error: "Please extract colors from an image first",
|
|
573
|
+
theme_generation_failed: "Failed to generate theme",
|
|
574
|
+
theme_description_label: "Theme Description (Optional)",
|
|
575
|
+
theme_description_placeholder: "Optional: Describe the theme style you want (e.g., 'modern and minimalist', 'warm and cozy', 'professional corporate')",
|
|
576
|
+
apply_colors_button: "Apply Colors",
|
|
577
|
+
generate_button: "Generate AI Theme",
|
|
578
|
+
generating_button: "Generating...",
|
|
579
|
+
apply_colors_help_label: "Apply Colors:",
|
|
580
|
+
apply_colors_help_desc: "Maps the extracted palette to your base theme colors locally \u2014 no AI involved",
|
|
581
|
+
generate_help_label: "Generate AI Theme:",
|
|
582
|
+
generate_help_desc: "Uses AI to create a complete color scheme based on extracted colors and your description"
|
|
583
|
+
}
|
|
584
|
+
},
|
|
585
|
+
// Profile page
|
|
586
|
+
profile: {
|
|
587
|
+
title: "Profile",
|
|
588
|
+
subtitle: "Profile settings",
|
|
589
|
+
info: {
|
|
590
|
+
title: "Info",
|
|
591
|
+
name: "Name",
|
|
592
|
+
lastname: "Last name",
|
|
593
|
+
email: "Email",
|
|
594
|
+
save: "Save",
|
|
595
|
+
saving: "Saving..."
|
|
596
|
+
},
|
|
597
|
+
password: {
|
|
598
|
+
title: "Passwords",
|
|
599
|
+
current: "Current password",
|
|
600
|
+
new: "New password",
|
|
601
|
+
confirm: "Confirm new password",
|
|
602
|
+
save: "Save Passwords",
|
|
603
|
+
saving: "Saving Passwords..."
|
|
604
|
+
},
|
|
605
|
+
preferences: {
|
|
606
|
+
title: "Preferences"
|
|
607
|
+
},
|
|
608
|
+
validation: {
|
|
609
|
+
required: "This field is required",
|
|
610
|
+
password_mismatch: "Passwords do not match"
|
|
611
|
+
},
|
|
612
|
+
notify: {
|
|
613
|
+
success: "User updated successfully",
|
|
614
|
+
error: "Error updating user",
|
|
615
|
+
error_with_message: "Error updating user, %{message}"
|
|
616
|
+
}
|
|
509
617
|
}
|
|
510
618
|
};
|
|
511
619
|
var en_default = __spreadValues(__spreadValues({}, raEnglish), dashEnglish);
|
|
@@ -309,8 +309,55 @@ const dashSpanish = {
|
|
|
309
309
|
auto_reset_notice: "Esta pantalla se reiniciar\xE1 autom\xE1ticamente en 30 segundos",
|
|
310
310
|
loading: "Cargando..."
|
|
311
311
|
},
|
|
312
|
+
// Service account API keys
|
|
313
|
+
serviceAccount: {
|
|
314
|
+
reveal: {
|
|
315
|
+
title: "Copia tu API Key ahora",
|
|
316
|
+
warning: "Esta es la \xFAnica vez que se mostrar\xE1 esta clave. No se puede recuperar m\xE1s adelante \u2014 si la pierdes, tendr\xE1s que emitir una nueva.",
|
|
317
|
+
forKey: "Clave",
|
|
318
|
+
copy: "Copiar",
|
|
319
|
+
copied: "Copiado",
|
|
320
|
+
dismiss: "La he guardado"
|
|
321
|
+
},
|
|
322
|
+
status: {
|
|
323
|
+
active: "Activa",
|
|
324
|
+
disabled: "Deshabilitada"
|
|
325
|
+
},
|
|
326
|
+
expiration: {
|
|
327
|
+
"1": "1 d\xEDa",
|
|
328
|
+
"7": "7 d\xEDas",
|
|
329
|
+
"30": "30 d\xEDas",
|
|
330
|
+
never: "Nunca"
|
|
331
|
+
},
|
|
332
|
+
notify: {
|
|
333
|
+
enabled: "API Key habilitada",
|
|
334
|
+
disabled: "API Key deshabilitada",
|
|
335
|
+
toggle_error: "No se pudo cambiar el estado de la API Key"
|
|
336
|
+
},
|
|
337
|
+
action: {
|
|
338
|
+
enable: "Habilitar",
|
|
339
|
+
disable: "Deshabilitar"
|
|
340
|
+
},
|
|
341
|
+
// Shown when a tenancy-level role is selected: such a key reaches every
|
|
342
|
+
// tenant in the account, so the tenant field stops being a boundary.
|
|
343
|
+
tenancy_role_warning: "Este rol otorga acceso a todos los locales de la cuenta. El local seleccionado es informativo, no un l\xEDmite de seguridad."
|
|
344
|
+
},
|
|
312
345
|
// Resource labels for admin panel
|
|
313
346
|
resource: {
|
|
347
|
+
tenancy: {
|
|
348
|
+
serviceAccounts: {
|
|
349
|
+
label: "Cuentas de Servicio",
|
|
350
|
+
name: "Nombre",
|
|
351
|
+
tenant: "Local",
|
|
352
|
+
roles: "Roles",
|
|
353
|
+
expiration: "Expiraci\xF3n",
|
|
354
|
+
status: "Estado",
|
|
355
|
+
token: "Clave",
|
|
356
|
+
expires_at: "Expira",
|
|
357
|
+
last_used_at: "\xDAltimo uso",
|
|
358
|
+
created_at: "Creado"
|
|
359
|
+
}
|
|
360
|
+
},
|
|
314
361
|
// Groups
|
|
315
362
|
groups: {
|
|
316
363
|
system_resources: "Recursos de Sistema",
|
|
@@ -512,6 +559,67 @@ const dashSpanish = {
|
|
|
512
559
|
all_products: "Todos los Productos",
|
|
513
560
|
has_modifiers: "Personalizable",
|
|
514
561
|
no_more_products: "No hay m\xE1s productos"
|
|
562
|
+
},
|
|
563
|
+
// JSON Color Selector - extracción de tema desde imagen
|
|
564
|
+
colorSelector: {
|
|
565
|
+
imageExtractor: {
|
|
566
|
+
title_ai: "Generador de Tema con IA",
|
|
567
|
+
title_local: "Tema desde Imagen",
|
|
568
|
+
upload_prompt: "Sube una Imagen para Extraer Colores",
|
|
569
|
+
upload_hint: "Selecciona un archivo de imagen y extraeremos autom\xE1ticamente una paleta de colores",
|
|
570
|
+
upload_button: "Elegir Imagen",
|
|
571
|
+
drop_hint: "o arr\xE1strala aqu\xED",
|
|
572
|
+
invalid_file_type: "Por favor selecciona un archivo de imagen v\xE1lido",
|
|
573
|
+
file_too_large: "El archivo debe pesar menos de %{limit}MB",
|
|
574
|
+
extracting: "Extrayendo colores de la imagen...",
|
|
575
|
+
extracted_colors: "Colores Extra\xEDdos (%{count} colores encontrados)",
|
|
576
|
+
dominant_label: "Dominante",
|
|
577
|
+
uploaded_image_alt: "Imagen subida",
|
|
578
|
+
no_palette_error: "Primero extrae los colores de una imagen",
|
|
579
|
+
theme_generation_failed: "No se pudo generar el tema",
|
|
580
|
+
theme_description_label: "Descripci\xF3n del Tema (Opcional)",
|
|
581
|
+
theme_description_placeholder: "Opcional: Describe el estilo de tema que deseas (ej: 'moderno y minimalista', 'c\xE1lido y acogedor', 'corporativo profesional')",
|
|
582
|
+
apply_colors_button: "Aplicar Colores",
|
|
583
|
+
generate_button: "Generar Tema con IA",
|
|
584
|
+
generating_button: "Generando...",
|
|
585
|
+
apply_colors_help_label: "Aplicar Colores:",
|
|
586
|
+
apply_colors_help_desc: "Aplica la paleta extra\xEDda a los colores base de tu tema localmente \u2014 sin usar IA",
|
|
587
|
+
generate_help_label: "Generar Tema con IA:",
|
|
588
|
+
generate_help_desc: "Usa IA para crear un esquema de color completo basado en los colores extra\xEDdos y tu descripci\xF3n"
|
|
589
|
+
}
|
|
590
|
+
},
|
|
591
|
+
// Profile page
|
|
592
|
+
profile: {
|
|
593
|
+
title: "Perfil",
|
|
594
|
+
subtitle: "Configuraci\xF3n de perfil",
|
|
595
|
+
info: {
|
|
596
|
+
title: "Info",
|
|
597
|
+
name: "Nombre",
|
|
598
|
+
lastname: "Apellido",
|
|
599
|
+
email: "Email",
|
|
600
|
+
save: "Guardar",
|
|
601
|
+
saving: "Guardando..."
|
|
602
|
+
},
|
|
603
|
+
password: {
|
|
604
|
+
title: "Contrase\xF1as",
|
|
605
|
+
current: "Contrase\xF1a actual",
|
|
606
|
+
new: "Nueva contrase\xF1a",
|
|
607
|
+
confirm: "Repita nueva contrase\xF1a",
|
|
608
|
+
save: "Guardar Contrase\xF1as",
|
|
609
|
+
saving: "Guardando Contrase\xF1as..."
|
|
610
|
+
},
|
|
611
|
+
preferences: {
|
|
612
|
+
title: "Preferencias"
|
|
613
|
+
},
|
|
614
|
+
validation: {
|
|
615
|
+
required: "El campo es requerido",
|
|
616
|
+
password_mismatch: "Las contrase\xF1as no coinciden"
|
|
617
|
+
},
|
|
618
|
+
notify: {
|
|
619
|
+
success: "Usuario actualizado correctamente",
|
|
620
|
+
error: "Error al actualizar el usuario",
|
|
621
|
+
error_with_message: "Error al actualizar el usuario, %{message}"
|
|
622
|
+
}
|
|
515
623
|
}
|
|
516
624
|
};
|
|
517
625
|
var es_default = __spreadValues(__spreadValues({}, raSpanish), dashSpanish);
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
const isPlainObject = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
2
|
+
const mergeTranslations = (...sources) => {
|
|
3
|
+
const result = {};
|
|
4
|
+
for (const source of sources) {
|
|
5
|
+
if (!isPlainObject(source)) continue;
|
|
6
|
+
for (const key of Object.keys(source)) {
|
|
7
|
+
const incoming = source[key];
|
|
8
|
+
const existing = result[key];
|
|
9
|
+
result[key] = isPlainObject(existing) && isPlainObject(incoming) ? mergeTranslations(existing, incoming) : incoming;
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
return result;
|
|
13
|
+
};
|
|
14
|
+
var mergeTranslations_default = mergeTranslations;
|
|
15
|
+
export {
|
|
16
|
+
mergeTranslations_default as default,
|
|
17
|
+
mergeTranslations
|
|
18
|
+
};
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __defProps = Object.defineProperties;
|
|
3
|
+
var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
|
|
4
|
+
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __propIsEnum = Object.prototype.propertyIsEnumerable;
|
|
7
|
+
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
8
|
+
var __spreadValues = (a, b) => {
|
|
9
|
+
for (var prop in b || (b = {}))
|
|
10
|
+
if (__hasOwnProp.call(b, prop))
|
|
11
|
+
__defNormalProp(a, prop, b[prop]);
|
|
12
|
+
if (__getOwnPropSymbols)
|
|
13
|
+
for (var prop of __getOwnPropSymbols(b)) {
|
|
14
|
+
if (__propIsEnum.call(b, prop))
|
|
15
|
+
__defNormalProp(a, prop, b[prop]);
|
|
16
|
+
}
|
|
17
|
+
return a;
|
|
18
|
+
};
|
|
19
|
+
var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
|
|
20
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
21
|
+
import { useRecordContext } from "react-admin";
|
|
22
|
+
import { SingleImageUploader } from "dash-components";
|
|
23
|
+
import { useFormContext } from "react-hook-form";
|
|
24
|
+
const AvatarHandler = (props) => {
|
|
25
|
+
var _a, _b;
|
|
26
|
+
const { method, attribute } = props;
|
|
27
|
+
const record = useRecordContext();
|
|
28
|
+
const {
|
|
29
|
+
setValue,
|
|
30
|
+
formState: { errors }
|
|
31
|
+
} = useFormContext();
|
|
32
|
+
const onChange = (file) => {
|
|
33
|
+
setValue(attribute.attribute, file, { shouldDirty: true });
|
|
34
|
+
};
|
|
35
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
36
|
+
/* @__PURE__ */ jsx(
|
|
37
|
+
SingleImageUploader,
|
|
38
|
+
__spreadProps(__spreadValues({
|
|
39
|
+
classNamePrefix: "dash-profile"
|
|
40
|
+
}, method === "edit" && { currentUrl: `${record.image_path}` }), {
|
|
41
|
+
onChange
|
|
42
|
+
})
|
|
43
|
+
),
|
|
44
|
+
errors[attribute.attribute] && /* @__PURE__ */ jsx("span", { style: { color: "red" }, children: ((_b = (_a = errors[attribute.attribute]) == null ? void 0 : _a.message) == null ? void 0 : _b.toString()) || "Error" })
|
|
45
|
+
] });
|
|
46
|
+
};
|
|
47
|
+
const AvatarUploadField = ({ method, attribute, resourceConfig }) => {
|
|
48
|
+
switch (method) {
|
|
49
|
+
case "edit":
|
|
50
|
+
return /* @__PURE__ */ jsx(AvatarHandler, { attribute, method, resourceConfig });
|
|
51
|
+
case "create":
|
|
52
|
+
return /* @__PURE__ */ jsx(AvatarHandler, { attribute, method, resourceConfig });
|
|
53
|
+
case "view":
|
|
54
|
+
return /* @__PURE__ */ jsx(Fragment, {});
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
var AvatarUploadField_default = AvatarUploadField;
|
|
58
|
+
export {
|
|
59
|
+
AvatarHandler,
|
|
60
|
+
AvatarUploadField_default as default
|
|
61
|
+
};
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
+
import {
|
|
3
|
+
PasswordInput
|
|
4
|
+
} from "react-admin";
|
|
5
|
+
import { Box } from "@mui/material";
|
|
6
|
+
const PasswordShow = (_props) => {
|
|
7
|
+
return /* @__PURE__ */ jsx(Fragment, {});
|
|
8
|
+
};
|
|
9
|
+
const PasswordEdit = (_props) => {
|
|
10
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
11
|
+
/* @__PURE__ */ jsx(Box, { children: /* @__PURE__ */ jsx(
|
|
12
|
+
PasswordInput,
|
|
13
|
+
{
|
|
14
|
+
sx: { width: "100%" },
|
|
15
|
+
autoComplete: "off",
|
|
16
|
+
source: "Contrase\xF1a",
|
|
17
|
+
name: "password"
|
|
18
|
+
}
|
|
19
|
+
) }),
|
|
20
|
+
/* @__PURE__ */ jsx(Box, { children: /* @__PURE__ */ jsx(
|
|
21
|
+
PasswordInput,
|
|
22
|
+
{
|
|
23
|
+
sx: { width: "100%" },
|
|
24
|
+
autoComplete: "off",
|
|
25
|
+
source: "Confirmar Contrase\xF1a",
|
|
26
|
+
name: "password_confirmation"
|
|
27
|
+
}
|
|
28
|
+
) })
|
|
29
|
+
] });
|
|
30
|
+
};
|
|
31
|
+
const PasswordCreate = (_props) => {
|
|
32
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
33
|
+
/* @__PURE__ */ jsx(Box, { children: /* @__PURE__ */ jsx(
|
|
34
|
+
PasswordInput,
|
|
35
|
+
{
|
|
36
|
+
sx: { width: "100%" },
|
|
37
|
+
source: "Contrase\xF1a",
|
|
38
|
+
name: "password"
|
|
39
|
+
}
|
|
40
|
+
) }),
|
|
41
|
+
/* @__PURE__ */ jsx(Box, { children: /* @__PURE__ */ jsx(
|
|
42
|
+
PasswordInput,
|
|
43
|
+
{
|
|
44
|
+
sx: { width: "100%" },
|
|
45
|
+
source: "Confirmar Contrase\xF1a",
|
|
46
|
+
name: "password_confirmation"
|
|
47
|
+
}
|
|
48
|
+
) })
|
|
49
|
+
] });
|
|
50
|
+
};
|
|
51
|
+
const PasswordFields = ({ method, attribute, resourceConfig }) => {
|
|
52
|
+
switch (method) {
|
|
53
|
+
case "edit":
|
|
54
|
+
return /* @__PURE__ */ jsx(PasswordEdit, { attribute, method, resourceConfig });
|
|
55
|
+
case "create":
|
|
56
|
+
return /* @__PURE__ */ jsx(PasswordCreate, { attribute, method, resourceConfig });
|
|
57
|
+
case "view":
|
|
58
|
+
return /* @__PURE__ */ jsx(PasswordShow, { attribute, method, resourceConfig });
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
var PasswordFields_default = PasswordFields;
|
|
62
|
+
export {
|
|
63
|
+
PasswordCreate,
|
|
64
|
+
PasswordEdit,
|
|
65
|
+
PasswordShow,
|
|
66
|
+
PasswordFields_default as default
|
|
67
|
+
};
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { dashStorage } from "dash-utils";
|
|
2
|
+
const getProfileMenu = (resourceConfig) => {
|
|
3
|
+
const userStr = dashStorage.getItem("user");
|
|
4
|
+
const rolesStr = dashStorage.getItem("roles");
|
|
5
|
+
const user = userStr ? JSON.parse(userStr) : null;
|
|
6
|
+
const roles = rolesStr ? JSON.parse(rolesStr) : [];
|
|
7
|
+
const profileMenu = [
|
|
8
|
+
{
|
|
9
|
+
title: "Perfil",
|
|
10
|
+
redirect: "/profile"
|
|
11
|
+
}
|
|
12
|
+
];
|
|
13
|
+
const isCliente = roles ? roles.map((role) => role.name).includes("Cliente") : false;
|
|
14
|
+
if (isCliente) {
|
|
15
|
+
profileMenu.push(
|
|
16
|
+
{
|
|
17
|
+
title: "Comunas",
|
|
18
|
+
redirect: "/profile/commune"
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
title: "Centros Log\xEDsticos",
|
|
22
|
+
redirect: "/profile/logistic-center"
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
title: "Notificaciones",
|
|
26
|
+
redirect: "/profile/notification"
|
|
27
|
+
}
|
|
28
|
+
);
|
|
29
|
+
}
|
|
30
|
+
return profileMenu;
|
|
31
|
+
};
|
|
32
|
+
var getProfileMenu_default = getProfileMenu;
|
|
33
|
+
export {
|
|
34
|
+
getProfileMenu_default as default,
|
|
35
|
+
getProfileMenu
|
|
36
|
+
};
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { jsx } from "react/jsx-runtime";
|
|
2
|
+
import ResourceTemplate from "../../templates/ResourceTemplate";
|
|
3
|
+
import Dashboard from "@mui/icons-material/Dashboard";
|
|
4
|
+
import { DASHAdminSystemConstants } from "dash-constants";
|
|
5
|
+
import getProfileMenu from "./getProfileMenu";
|
|
6
|
+
const profileResource = {
|
|
7
|
+
filterWithSubmit: true,
|
|
8
|
+
roles: [
|
|
9
|
+
"*"
|
|
10
|
+
/*
|
|
11
|
+
DASHAdminSystemConstants.system.DASH_SYSTEM_ROLE,
|
|
12
|
+
DASHAppConstants.system.TENANT_ROLE,
|
|
13
|
+
DASHAppConstants.system.USER_ROLE,
|
|
14
|
+
DASHAppConstants.system.CREATOR_ROLE,
|
|
15
|
+
DASHAppConstants.system.CLOSING_ROLE,
|
|
16
|
+
DASHAppConstants.system.GUNNER_ROLE,
|
|
17
|
+
DASHAppConstants.system.DRIVER_ROLE
|
|
18
|
+
*/
|
|
19
|
+
],
|
|
20
|
+
component: ResourceTemplate,
|
|
21
|
+
hidden: true,
|
|
22
|
+
model: "profile",
|
|
23
|
+
group: "Perfil",
|
|
24
|
+
label: "Perfil",
|
|
25
|
+
icon: /* @__PURE__ */ jsx(Dashboard, {}),
|
|
26
|
+
schema: null,
|
|
27
|
+
menu: getProfileMenu,
|
|
28
|
+
listProps: { perPage: DASHAdminSystemConstants.system.DEFAULT_PER_PAGE || 50 }
|
|
29
|
+
};
|
|
30
|
+
var profileResource_default = profileResource;
|
|
31
|
+
export {
|
|
32
|
+
profileResource_default as default
|
|
33
|
+
};
|