@vention/machine-apps-components 0.3.22 → 0.4.0

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 (31) hide show
  1. package/index.esm.js +1573 -171
  2. package/package.json +7 -1
  3. package/src/constants/z-index.d.ts +8 -0
  4. package/src/contexts/i18n-context.d.ts +12 -0
  5. package/src/contexts/i18n-provider.d.ts +13 -0
  6. package/src/hooks/use-i18n.d.ts +19 -0
  7. package/src/i18n/config.d.ts +8 -0
  8. package/src/i18n/locales/de.d.ts +118 -0
  9. package/src/i18n/locales/en.d.ts +118 -0
  10. package/src/i18n/locales/es.d.ts +118 -0
  11. package/src/i18n/locales/fr.d.ts +118 -0
  12. package/src/i18n/utils.d.ts +13 -0
  13. package/src/index.d.ts +13 -0
  14. package/src/lib/action-button/action-button.d.ts +14 -0
  15. package/src/lib/action-button/action-button.stories.d.ts +15 -0
  16. package/src/lib/file-upload-panel/file-upload-panel.d.ts +23 -0
  17. package/src/lib/file-upload-panel/file-upload-panel.stories.d.ts +12 -0
  18. package/src/lib/i18n-settings/i18n-settings.d.ts +8 -0
  19. package/src/lib/i18n-settings/i18n-settings.stories.d.ts +7 -0
  20. package/src/lib/logs/logs-panel.stories.d.ts +6 -0
  21. package/src/lib/navigation-bar/navigation-bar.stories.d.ts +6 -0
  22. package/src/lib/navigation-bar/password-protection-modal.stories.d.ts +6 -0
  23. package/src/lib/settings-page/settings-page.d.ts +11 -0
  24. package/src/lib/settings-page/settings-page.stories.d.ts +9 -0
  25. package/src/lib/sidebar/sidebar.d.ts +1 -1
  26. package/src/lib/sidebar/sidebar.stories.d.ts +6 -0
  27. package/src/lib/status-top-bar/status-top-bar.stories.d.ts +7 -0
  28. package/src/lib/step-progress-circle/step-progress-circle.d.ts +14 -0
  29. package/src/lib/step-progress-circle/step-progress-circle.stories.d.ts +16 -0
  30. package/src/test-utils.d.ts +7 -6
  31. package/src/types/user-level.d.ts +6 -0
package/index.esm.js CHANGED
@@ -1,29 +1,930 @@
1
1
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
2
- import { useLocation, useNavigate } from 'react-router-dom';
3
- import { useTheme, Typography, Box, Button, InputAdornment, IconButton, Divider, TableContainer, Paper, Table, TableHead, TableRow, TableCell, TableBody } from '@mui/material';
4
- import { tss } from 'tss-react/mui';
5
- import { COLORS, VentionModalBase, VentionIcon, VentionTextInput, VentionButton, VentionStatusIndicator, VentionSpinner, VentionAlert, VentionSelect } from '@vention/machine-ui';
6
- import React, { useState, useEffect, memo, useRef, forwardRef, useCallback, useImperativeHandle } from 'react';
2
+ import React, { createContext, useState, useEffect, useCallback, useContext, useMemo, memo, useRef, forwardRef, useImperativeHandle } from 'react';
3
+ import i18n from 'i18next';
4
+ import { initReactI18next, useTranslation } from 'react-i18next';
5
+ import LanguageDetector from 'i18next-browser-languagedetector';
7
6
  import dayjs from 'dayjs';
7
+ import utc from 'dayjs/plugin/utc';
8
+ import timezone from 'dayjs/plugin/timezone';
9
+ import 'dayjs/locale/en';
10
+ import 'dayjs/locale/fr';
11
+ import 'dayjs/locale/de';
12
+ import 'dayjs/locale/es';
13
+ import { Box, useTheme, Typography, Button, InputAdornment, IconButton, TableContainer, Paper, Table, TableHead, TableRow, TableCell, TableBody } from '@mui/material';
14
+ import { VentionSelect, COLORS, VentionModalBase, VentionIcon, VentionTextInput, VentionButton, VentionStatusIndicator, VentionSpinner, VentionAlert, VentionDropZone, VentionUploadFile, VentionIconButton } from '@vention/machine-ui';
15
+ import { tss } from 'tss-react/mui';
16
+ import { useLocation, useNavigate } from 'react-router-dom';
17
+
18
+ const I18nContext = createContext(undefined);
19
+
20
+ var enTranslations = {
21
+ common: {
22
+ units: {
23
+ mm: "mm",
24
+ in: "in",
25
+ metric: "Metric",
26
+ imperial: "Imperial"
27
+ },
28
+ settings: {
29
+ unitSystem: "Unit System",
30
+ timezone: "Timezone",
31
+ autoDetect: "Auto-detect",
32
+ locale: "Language"
33
+ }
34
+ },
35
+ actionButton: {
36
+ home: "Home",
37
+ start: "Start",
38
+ stop: "Stop",
39
+ pause: "Pause",
40
+ reset: "Reset",
41
+ clear: "Clear",
42
+ run: "Run",
43
+ resume: "Resume"
44
+ },
45
+ logs: {
46
+ table: {
47
+ date: "Date",
48
+ type: "Type",
49
+ code: "Code",
50
+ message: "Message",
51
+ description: "Description"
52
+ },
53
+ type: {
54
+ error: "Error",
55
+ warning: "Warning",
56
+ info: "Info"
57
+ },
58
+ emptyState: {
59
+ noLogs: "You have no logs"
60
+ },
61
+ loading: "Loading logs...",
62
+ loadingMore: "Loading more logs...",
63
+ noMoreLogs: "No more logs to load",
64
+ error: {
65
+ loading: "Error loading logs"
66
+ },
67
+ filter: {
68
+ from: "From",
69
+ to: "To",
70
+ type: "Type",
71
+ sort: "Sort",
72
+ reset: "Reset",
73
+ typeOptions: {
74
+ all: "All",
75
+ error: "Error",
76
+ warning: "Warning",
77
+ info: "Info"
78
+ },
79
+ sortOptions: {
80
+ latest: "From latest",
81
+ oldest: "From oldest"
82
+ },
83
+ chooseType: "Choose type"
84
+ }
85
+ },
86
+ navigation: {
87
+ pages: {
88
+ home: "Home",
89
+ operation: "Operation",
90
+ logs: "Logs",
91
+ calibration: "Calibration",
92
+ settings: "Settings"
93
+ },
94
+ bar: {
95
+ controlCenter: "Control Center",
96
+ support: "Support"
97
+ },
98
+ modal: {
99
+ exit: {
100
+ title: "You are about to exit the application",
101
+ message: "Please make sure your changes are saved before you leave the app."
102
+ },
103
+ goToControlCenter: "Go to Control Center",
104
+ goToRemoteSupport: "Go to Remote Support",
105
+ password: {
106
+ title: "Administrator login required",
107
+ label: "Password",
108
+ error: "Incorrect password",
109
+ confirm: "Confirm"
110
+ }
111
+ }
112
+ },
113
+ pagination: {
114
+ page: "Page",
115
+ of: "of"
116
+ },
117
+ fileUploadPanel: {
118
+ defaultTitle: "Upload Files",
119
+ dropzoneTitle: "Drop files here or click to browse",
120
+ defaultFileCriteria: "All file types accepted"
121
+ },
122
+ stepProgressCircle: {
123
+ title: {
124
+ progress: "Progress",
125
+ manufacturing: "Manufacturing",
126
+ processing: "Processing",
127
+ uploading: "Uploading",
128
+ notstarted: "Not Started",
129
+ ready: "Ready",
130
+ inprogress: "In Progress",
131
+ complete: "Complete",
132
+ loading: "Loading",
133
+ waiting: "Waiting"
134
+ }
135
+ }
136
+ };
137
+
138
+ var frTranslations = {
139
+ common: {
140
+ units: {
141
+ mm: "mm",
142
+ in: "po",
143
+ metric: "Métrique",
144
+ imperial: "Impérial"
145
+ },
146
+ settings: {
147
+ unitSystem: "Système d'unités",
148
+ timezone: "Fuseau horaire",
149
+ autoDetect: "Détection automatique",
150
+ locale: "Langue"
151
+ }
152
+ },
153
+ actionButton: {
154
+ home: "Origine",
155
+ start: "Démarrer",
156
+ stop: "Arrêter",
157
+ pause: "Pause",
158
+ reset: "Réinitialiser",
159
+ clear: "Effacer",
160
+ run: "Exécuter",
161
+ resume: "Reprendre"
162
+ },
163
+ logs: {
164
+ table: {
165
+ date: "Date",
166
+ type: "Type",
167
+ code: "Code",
168
+ message: "Message",
169
+ description: "Description"
170
+ },
171
+ type: {
172
+ error: "Erreur",
173
+ warning: "Avertissement",
174
+ info: "Information"
175
+ },
176
+ emptyState: {
177
+ noLogs: "Vous n'avez aucun journal"
178
+ },
179
+ loading: "Chargement des journaux...",
180
+ loadingMore: "Chargement de plus de journaux...",
181
+ noMoreLogs: "Aucun autre journal à charger",
182
+ error: {
183
+ loading: "Erreur lors du chargement des journaux"
184
+ },
185
+ filter: {
186
+ from: "De",
187
+ to: "À",
188
+ type: "Type",
189
+ sort: "Trier",
190
+ reset: "Réinitialiser",
191
+ typeOptions: {
192
+ all: "Tous",
193
+ error: "Erreur",
194
+ warning: "Avertissement",
195
+ info: "Information"
196
+ },
197
+ sortOptions: {
198
+ latest: "Du plus récent",
199
+ oldest: "Du plus ancien"
200
+ },
201
+ chooseType: "Choisir le type"
202
+ }
203
+ },
204
+ navigation: {
205
+ pages: {
206
+ home: "Accueil",
207
+ operation: "Opération",
208
+ logs: "Journaux",
209
+ calibration: "Calibration",
210
+ settings: "Paramètres"
211
+ },
212
+ bar: {
213
+ controlCenter: "Centre de contrôle",
214
+ support: "Support"
215
+ },
216
+ modal: {
217
+ exit: {
218
+ title: "Vous êtes sur le point de quitter l'application",
219
+ message: "Veuillez vous assurer que vos modifications sont enregistrées avant de quitter l'application."
220
+ },
221
+ goToControlCenter: "Aller au Centre de contrôle",
222
+ goToRemoteSupport: "Aller au Support à distance",
223
+ password: {
224
+ title: "Connexion administrateur requise",
225
+ label: "Mot de passe",
226
+ error: "Mot de passe incorrect",
227
+ confirm: "Confirmer"
228
+ }
229
+ }
230
+ },
231
+ pagination: {
232
+ page: "Page",
233
+ of: "sur"
234
+ },
235
+ fileUploadPanel: {
236
+ defaultTitle: "Téléverser des fichiers",
237
+ dropzoneTitle: "Déposez les fichiers ici ou cliquez pour parcourir",
238
+ defaultFileCriteria: "Tous les types de fichiers acceptés"
239
+ },
240
+ stepProgressCircle: {
241
+ title: {
242
+ progress: "Progression",
243
+ manufacturing: "Fabrication",
244
+ processing: "Traitement",
245
+ uploading: "Téléversement",
246
+ notstarted: "Non démarré",
247
+ ready: "Prêt",
248
+ inprogress: "En cours",
249
+ complete: "Terminé",
250
+ loading: "Chargement",
251
+ waiting: "En attente"
252
+ }
253
+ }
254
+ };
255
+
256
+ var deTranslations = {
257
+ common: {
258
+ units: {
259
+ mm: "mm",
260
+ in: "Zoll",
261
+ metric: "Metrisch",
262
+ imperial: "Imperial"
263
+ },
264
+ settings: {
265
+ unitSystem: "Einheitensystem",
266
+ timezone: "Zeitzone",
267
+ autoDetect: "Automatisch erkennen",
268
+ locale: "Sprache"
269
+ }
270
+ },
271
+ actionButton: {
272
+ home: "Referenzfahrt",
273
+ start: "Starten",
274
+ stop: "Stoppen",
275
+ pause: "Pause",
276
+ reset: "Zurücksetzen",
277
+ clear: "Löschen",
278
+ run: "Ausführen",
279
+ resume: "Fortsetzen"
280
+ },
281
+ logs: {
282
+ table: {
283
+ date: "Datum",
284
+ type: "Typ",
285
+ code: "Code",
286
+ message: "Nachricht",
287
+ description: "Beschreibung"
288
+ },
289
+ type: {
290
+ error: "Fehler",
291
+ warning: "Warnung",
292
+ info: "Information"
293
+ },
294
+ emptyState: {
295
+ noLogs: "Sie haben keine Protokolle"
296
+ },
297
+ loading: "Protokolle werden geladen...",
298
+ loadingMore: "Weitere Protokolle werden geladen...",
299
+ noMoreLogs: "Keine weiteren Protokolle zum Laden",
300
+ error: {
301
+ loading: "Fehler beim Laden der Protokolle"
302
+ },
303
+ filter: {
304
+ from: "Von",
305
+ to: "Bis",
306
+ type: "Typ",
307
+ sort: "Sortieren",
308
+ reset: "Zurücksetzen",
309
+ typeOptions: {
310
+ all: "Alle",
311
+ error: "Fehler",
312
+ warning: "Warnung",
313
+ info: "Information"
314
+ },
315
+ sortOptions: {
316
+ latest: "Neueste zuerst",
317
+ oldest: "Älteste zuerst"
318
+ },
319
+ chooseType: "Typ auswählen"
320
+ }
321
+ },
322
+ navigation: {
323
+ pages: {
324
+ home: "Startseite",
325
+ operation: "Betrieb",
326
+ logs: "Protokolle",
327
+ calibration: "Kalibrierung",
328
+ settings: "Einstellungen"
329
+ },
330
+ bar: {
331
+ controlCenter: "Kontrollzentrum",
332
+ support: "Support"
333
+ },
334
+ modal: {
335
+ exit: {
336
+ title: "Sie sind dabei, die Anwendung zu verlassen",
337
+ message: "Bitte stellen Sie sicher, dass Ihre Änderungen gespeichert sind, bevor Sie die App verlassen."
338
+ },
339
+ goToControlCenter: "Zum Kontrollzentrum gehen",
340
+ goToRemoteSupport: "Zum Remote-Support gehen",
341
+ password: {
342
+ title: "Administrator-Anmeldung erforderlich",
343
+ label: "Passwort",
344
+ error: "Falsches Passwort",
345
+ confirm: "Bestätigen"
346
+ }
347
+ }
348
+ },
349
+ pagination: {
350
+ page: "Seite",
351
+ of: "von"
352
+ },
353
+ fileUploadPanel: {
354
+ defaultTitle: "Dateien hochladen",
355
+ dropzoneTitle: "Dateien hier ablegen oder klicken zum Durchsuchen",
356
+ defaultFileCriteria: "Alle Dateitypen akzeptiert"
357
+ },
358
+ stepProgressCircle: {
359
+ title: {
360
+ progress: "Fortschritt",
361
+ manufacturing: "Fertigung",
362
+ processing: "Verarbeitung",
363
+ uploading: "Hochladen",
364
+ notstarted: "Nicht gestartet",
365
+ ready: "Bereit",
366
+ inprogress: "In Bearbeitung",
367
+ complete: "Abgeschlossen",
368
+ loading: "Laden",
369
+ waiting: "Warten"
370
+ }
371
+ }
372
+ };
373
+
374
+ var esTranslations = {
375
+ common: {
376
+ units: {
377
+ mm: "mm",
378
+ in: "pulg",
379
+ metric: "Métrico",
380
+ imperial: "Imperial"
381
+ },
382
+ settings: {
383
+ unitSystem: "Sistema de unidades",
384
+ timezone: "Zona horaria",
385
+ autoDetect: "Detección automática",
386
+ locale: "Idioma"
387
+ }
388
+ },
389
+ actionButton: {
390
+ home: "Origen",
391
+ start: "Iniciar",
392
+ stop: "Detener",
393
+ pause: "Pausar",
394
+ reset: "Restablecer",
395
+ clear: "Limpiar",
396
+ run: "Ejecutar",
397
+ resume: "Reanudar"
398
+ },
399
+ logs: {
400
+ table: {
401
+ date: "Fecha",
402
+ type: "Tipo",
403
+ code: "Código",
404
+ message: "Mensaje",
405
+ description: "Descripción"
406
+ },
407
+ type: {
408
+ error: "Error",
409
+ warning: "Advertencia",
410
+ info: "Información"
411
+ },
412
+ emptyState: {
413
+ noLogs: "No tienes registros"
414
+ },
415
+ loading: "Cargando registros...",
416
+ loadingMore: "Cargando más registros...",
417
+ noMoreLogs: "No hay más registros para cargar",
418
+ error: {
419
+ loading: "Error al cargar los registros"
420
+ },
421
+ filter: {
422
+ from: "Desde",
423
+ to: "Hasta",
424
+ type: "Tipo",
425
+ sort: "Ordenar",
426
+ reset: "Restablecer",
427
+ typeOptions: {
428
+ all: "Todos",
429
+ error: "Error",
430
+ warning: "Advertencia",
431
+ info: "Información"
432
+ },
433
+ sortOptions: {
434
+ latest: "Más recientes",
435
+ oldest: "Más antiguos"
436
+ },
437
+ chooseType: "Elegir tipo"
438
+ }
439
+ },
440
+ navigation: {
441
+ pages: {
442
+ home: "Inicio",
443
+ operation: "Operación",
444
+ logs: "Registros",
445
+ calibration: "Calibración",
446
+ settings: "Ajustes"
447
+ },
448
+ bar: {
449
+ controlCenter: "Centro de control",
450
+ support: "Soporte"
451
+ },
452
+ modal: {
453
+ exit: {
454
+ title: "Estás a punto de salir de la aplicación",
455
+ message: "Por favor, asegúrate de que tus cambios estén guardados antes de salir de la aplicación."
456
+ },
457
+ goToControlCenter: "Ir al Centro de control",
458
+ goToRemoteSupport: "Ir al Soporte remoto",
459
+ password: {
460
+ title: "Se requiere inicio de sesión de administrador",
461
+ label: "Contraseña",
462
+ error: "Contraseña incorrecta",
463
+ confirm: "Confirmar"
464
+ }
465
+ }
466
+ },
467
+ pagination: {
468
+ page: "Página",
469
+ of: "de"
470
+ },
471
+ fileUploadPanel: {
472
+ defaultTitle: "Subir archivos",
473
+ dropzoneTitle: "Suelta los archivos aquí o haz clic para explorar",
474
+ defaultFileCriteria: "Se aceptan todos los tipos de archivos"
475
+ },
476
+ stepProgressCircle: {
477
+ title: {
478
+ progress: "Progreso",
479
+ manufacturing: "Fabricación",
480
+ processing: "Procesamiento",
481
+ uploading: "Subiendo",
482
+ notstarted: "No iniciado",
483
+ ready: "Listo",
484
+ inprogress: "En progreso",
485
+ complete: "Completo",
486
+ loading: "Cargando",
487
+ waiting: "Esperando"
488
+ }
489
+ }
490
+ };
491
+
492
+ dayjs.extend(utc);
493
+ dayjs.extend(timezone);
494
+ if (!i18n.isInitialized) {
495
+ const getStoredTimezone = function getStoredTimezone() {
496
+ if (typeof window === "undefined") return "auto";
497
+ try {
498
+ const stored = localStorage.getItem("machine-apps-components:timezone");
499
+ return stored || "auto";
500
+ } catch (_a) {
501
+ return "auto";
502
+ }
503
+ };
504
+ const initialTimezone = getStoredTimezone();
505
+ if (initialTimezone !== "auto" && typeof window !== "undefined") {
506
+ try {
507
+ dayjs.tz.setDefault(initialTimezone);
508
+ } catch (error) {
509
+ console.warn("i18n: Failed to set default timezone", error);
510
+ }
511
+ }
512
+ i18n.use(LanguageDetector).use(initReactI18next).init({
513
+ resources: {
514
+ en: {
515
+ translation: enTranslations
516
+ },
517
+ fr: {
518
+ translation: frTranslations
519
+ },
520
+ de: {
521
+ translation: deTranslations
522
+ },
523
+ es: {
524
+ translation: esTranslations
525
+ }
526
+ },
527
+ fallbackLng: "en",
528
+ defaultNS: "translation",
529
+ interpolation: {
530
+ escapeValue: false
531
+ },
532
+ detection: {
533
+ order: ["localStorage", "navigator"],
534
+ lookupLocalStorage: "machine-apps-components:locale",
535
+ caches: ["localStorage"]
536
+ }
537
+ });
538
+ i18n.on("languageChanged", function handleLanguageChanged(lng) {
539
+ const dayjsLocale = lng.split("-")[0];
540
+ try {
541
+ dayjs.locale(dayjsLocale);
542
+ } catch (error) {
543
+ console.warn("i18n: Failed to set dayjs locale", error);
544
+ }
545
+ });
546
+ }
547
+ const getSupportedLanguages = function getSupportedLanguages() {
548
+ try {
549
+ if (!i18n.isInitialized) {
550
+ return ["en", "fr", "de", "es"];
551
+ }
552
+ const resources = i18n.options.resources || {};
553
+ const languages = Object.keys(resources);
554
+ return languages.length > 0 ? languages : ["en", "fr", "de", "es"];
555
+ } catch (error) {
556
+ console.warn("Error getting supported languages:", error);
557
+ return ["en", "fr", "de", "es"];
558
+ }
559
+ };
560
+ const getLanguageDisplayName = function getLanguageDisplayName(code) {
561
+ const languageNames = {
562
+ en: "English",
563
+ fr: "Français",
564
+ es: "Español",
565
+ de: "Deutsch"
566
+ };
567
+ return languageNames[code] || code.toUpperCase();
568
+ };
569
+
570
+ const STORAGE_KEYS = {
571
+ locale: "machine-apps-components:locale",
572
+ unitSystem: "machine-apps-components:unitSystem",
573
+ timezone: "machine-apps-components:timezone"
574
+ };
575
+ const normalizeLocale = function normalizeLocale(locale, supportedLanguages) {
576
+ const normalized = locale.split("-")[0].toLowerCase();
577
+ if (supportedLanguages.includes(normalized)) {
578
+ return normalized;
579
+ }
580
+ return supportedLanguages.length > 0 ? supportedLanguages[0] : "en";
581
+ };
582
+ const I18nProvider = function I18nProvider({
583
+ children,
584
+ defaultLocale = "en",
585
+ defaultUnitSystem = "metric",
586
+ defaultTimezone = "auto",
587
+ supportedLanguages = ["en", "fr", "de", "es"]
588
+ }) {
589
+ const [locale, setLocaleState] = useState(function getInitialLocale() {
590
+ if (typeof window === "undefined") return normalizeLocale(defaultLocale, supportedLanguages);
591
+ try {
592
+ const stored = localStorage.getItem(STORAGE_KEYS.locale);
593
+ if (stored) {
594
+ return normalizeLocale(stored, supportedLanguages);
595
+ }
596
+ return normalizeLocale(defaultLocale, supportedLanguages);
597
+ } catch (_a) {
598
+ return normalizeLocale(defaultLocale, supportedLanguages);
599
+ }
600
+ });
601
+ const [unitSystem, setUnitSystemState] = useState(function getInitialUnitSystem() {
602
+ if (typeof window === "undefined") return defaultUnitSystem;
603
+ try {
604
+ const stored = localStorage.getItem(STORAGE_KEYS.unitSystem);
605
+ if (stored === "metric" || stored === "imperial") {
606
+ return stored;
607
+ }
608
+ return defaultUnitSystem;
609
+ } catch (_a) {
610
+ return defaultUnitSystem;
611
+ }
612
+ });
613
+ const [timezone, setTimezoneState] = useState(function getInitialTimezone() {
614
+ if (typeof window === "undefined") return defaultTimezone;
615
+ try {
616
+ const stored = localStorage.getItem(STORAGE_KEYS.timezone);
617
+ return stored || defaultTimezone;
618
+ } catch (_a) {
619
+ return defaultTimezone;
620
+ }
621
+ });
622
+ useEffect(function syncI18nLocale() {
623
+ const normalizedLocale = normalizeLocale(locale, supportedLanguages);
624
+ i18n.changeLanguage(normalizedLocale);
625
+ if (typeof window !== "undefined") {
626
+ localStorage.setItem(STORAGE_KEYS.locale, normalizedLocale);
627
+ }
628
+ }, [locale, supportedLanguages]);
629
+ useEffect(function persistUnitSystem() {
630
+ if (typeof window !== "undefined") {
631
+ localStorage.setItem(STORAGE_KEYS.unitSystem, unitSystem);
632
+ }
633
+ }, [unitSystem]);
634
+ useEffect(function syncDayjsTimezone() {
635
+ if (typeof window === "undefined") return;
636
+ localStorage.setItem(STORAGE_KEYS.timezone, timezone);
637
+ try {
638
+ const dayjsWithTz = dayjs;
639
+ if (dayjsWithTz.tz && typeof dayjsWithTz.tz.setDefault === "function") {
640
+ if (timezone !== "auto") {
641
+ dayjsWithTz.tz.setDefault(timezone);
642
+ } else {
643
+ const detected = Intl.DateTimeFormat().resolvedOptions().timeZone;
644
+ dayjsWithTz.tz.setDefault(detected);
645
+ }
646
+ }
647
+ } catch (error) {
648
+ console.warn("Failed to set timezone:", error);
649
+ }
650
+ }, [timezone]);
651
+ const setLocale = useCallback(function setLocale(newLocale) {
652
+ setLocaleState(normalizeLocale(newLocale, supportedLanguages));
653
+ }, [supportedLanguages]);
654
+ const setUnitSystem = useCallback(function setUnitSystem(newSystem) {
655
+ setUnitSystemState(newSystem);
656
+ }, []);
657
+ const setTimezone = useCallback(function setTimezone(newTimezone) {
658
+ setTimezoneState(newTimezone);
659
+ }, []);
660
+ const value = {
661
+ locale,
662
+ unitSystem,
663
+ timezone,
664
+ supportedLanguages,
665
+ setLocale,
666
+ setUnitSystem,
667
+ setTimezone
668
+ };
669
+ return jsx(I18nContext.Provider, {
670
+ value: value,
671
+ children: children
672
+ });
673
+ };
674
+ I18nProvider.displayName = "I18nProvider";
675
+
676
+ const MM_TO_INCH = 0.0393701;
677
+ const INCH_TO_MM = 25.4;
678
+ function mmToInches(mm) {
679
+ return mm * MM_TO_INCH;
680
+ }
681
+ function inchesToMm(inches) {
682
+ return inches * INCH_TO_MM;
683
+ }
684
+ function formatValueToDisplayUnit(value, unitSystem, options) {
685
+ var _a;
686
+ const decimals = (_a = options === null || options === void 0 ? void 0 : options.decimals) !== null && _a !== void 0 ? _a : 2;
687
+ const showUnit = (options === null || options === void 0 ? void 0 : options.showUnit) !== false;
688
+ if (unitSystem === "imperial") {
689
+ const inches = mmToInches(value);
690
+ return showUnit ? `${inches.toFixed(decimals)} in` : inches.toFixed(decimals);
691
+ }
692
+ return showUnit ? `${value.toFixed(decimals)} mm` : value.toFixed(decimals);
693
+ }
694
+ function convertDisplayValueToMm(displayValue, unitSystem) {
695
+ if (unitSystem === "imperial") {
696
+ return inchesToMm(displayValue);
697
+ }
698
+ return displayValue;
699
+ }
700
+ function getUnitDisplayLabel(unitSystem) {
701
+ return unitSystem === "imperial" ? "in" : "mm";
702
+ }
703
+ function getAvailableTimezones() {
704
+ return ["America/New_York", "America/Chicago", "America/Denver", "America/Los_Angeles", "America/Toronto", "America/Vancouver", "Europe/London", "Europe/Paris", "Europe/Berlin", "Europe/Madrid", "Europe/Rome", "Asia/Tokyo", "Asia/Shanghai", "Asia/Hong_Kong", "Asia/Singapore", "Australia/Sydney", "Australia/Melbourne", "UTC"];
705
+ }
706
+
707
+ const DEFAULT_VALUES = {
708
+ locale: "en",
709
+ unitSystem: "metric",
710
+ timezone: "auto",
711
+ supportedLanguages: ["en"],
712
+ setLocale: function defaultSetLocale(_newLocale) {
713
+ return undefined;
714
+ },
715
+ setUnitSystem: function defaultSetUnitSystem(_system) {
716
+ return undefined;
717
+ },
718
+ setTimezone: function defaultSetTimezone(_tz) {
719
+ return undefined;
720
+ }
721
+ };
722
+ const useI18n = function useI18n() {
723
+ const {
724
+ t
725
+ } = useTranslation();
726
+ const context = useContext(I18nContext);
727
+ const {
728
+ locale = DEFAULT_VALUES.locale,
729
+ unitSystem = DEFAULT_VALUES.unitSystem,
730
+ timezone = DEFAULT_VALUES.timezone,
731
+ supportedLanguages = DEFAULT_VALUES.supportedLanguages,
732
+ setLocale = DEFAULT_VALUES.setLocale,
733
+ setUnitSystem = DEFAULT_VALUES.setUnitSystem,
734
+ setTimezone = DEFAULT_VALUES.setTimezone
735
+ } = context || {};
736
+ const formatDate = useCallback(function formatDate(utcTimestamp, format) {
737
+ const tz = timezone === "auto" ? Intl.DateTimeFormat().resolvedOptions().timeZone : timezone;
738
+ try {
739
+ const dayjsWithTz = dayjs;
740
+ const hasTimezonePlugin = dayjsWithTz.tz && typeof dayjsWithTz.utc === "function";
741
+ if (hasTimezonePlugin) {
742
+ const utcInstance = dayjsWithTz.utc(utcTimestamp);
743
+ return utcInstance.tz(tz).locale(locale.split("-")[0]).format(format || "YYYY-MM-DD HH:mm:ss");
744
+ }
745
+ return dayjs(utcTimestamp).locale(locale.split("-")[0]).format(format || "YYYY-MM-DD HH:mm:ss");
746
+ } catch (error) {
747
+ return dayjs(utcTimestamp).locale(locale.split("-")[0]).format(format || "YYYY-MM-DD HH:mm:ss");
748
+ }
749
+ }, [timezone, locale]);
750
+ const formatValueToDisplayUnit$1 = useCallback(function formatValueToDisplayUnit$1(value, options) {
751
+ return formatValueToDisplayUnit(value, unitSystem, options);
752
+ }, [unitSystem]);
753
+ const convertDisplayValueToMmValue = useCallback(function convertDisplayValueToMmValue(value) {
754
+ return convertDisplayValueToMm(value, unitSystem);
755
+ }, [unitSystem]);
756
+ const getUnitDisplayLabelValue = useCallback(function getUnitDisplayLabelValue() {
757
+ return getUnitDisplayLabel(unitSystem);
758
+ }, [unitSystem]);
759
+ return {
760
+ t,
761
+ formatDate,
762
+ formatValueToDisplayUnit: formatValueToDisplayUnit$1,
763
+ convertDisplayValueToMm: convertDisplayValueToMmValue,
764
+ getUnitDisplayLabel: getUnitDisplayLabelValue,
765
+ locale,
766
+ unitSystem,
767
+ timezone,
768
+ supportedLanguages,
769
+ setLocale,
770
+ setUnitSystem,
771
+ setTimezone
772
+ };
773
+ };
774
+
775
+ const I18nSettings = function I18nSettings({
776
+ className,
777
+ layout = "stacked"
778
+ }) {
779
+ const {
780
+ classes,
781
+ cx
782
+ } = useStyles$f({
783
+ layout
784
+ });
785
+ const {
786
+ locale,
787
+ unitSystem,
788
+ timezone,
789
+ supportedLanguages,
790
+ setLocale,
791
+ setUnitSystem,
792
+ setTimezone,
793
+ t
794
+ } = useI18n();
795
+ const unitSystemOptions = useMemo(function getUnitSystemOptions() {
796
+ return [{
797
+ value: "metric",
798
+ displayText: t("common.units.metric", {
799
+ defaultValue: "Metric"
800
+ })
801
+ }, {
802
+ value: "imperial",
803
+ displayText: t("common.units.imperial", {
804
+ defaultValue: "Imperial"
805
+ })
806
+ }];
807
+ }, [t]);
808
+ const timezoneOptions = useMemo(function getTimezoneOptions() {
809
+ const timezones = getAvailableTimezones();
810
+ return [{
811
+ value: "auto",
812
+ displayText: t("common.settings.autoDetect", {
813
+ defaultValue: "Auto-detect"
814
+ })
815
+ }, ...timezones.map(tz => ({
816
+ value: tz,
817
+ displayText: tz
818
+ }))];
819
+ }, [t]);
820
+ const localeOptions = useMemo(function getLocaleOptions() {
821
+ return supportedLanguages.map(langCode => ({
822
+ value: langCode,
823
+ displayText: getLanguageDisplayName(langCode)
824
+ }));
825
+ }, [supportedLanguages]);
826
+ const handleUnitSystemChange = function handleUnitSystemChange(event) {
827
+ setUnitSystem(event.target.value);
828
+ };
829
+ const handleTimezoneChange = function handleTimezoneChange(event) {
830
+ setTimezone(event.target.value);
831
+ };
832
+ const handleLocaleChange = function handleLocaleChange(event) {
833
+ setLocale(event.target.value);
834
+ };
835
+ return jsxs(Box, {
836
+ className: cx(classes.container, className),
837
+ children: [jsx(VentionSelect, {
838
+ className: classes.settingItem,
839
+ size: "xx-large",
840
+ variant: "outlined",
841
+ labelText: t("common.settings.unitSystem"),
842
+ value: unitSystem,
843
+ onChange: handleUnitSystemChange,
844
+ menuItems: unitSystemOptions
845
+ }), jsx(VentionSelect, {
846
+ className: classes.settingItem,
847
+ size: "xx-large",
848
+ variant: "outlined",
849
+ labelText: t("common.settings.timezone"),
850
+ value: timezone,
851
+ onChange: handleTimezoneChange,
852
+ menuItems: timezoneOptions
853
+ }), supportedLanguages.length > 1 && jsx(VentionSelect, {
854
+ className: classes.settingItem,
855
+ size: "xx-large",
856
+ variant: "outlined",
857
+ labelText: t("common.settings.locale"),
858
+ value: locale,
859
+ onChange: handleLocaleChange,
860
+ menuItems: localeOptions
861
+ })]
862
+ });
863
+ };
864
+ I18nSettings.displayName = "I18nSettings";
865
+ const useStyles$f = tss.withParams().create(({
866
+ theme,
867
+ layout
868
+ }) => ({
869
+ container: {
870
+ display: "flex",
871
+ flexDirection: layout === "horizontal" ? "row" : "column",
872
+ flexWrap: layout === "horizontal" ? "wrap" : "nowrap",
873
+ gap: theme.spacing(4),
874
+ width: "100%",
875
+ maxWidth: layout === "horizontal" ? "none" : "500px"
876
+ },
877
+ settingItem: layout === "horizontal" ? {
878
+ flex: "1 1 200px",
879
+ maxWidth: "300px"
880
+ } : {}
881
+ }));
8
882
 
9
883
  function TimeLabel({
10
884
  className,
11
885
  color
12
886
  }) {
13
887
  const theme = useTheme();
14
- const [timeLabel, setTimeLabel] = useState(() => new Date().toLocaleTimeString([], {
15
- hour: "numeric",
16
- minute: "2-digit"
17
- }).toLowerCase().replace(" ", ""));
18
- useEffect(function updateTimeLabel() {
19
- const intervalId = setInterval(() => {
888
+ const {
889
+ formatDate,
890
+ timezone,
891
+ locale
892
+ } = useI18n();
893
+ const [timeLabel, setTimeLabel] = useState(() => {
894
+ try {
895
+ return formatDate(Date.now(), "HH:mm");
896
+ } catch (_a) {
897
+ return new Date().toLocaleTimeString([], {
898
+ hour: "numeric",
899
+ minute: "2-digit"
900
+ }).toLowerCase().replace(" ", "");
901
+ }
902
+ });
903
+ useEffect(function updateTimeLabelOnTimezoneChange() {
904
+ try {
905
+ const formatted = formatDate(Date.now(), "HH:mm");
906
+ setTimeLabel(formatted);
907
+ } catch (_a) {
20
908
  setTimeLabel(new Date().toLocaleTimeString([], {
21
909
  hour: "numeric",
22
910
  minute: "2-digit"
23
911
  }).toLowerCase().replace(" ", ""));
912
+ }
913
+ }, [formatDate, timezone, locale]);
914
+ useEffect(function updateTimeLabel() {
915
+ const intervalId = setInterval(() => {
916
+ try {
917
+ const formatted = formatDate(Date.now(), "HH:mm");
918
+ setTimeLabel(formatted);
919
+ } catch (_a) {
920
+ setTimeLabel(new Date().toLocaleTimeString([], {
921
+ hour: "numeric",
922
+ minute: "2-digit"
923
+ }).toLowerCase().replace(" ", ""));
924
+ }
24
925
  }, 1000);
25
926
  return () => clearInterval(intervalId);
26
- }, []);
927
+ }, [formatDate, timezone, locale]);
27
928
  return jsx(Typography, {
28
929
  className: className,
29
930
  color: color !== null && color !== void 0 ? color : theme.palette.common.white,
@@ -53,7 +954,7 @@ const navigateControlCenter = route => {
53
954
  window.parent.postMessage(`navigateTo${capitalizedRoute}`, "*");
54
955
  };
55
956
 
56
- const NavigationConfirmationModal = props => {
957
+ const NavigationConfirmationModal = function NavigationConfirmationModal(props) {
57
958
  const {
58
959
  isOpen,
59
960
  destination,
@@ -61,8 +962,11 @@ const NavigationConfirmationModal = props => {
61
962
  } = props;
62
963
  const {
63
964
  classes
64
- } = useStyles$a();
65
- const handleConfirm = () => {
965
+ } = useStyles$e();
966
+ const {
967
+ t
968
+ } = useI18n();
969
+ const handleConfirm = function handleConfirm() {
66
970
  if (!destination) return;
67
971
  onClose();
68
972
  if (destination === "controlCenter") {
@@ -71,11 +975,15 @@ const NavigationConfirmationModal = props => {
71
975
  navigateControlCenter(destination);
72
976
  }
73
977
  };
74
- const getButtonText = () => {
978
+ const getButtonText = function getButtonText() {
75
979
  if (destination === "controlCenter") {
76
- return "Go to Control Center";
980
+ return t("navigation.modal.goToControlCenter", {
981
+ defaultValue: "Go to Control Center"
982
+ });
77
983
  }
78
- return "Go to Remote Support";
984
+ return t("navigation.modal.goToRemoteSupport", {
985
+ defaultValue: "Go to Remote Support"
986
+ });
79
987
  };
80
988
  return jsx(VentionModalBase, {
81
989
  isOpen: isOpen,
@@ -94,10 +1002,14 @@ const NavigationConfirmationModal = props => {
94
1002
  })
95
1003
  }), jsx(Typography, {
96
1004
  className: classes.title,
97
- children: "You are about to exit the application"
1005
+ children: t("navigation.modal.exit.title", {
1006
+ defaultValue: "You are about to exit the application"
1007
+ })
98
1008
  }), jsx(Typography, {
99
1009
  className: classes.body,
100
- children: "Please make sure your changes are saved before you leave the app."
1010
+ children: t("navigation.modal.exit.message", {
1011
+ defaultValue: "Please make sure your changes are saved before you leave the app."
1012
+ })
101
1013
  }), jsx(Button, {
102
1014
  onClick: handleConfirm,
103
1015
  className: classes.button,
@@ -113,7 +1025,7 @@ const NavigationConfirmationModal = props => {
113
1025
  })
114
1026
  });
115
1027
  };
116
- const useStyles$a = tss.create(({
1028
+ const useStyles$e = tss.create(({
117
1029
  theme
118
1030
  }) => ({
119
1031
  modalContent: {
@@ -135,11 +1047,13 @@ const useStyles$a = tss.create(({
135
1047
  textAlign: "center"
136
1048
  }),
137
1049
  button: {
138
- width: "320px",
1050
+ minWidth: "320px",
1051
+ width: "auto",
1052
+ maxWidth: "100%",
139
1053
  height: "80px",
140
1054
  backgroundColor: COLORS.slate[800],
141
1055
  borderRadius: "4px",
142
- padding: "8px",
1056
+ padding: "8px 16px",
143
1057
  boxSizing: "border-box",
144
1058
  marginTop: "auto"
145
1059
  },
@@ -148,7 +1062,8 @@ const useStyles$a = tss.create(({
148
1062
  alignItems: "center",
149
1063
  justifyContent: "center",
150
1064
  padding: "0 8px",
151
- boxSizing: "border-box"
1065
+ boxSizing: "border-box",
1066
+ width: "100%"
152
1067
  },
153
1068
  buttonText: {
154
1069
  fontFamily: "Inter",
@@ -161,7 +1076,7 @@ const useStyles$a = tss.create(({
161
1076
  }
162
1077
  }));
163
1078
 
164
- const PasswordProtectionModal = props => {
1079
+ const PasswordProtectionModal = function PasswordProtectionModal(props) {
165
1080
  const {
166
1081
  isOpen,
167
1082
  onClose,
@@ -171,11 +1086,14 @@ const PasswordProtectionModal = props => {
171
1086
  const [isKeyboardVisible, setIsKeyboardVisible] = useState(false);
172
1087
  const {
173
1088
  classes
174
- } = useStyles$9();
1089
+ } = useStyles$d();
1090
+ const {
1091
+ t
1092
+ } = useI18n();
175
1093
  const [password, setPassword] = useState("");
176
1094
  const [showPassword, setShowPassword] = useState(false);
177
1095
  const [error, setError] = useState(false);
178
- const handleConfirm = () => {
1096
+ const handleConfirm = function handleConfirm() {
179
1097
  if (password === correctPassword) {
180
1098
  setPassword("");
181
1099
  setError(false);
@@ -185,17 +1103,12 @@ const PasswordProtectionModal = props => {
185
1103
  setError(true);
186
1104
  }
187
1105
  };
188
- const handleClose = () => {
1106
+ const handleClose = function handleClose() {
189
1107
  setPassword("");
190
1108
  setError(false);
191
1109
  onClose();
192
1110
  };
193
- const handleKeyPress = event => {
194
- if (event.key === "Enter") {
195
- handleConfirm();
196
- }
197
- };
198
- useEffect(() => {
1111
+ useEffect(function handleKeyboardVisibility() {
199
1112
  if (!isOpen || !isTouchScreenDevice()) {
200
1113
  setIsKeyboardVisible(false);
201
1114
  return;
@@ -234,20 +1147,31 @@ const PasswordProtectionModal = props => {
234
1147
  className: classes.modalContent,
235
1148
  children: [jsx(Typography, {
236
1149
  className: classes.title,
237
- children: "Administrator login required"
1150
+ children: t("navigation.modal.password.title", {
1151
+ defaultValue: "Administrator login required"
1152
+ })
238
1153
  }), jsx(Box, {
1154
+ component: "form",
1155
+ id: "password-form",
1156
+ onSubmit: event => {
1157
+ event.preventDefault();
1158
+ handleConfirm();
1159
+ },
239
1160
  className: classes.inputContainer,
240
1161
  children: jsx(VentionTextInput, {
241
- label: "Password",
1162
+ label: t("navigation.modal.password.label", {
1163
+ defaultValue: "Password"
1164
+ }),
242
1165
  type: showPassword ? "text" : "password",
243
1166
  value: password,
244
1167
  onChange: event => {
245
1168
  setPassword(event.target.value);
246
1169
  setError(false);
247
1170
  },
248
- onKeyPress: handleKeyPress,
249
1171
  state: error ? "error" : "default",
250
- helperText: error ? "Incorrect password" : "",
1172
+ helperText: error ? t("navigation.modal.password.error", {
1173
+ defaultValue: "Incorrect password"
1174
+ }) : "",
251
1175
  fullWidth: true,
252
1176
  size: "xx-large",
253
1177
  InputProps: {
@@ -257,6 +1181,7 @@ const PasswordProtectionModal = props => {
257
1181
  onClick: () => setShowPassword(!showPassword),
258
1182
  edge: "end",
259
1183
  disableRipple: true,
1184
+ type: "button",
260
1185
  children: jsx(VentionIcon, {
261
1186
  type: showPassword ? "eye-closed" : "eye",
262
1187
  size: 28,
@@ -267,14 +1192,17 @@ const PasswordProtectionModal = props => {
267
1192
  }
268
1193
  })
269
1194
  }), jsx(Button, {
270
- onClick: handleConfirm,
271
1195
  className: classes.button,
272
1196
  disableRipple: true,
1197
+ type: "submit",
1198
+ form: "password-form",
273
1199
  children: jsx(Box, {
274
1200
  className: classes.buttonLabel,
275
1201
  children: jsx(Typography, {
276
1202
  className: classes.buttonText,
277
- children: "Confirm"
1203
+ children: t("navigation.modal.password.confirm", {
1204
+ defaultValue: "Confirm"
1205
+ })
278
1206
  })
279
1207
  })
280
1208
  })]
@@ -282,7 +1210,7 @@ const PasswordProtectionModal = props => {
282
1210
  })]
283
1211
  });
284
1212
  };
285
- const useStyles$9 = tss.create(({
1213
+ const useStyles$d = tss.create(({
286
1214
  theme
287
1215
  }) => ({
288
1216
  modalContent: {
@@ -337,7 +1265,7 @@ const useStyles$9 = tss.create(({
337
1265
  }
338
1266
  }));
339
1267
 
340
- const NavigationBarItem = props => {
1268
+ const NavigationBarItem = function NavigationBarItem(props) {
341
1269
  const {
342
1270
  icon,
343
1271
  iconDisabled,
@@ -354,17 +1282,18 @@ const NavigationBarItem = props => {
354
1282
  const {
355
1283
  classes,
356
1284
  cx
357
- } = useStyles$8();
1285
+ } = useStyles$c();
1286
+ const {
1287
+ t
1288
+ } = useI18n();
358
1289
  const isActive = (location === null || location === void 0 ? void 0 : location.pathname) === path;
359
1290
  const currentIcon = isDisabled && iconDisabled ? iconDisabled : icon;
360
- const handleItemClick = () => {
1291
+ const handleItemClick = function handleItemClick() {
361
1292
  if (isDisabled || !handleNavigate || !setPasswordProtectedItem) return;
362
- // If destination has a password and it's different from current password, show modal
363
1293
  if (password && password !== currentPassword) {
364
1294
  setPasswordProtectedItem(props);
365
1295
  return;
366
1296
  }
367
- // Otherwise navigate directly
368
1297
  onClick ? onClick() : handleNavigate(path);
369
1298
  };
370
1299
  return jsxs(Button, {
@@ -380,11 +1309,13 @@ const NavigationBarItem = props => {
380
1309
  children: currentIcon
381
1310
  }), jsx(Typography, {
382
1311
  className: classes.navLabel,
383
- children: label
1312
+ children: t(label, {
1313
+ defaultValue: label
1314
+ })
384
1315
  })]
385
1316
  });
386
1317
  };
387
- const useStyles$8 = tss.create(({
1318
+ const useStyles$c = tss.create(({
388
1319
  theme
389
1320
  }) => ({
390
1321
  tabButton: {
@@ -426,8 +1357,17 @@ const useStyles$8 = tss.create(({
426
1357
  navLabel: Object.assign({}, theme.typography.hmiText22Regular)
427
1358
  }));
428
1359
 
1360
+ const Z_INDEX = {
1361
+ NAVIGATION: 1100,
1362
+ MENU: 1200,
1363
+ MENU_OVERLAY: 1210,
1364
+ MODAL: 1300,
1365
+ SNACKBAR: 1400,
1366
+ TOOLTIP: 1500
1367
+ };
1368
+
429
1369
  const iconSize = 32;
430
- const NavigationBarRoot = props => {
1370
+ const NavigationBarRoot = function NavigationBarRoot(props) {
431
1371
  var _a;
432
1372
  const {
433
1373
  children,
@@ -445,15 +1385,18 @@ const NavigationBarRoot = props => {
445
1385
  const theme = useTheme();
446
1386
  const {
447
1387
  classes
448
- } = useStyles$7();
1388
+ } = useStyles$b();
1389
+ const {
1390
+ t
1391
+ } = useI18n();
449
1392
  const [modalDestination, setModalDestination] = useState(null);
450
1393
  const [passwordProtectedItem, setPasswordProtectedItem] = useState(null);
451
1394
  const [currentPassword, setCurrentPassword] = useState(null);
452
1395
  const disabledSet = new Set(disabledNavigationItems);
453
- const getFadedColor = (color, opacity = 1) => {
1396
+ const getFadedColor = function getFadedColor(color, opacity = 1) {
454
1397
  return `${color}${Math.round(opacity * 255).toString(16).padStart(2, "0")}`;
455
1398
  };
456
- const handleNavigate = path => {
1399
+ const handleNavigate = function handleNavigate(path) {
457
1400
  if (location.pathname !== path) navigate(path);
458
1401
  };
459
1402
  useEffect(function updateCurrentPassword() {
@@ -461,7 +1404,7 @@ const NavigationBarRoot = props => {
461
1404
  const currentPagePassword = React.isValidElement(currentPage) ? currentPage.props.password : undefined;
462
1405
  setCurrentPassword(currentPagePassword !== null && currentPagePassword !== void 0 ? currentPagePassword : null);
463
1406
  }, [location.pathname, children]);
464
- const handleControlCenterClick = () => {
1407
+ const handleControlCenterClick = function handleControlCenterClick() {
465
1408
  if (isControlCenterDisabled) return;
466
1409
  if (onControlCenterClick) {
467
1410
  onControlCenterClick();
@@ -469,7 +1412,7 @@ const NavigationBarRoot = props => {
469
1412
  setModalDestination("controlCenter");
470
1413
  }
471
1414
  };
472
- const handleSupportClick = () => {
1415
+ const handleSupportClick = function handleSupportClick() {
473
1416
  if (isSupportDisabled) return;
474
1417
  if (onSupportClick) {
475
1418
  onSupportClick();
@@ -477,7 +1420,7 @@ const NavigationBarRoot = props => {
477
1420
  setModalDestination("remoteSupport");
478
1421
  }
479
1422
  };
480
- const handlePasswordSuccess = () => {
1423
+ const handlePasswordSuccess = function handlePasswordSuccess() {
481
1424
  if (passwordProtectedItem) {
482
1425
  if (passwordProtectedItem.onClick) {
483
1426
  passwordProtectedItem.onClick();
@@ -486,7 +1429,7 @@ const NavigationBarRoot = props => {
486
1429
  }
487
1430
  }
488
1431
  };
489
- const processedChildren = React.Children.map(children, child => {
1432
+ const processedChildren = React.Children.map(children, function processChild(child) {
490
1433
  if (!React.isValidElement(child)) return child;
491
1434
  if (child.type !== NavigationBarItem) return child;
492
1435
  const itemId = child.props.id;
@@ -499,14 +1442,20 @@ const NavigationBarRoot = props => {
499
1442
  setPasswordProtectedItem: setPasswordProtectedItem
500
1443
  }));
501
1444
  });
1445
+ const handleCloseConfirmation = function handleCloseConfirmation() {
1446
+ setModalDestination(null);
1447
+ };
1448
+ const handleClosePassword = function handleClosePassword() {
1449
+ setPasswordProtectedItem(null);
1450
+ };
502
1451
  return jsxs(Fragment, {
503
1452
  children: [jsx(NavigationConfirmationModal, {
504
1453
  isOpen: modalDestination !== null,
505
1454
  destination: modalDestination,
506
- onClose: () => setModalDestination(null)
1455
+ onClose: handleCloseConfirmation
507
1456
  }), jsx(PasswordProtectionModal, {
508
1457
  isOpen: passwordProtectedItem !== null,
509
- onClose: () => setPasswordProtectedItem(null),
1458
+ onClose: handleClosePassword,
510
1459
  onSuccess: handlePasswordSuccess,
511
1460
  correctPassword: (_a = passwordProtectedItem === null || passwordProtectedItem === void 0 ? void 0 : passwordProtectedItem.password) !== null && _a !== void 0 ? _a : ""
512
1461
  }), jsx("footer", {
@@ -531,7 +1480,9 @@ const NavigationBarRoot = props => {
531
1480
  style: {
532
1481
  color: isControlCenterDisabled ? getFadedColor(theme.palette.common.white) : theme.palette.common.white
533
1482
  },
534
- children: "Control Center"
1483
+ children: t("navigation.bar.controlCenter", {
1484
+ defaultValue: "Control Center"
1485
+ })
535
1486
  })
536
1487
  })
537
1488
  }), jsx("nav", {
@@ -560,7 +1511,9 @@ const NavigationBarRoot = props => {
560
1511
  style: {
561
1512
  color: isSupportDisabled ? getFadedColor(theme.palette.common.white) : theme.palette.common.white
562
1513
  },
563
- children: "Support"
1514
+ children: t("navigation.bar.support", {
1515
+ defaultValue: "Support"
1516
+ })
564
1517
  })
565
1518
  }), showTimer && jsx(TimeLabel, {
566
1519
  className: classes.timeLabel,
@@ -571,7 +1524,7 @@ const NavigationBarRoot = props => {
571
1524
  })]
572
1525
  });
573
1526
  };
574
- const useStyles$7 = tss.create(({
1527
+ const useStyles$b = tss.create(({
575
1528
  theme
576
1529
  }) => ({
577
1530
  root: {
@@ -586,7 +1539,8 @@ const useStyles$7 = tss.create(({
586
1539
  left: 0,
587
1540
  right: 0,
588
1541
  bottom: 0,
589
- borderTop: `1px solid ${COLORS.slate[800]}`
1542
+ borderTop: `1px solid ${COLORS.slate[800]}`,
1543
+ zIndex: Z_INDEX.NAVIGATION
590
1544
  },
591
1545
  container: {
592
1546
  display: "flex",
@@ -655,7 +1609,7 @@ const NavigationBar = Object.assign(NavigationBarRoot, {
655
1609
  Item: NavigationBarItem
656
1610
  });
657
1611
 
658
- const StatusTopBarButton = props => {
1612
+ const StatusTopBarButton = function StatusTopBarButton(props) {
659
1613
  const {
660
1614
  label,
661
1615
  onClick,
@@ -672,9 +1626,9 @@ const StatusTopBarButton = props => {
672
1626
  } = props;
673
1627
  const {
674
1628
  classes
675
- } = useStyles$6();
1629
+ } = useStyles$a();
676
1630
  if (!visible) return null;
677
- const getFadedColor = (color, opacity = 1) => {
1631
+ const getFadedColor = function getFadedColor(color, opacity = 1) {
678
1632
  return `${color}${Math.round(opacity * 255).toString(16).padStart(2, "0")}`;
679
1633
  };
680
1634
  const hasBackgroundColor = !!backgroundColor;
@@ -684,7 +1638,7 @@ const StatusTopBarButton = props => {
684
1638
  const finalBorderColor = disabled && borderColor ? getFadedColor(borderColor) : borderColor;
685
1639
  const finalTextColor = disabled && textColor ? getFadedColor(textColor) : textColor;
686
1640
  const finalIcon = disabled && iconDisabled ? iconDisabled : icon;
687
- const handleClick = () => {
1641
+ const handleClick = function handleClick() {
688
1642
  if (!disabled && onClick) {
689
1643
  onClick();
690
1644
  }
@@ -718,7 +1672,7 @@ const StatusTopBarButton = props => {
718
1672
  })
719
1673
  });
720
1674
  };
721
- const useStyles$6 = tss.create(({
1675
+ const useStyles$a = tss.create(({
722
1676
  theme
723
1677
  }) => ({
724
1678
  actionButton: {
@@ -746,14 +1700,14 @@ const useStyles$6 = tss.create(({
746
1700
  }
747
1701
  }));
748
1702
 
749
- const StatusTopBarRoot = props => {
1703
+ const StatusTopBarRoot = function StatusTopBarRoot(props) {
750
1704
  const {
751
1705
  status,
752
1706
  buttonConfigs = []
753
1707
  } = props;
754
1708
  const {
755
1709
  classes
756
- } = useStyles$5();
1710
+ } = useStyles$9();
757
1711
  const visibleButtons = buttonConfigs.filter(config => config.visible !== false);
758
1712
  const hasVisibleButtons = visibleButtons.length > 0;
759
1713
  return jsxs("header", {
@@ -778,7 +1732,7 @@ const StatusTopBarRoot = props => {
778
1732
  })]
779
1733
  });
780
1734
  };
781
- const useStyles$5 = tss.create(({
1735
+ const useStyles$9 = tss.create(({
782
1736
  theme
783
1737
  }) => ({
784
1738
  root: {
@@ -788,7 +1742,8 @@ const useStyles$5 = tss.create(({
788
1742
  right: 0,
789
1743
  left: 0,
790
1744
  backgroundColor: theme.palette.common.white,
791
- height: "128px"
1745
+ height: "128px",
1746
+ zIndex: Z_INDEX.NAVIGATION
792
1747
  },
793
1748
  content: {
794
1749
  display: "flex",
@@ -817,23 +1772,19 @@ const useStyles$5 = tss.create(({
817
1772
  }));
818
1773
  const StatusTopBar = StatusTopBarRoot;
819
1774
 
820
- const Sidebar = props => {
1775
+ const Sidebar = function Sidebar(props) {
821
1776
  const {
822
1777
  classes
823
- } = useStyles$4();
1778
+ } = useStyles$8();
824
1779
  return jsx(Box, {
825
1780
  className: classes.container,
826
- children: props.items.map((item, index) => jsxs(React.Fragment, {
827
- children: [jsx(SidebarItemComponent, {
828
- item: item
829
- }), index < props.items.length - 1 && jsx(Divider, {
830
- className: classes.divider
831
- })]
1781
+ children: props.items.map(item => jsx(SidebarItemComponent, {
1782
+ item: item
832
1783
  }, item.id))
833
1784
  });
834
1785
  };
835
1786
  const ICON_SIZE = 32;
836
- const SidebarItemComponent = props => {
1787
+ const SidebarItemComponent = function SidebarItemComponent(props) {
837
1788
  const {
838
1789
  item
839
1790
  } = props;
@@ -880,40 +1831,40 @@ const SidebarItemComponent = props => {
880
1831
  })
881
1832
  });
882
1833
  };
883
- const useStyles$4 = tss.create(({
1834
+ const useStyles$8 = tss.create(({
884
1835
  theme
885
1836
  }) => ({
886
1837
  container: {
887
1838
  display: "flex",
888
1839
  flexDirection: "column",
889
- width: "100%"
890
- },
891
- divider: {
892
- borderColor: theme.palette.border.main
1840
+ width: "100%",
1841
+ padding: theme.spacing(2),
1842
+ gap: theme.spacing(1)
893
1843
  }
894
1844
  }));
895
- const useSidebarItemStyles = tss.withParams().create(({
1845
+ const useSidebarItemStyles = tss.withParams().create(function createSidebarItemStyles({
896
1846
  theme,
897
1847
  state
898
- }) => {
1848
+ }) {
899
1849
  const isActive = state === "active";
900
1850
  const isDisabled = state === "disabled";
901
1851
  return {
902
1852
  button: {
903
1853
  width: "100%",
904
- height: theme.spacing(14),
905
- padding: theme.spacing(7, 5),
1854
+ minHeight: theme.spacing(14),
1855
+ padding: theme.spacing(3, 4),
906
1856
  textAlign: "left",
907
1857
  textTransform: "none",
908
- borderRadius: 0,
909
- backgroundColor: isActive ? theme.palette.background.surface1active : "transparent",
910
- border: isActive ? `1px solid ${theme.palette.border.main}` : "1px solid transparent",
1858
+ borderRadius: theme.spacing(2),
1859
+ backgroundColor: isActive ? theme.palette.background.surface1active : theme.palette.background.paper,
1860
+ border: `1px solid ${isActive ? theme.palette.border.main : theme.palette.divider}`,
911
1861
  display: "flex",
912
1862
  alignItems: "center",
913
1863
  justifyContent: "flex-start",
914
- transition: "background-color 0.2s ease",
1864
+ transition: "all 0.2s ease",
915
1865
  "&:hover": {
916
- backgroundColor: isDisabled ? "transparent" : isActive ? theme.palette.background.surface1active : theme.palette.action.hover
1866
+ backgroundColor: isDisabled ? theme.palette.background.paper : isActive ? theme.palette.background.surface1active : theme.palette.action.hover,
1867
+ borderColor: isDisabled ? theme.palette.divider : theme.palette.border.main
917
1868
  }
918
1869
  },
919
1870
  content: {
@@ -967,17 +1918,24 @@ const LogsTable = memo(({
967
1918
  hasMoreLogs,
968
1919
  onLogClick,
969
1920
  tableHeight,
970
- emptyStateMessage = "You have no logs",
1921
+ emptyStateMessage,
971
1922
  emptyStateIcon
972
1923
  }) => {
973
1924
  const {
974
1925
  classes,
975
1926
  cx
976
- } = useStyles$3({
1927
+ } = useStyles$7({
977
1928
  tableHeight
978
1929
  });
979
1930
  const theme = useTheme();
1931
+ const {
1932
+ t,
1933
+ formatDate
1934
+ } = useI18n();
980
1935
  const loadMoreRef = useRef(null);
1936
+ const emptyMessage = emptyStateMessage || t("logs.emptyState.noLogs", {
1937
+ defaultValue: "You have no logs"
1938
+ });
981
1939
  useEffect(function setupInfiniteScroll() {
982
1940
  if (!onLoadMoreLogs || !hasMoreLogs || !loadMoreRef.current) return;
983
1941
  const observer = new IntersectionObserver(entries => {
@@ -1004,7 +1962,9 @@ const LogsTable = memo(({
1004
1962
  sx: {
1005
1963
  marginTop: 2
1006
1964
  },
1007
- children: "Loading logs..."
1965
+ children: t("logs.loading", {
1966
+ defaultValue: "Loading logs..."
1967
+ })
1008
1968
  })]
1009
1969
  })
1010
1970
  });
@@ -1016,7 +1976,9 @@ const LogsTable = memo(({
1016
1976
  className: classes.errorState,
1017
1977
  children: jsx(VentionAlert, {
1018
1978
  severity: "error",
1019
- title: "Error loading logs",
1979
+ title: t("logs.error.loading", {
1980
+ defaultValue: "Error loading logs"
1981
+ }),
1020
1982
  descriptionText: error,
1021
1983
  size: "large"
1022
1984
  })
@@ -1033,7 +1995,7 @@ const LogsTable = memo(({
1033
1995
  children: emptyStateIcon
1034
1996
  }), jsx(Typography, {
1035
1997
  variant: "heading24Medium",
1036
- children: emptyStateMessage
1998
+ children: emptyMessage
1037
1999
  })]
1038
2000
  })
1039
2001
  });
@@ -1071,8 +2033,30 @@ const LogsTable = memo(({
1071
2033
  color: theme.palette.info.main
1072
2034
  });
1073
2035
  };
1074
- const formatDate = dateStr => {
1075
- return dayjs(dateStr).format("YYYY-MM-DD h:mm:ssa");
2036
+ const formatLogDate = dateStr => {
2037
+ try {
2038
+ const timestamp = new Date(dateStr).getTime();
2039
+ if (isNaN(timestamp)) {
2040
+ return dateStr;
2041
+ }
2042
+ return formatDate(timestamp, "YYYY-MM-DD h:mm:ssa");
2043
+ } catch (_a) {
2044
+ try {
2045
+ const date = new Date(dateStr);
2046
+ if (isNaN(date.getTime())) return dateStr;
2047
+ return date.toLocaleString("en-US", {
2048
+ year: "numeric",
2049
+ month: "2-digit",
2050
+ day: "2-digit",
2051
+ hour: "numeric",
2052
+ minute: "2-digit",
2053
+ second: "2-digit",
2054
+ hour12: true
2055
+ });
2056
+ } catch (_b) {
2057
+ return dateStr;
2058
+ }
2059
+ }
1076
2060
  };
1077
2061
  return jsxs(Box, {
1078
2062
  className: classes.tableSection,
@@ -1091,35 +2075,45 @@ const LogsTable = memo(({
1091
2075
  children: jsx(Typography, {
1092
2076
  variant: "heading24Medium",
1093
2077
  className: classes.tableText,
1094
- children: "Date"
2078
+ children: t("logs.table.date", {
2079
+ defaultValue: "Date"
2080
+ })
1095
2081
  })
1096
2082
  }), jsx(TableCell, {
1097
2083
  className: classes.tableHeaderCell,
1098
2084
  children: jsx(Typography, {
1099
2085
  variant: "heading24Medium",
1100
2086
  className: classes.tableText,
1101
- children: "Type"
2087
+ children: t("logs.table.type", {
2088
+ defaultValue: "Type"
2089
+ })
1102
2090
  })
1103
2091
  }), jsx(TableCell, {
1104
2092
  className: classes.tableHeaderCell,
1105
2093
  children: jsx(Typography, {
1106
2094
  variant: "heading24Medium",
1107
2095
  className: classes.tableText,
1108
- children: "Code"
2096
+ children: t("logs.table.code", {
2097
+ defaultValue: "Code"
2098
+ })
1109
2099
  })
1110
2100
  }), jsx(TableCell, {
1111
2101
  className: classes.tableHeaderCell,
1112
2102
  children: jsx(Typography, {
1113
2103
  variant: "heading24Medium",
1114
2104
  className: classes.tableText,
1115
- children: "Message"
2105
+ children: t("logs.table.message", {
2106
+ defaultValue: "Message"
2107
+ })
1116
2108
  })
1117
2109
  }), jsx(TableCell, {
1118
2110
  className: classes.tableHeaderCell,
1119
2111
  children: jsx(Typography, {
1120
2112
  variant: "heading24Medium",
1121
2113
  className: classes.tableText,
1122
- children: "Description"
2114
+ children: t("logs.table.description", {
2115
+ defaultValue: "Description"
2116
+ })
1123
2117
  })
1124
2118
  })]
1125
2119
  })
@@ -1138,14 +2132,16 @@ const LogsTable = memo(({
1138
2132
  children: jsx(Typography, {
1139
2133
  variant: "heading24Medium",
1140
2134
  className: classes.tableText,
1141
- children: formatDate(log.date)
2135
+ children: formatLogDate(log.date)
1142
2136
  })
1143
2137
  }), jsx(TableCell, {
1144
2138
  className: cx(classes.typeCell, getTypeClassName(log.level)),
1145
2139
  children: jsx(Typography, {
1146
2140
  variant: "heading24Medium",
1147
2141
  className: classes.tableText,
1148
- children: log.level
2142
+ children: t(`logs.type.${log.level}`, {
2143
+ defaultValue: log.level
2144
+ })
1149
2145
  })
1150
2146
  }), jsx(TableCell, {
1151
2147
  children: jsx(Typography, {
@@ -1177,19 +2173,23 @@ const LogsTable = memo(({
1177
2173
  }), jsx(Typography, {
1178
2174
  variant: "uiText14Regular",
1179
2175
  className: classes.loadMoreText,
1180
- children: "Loading more logs..."
2176
+ children: t("logs.loadingMore", {
2177
+ defaultValue: "Loading more logs..."
2178
+ })
1181
2179
  })]
1182
2180
  }), onLoadMoreLogs && !hasMoreLogs && logs.length > 0 && jsx(Box, {
1183
2181
  className: classes.endMessage,
1184
2182
  children: jsx(Typography, {
1185
2183
  variant: "uiText14Regular",
1186
- children: "No more logs to load"
2184
+ children: t("logs.noMoreLogs", {
2185
+ defaultValue: "No more logs to load"
2186
+ })
1187
2187
  })
1188
2188
  })]
1189
2189
  });
1190
2190
  });
1191
2191
  LogsTable.displayName = "LogsTable";
1192
- const useStyles$3 = tss.withParams().create(({
2192
+ const useStyles$7 = tss.withParams().create(({
1193
2193
  theme,
1194
2194
  tableHeight
1195
2195
  }) => ({
@@ -1303,31 +2303,62 @@ const LogFilterForm = memo(({
1303
2303
  var _a, _b, _c, _d;
1304
2304
  const {
1305
2305
  classes
1306
- } = useStyles$2();
2306
+ } = useStyles$6();
2307
+ const {
2308
+ t
2309
+ } = useI18n();
2310
+ const handleFilterChangeRef = useRef(onFilterChange);
2311
+ useEffect(function updateFilterChangeRef() {
2312
+ handleFilterChangeRef.current = onFilterChange;
2313
+ }, [onFilterChange]);
1307
2314
  const [fromDate, setFromDate] = useState((_a = initialFilters === null || initialFilters === void 0 ? void 0 : initialFilters.fromDate) !== null && _a !== void 0 ? _a : "");
1308
2315
  const [toDate, setToDate] = useState((_b = initialFilters === null || initialFilters === void 0 ? void 0 : initialFilters.toDate) !== null && _b !== void 0 ? _b : "");
1309
2316
  const [logType, setLogType] = useState((_c = initialFilters === null || initialFilters === void 0 ? void 0 : initialFilters.logType) !== null && _c !== void 0 ? _c : null);
1310
2317
  const [sortOrder, setSortOrder] = useState((_d = initialFilters === null || initialFilters === void 0 ? void 0 : initialFilters.sortOrder) !== null && _d !== void 0 ? _d : "latest");
1311
- const typeOptions = [{
2318
+ const prevInitialFiltersRef = useRef(initialFilters);
2319
+ useEffect(function syncInitialFilters() {
2320
+ if (prevInitialFiltersRef.current !== initialFilters) {
2321
+ prevInitialFiltersRef.current = initialFilters;
2322
+ if (initialFilters) {
2323
+ if (initialFilters.fromDate !== undefined) setFromDate(initialFilters.fromDate);
2324
+ if (initialFilters.toDate !== undefined) setToDate(initialFilters.toDate);
2325
+ if (initialFilters.logType !== undefined) setLogType(initialFilters.logType);
2326
+ if (initialFilters.sortOrder !== undefined) setSortOrder(initialFilters.sortOrder);
2327
+ }
2328
+ }
2329
+ }, [initialFilters]);
2330
+ const typeOptions = useMemo(() => [{
1312
2331
  value: "",
1313
- displayText: "All"
2332
+ displayText: t("logs.filter.typeOptions.all", {
2333
+ defaultValue: "All"
2334
+ })
1314
2335
  }, {
1315
2336
  value: "error",
1316
- displayText: "Error"
2337
+ displayText: t("logs.filter.typeOptions.error", {
2338
+ defaultValue: "Error"
2339
+ })
1317
2340
  }, {
1318
2341
  value: "warning",
1319
- displayText: "Warning"
2342
+ displayText: t("logs.filter.typeOptions.warning", {
2343
+ defaultValue: "Warning"
2344
+ })
1320
2345
  }, {
1321
2346
  value: "info",
1322
- displayText: "Info"
1323
- }];
1324
- const sortOptions = [{
2347
+ displayText: t("logs.filter.typeOptions.info", {
2348
+ defaultValue: "Info"
2349
+ })
2350
+ }], [t]);
2351
+ const sortOptions = useMemo(() => [{
1325
2352
  value: "latest",
1326
- displayText: "From latest"
2353
+ displayText: t("logs.filter.sortOptions.latest", {
2354
+ defaultValue: "From latest"
2355
+ })
1327
2356
  }, {
1328
2357
  value: "oldest",
1329
- displayText: "From oldest"
1330
- }];
2358
+ displayText: t("logs.filter.sortOptions.oldest", {
2359
+ defaultValue: "From oldest"
2360
+ })
2361
+ }], [t]);
1331
2362
  const handleReset = () => {
1332
2363
  setFromDate("");
1333
2364
  setToDate("");
@@ -1336,20 +2367,23 @@ const LogFilterForm = memo(({
1336
2367
  onReset === null || onReset === void 0 ? void 0 : onReset();
1337
2368
  };
1338
2369
  useEffect(function notifyFilterChange() {
1339
- onFilterChange === null || onFilterChange === void 0 ? void 0 : onFilterChange({
2370
+ var _a;
2371
+ (_a = handleFilterChangeRef.current) === null || _a === void 0 ? void 0 : _a.call(handleFilterChangeRef, {
1340
2372
  fromDate,
1341
2373
  toDate,
1342
2374
  logType,
1343
2375
  sortOrder
1344
2376
  });
1345
- }, [fromDate, toDate, logType, sortOrder, onFilterChange]);
2377
+ }, [fromDate, toDate, logType, sortOrder]);
1346
2378
  return jsxs(Box, {
1347
2379
  className: classes.filterSection,
1348
2380
  children: [jsx(Box, {
1349
2381
  className: classes.filterInput,
1350
2382
  children: jsx(VentionTextInput, {
1351
2383
  size: "xx-large",
1352
- label: "From",
2384
+ label: t("logs.filter.from", {
2385
+ defaultValue: "From"
2386
+ }),
1353
2387
  value: fromDate,
1354
2388
  onChange: event => setFromDate(event.target.value),
1355
2389
  type: "date"
@@ -1358,7 +2392,9 @@ const LogFilterForm = memo(({
1358
2392
  className: classes.filterInput,
1359
2393
  children: jsx(VentionTextInput, {
1360
2394
  size: "xx-large",
1361
- label: "To",
2395
+ label: t("logs.filter.to", {
2396
+ defaultValue: "To"
2397
+ }),
1362
2398
  value: toDate,
1363
2399
  onChange: event => setToDate(event.target.value),
1364
2400
  type: "date"
@@ -1368,10 +2404,17 @@ const LogFilterForm = memo(({
1368
2404
  children: jsx(VentionSelect, {
1369
2405
  size: "xx-large",
1370
2406
  variant: "outlined",
1371
- labelText: "Type",
1372
- value: logType,
1373
- onChange: event => setLogType(event.target.value),
1374
- placeholder: "Choose type",
2407
+ labelText: t("logs.filter.type", {
2408
+ defaultValue: "Type"
2409
+ }),
2410
+ value: logType !== null && logType !== void 0 ? logType : "",
2411
+ onChange: event => {
2412
+ const value = event.target.value;
2413
+ setLogType(value === "" ? null : value);
2414
+ },
2415
+ placeholder: t("logs.filter.chooseType", {
2416
+ defaultValue: "Choose type"
2417
+ }),
1375
2418
  menuItems: typeOptions
1376
2419
  })
1377
2420
  }), jsx(Box, {
@@ -1379,7 +2422,9 @@ const LogFilterForm = memo(({
1379
2422
  children: jsx(VentionSelect, {
1380
2423
  size: "xx-large",
1381
2424
  variant: "outlined",
1382
- labelText: "Sort",
2425
+ labelText: t("logs.filter.sort", {
2426
+ defaultValue: "Sort"
2427
+ }),
1383
2428
  value: sortOrder,
1384
2429
  onChange: event => setSortOrder(event.target.value),
1385
2430
  menuItems: sortOptions
@@ -1388,12 +2433,14 @@ const LogFilterForm = memo(({
1388
2433
  size: "x-large",
1389
2434
  onClick: handleReset,
1390
2435
  className: classes.resetButton,
1391
- children: "Reset"
2436
+ children: t("logs.filter.reset", {
2437
+ defaultValue: "Reset"
2438
+ })
1392
2439
  })]
1393
2440
  });
1394
2441
  });
1395
2442
  LogFilterForm.displayName = "LogFilterForm";
1396
- const useStyles$2 = tss.create(({
2443
+ const useStyles$6 = tss.create(({
1397
2444
  theme
1398
2445
  }) => ({
1399
2446
  filterSection: {
@@ -1457,7 +2504,10 @@ const LogsPagination = memo(({
1457
2504
  }) => {
1458
2505
  const {
1459
2506
  classes
1460
- } = useStyles$1();
2507
+ } = useStyles$5();
2508
+ const {
2509
+ t
2510
+ } = useI18n();
1461
2511
  const handlePrevious = () => {
1462
2512
  if (currentPage > 1) {
1463
2513
  onPageChange(currentPage - 1);
@@ -1478,7 +2528,11 @@ const LogsPagination = memo(({
1478
2528
  children: "\u2190"
1479
2529
  }), jsxs(Typography, {
1480
2530
  variant: "heading18SemiBold",
1481
- children: ["Page ", currentPage, " / ", totalPages]
2531
+ children: [t("pagination.page", {
2532
+ defaultValue: "Page"
2533
+ }), " ", currentPage, " ", t("pagination.of", {
2534
+ defaultValue: "of"
2535
+ }), " ", totalPages]
1482
2536
  }), jsx(VentionButton, {
1483
2537
  size: "x-large",
1484
2538
  className: classes.paginationButton,
@@ -1489,7 +2543,7 @@ const LogsPagination = memo(({
1489
2543
  });
1490
2544
  });
1491
2545
  LogsPagination.displayName = "LogsPagination";
1492
- const useStyles$1 = tss.create(({
2546
+ const useStyles$5 = tss.create(({
1493
2547
  theme
1494
2548
  }) => ({
1495
2549
  paginationSection: {
@@ -1539,7 +2593,7 @@ const LogsPanel = forwardRef((props, ref) => {
1539
2593
  const {
1540
2594
  classes,
1541
2595
  cx
1542
- } = useStyles();
2596
+ } = useStyles$4();
1543
2597
  const [logs, setLogs] = useState([]);
1544
2598
  const [isLoading, setIsLoading] = useState(true);
1545
2599
  const [error, setError] = useState(null);
@@ -1554,43 +2608,45 @@ const LogsPanel = forwardRef((props, ref) => {
1554
2608
  const [currentPage, setCurrentPage] = useState((_g = pagination === null || pagination === void 0 ? void 0 : pagination.initialPage) !== null && _g !== void 0 ? _g : 1);
1555
2609
  const [totalPages, setTotalPages] = useState(1);
1556
2610
  const [hasMorePages, setHasMorePages] = useState(false);
1557
- const fetchData = useCallback(page => __awaiter(void 0, void 0, void 0, function* () {
1558
- let isCancelled = false;
1559
- setIsLoading(true);
1560
- setError(null);
1561
- try {
1562
- const result = yield dataFetcher({
1563
- filters,
1564
- page,
1565
- pageSize
1566
- });
1567
- if (!isCancelled) {
1568
- if (paginationMode === "infinite-scroll" && page > 1) {
1569
- setLogs(prev => [...prev, ...result.logs]);
1570
- } else {
1571
- setLogs(result.logs);
2611
+ const fetchData = useCallback(function fetchData(page, signal) {
2612
+ return __awaiter(this, void 0, void 0, function* () {
2613
+ setIsLoading(true);
2614
+ setError(null);
2615
+ try {
2616
+ const result = yield dataFetcher({
2617
+ filters,
2618
+ page,
2619
+ pageSize
2620
+ });
2621
+ if (!(signal === null || signal === void 0 ? void 0 : signal.aborted)) {
2622
+ if (paginationMode === "infinite-scroll" && page > 1) {
2623
+ setLogs(prev => [...prev, ...result.logs]);
2624
+ } else {
2625
+ setLogs(result.logs);
2626
+ }
2627
+ setTotalPages(result.totalPages);
2628
+ setHasMorePages(result.hasMorePages);
2629
+ setCurrentPage(result.currentPage);
2630
+ setIsLoading(false);
1572
2631
  }
1573
- setTotalPages(result.totalPages);
1574
- setHasMorePages(result.hasMorePages);
1575
- setCurrentPage(result.currentPage);
1576
- setIsLoading(false);
1577
- }
1578
- } catch (error) {
1579
- if (!isCancelled) {
1580
- const errorMessage = error instanceof Error ? error.message : "Failed to load logs";
1581
- setError(errorMessage);
1582
- setIsLoading(false);
1583
- if (onError) {
1584
- onError(error);
2632
+ } catch (error) {
2633
+ if (!(signal === null || signal === void 0 ? void 0 : signal.aborted)) {
2634
+ const errorMessage = error instanceof Error ? error.message : "Failed to load logs";
2635
+ setError(errorMessage);
2636
+ setIsLoading(false);
2637
+ if (onError) {
2638
+ onError(error);
2639
+ }
1585
2640
  }
1586
2641
  }
1587
- }
2642
+ });
2643
+ }, [dataFetcher, filters, pageSize, paginationMode, onError]);
2644
+ useEffect(function fetchDataOnChange() {
2645
+ const controller = new AbortController();
2646
+ fetchData(currentPage, controller.signal);
1588
2647
  return function cleanup() {
1589
- isCancelled = true;
2648
+ controller.abort();
1590
2649
  };
1591
- }), [dataFetcher, filters, pageSize, paginationMode, onError]);
1592
- useEffect(function fetchDataOnChange() {
1593
- fetchData(currentPage);
1594
2650
  }, [fetchData, currentPage]);
1595
2651
  const handlePageChange = useCallback(page => {
1596
2652
  setCurrentPage(page);
@@ -1672,7 +2728,7 @@ const LogsPanel = forwardRef((props, ref) => {
1672
2728
  });
1673
2729
  });
1674
2730
  LogsPanel.displayName = "LogsPanel";
1675
- const useStyles = tss.create(({
2731
+ const useStyles$4 = tss.create(({
1676
2732
  theme
1677
2733
  }) => ({
1678
2734
  root: {
@@ -1683,6 +2739,352 @@ const useStyles = tss.create(({
1683
2739
  }
1684
2740
  }));
1685
2741
 
2742
+ const SettingsPage = function SettingsPage({
2743
+ sidebarItems,
2744
+ children,
2745
+ sidebarWidth = 320
2746
+ }) {
2747
+ const {
2748
+ classes
2749
+ } = useStyles$3({
2750
+ sidebarWidth
2751
+ });
2752
+ return jsxs(Box, {
2753
+ className: classes.root,
2754
+ children: [jsx(Box, {
2755
+ className: classes.sidebar,
2756
+ children: jsx(Sidebar, {
2757
+ items: sidebarItems
2758
+ })
2759
+ }), jsx(Box, {
2760
+ className: classes.content,
2761
+ children: children
2762
+ })]
2763
+ });
2764
+ };
2765
+ SettingsPage.displayName = "SettingsPage";
2766
+ const useStyles$3 = tss.withParams().create(({
2767
+ theme,
2768
+ sidebarWidth
2769
+ }) => ({
2770
+ root: {
2771
+ display: "flex",
2772
+ flex: 1,
2773
+ height: "100%"
2774
+ },
2775
+ sidebar: {
2776
+ width: sidebarWidth,
2777
+ borderRight: `1px solid ${theme.palette.divider}`,
2778
+ backgroundColor: theme.palette.background.paper
2779
+ },
2780
+ content: {
2781
+ flex: 1,
2782
+ padding: theme.spacing(4),
2783
+ overflow: "auto"
2784
+ }
2785
+ }));
2786
+
2787
+ function formatFileSize(bytes) {
2788
+ if (bytes === 0) return "0 B";
2789
+ const units = ["B", "KB", "MB", "GB"];
2790
+ const exponent = Math.min(Math.floor(Math.log(bytes) / Math.log(1024)), units.length - 1);
2791
+ const size = (bytes / Math.pow(1024, exponent)).toFixed(1);
2792
+ return `${size} ${units[exponent]}`;
2793
+ }
2794
+ function FileUploadPanel({
2795
+ title,
2796
+ files,
2797
+ onFilesSelect,
2798
+ onFileRemove,
2799
+ onFileRetry,
2800
+ onFileCancel,
2801
+ fileCriteriaDescription,
2802
+ dropzoneTitle,
2803
+ disabled = false,
2804
+ maxHeight
2805
+ }) {
2806
+ const {
2807
+ classes
2808
+ } = useStyles$2({
2809
+ maxHeight
2810
+ });
2811
+ const {
2812
+ t
2813
+ } = useTranslation();
2814
+ const displayTitle = title !== null && title !== void 0 ? title : t("fileUploadPanel.defaultTitle");
2815
+ const displayDropzoneTitle = dropzoneTitle !== null && dropzoneTitle !== void 0 ? dropzoneTitle : t("fileUploadPanel.dropzoneTitle");
2816
+ const displayFileCriteria = fileCriteriaDescription !== null && fileCriteriaDescription !== void 0 ? fileCriteriaDescription : t("fileUploadPanel.defaultFileCriteria");
2817
+ function handleFileRemove(fileId) {
2818
+ onFileRemove(fileId);
2819
+ }
2820
+ function handleFileRetry(fileId) {
2821
+ if (onFileRetry) {
2822
+ onFileRetry(fileId);
2823
+ }
2824
+ }
2825
+ function handleFileCancel(fileId) {
2826
+ if (onFileCancel) {
2827
+ onFileCancel(fileId);
2828
+ }
2829
+ }
2830
+ return jsxs(Box, {
2831
+ className: classes.container,
2832
+ children: [displayTitle && jsx(Typography, {
2833
+ variant: "heading18SemiBold",
2834
+ className: classes.title,
2835
+ children: displayTitle
2836
+ }), jsx(VentionDropZone, {
2837
+ style: "outline",
2838
+ size: "large",
2839
+ onFilesSelect: onFilesSelect,
2840
+ fileCriteriaDescription: displayFileCriteria,
2841
+ defaultTitle: displayDropzoneTitle,
2842
+ disabled: disabled
2843
+ }), files.length > 0 && jsx(Box, {
2844
+ className: classes.fileList,
2845
+ children: files.map(file => jsx(VentionUploadFile, {
2846
+ fileName: file.name,
2847
+ fileSize: formatFileSize(file.size),
2848
+ state: file.state,
2849
+ errorMessage: file.errorMessage,
2850
+ size: "large",
2851
+ style: "shaded",
2852
+ onRemove: () => handleFileRemove(file.id),
2853
+ onRetry: () => handleFileRetry(file.id),
2854
+ onCancel: () => handleFileCancel(file.id)
2855
+ }, file.id))
2856
+ })]
2857
+ });
2858
+ }
2859
+ FileUploadPanel.displayName = "FileUploadPanel";
2860
+ const useStyles$2 = tss.withParams().create(({
2861
+ theme,
2862
+ maxHeight
2863
+ }) => ({
2864
+ container: {
2865
+ display: "flex",
2866
+ flexDirection: "column",
2867
+ gap: theme.spacing(2),
2868
+ width: "100%"
2869
+ },
2870
+ title: {
2871
+ marginBottom: theme.spacing(1)
2872
+ },
2873
+ fileList: {
2874
+ display: "flex",
2875
+ flexDirection: "column",
2876
+ gap: theme.spacing(1),
2877
+ maxHeight: maxHeight !== null && maxHeight !== void 0 ? maxHeight : "auto",
2878
+ overflowY: maxHeight ? "auto" : "visible"
2879
+ }
2880
+ }));
2881
+
2882
+ function StepProgressCircle({
2883
+ currentStep,
2884
+ totalSteps,
2885
+ title,
2886
+ variant = "default",
2887
+ size = 180,
2888
+ strokeWidth = 12,
2889
+ showTitle = true
2890
+ }) {
2891
+ var _a;
2892
+ const {
2893
+ t
2894
+ } = useTranslation();
2895
+ const {
2896
+ classes
2897
+ } = useStyles$1({
2898
+ size,
2899
+ strokeWidth,
2900
+ variant
2901
+ });
2902
+ const titleKey = (_a = title === null || title === void 0 ? void 0 : title.toLowerCase().replace(/\s/g, "")) !== null && _a !== void 0 ? _a : "progress";
2903
+ const displayTitle = t(`stepProgressCircle.title.${titleKey}`, {
2904
+ defaultValue: title !== null && title !== void 0 ? title : "Progress"
2905
+ });
2906
+ const percentage = totalSteps > 0 ? Math.round(currentStep / totalSteps * 100) : 0;
2907
+ const radius = (size - strokeWidth) / 2 - 10;
2908
+ const circumference = 2 * Math.PI * radius;
2909
+ const strokeDashoffset = circumference - percentage / 100 * circumference;
2910
+ const center = size / 2;
2911
+ const progressText = totalSteps > 0 ? `${currentStep}/${totalSteps}` : "-/-";
2912
+ return jsxs(Box, {
2913
+ className: classes.container,
2914
+ children: [showTitle && jsx(Typography, {
2915
+ variant: "heading18SemiBold",
2916
+ className: classes.title,
2917
+ children: displayTitle
2918
+ }), jsxs(Box, {
2919
+ className: classes.circleContainer,
2920
+ children: [jsxs("svg", {
2921
+ className: classes.svg,
2922
+ width: size,
2923
+ height: size,
2924
+ viewBox: `0 0 ${size} ${size}`,
2925
+ children: [jsx("circle", {
2926
+ cx: center,
2927
+ cy: center,
2928
+ r: radius,
2929
+ className: classes.backgroundCircle,
2930
+ fill: "none"
2931
+ }), jsx("circle", {
2932
+ cx: center,
2933
+ cy: center,
2934
+ r: radius,
2935
+ className: classes.progressCircle,
2936
+ fill: "none",
2937
+ strokeLinecap: "round",
2938
+ transform: `rotate(-90 ${center} ${center})`,
2939
+ strokeDasharray: circumference,
2940
+ strokeDashoffset: strokeDashoffset
2941
+ })]
2942
+ }), jsx(Box, {
2943
+ className: classes.textContainer,
2944
+ children: jsx(Typography, {
2945
+ variant: "heading24SemiBold",
2946
+ className: classes.progressText,
2947
+ children: progressText
2948
+ })
2949
+ })]
2950
+ })]
2951
+ });
2952
+ }
2953
+ StepProgressCircle.displayName = "StepProgressCircle";
2954
+ const useStyles$1 = tss.withParams().create(({
2955
+ theme,
2956
+ size,
2957
+ strokeWidth,
2958
+ variant
2959
+ }) => {
2960
+ const variantColors = {
2961
+ default: theme.palette.primary.main,
2962
+ success: theme.palette.success.main,
2963
+ error: theme.palette.error.main,
2964
+ warning: theme.palette.warning.main
2965
+ };
2966
+ return {
2967
+ container: {
2968
+ display: "flex",
2969
+ flexDirection: "column",
2970
+ alignItems: "center",
2971
+ justifyContent: "center"
2972
+ },
2973
+ title: {
2974
+ marginBottom: theme.spacing(2),
2975
+ color: theme.palette.text.primary
2976
+ },
2977
+ circleContainer: {
2978
+ position: "relative",
2979
+ width: size,
2980
+ height: size
2981
+ },
2982
+ svg: {
2983
+ width: size,
2984
+ height: size
2985
+ },
2986
+ backgroundCircle: {
2987
+ stroke: theme.palette.grey[200],
2988
+ strokeWidth
2989
+ },
2990
+ progressCircle: {
2991
+ stroke: variantColors[variant],
2992
+ strokeWidth,
2993
+ transition: "stroke-dashoffset 0.5s ease-in-out, stroke 0.3s ease-in-out"
2994
+ },
2995
+ textContainer: {
2996
+ position: "absolute",
2997
+ top: "50%",
2998
+ left: "50%",
2999
+ transform: "translate(-50%, -50%)",
3000
+ display: "flex",
3001
+ alignItems: "center",
3002
+ justifyContent: "center"
3003
+ },
3004
+ progressText: {
3005
+ color: theme.palette.text.primary
3006
+ }
3007
+ };
3008
+ });
3009
+
3010
+ const ActionButton = function ActionButton({
3011
+ variant = "primary",
3012
+ onClick,
3013
+ disabled = false,
3014
+ icon,
3015
+ label,
3016
+ size = 96
3017
+ }) {
3018
+ const {
3019
+ classes
3020
+ } = useStyles({
3021
+ size
3022
+ });
3023
+ const {
3024
+ t
3025
+ } = useTranslation();
3026
+ const translationKey = label.toLowerCase().replace(/\s+/g, "_");
3027
+ const translatedLabel = t(`actionButton.${translationKey}`, {
3028
+ defaultValue: label
3029
+ });
3030
+ return jsx(VentionIconButton, {
3031
+ onClick: onClick,
3032
+ disabled: disabled,
3033
+ size: "x-large",
3034
+ variant: variant === "destructive" ? "destructive" : "filled",
3035
+ className: classes.button,
3036
+ "data-testid": "action-button",
3037
+ children: jsxs(Box, {
3038
+ className: classes.content,
3039
+ children: [jsx(Box, {
3040
+ className: classes.iconContainer,
3041
+ children: icon
3042
+ }), jsx(Typography, {
3043
+ variant: "uiText14SemiBold",
3044
+ className: classes.label,
3045
+ children: translatedLabel
3046
+ })]
3047
+ })
3048
+ });
3049
+ };
3050
+ ActionButton.displayName = "ActionButton";
3051
+ const useStyles = tss.withParams().create(({
3052
+ theme,
3053
+ size
3054
+ }) => ({
3055
+ button: {
3056
+ height: size,
3057
+ width: size,
3058
+ minWidth: size,
3059
+ padding: theme.spacing(2)
3060
+ },
3061
+ content: {
3062
+ display: "flex",
3063
+ flexDirection: "column",
3064
+ alignItems: "center",
3065
+ justifyContent: "center",
3066
+ gap: theme.spacing(1)
3067
+ },
3068
+ iconContainer: {
3069
+ display: "flex",
3070
+ alignItems: "center",
3071
+ justifyContent: "center"
3072
+ },
3073
+ label: {
3074
+ textAlign: "center"
3075
+ }
3076
+ }));
3077
+
3078
+ var UserLevel;
3079
+ (function (UserLevel) {
3080
+ UserLevel[UserLevel["Operator"] = 1] = "Operator";
3081
+ UserLevel[UserLevel["Maintenance"] = 2] = "Maintenance";
3082
+ UserLevel[UserLevel["Admin"] = 3] = "Admin";
3083
+ })(UserLevel || (UserLevel = {}));
3084
+ function hasSufficientLevel(requiredLevel, currentLevel) {
3085
+ return currentLevel >= requiredLevel;
3086
+ }
3087
+
1686
3088
  /**
1687
3089
  * This module provides utilities for generating API base URLs for machine apps.
1688
3090
  * It automatically detects the environment and returns the appropriate URL:
@@ -1739,4 +3141,4 @@ function getApiBaseUrl(options) {
1739
3141
  return getExecutionEngineHttpUrl(processName);
1740
3142
  }
1741
3143
 
1742
- export { LogFilterForm, LogsPagination, LogsPanel, LogsTable, NavigationBar, NavigationConfirmationModal, PasswordProtectionModal, Sidebar, StatusTopBar, TimeLabel, closeCustomUi, formatDateToInput, getApiBaseUrl, isOnEdge, isTouchScreenDevice, navigateControlCenter, parseLogDate };
3144
+ export { ActionButton, FileUploadPanel, I18nProvider, I18nSettings, LogFilterForm, LogsPagination, LogsPanel, LogsTable, NavigationBar, NavigationConfirmationModal, PasswordProtectionModal, SettingsPage, Sidebar, StatusTopBar, StepProgressCircle, TimeLabel, UserLevel, Z_INDEX, closeCustomUi, formatDateToInput, getApiBaseUrl, getAvailableTimezones, getLanguageDisplayName, getSupportedLanguages, hasSufficientLevel, isOnEdge, isTouchScreenDevice, navigateControlCenter, parseLogDate, useI18n };