web-mojo 2.2.66 → 2.2.67

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 (91) hide show
  1. package/dist/admin.cjs.js +1 -1
  2. package/dist/admin.es.js +1 -1
  3. package/dist/auth.cjs.js +1 -1
  4. package/dist/auth.es.js +1 -1
  5. package/dist/charts.cjs.js +1 -1
  6. package/dist/charts.es.js +1 -1
  7. package/dist/chunks/{ChatView-DTcs3Xh7.js → ChatView-Cfe0ZGvr.js} +2 -2
  8. package/dist/chunks/{ChatView-DTcs3Xh7.js.map → ChatView-Cfe0ZGvr.js.map} +1 -1
  9. package/dist/chunks/{ChatView-CYIOOvHM.js → ChatView-DuQVFrCY.js} +2 -2
  10. package/dist/chunks/{ChatView-CYIOOvHM.js.map → ChatView-DuQVFrCY.js.map} +1 -1
  11. package/dist/chunks/{Collection-BgfCzEE5.js → Collection-BWKmydl5.js} +2 -2
  12. package/dist/chunks/{Collection-BgfCzEE5.js.map → Collection-BWKmydl5.js.map} +1 -1
  13. package/dist/chunks/{Collection-DSBRXpwK.js → Collection-CmjTsmrP.js} +2 -2
  14. package/dist/chunks/{Collection-DSBRXpwK.js.map → Collection-CmjTsmrP.js.map} +1 -1
  15. package/dist/chunks/{ContextMenu-C7QJDUar.js → ContextMenu-8vTiZZQV.js} +2 -2
  16. package/dist/chunks/{ContextMenu-C7QJDUar.js.map → ContextMenu-8vTiZZQV.js.map} +1 -1
  17. package/dist/chunks/{ContextMenu-C9RiB1kl.js → ContextMenu-DBw0WMTO.js} +2 -2
  18. package/dist/chunks/{ContextMenu-C9RiB1kl.js.map → ContextMenu-DBw0WMTO.js.map} +1 -1
  19. package/dist/chunks/{DataView-Dl2jl_0h.js → DataView-BEovBggn.js} +2 -2
  20. package/dist/chunks/{DataView-Dl2jl_0h.js.map → DataView-BEovBggn.js.map} +1 -1
  21. package/dist/chunks/{DataView-CK3Z0TJH.js → DataView-DyJKgOn3.js} +2 -2
  22. package/dist/chunks/{DataView-CK3Z0TJH.js.map → DataView-DyJKgOn3.js.map} +1 -1
  23. package/dist/chunks/{Dialog-9FzcToYV.js → Dialog-DW7PHzUc.js} +2 -2
  24. package/dist/chunks/{Dialog-9FzcToYV.js.map → Dialog-DW7PHzUc.js.map} +1 -1
  25. package/dist/chunks/{Dialog-DZG_XYbk.js → Dialog-jfBsXy5X.js} +2 -2
  26. package/dist/chunks/{Dialog-DZG_XYbk.js.map → Dialog-jfBsXy5X.js.map} +1 -1
  27. package/dist/chunks/{Files-B_NE3QwI.js → Files-C-ChBvr5.js} +2 -2
  28. package/dist/chunks/{Files-B_NE3QwI.js.map → Files-C-ChBvr5.js.map} +1 -1
  29. package/dist/chunks/{Files-BDqCTw9A.js → Files-DNbHDy43.js} +2 -2
  30. package/dist/chunks/{Files-BDqCTw9A.js.map → Files-DNbHDy43.js.map} +1 -1
  31. package/dist/chunks/{FormView-D2Ia0Idj.js → FormView-EoB_ZdIB.js} +3 -3
  32. package/dist/chunks/{FormView-D2Ia0Idj.js.map → FormView-EoB_ZdIB.js.map} +1 -1
  33. package/dist/chunks/{FormView-CQ0eFCJu.js → FormView-Q_lFA0nr.js} +3 -3
  34. package/dist/chunks/{FormView-CQ0eFCJu.js.map → FormView-Q_lFA0nr.js.map} +1 -1
  35. package/dist/chunks/{ListView-BunTmkAU.js → ListView-BLFFK_Ir.js} +2 -2
  36. package/dist/chunks/{ListView-BunTmkAU.js.map → ListView-BLFFK_Ir.js.map} +1 -1
  37. package/dist/chunks/{ListView-DVStKiMi.js → ListView-CMZpwyyC.js} +2 -2
  38. package/dist/chunks/{ListView-DVStKiMi.js.map → ListView-CMZpwyyC.js.map} +1 -1
  39. package/dist/chunks/{MetricsCountryMapView-CnAEbUw_.js → MetricsCountryMapView-B0kWK-Js.js} +2 -2
  40. package/dist/chunks/{MetricsCountryMapView-CnAEbUw_.js.map → MetricsCountryMapView-B0kWK-Js.js.map} +1 -1
  41. package/dist/chunks/{MetricsCountryMapView-C_p6hcly.js → MetricsCountryMapView-DuBKO7gz.js} +2 -2
  42. package/dist/chunks/{MetricsCountryMapView-C_p6hcly.js.map → MetricsCountryMapView-DuBKO7gz.js.map} +1 -1
  43. package/dist/chunks/{MetricsMiniChartWidget-C1RCd-Xw.js → MetricsMiniChartWidget-BkMjI-gz.js} +2 -2
  44. package/dist/chunks/{MetricsMiniChartWidget-C1RCd-Xw.js.map → MetricsMiniChartWidget-BkMjI-gz.js.map} +1 -1
  45. package/dist/chunks/{MetricsMiniChartWidget-C9QdxxBn.js → MetricsMiniChartWidget-ChC5GGm6.js} +2 -2
  46. package/dist/chunks/{MetricsMiniChartWidget-C9QdxxBn.js.map → MetricsMiniChartWidget-ChC5GGm6.js.map} +1 -1
  47. package/dist/chunks/{PDFViewer-B_LSyM7g.js → PDFViewer-iOqYpg-6.js} +2 -2
  48. package/dist/chunks/{PDFViewer-B_LSyM7g.js.map → PDFViewer-iOqYpg-6.js.map} +1 -1
  49. package/dist/chunks/{PDFViewer-DI9v3Vkg.js → PDFViewer-sFoyopz3.js} +2 -2
  50. package/dist/chunks/{PDFViewer-DI9v3Vkg.js.map → PDFViewer-sFoyopz3.js.map} +1 -1
  51. package/dist/chunks/{Rest-Ds9e8tN8.js → Rest-B1eUyLX5.js} +2 -2
  52. package/dist/chunks/{Rest-Ds9e8tN8.js.map → Rest-B1eUyLX5.js.map} +1 -1
  53. package/dist/chunks/{Rest-DFnCoMvk.js → Rest-BJ3Mvx1L.js} +2 -2
  54. package/dist/chunks/{Rest-DFnCoMvk.js.map → Rest-BJ3Mvx1L.js.map} +1 -1
  55. package/dist/chunks/{TokenManager-DzLjXShS.js → TokenManager-BYMKH_aW.js} +2 -2
  56. package/dist/chunks/{TokenManager-DzLjXShS.js.map → TokenManager-BYMKH_aW.js.map} +1 -1
  57. package/dist/chunks/{TokenManager-Dk5oiCh1.js → TokenManager-DhDUKmaw.js} +2 -2
  58. package/dist/chunks/{TokenManager-Dk5oiCh1.js.map → TokenManager-DhDUKmaw.js.map} +1 -1
  59. package/dist/chunks/{User-CbqYlTBK.js → User-BnlvMG5J.js} +2 -2
  60. package/dist/chunks/{User-CbqYlTBK.js.map → User-BnlvMG5J.js.map} +1 -1
  61. package/dist/chunks/{User-BwDOeY-q.js → User-DSqcOwPL.js} +2 -2
  62. package/dist/chunks/{User-BwDOeY-q.js.map → User-DSqcOwPL.js.map} +1 -1
  63. package/dist/chunks/{WebApp-BCfA2Dlw.js → WebApp-B0m6JCjO.js} +2 -2
  64. package/dist/chunks/{WebApp-BCfA2Dlw.js.map → WebApp-B0m6JCjO.js.map} +1 -1
  65. package/dist/chunks/{WebApp-kKz5FV57.js → WebApp-Bsic6FPo.js} +2 -2
  66. package/dist/chunks/{WebApp-kKz5FV57.js.map → WebApp-Bsic6FPo.js.map} +1 -1
  67. package/dist/chunks/{WebSocketClient-fEGJDFXJ.js → WebSocketClient-Bh0Mmtje.js} +2 -2
  68. package/dist/chunks/{WebSocketClient-fEGJDFXJ.js.map → WebSocketClient-Bh0Mmtje.js.map} +1 -1
  69. package/dist/chunks/{WebSocketClient-BxL2M7p0.js → WebSocketClient-CLgYPxWX.js} +2 -2
  70. package/dist/chunks/{WebSocketClient-BxL2M7p0.js.map → WebSocketClient-CLgYPxWX.js.map} +1 -1
  71. package/dist/chunks/{version-Bykv8fhW.js → version-BY7AsEkb.js} +2 -2
  72. package/dist/chunks/{version-Bykv8fhW.js.map → version-BY7AsEkb.js.map} +1 -1
  73. package/dist/chunks/{version-D0hwRoO4.js → version-BdfRyQDm.js} +2 -2
  74. package/dist/chunks/{version-D0hwRoO4.js.map → version-BdfRyQDm.js.map} +1 -1
  75. package/dist/docit.cjs.js +1 -1
  76. package/dist/docit.es.js +1 -1
  77. package/dist/index.cjs.js +1 -1
  78. package/dist/index.cjs.js.map +1 -1
  79. package/dist/index.es.js +1 -1
  80. package/dist/index.es.js.map +1 -1
  81. package/dist/lightbox.cjs.js +1 -1
  82. package/dist/lightbox.es.js +1 -1
  83. package/dist/map.cjs.js +1 -1
  84. package/dist/map.es.js +1 -1
  85. package/dist/timeline.cjs.js +1 -1
  86. package/dist/timeline.es.js +1 -1
  87. package/dist/web-mojo.lite.iife.js +4 -0
  88. package/dist/web-mojo.lite.iife.js.map +1 -1
  89. package/dist/web-mojo.lite.iife.min.js +1 -1
  90. package/dist/web-mojo.lite.iife.min.js.map +1 -1
  91. package/package.json +8 -7
@@ -1 +1 @@
1
- {"version":3,"file":"User-BwDOeY-q.js","sources":["../../src/core/services/ToastService.js","../../src/core/models/Group.js","../../src/core/models/User.js"],"sourcesContent":["/**\n * ToastService - Bootstrap 5 Toast Notification Service\n * Provides methods to display toast notifications with different types and options\n *\n * Features:\n * - Bootstrap 5 toast integration\n * - Multiple toast types (success, error, info, warning)\n * - Auto-dismiss with customizable delays\n * - Toast container management\n * - Event integration\n * - Proper cleanup and memory management\n *\n * @example\n * const toastService = new ToastService();\n * toastService.success('Operation completed successfully!');\n * toastService.error('Something went wrong');\n * toastService.info('FYI: This is informational');\n * toastService.warning('Please be careful');\n */\n\nclass ToastService {\n constructor(options = {}) {\n this.options = {\n containerId: 'toast-container',\n position: 'top-end', // top-start, top-center, top-end, middle-start, etc.\n autohide: true,\n defaultDelay: 5000, // 5 seconds\n maxToasts: 5, // Maximum number of toasts to show at once\n ...options\n };\n\n this.toasts = new Map(); // Track active toasts\n this.toastCounter = 0; // For unique IDs\n\n this.init();\n }\n\n /**\n * Initialize the toast service\n */\n init() {\n this.createContainer();\n }\n\n /**\n * Create the toast container if it doesn't exist\n */\n createContainer() {\n let container = document.getElementById(this.options.containerId);\n\n if (!container) {\n container = document.createElement('div');\n container.id = this.options.containerId;\n container.className = `toast-container position-fixed ${this.getPositionClasses()}`;\n container.style.zIndex = '1070'; // Bootstrap toast z-index\n container.setAttribute('aria-live', 'polite');\n container.setAttribute('aria-atomic', 'true');\n\n document.body.appendChild(container);\n }\n\n this.container = container;\n }\n\n /**\n * Get CSS classes for toast positioning\n */\n getPositionClasses() {\n const positionMap = {\n 'top-start': 'top-0 start-0 p-3',\n 'top-center': 'top-0 start-50 translate-middle-x p-3',\n 'top-end': 'top-0 end-0 p-3',\n 'middle-start': 'top-50 start-0 translate-middle-y p-3',\n 'middle-center': 'top-50 start-50 translate-middle p-3',\n 'middle-end': 'top-50 end-0 translate-middle-y p-3',\n 'bottom-start': 'bottom-0 start-0 p-3',\n 'bottom-center': 'bottom-0 start-50 translate-middle-x p-3',\n 'bottom-end': 'bottom-0 end-0 p-3'\n };\n\n return positionMap[this.options.position] || positionMap['top-end'];\n }\n\n\n\n /**\n * Show a success toast\n * @param {string} message - The message to display\n * @param {object} options - Additional options\n */\n success(message, options = {}) {\n return this.show(message, 'success', {\n icon: 'bi-check-circle-fill',\n ...options\n });\n }\n\n /**\n * Show an error toast\n * @param {string} message - The message to display\n * @param {object} options - Additional options\n */\n error(message, options = {}) {\n return this.show(message, 'error', {\n icon: 'bi-exclamation-triangle-fill',\n autohide: true, // Keep error toasts visible until manually dismissed\n ...options\n });\n }\n\n /**\n * Show an info toast\n * @param {string} message - The message to display\n * @param {object} options - Additional options\n */\n info(message, options = {}) {\n return this.show(message, 'info', {\n icon: 'bi-info-circle-fill',\n ...options\n });\n }\n\n /**\n * Show a warning toast\n * @param {string} message - The message to display\n * @param {object} options - Additional options\n */\n warning(message, options = {}) {\n return this.show(message, 'warning', {\n icon: 'bi-exclamation-triangle-fill',\n ...options\n });\n }\n\n /**\n * Show a plain toast without specific styling\n * @param {string} message - The message to display\n * @param {object} options - Additional options\n */\n plain(message, options = {}) {\n return this.show(message, 'plain', {\n ...options\n });\n }\n\n /**\n * Show a toast with specified type and options\n * @param {string} message - The message to display\n * @param {string} type - Toast type (success, error, info, warning)\n * @param {object} options - Additional options\n */\n show(message, type = 'info', options = {}) {\n // Enforce max toasts limit\n this.enforceMaxToasts();\n\n const toastId = `toast-${++this.toastCounter}`;\n const config = {\n title: this.getDefaultTitle(type),\n icon: this.getDefaultIcon(type),\n autohide: this.options.autohide,\n delay: this.options.defaultDelay,\n dismissible: true,\n ...options\n };\n\n const toastElement = this.createToastElement(toastId, message, type, config);\n this.container.appendChild(toastElement);\n\n // Initialize Bootstrap toast\n if (typeof bootstrap === 'undefined') {\n throw new Error('Bootstrap is required for ToastService. Make sure Bootstrap 5 is loaded.');\n }\n const bsToast = new bootstrap.Toast(toastElement, {\n autohide: config.autohide,\n delay: config.delay\n });\n\n // Store toast reference\n this.toasts.set(toastId, {\n element: toastElement,\n bootstrap: bsToast,\n type: type,\n message: message\n });\n\n // Setup cleanup on hide\n toastElement.addEventListener('hidden.bs.toast', () => {\n this.cleanup(toastId);\n });\n\n // Show the toast\n bsToast.show();\n\n return {\n id: toastId,\n hide: () => {\n try {\n bsToast.hide();\n } catch (error) {\n console.warn('Error hiding toast:', error);\n }\n },\n dispose: () => this.cleanup(toastId),\n updateProgress: options.updateProgress || null\n };\n }\n\n /**\n * Show a toast with a View component in the body\n * @param {View} view - The View component to display\n * @param {string} type - Toast type (success, error, info, warning, plain)\n * @param {object} options - Additional options\n */\n showView(view, type = 'info', options = {}) {\n // Enforce max toasts limit\n this.enforceMaxToasts();\n\n const toastId = `toast-${++this.toastCounter}`;\n const config = {\n title: options.title || this.getDefaultTitle(type),\n icon: options.icon || this.getDefaultIcon(type),\n autohide: this.options.autohide,\n delay: this.options.defaultDelay,\n dismissible: true,\n ...options\n };\n\n const toastElement = this.createViewToastElement(toastId, view, type, config);\n this.container.appendChild(toastElement);\n\n // Initialize Bootstrap toast\n if (typeof bootstrap === 'undefined') {\n throw new Error('Bootstrap is required for ToastService. Make sure Bootstrap 5 is loaded.');\n }\n const bsToast = new bootstrap.Toast(toastElement, {\n autohide: config.autohide,\n delay: config.delay\n });\n\n // Store toast reference with view\n this.toasts.set(toastId, {\n element: toastElement,\n bootstrap: bsToast,\n type: type,\n view: view,\n message: 'View toast'\n });\n\n // Setup cleanup on hide - dispose view properly\n toastElement.addEventListener('hidden.bs.toast', () => {\n this.cleanupView(toastId);\n });\n\n // Mount and render the view\n const bodyContainer = toastElement.querySelector('.toast-view-body');\n if (bodyContainer && view) {\n view.render(true, bodyContainer);\n }\n\n // Show the toast\n bsToast.show();\n\n return {\n id: toastId,\n view: view,\n hide: () => {\n try {\n bsToast.hide();\n } catch (error) {\n console.warn('Error hiding view toast:', error);\n }\n },\n dispose: () => this.cleanupView(toastId),\n updateProgress: (progressInfo) => {\n if (view && typeof view.updateProgress === 'function') {\n view.updateProgress(progressInfo);\n }\n }\n };\n }\n\n /**\n * Create toast DOM element\n */\n createToastElement(id, message, type, config) {\n const toast = document.createElement('div');\n toast.id = id;\n toast.className = `toast toast-service-${type}`;\n toast.setAttribute('role', 'alert');\n toast.setAttribute('aria-live', 'assertive');\n toast.setAttribute('aria-atomic', 'true');\n\n const header = config.title || config.icon ? this.createToastHeader(config, type) : '';\n const body = this.createToastBody(message, config.icon && !config.title);\n\n toast.innerHTML = `\n ${header}\n ${body}\n `;\n\n return toast;\n }\n\n /**\n * Create toast DOM element for View component\n */\n createViewToastElement(id, view, type, config) {\n const toast = document.createElement('div');\n toast.id = id;\n toast.className = `toast toast-service-${type}`;\n toast.setAttribute('role', 'alert');\n toast.setAttribute('aria-live', 'assertive');\n toast.setAttribute('aria-atomic', 'true');\n\n const header = config.title || config.icon ? this.createToastHeader(config, type) : '';\n const body = this.createViewToastBody();\n\n toast.innerHTML = `\n ${header}\n ${body}\n `;\n\n return toast;\n }\n\n /**\n * Create toast body for View component\n */\n createViewToastBody() {\n return `\n <div class=\"toast-body p-0\">\n <div class=\"toast-view-body p-3\"></div>\n </div>\n `;\n }\n\n /**\n * Create toast header with title and icon\n */\n createToastHeader(config, _type) {\n const iconHtml = config.icon ?\n `<i class=\"${config.icon} toast-service-icon me-2\"></i>` : '';\n\n const titleHtml = config.title ?\n `<strong class=\"me-auto\">${iconHtml}${this.escapeHtml(config.title)}</strong>` : '';\n\n const timeHtml = config.showTime ?\n `<small class=\"text-muted\">${this.getTimeString()}</small>` : '';\n\n const closeButton = config.dismissible ?\n `<button type=\"button\" class=\"btn-close toast-service-close\" data-bs-dismiss=\"toast\" aria-label=\"Close\"></button>` : '';\n\n if (!titleHtml && !timeHtml && !closeButton) {\n return '';\n }\n\n return `\n <div class=\"toast-header\">\n ${titleHtml}\n ${timeHtml}\n ${closeButton}\n </div>\n `;\n }\n\n /**\n * Create toast body with message\n */\n createToastBody(message, showIcon = false) {\n const iconHtml = showIcon ?\n `<i class=\"${this.getDefaultIcon('info')} toast-service-icon me-2\"></i>` : '';\n\n return `\n <div class=\"toast-body d-flex align-items-center\">\n ${iconHtml}\n <span>${this.escapeHtml(message)}</span>\n </div>\n `;\n }\n\n /**\n * Get default title for toast type\n */\n getDefaultTitle(type) {\n const titles = {\n success: 'Success',\n error: 'Error',\n warning: 'Warning',\n info: 'Information',\n plain: ''\n };\n return titles[type] || 'Notification';\n }\n\n /**\n * Get default icon for toast type\n */\n getDefaultIcon(type) {\n const icons = {\n success: 'bi-check-circle-fill',\n error: 'bi-exclamation-triangle-fill',\n warning: 'bi-exclamation-triangle-fill',\n info: 'bi-info-circle-fill',\n plain: ''\n };\n return icons[type] || 'bi-info-circle-fill';\n }\n\n /**\n * Enforce maximum number of toasts\n */\n enforceMaxToasts() {\n const activeToasts = Array.from(this.toasts.values());\n\n if (activeToasts.length >= this.options.maxToasts) {\n // Remove oldest toast\n const oldestId = this.toasts.keys().next().value;\n const oldest = this.toasts.get(oldestId);\n\n if (oldest) {\n oldest.bootstrap.hide();\n }\n }\n }\n\n /**\n * Clean up toast resources\n */\n cleanup(toastId) {\n const toast = this.toasts.get(toastId);\n\n if (toast) {\n // Dispose Bootstrap toast\n try {\n toast.bootstrap.dispose();\n } catch (e) {\n console.warn('Error disposing toast:', e);\n }\n\n // Remove from DOM\n if (toast.element && toast.element.parentNode) {\n toast.element.parentNode.removeChild(toast.element);\n }\n\n // Remove from tracking\n this.toasts.delete(toastId);\n }\n }\n\n /**\n * Clean up view toast resources with proper view disposal\n */\n cleanupView(toastId) {\n const toast = this.toasts.get(toastId);\n\n if (toast) {\n // Dispose view first if it exists\n if (toast.view && typeof toast.view.dispose === 'function') {\n try {\n toast.view.dispose();\n } catch (e) {\n console.warn('Error disposing view in toast:', e);\n }\n }\n\n // Dispose Bootstrap toast\n try {\n toast.bootstrap.dispose();\n } catch (e) {\n console.warn('Error disposing toast:', e);\n }\n\n // Remove from DOM\n if (toast.element && toast.element.parentNode) {\n toast.element.parentNode.removeChild(toast.element);\n }\n\n // Remove from tracking\n this.toasts.delete(toastId);\n }\n }\n\n /**\n * Hide all active toasts\n */\n hideAll() {\n this.toasts.forEach((toast, _id) => {\n toast.bootstrap.hide();\n });\n }\n\n /**\n * Clear all toasts immediately\n */\n clearAll() {\n this.toasts.forEach((toast, id) => {\n this.cleanup(id);\n });\n }\n\n /**\n * Get current time string\n */\n getTimeString() {\n return new Date().toLocaleTimeString([], {\n hour: '2-digit',\n minute: '2-digit'\n });\n }\n\n /**\n * Escape HTML to prevent XSS\n */\n escapeHtml(str) {\n const div = document.createElement('div');\n div.textContent = str;\n return div.innerHTML;\n }\n\n /**\n * Dispose of the entire toast service\n */\n dispose() {\n this.clearAll();\n\n if (this.container && this.container.parentNode) {\n this.container.parentNode.removeChild(this.container);\n }\n }\n\n /**\n * Get statistics about active toasts\n */\n getStats() {\n const stats = {\n total: this.toasts.size,\n byType: {}\n };\n\n this.toasts.forEach(toast => {\n stats.byType[toast.type] = (stats.byType[toast.type] || 0) + 1;\n });\n\n return stats;\n }\n\n /**\n * Set global options\n */\n setOptions(newOptions) {\n this.options = { ...this.options, ...newOptions };\n\n // Recreate container if position changed\n if (newOptions.position) {\n if (this.container) {\n this.container.className = `toast-container position-fixed ${this.getPositionClasses()}`;\n }\n }\n }\n}\n\nexport default ToastService;\n","\nimport Collection from '@core/Collection.js';\nimport Model from '@core/Model.js';\n\n/**\n * Group Model - Represents an organization, team, or group entity\n *\n * Features:\n * - Hierarchical group support (parent/child relationships)\n * - Member management\n * - Search and filtering capabilities\n * - Role-based permissions within groups\n * - Metadata and settings management\n */\nclass Group extends Model {\n constructor(data = {}) {\n super(data, {\n endpoint: '/api/group'\n });\n }\n}\n\n/**\n * GroupCollection - Enhanced collection for managing groups with advanced search and filtering\n */\nclass GroupList extends Collection {\n constructor(options = {}) {\n super({\n ModelClass: Group,\n endpoint: '/api/group',\n size: 10,\n ...options\n });\n }\n}\n\nconst GroupKinds = {\n 'org': 'Organization',\n 'division': 'Division',\n 'department': 'Department',\n 'team': 'Team',\n 'merchant': 'Merchant',\n 'partner': 'Partner',\n 'client': 'Client',\n 'iso': 'ISO',\n 'sales': 'Sales',\n 'reseller': 'Reseller',\n 'location': 'Location',\n 'region': 'Region',\n 'route': 'Route',\n 'project': 'Project',\n \"inventory\": \"Inventory\",\n 'test': 'Testing',\n 'misc': 'Miscellaneous',\n 'qa': 'Quality Assurance'\n};\n\n// Convert GroupKinds to select options\nconst GroupKindOptions = Object.entries(GroupKinds).map(([key, label]) => ({\n value: key,\n label: label\n}));\n\n/**\n * Form configurations for group management\n */\nconst GroupForms = {\n create: {\n title: 'Create Group',\n fields: [\n {\n name: 'name',\n type: 'text',\n label: 'Group Name',\n required: true,\n placeholder: 'Enter group name'\n },\n {\n name: 'kind',\n type: 'select',\n label: 'Group Kind',\n required: true,\n options: GroupKindOptions\n },\n {\n type: 'collection',\n name: 'parent',\n label: 'Parent Group',\n Collection: GroupList, // Collection class\n labelField: 'name', // Field to display in dropdown\n valueField: 'id', // Field to use as value\n maxItems: 10, // Max items to show in dropdown\n placeholder: 'Search groups...',\n emptyFetch: false,\n debounceMs: 300, // Search debounce delay\n }\n ]\n },\n\n edit: {\n title: 'Edit Group',\n fields: [\n {\n name: 'name',\n type: 'text',\n label: 'Group Name',\n required: true,\n placeholder: 'Enter group name',\n },\n {\n name: 'kind',\n type: 'select',\n label: 'Group Kind',\n required: true,\n options: GroupKindOptions\n },\n {\n type: 'collection',\n name: 'parent',\n label: 'Parent Group',\n Collection: GroupList, // Collection class\n labelField: 'name', // Field to display in dropdown\n valueField: 'id', // Field to use as value\n maxItems: 10, // Max items to show in dropdown\n placeholder: 'Search groups...',\n emptyFetch: false,\n debounceMs: 300, // Search debounce delay\n },\n {\n name: 'metadata.domain',\n type: 'text',\n label: 'Default Domain',\n placeholder: 'Enter Domain',\n },\n {\n name: 'metadata.portal',\n type: 'text',\n label: 'Default Portal',\n placeholder: 'Enter Portal URL',\n },\n {\n name: 'is_active',\n type: 'switch',\n label: 'Is Active',\n cols: 4\n },\n ]\n },\n\n detailed: {\n title: 'Group Details',\n fields: [\n // Profile Header\n {\n type: 'header',\n text: 'Profile Information',\n level: 4,\n class: 'text-primary mb-3'\n },\n\n // Avatar and Basic Info\n {\n type: 'group',\n columns: { xs: 12, md: 4 },\n fields: [\n {\n type: 'image',\n name: 'avatar',\n size: 'lg',\n imageSize: { width: 200, height: 200 },\n placeholder: 'Upload your avatar',\n help: 'Square images work best',\n columns: 12\n },\n {\n name: 'is_active',\n type: 'switch',\n label: 'Is Active',\n columns: 12\n },\n ]\n },\n\n // Profile Details\n {\n type: 'group',\n columns: { xs: 12, md: 8 },\n title: 'Details',\n fields: [\n {\n name: 'name',\n type: 'text',\n label: 'Group Name',\n required: true,\n placeholder: 'Enter group name',\n columns: 12\n },\n {\n name: 'kind',\n type: 'select',\n label: 'Group Kind',\n required: true,\n columns: 12,\n options: [\n { value: 'org', label: 'Organization' },\n { value: 'team', label: 'Team' },\n { value: 'department', label: 'Department' },\n { value: 'merchant', label: 'Merchant' },\n { value: 'iso', label: 'ISO' },\n { value: 'group', label: 'Group' }\n ]\n },\n {\n type: 'collection',\n name: 'parent',\n label: 'Parent Group',\n Collection: GroupList, // Collection class\n labelField: 'name', // Field to display in dropdown\n valueField: 'id', // Field to use as value\n maxItems: 10, // Max items to show in dropdown\n placeholder: 'Search groups...',\n emptyFetch: false,\n debounceMs: 300, // Search debounce delay\n columns: 12\n }\n ]\n },\n\n // Account Settings\n {\n type: 'group',\n columns: 12,\n title: 'Account Settings',\n class: \"pt-3\",\n fields: [\n {\n type: 'select',\n name: 'metadata.timezone',\n label: 'Timezone',\n columns: 6,\n value: 'America/Los_Angeles',\n options: [\n { value: 'America/New_York', text: 'Eastern Time' },\n { value: 'America/Chicago', text: 'Central Time' },\n { value: 'America/Denver', text: 'Mountain Time' },\n { value: 'America/Los_Angeles', text: 'Pacific Time' },\n { value: 'UTC', text: 'UTC' }\n ]\n },\n {\n type: 'select',\n name: 'metadata.eod_hour',\n label: 'End of Day Hour',\n columns: 6,\n options: [\n { value: 0, text: 'Midnight' },\n { value: 1, text: '1 AM' },\n { value: 2, text: '2 AM' },\n { value: 3, text: '3 AM' },\n { value: 4, text: '4 AM' },\n { value: 5, text: '5 AM' },\n { value: 6, text: '6 AM' },\n { value: 7, text: '7 AM' },\n { value: 8, text: '8 AM' },\n { value: 9, text: '9 AM' },\n { value: 10, text: '10 AM' },\n { value: 11, text: '11 AM' },\n { value: 12, text: '12 PM' },\n { value: 13, text: '1 PM' },\n { value: 14, text: '2 PM' },\n { value: 15, text: '3 PM' },\n { value: 16, text: '4 PM' },\n { value: 17, text: '5 PM' },\n { value: 18, text: '6 PM' },\n { value: 19, text: '7 PM' },\n { value: 20, text: '8 PM' },\n { value: 21, text: '9 PM' },\n { value: 22, text: '10 PM' },\n { value: 23, text: '11 PM' }\n ]\n }\n ]\n },\n {\n type: \"text\",\n label: \"Email Template (Prefix)\",\n name: \"metadata.email_template\",\n columns: 12\n }\n ]\n },\n};\n\nGroup.EDIT_FORM = GroupForms.edit;\nGroup.ADD_FORM = GroupForms.create;\nGroup.CREATE_FORM = GroupForms.create; // Alias for compatibility\nGroup.GroupKindOptions = GroupKindOptions;\nGroup.GroupKinds = GroupKinds;\nexport { Group, GroupList, GroupForms };\n","import Collection from '@core/Collection.js';\nimport Model from '@core/Model.js';\n\nimport { GroupList } from './Group.js';\n\nclass User extends Model {\n constructor(data = {}) {\n super(data, {\n endpoint: '/api/user'\n });\n }\n\n hasPermission(permission) {\n if (this.get(\"is_superuser\")) return true;\n if (Array.isArray(permission)) {\n return permission.some(p => this.hasPermission(p));\n }\n\n // Check if permission has \"sys.\" prefix\n const isSysPermission = permission.startsWith('sys.');\n const permissionToCheck = isSysPermission ? permission.substring(4) : permission;\n\n if (this._hasPermission(permissionToCheck)) {\n return true;\n }\n\n // Only check member permissions if it's not a system permission\n if (!isSysPermission && this.member && this.member.hasPermission(permission)) {\n return true;\n }\n\n return false;\n }\n\n _hasPermission(permission) {\n const permissions = this.get(\"permissions\");\n if (!permissions) {\n return false;\n }\n return permissions[permission] == true;\n }\n\n hasPerm(p) {\n return this.hasPermission(p);\n }\n}\n\nclass UserList extends Collection {\n constructor(options = {}) {\n super({\n ModelClass: User,\n endpoint: '/api/user',\n ...options\n });\n }\n}\n\nUser.PERMISSIONS = [\n { name: \"manage_users\", label: \"Manage Users\" },\n { name: \"view_users\", label: \"View Users\" },\n { name: \"view_groups\", label: \"View Groups\" },\n { name: \"manage_groups\", label: \"Manage Groups\" },\n { name: \"view_metrics\", label: \"View System Metrics\" },\n { name: \"manage_metrics\", label: \"Manage System Metrics\" },\n { name: \"view_logs\", label: \"View Logs\" },\n { name: \"view_incidents\", label: \"View Incidents\" },\n { name: \"manage_incidents\", label: \"Manage Incidents\" },\n { name: \"view_tickets\", label: \"View Tickets\" },\n { name: \"manage_tickets\", label: \"Manage Tickets\" },\n { name: \"view_admin\", label: \"View Admin\" },\n { name: \"view_jobs\", label: \"View Jobs\" },\n { name: \"manage_jobs\", label: \"Manage Jobs\" },\n { name: \"view_global\", label: \"View Global\" },\n { name: \"manage_notifications\", label: \"Manage Notifications\" },\n { name: \"manage_files\", label: \"Manage Files\" },\n { name: \"force_single_session\", label: \"Force Single Session\" },\n { name: \"file_vault\", label: \"Access File Vault\" },\n { name: \"manage_aws\", label: \"Manage AWS\" },\n { name: \"manage_docit\", label: \"Manage DocIt\" }\n];\n\n\nUser.PERMISSION_FIELDS = [\n ...User.PERMISSIONS.map(permission => ({\n name: `permissions.${permission.name}`,\n type: 'switch',\n label: permission.label,\n columns: 4\n }))\n];\n\nconst UserForms = {\n create: {\n title: 'Create User',\n fields: [\n { name: 'email', type: 'text', label: 'Email', required: true },\n { name: 'phone_number', type: 'text', label: 'Phone number', columns: 12 },\n { name: 'display_name', type: 'text', label: 'Display Name' }\n ]\n },\n edit: {\n title: 'Edit User',\n fields: [\n { name: 'email', type: 'email', label: 'Email', columns: 12 },\n { name: 'display_name', type: 'text', label: 'Display Name', columns: 12},\n { name: 'phone_number', type: 'text', label: 'Phone number', columns: 12 },\n { type: 'collection', name: 'org', label: 'Organization', Collection: GroupList, labelField: 'name', valueField: 'id', columns: 12 },\n ]\n },\n permissions: {\n title: 'Edit Permissions',\n fields: User.PERMISSION_FIELDS\n }\n};\n\n\n// DataView configuration for User model\nconst UserDataView = {\n // Basic user profile view\n profile: {\n title: 'User Profile',\n columns: 2,\n fields: [\n {\n name: 'id',\n label: 'User ID',\n type: 'number',\n columns: 4\n },\n {\n name: 'last_login',\n label: 'Last Login',\n type: 'datetime',\n format: 'relative',\n columns: 4\n },\n {\n name: 'last_activity',\n label: 'Last Activity',\n type: 'datetime',\n format: 'relative',\n columns: 4\n },\n {\n name: 'username',\n label: 'Username',\n type: 'text',\n format: 'lowercase',\n columns: 4\n },\n {\n name: 'display_name',\n label: 'Display Name',\n type: 'text',\n columns: 4\n },\n\n {\n name: 'email',\n label: 'Email',\n type: 'email',\n columns: 12\n },\n\n {\n name: 'org.name',\n label: 'Organization',\n type: 'text',\n columns: 6\n },\n {\n name: 'phone_number',\n label: 'Phone Number',\n type: 'text',\n columns: 6\n }\n ]\n },\n\n // Activity tracking view\n activity: {\n title: 'User Activity',\n columns: 2,\n fields: [\n {\n name: 'last_login',\n label: 'Last Login',\n type: 'datetime',\n format: 'relative',\n colSize: 6\n },\n {\n name: 'last_activity',\n label: 'Last Activity',\n type: 'datetime',\n format: 'relative',\n colSize: 6\n }\n ]\n },\n\n // Comprehensive view with all data\n detailed: {\n title: 'Detailed User Information',\n columns: 2,\n showEmptyValues: true,\n emptyValueText: 'Not set',\n fields: [\n // Basic Info Section\n {\n name: 'id',\n label: 'User ID',\n type: 'number',\n colSize: 3\n },\n {\n name: 'display_name',\n label: 'Display Name',\n type: 'text',\n format: 'capitalize|default(\"Unnamed User\")',\n colSize: 9\n },\n {\n name: 'username',\n label: 'Username',\n type: 'text',\n format: 'lowercase',\n colSize: 6\n },\n {\n name: 'email',\n label: 'Email Address',\n type: 'email',\n colSize: 6\n },\n {\n name: 'phone_number',\n label: 'Phone Number',\n type: 'phone',\n format: 'phone|default(\"Not provided\")',\n colSize: 6\n },\n {\n name: 'is_active',\n label: 'Account Status',\n type: 'boolean',\n colSize: 6\n },\n\n // Activity Info\n {\n name: 'last_login',\n label: 'Last Login',\n type: 'datetime',\n format: 'relative',\n colSize: 6\n },\n {\n name: 'last_activity',\n label: 'Last Activity',\n type: 'datetime',\n format: 'relative',\n colSize: 6\n },\n\n // Avatar Info\n {\n name: 'avatar.url',\n label: 'Avatar',\n type: 'url',\n colSize: 12\n },\n\n // Complex Data (will use full width automatically)\n {\n name: 'permissions',\n label: 'User Permissions',\n type: 'dataview',\n dataViewColumns: 2,\n showEmptyValues: false\n },\n {\n name: 'metadata',\n label: 'User Metadata',\n type: 'dataview',\n dataViewColumns: 1\n },\n {\n name: 'avatar',\n label: 'Avatar Details',\n type: 'dataview',\n dataViewColumns: 1\n }\n ]\n },\n\n // Permissions-focused view\n permissions: {\n title: 'User Permissions',\n columns: 1,\n fields: [\n {\n name: 'display_name',\n label: 'User',\n type: 'text',\n format: 'capitalize',\n columns: 12\n },\n {\n name: 'permissions',\n label: 'Assigned Permissions',\n type: 'dataview',\n dataViewColumns: 3,\n showEmptyValues: false,\n colSize: 12\n }\n ]\n },\n\n // Compact summary view\n summary: {\n title: 'User Summary',\n columns: 3,\n fields: [\n {\n name: 'display_name',\n label: 'Name',\n type: 'text',\n format: 'capitalize|truncate(30)'\n },\n {\n name: 'email',\n label: 'Email',\n type: 'email'\n },\n {\n name: 'is_active',\n label: 'Status',\n type: 'boolean'\n },\n {\n name: 'last_activity',\n label: 'Last Seen',\n type: 'datetime',\n format: 'relative',\n colSize: 12\n }\n ]\n }\n};\n\nUser.DATA_VIEW = UserDataView.detailed;\nUser.EDIT_FORM = UserForms.edit;\nUser.ADD_FORM = UserForms.create;\n\n/* =========================\n * UserDevice\n * ========================= */\nclass UserDevice extends Model {\n constructor(data = {}) {\n super(data, {\n endpoint: '/api/user/device',\n });\n }\n\n static async getByDuid(duid) {\n const model = new UserDevice();\n const resp = await model.rest.GET('/api/user/device/lookup', { duid: duid });\n if (resp.success && resp.data && resp.data.data) {\n // A direct lookup should return a single object\n return new UserDevice(resp.data.data);\n }\n return null;\n }\n}\n\nclass UserDeviceList extends Collection {\n constructor(options = {}) {\n super({\n ModelClass: UserDevice,\n endpoint: '/api/user/device',\n ...options,\n });\n }\n}\n\n/* =========================\n * UserDeviceLocation\n * ========================= */\nclass UserDeviceLocation extends Model {\n constructor(data = {}) {\n super(data, {\n endpoint: '/api/user/device/location',\n });\n }\n}\n\nclass UserDeviceLocationList extends Collection {\n constructor(options = {}) {\n super({\n ModelClass: UserDeviceLocation,\n endpoint: '/api/user/device/location',\n ...options,\n });\n }\n}\n\nexport { User, UserList, UserForms, UserDataView, UserDevice, UserDeviceList, UserDeviceLocation, UserDeviceLocationList };\n"],"names":["ToastService","constructor","options","this","containerId","position","autohide","defaultDelay","maxToasts","toasts","Map","toastCounter","init","createContainer","container","document","getElementById","createElement","id","className","getPositionClasses","style","zIndex","setAttribute","body","appendChild","positionMap","success","message","show","icon","error","info","warning","plain","type","enforceMaxToasts","toastId","config","title","getDefaultTitle","getDefaultIcon","delay","dismissible","toastElement","createToastElement","bootstrap","Error","bsToast","Toast","set","element","addEventListener","cleanup","hide","console","warn","dispose","updateProgress","showView","view","createViewToastElement","cleanupView","bodyContainer","querySelector","render","progressInfo","toast","header","createToastHeader","createToastBody","innerHTML","createViewToastBody","_type","iconHtml","titleHtml","escapeHtml","timeHtml","showTime","getTimeString","closeButton","showIcon","Array","from","values","length","oldestId","keys","next","value","oldest","get","e","parentNode","removeChild","delete","hideAll","forEach","_id","clearAll","Date","toLocaleTimeString","hour","minute","str","div","textContent","getStats","stats","total","size","byType","setOptions","newOptions","Group","Model","data","super","endpoint","GroupList","Collection","ModelClass","GroupKinds","org","division","department","team","merchant","partner","client","iso","sales","reseller","location","region","route","project","inventory","test","misc","qa","GroupKindOptions","Object","entries","map","key","label","GroupForms","create","fields","name","required","placeholder","labelField","valueField","maxItems","emptyFetch","debounceMs","edit","cols","detailed","text","level","class","columns","xs","md","imageSize","width","height","help","EDIT_FORM","ADD_FORM","CREATE_FORM","User","hasPermission","permission","isArray","some","p","isSysPermission","startsWith","permissionToCheck","substring","_hasPermission","member","permissions","hasPerm","UserList","PERMISSIONS","PERMISSION_FIELDS","UserForms","UserDataView","profile","format","activity","colSize","showEmptyValues","emptyValueText","dataViewColumns","summary","DATA_VIEW","UserDevice","getByDuid","duid","model","resp","rest","GET","UserDeviceList","UserDeviceLocation","UserDeviceLocationList"],"mappings":"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"}
1
+ {"version":3,"file":"User-DSqcOwPL.js","sources":["../../src/core/services/ToastService.js","../../src/core/models/Group.js","../../src/core/models/User.js"],"sourcesContent":["/**\n * ToastService - Bootstrap 5 Toast Notification Service\n * Provides methods to display toast notifications with different types and options\n *\n * Features:\n * - Bootstrap 5 toast integration\n * - Multiple toast types (success, error, info, warning)\n * - Auto-dismiss with customizable delays\n * - Toast container management\n * - Event integration\n * - Proper cleanup and memory management\n *\n * @example\n * const toastService = new ToastService();\n * toastService.success('Operation completed successfully!');\n * toastService.error('Something went wrong');\n * toastService.info('FYI: This is informational');\n * toastService.warning('Please be careful');\n */\n\nclass ToastService {\n constructor(options = {}) {\n this.options = {\n containerId: 'toast-container',\n position: 'top-end', // top-start, top-center, top-end, middle-start, etc.\n autohide: true,\n defaultDelay: 5000, // 5 seconds\n maxToasts: 5, // Maximum number of toasts to show at once\n ...options\n };\n\n this.toasts = new Map(); // Track active toasts\n this.toastCounter = 0; // For unique IDs\n\n this.init();\n }\n\n /**\n * Initialize the toast service\n */\n init() {\n this.createContainer();\n }\n\n /**\n * Create the toast container if it doesn't exist\n */\n createContainer() {\n let container = document.getElementById(this.options.containerId);\n\n if (!container) {\n container = document.createElement('div');\n container.id = this.options.containerId;\n container.className = `toast-container position-fixed ${this.getPositionClasses()}`;\n container.style.zIndex = '1070'; // Bootstrap toast z-index\n container.setAttribute('aria-live', 'polite');\n container.setAttribute('aria-atomic', 'true');\n\n document.body.appendChild(container);\n }\n\n this.container = container;\n }\n\n /**\n * Get CSS classes for toast positioning\n */\n getPositionClasses() {\n const positionMap = {\n 'top-start': 'top-0 start-0 p-3',\n 'top-center': 'top-0 start-50 translate-middle-x p-3',\n 'top-end': 'top-0 end-0 p-3',\n 'middle-start': 'top-50 start-0 translate-middle-y p-3',\n 'middle-center': 'top-50 start-50 translate-middle p-3',\n 'middle-end': 'top-50 end-0 translate-middle-y p-3',\n 'bottom-start': 'bottom-0 start-0 p-3',\n 'bottom-center': 'bottom-0 start-50 translate-middle-x p-3',\n 'bottom-end': 'bottom-0 end-0 p-3'\n };\n\n return positionMap[this.options.position] || positionMap['top-end'];\n }\n\n\n\n /**\n * Show a success toast\n * @param {string} message - The message to display\n * @param {object} options - Additional options\n */\n success(message, options = {}) {\n return this.show(message, 'success', {\n icon: 'bi-check-circle-fill',\n ...options\n });\n }\n\n /**\n * Show an error toast\n * @param {string} message - The message to display\n * @param {object} options - Additional options\n */\n error(message, options = {}) {\n return this.show(message, 'error', {\n icon: 'bi-exclamation-triangle-fill',\n autohide: true, // Keep error toasts visible until manually dismissed\n ...options\n });\n }\n\n /**\n * Show an info toast\n * @param {string} message - The message to display\n * @param {object} options - Additional options\n */\n info(message, options = {}) {\n return this.show(message, 'info', {\n icon: 'bi-info-circle-fill',\n ...options\n });\n }\n\n /**\n * Show a warning toast\n * @param {string} message - The message to display\n * @param {object} options - Additional options\n */\n warning(message, options = {}) {\n return this.show(message, 'warning', {\n icon: 'bi-exclamation-triangle-fill',\n ...options\n });\n }\n\n /**\n * Show a plain toast without specific styling\n * @param {string} message - The message to display\n * @param {object} options - Additional options\n */\n plain(message, options = {}) {\n return this.show(message, 'plain', {\n ...options\n });\n }\n\n /**\n * Show a toast with specified type and options\n * @param {string} message - The message to display\n * @param {string} type - Toast type (success, error, info, warning)\n * @param {object} options - Additional options\n */\n show(message, type = 'info', options = {}) {\n // Enforce max toasts limit\n this.enforceMaxToasts();\n\n const toastId = `toast-${++this.toastCounter}`;\n const config = {\n title: this.getDefaultTitle(type),\n icon: this.getDefaultIcon(type),\n autohide: this.options.autohide,\n delay: this.options.defaultDelay,\n dismissible: true,\n ...options\n };\n\n const toastElement = this.createToastElement(toastId, message, type, config);\n this.container.appendChild(toastElement);\n\n // Initialize Bootstrap toast\n if (typeof bootstrap === 'undefined') {\n throw new Error('Bootstrap is required for ToastService. Make sure Bootstrap 5 is loaded.');\n }\n const bsToast = new bootstrap.Toast(toastElement, {\n autohide: config.autohide,\n delay: config.delay\n });\n\n // Store toast reference\n this.toasts.set(toastId, {\n element: toastElement,\n bootstrap: bsToast,\n type: type,\n message: message\n });\n\n // Setup cleanup on hide\n toastElement.addEventListener('hidden.bs.toast', () => {\n this.cleanup(toastId);\n });\n\n // Show the toast\n bsToast.show();\n\n return {\n id: toastId,\n hide: () => {\n try {\n bsToast.hide();\n } catch (error) {\n console.warn('Error hiding toast:', error);\n }\n },\n dispose: () => this.cleanup(toastId),\n updateProgress: options.updateProgress || null\n };\n }\n\n /**\n * Show a toast with a View component in the body\n * @param {View} view - The View component to display\n * @param {string} type - Toast type (success, error, info, warning, plain)\n * @param {object} options - Additional options\n */\n showView(view, type = 'info', options = {}) {\n // Enforce max toasts limit\n this.enforceMaxToasts();\n\n const toastId = `toast-${++this.toastCounter}`;\n const config = {\n title: options.title || this.getDefaultTitle(type),\n icon: options.icon || this.getDefaultIcon(type),\n autohide: this.options.autohide,\n delay: this.options.defaultDelay,\n dismissible: true,\n ...options\n };\n\n const toastElement = this.createViewToastElement(toastId, view, type, config);\n this.container.appendChild(toastElement);\n\n // Initialize Bootstrap toast\n if (typeof bootstrap === 'undefined') {\n throw new Error('Bootstrap is required for ToastService. Make sure Bootstrap 5 is loaded.');\n }\n const bsToast = new bootstrap.Toast(toastElement, {\n autohide: config.autohide,\n delay: config.delay\n });\n\n // Store toast reference with view\n this.toasts.set(toastId, {\n element: toastElement,\n bootstrap: bsToast,\n type: type,\n view: view,\n message: 'View toast'\n });\n\n // Setup cleanup on hide - dispose view properly\n toastElement.addEventListener('hidden.bs.toast', () => {\n this.cleanupView(toastId);\n });\n\n // Mount and render the view\n const bodyContainer = toastElement.querySelector('.toast-view-body');\n if (bodyContainer && view) {\n view.render(true, bodyContainer);\n }\n\n // Show the toast\n bsToast.show();\n\n return {\n id: toastId,\n view: view,\n hide: () => {\n try {\n bsToast.hide();\n } catch (error) {\n console.warn('Error hiding view toast:', error);\n }\n },\n dispose: () => this.cleanupView(toastId),\n updateProgress: (progressInfo) => {\n if (view && typeof view.updateProgress === 'function') {\n view.updateProgress(progressInfo);\n }\n }\n };\n }\n\n /**\n * Create toast DOM element\n */\n createToastElement(id, message, type, config) {\n const toast = document.createElement('div');\n toast.id = id;\n toast.className = `toast toast-service-${type}`;\n toast.setAttribute('role', 'alert');\n toast.setAttribute('aria-live', 'assertive');\n toast.setAttribute('aria-atomic', 'true');\n\n const header = config.title || config.icon ? this.createToastHeader(config, type) : '';\n const body = this.createToastBody(message, config.icon && !config.title);\n\n toast.innerHTML = `\n ${header}\n ${body}\n `;\n\n return toast;\n }\n\n /**\n * Create toast DOM element for View component\n */\n createViewToastElement(id, view, type, config) {\n const toast = document.createElement('div');\n toast.id = id;\n toast.className = `toast toast-service-${type}`;\n toast.setAttribute('role', 'alert');\n toast.setAttribute('aria-live', 'assertive');\n toast.setAttribute('aria-atomic', 'true');\n\n const header = config.title || config.icon ? this.createToastHeader(config, type) : '';\n const body = this.createViewToastBody();\n\n toast.innerHTML = `\n ${header}\n ${body}\n `;\n\n return toast;\n }\n\n /**\n * Create toast body for View component\n */\n createViewToastBody() {\n return `\n <div class=\"toast-body p-0\">\n <div class=\"toast-view-body p-3\"></div>\n </div>\n `;\n }\n\n /**\n * Create toast header with title and icon\n */\n createToastHeader(config, _type) {\n const iconHtml = config.icon ?\n `<i class=\"${config.icon} toast-service-icon me-2\"></i>` : '';\n\n const titleHtml = config.title ?\n `<strong class=\"me-auto\">${iconHtml}${this.escapeHtml(config.title)}</strong>` : '';\n\n const timeHtml = config.showTime ?\n `<small class=\"text-muted\">${this.getTimeString()}</small>` : '';\n\n const closeButton = config.dismissible ?\n `<button type=\"button\" class=\"btn-close toast-service-close\" data-bs-dismiss=\"toast\" aria-label=\"Close\"></button>` : '';\n\n if (!titleHtml && !timeHtml && !closeButton) {\n return '';\n }\n\n return `\n <div class=\"toast-header\">\n ${titleHtml}\n ${timeHtml}\n ${closeButton}\n </div>\n `;\n }\n\n /**\n * Create toast body with message\n */\n createToastBody(message, showIcon = false) {\n const iconHtml = showIcon ?\n `<i class=\"${this.getDefaultIcon('info')} toast-service-icon me-2\"></i>` : '';\n\n return `\n <div class=\"toast-body d-flex align-items-center\">\n ${iconHtml}\n <span>${this.escapeHtml(message)}</span>\n </div>\n `;\n }\n\n /**\n * Get default title for toast type\n */\n getDefaultTitle(type) {\n const titles = {\n success: 'Success',\n error: 'Error',\n warning: 'Warning',\n info: 'Information',\n plain: ''\n };\n return titles[type] || 'Notification';\n }\n\n /**\n * Get default icon for toast type\n */\n getDefaultIcon(type) {\n const icons = {\n success: 'bi-check-circle-fill',\n error: 'bi-exclamation-triangle-fill',\n warning: 'bi-exclamation-triangle-fill',\n info: 'bi-info-circle-fill',\n plain: ''\n };\n return icons[type] || 'bi-info-circle-fill';\n }\n\n /**\n * Enforce maximum number of toasts\n */\n enforceMaxToasts() {\n const activeToasts = Array.from(this.toasts.values());\n\n if (activeToasts.length >= this.options.maxToasts) {\n // Remove oldest toast\n const oldestId = this.toasts.keys().next().value;\n const oldest = this.toasts.get(oldestId);\n\n if (oldest) {\n oldest.bootstrap.hide();\n }\n }\n }\n\n /**\n * Clean up toast resources\n */\n cleanup(toastId) {\n const toast = this.toasts.get(toastId);\n\n if (toast) {\n // Dispose Bootstrap toast\n try {\n toast.bootstrap.dispose();\n } catch (e) {\n console.warn('Error disposing toast:', e);\n }\n\n // Remove from DOM\n if (toast.element && toast.element.parentNode) {\n toast.element.parentNode.removeChild(toast.element);\n }\n\n // Remove from tracking\n this.toasts.delete(toastId);\n }\n }\n\n /**\n * Clean up view toast resources with proper view disposal\n */\n cleanupView(toastId) {\n const toast = this.toasts.get(toastId);\n\n if (toast) {\n // Dispose view first if it exists\n if (toast.view && typeof toast.view.dispose === 'function') {\n try {\n toast.view.dispose();\n } catch (e) {\n console.warn('Error disposing view in toast:', e);\n }\n }\n\n // Dispose Bootstrap toast\n try {\n toast.bootstrap.dispose();\n } catch (e) {\n console.warn('Error disposing toast:', e);\n }\n\n // Remove from DOM\n if (toast.element && toast.element.parentNode) {\n toast.element.parentNode.removeChild(toast.element);\n }\n\n // Remove from tracking\n this.toasts.delete(toastId);\n }\n }\n\n /**\n * Hide all active toasts\n */\n hideAll() {\n this.toasts.forEach((toast, _id) => {\n toast.bootstrap.hide();\n });\n }\n\n /**\n * Clear all toasts immediately\n */\n clearAll() {\n this.toasts.forEach((toast, id) => {\n this.cleanup(id);\n });\n }\n\n /**\n * Get current time string\n */\n getTimeString() {\n return new Date().toLocaleTimeString([], {\n hour: '2-digit',\n minute: '2-digit'\n });\n }\n\n /**\n * Escape HTML to prevent XSS\n */\n escapeHtml(str) {\n const div = document.createElement('div');\n div.textContent = str;\n return div.innerHTML;\n }\n\n /**\n * Dispose of the entire toast service\n */\n dispose() {\n this.clearAll();\n\n if (this.container && this.container.parentNode) {\n this.container.parentNode.removeChild(this.container);\n }\n }\n\n /**\n * Get statistics about active toasts\n */\n getStats() {\n const stats = {\n total: this.toasts.size,\n byType: {}\n };\n\n this.toasts.forEach(toast => {\n stats.byType[toast.type] = (stats.byType[toast.type] || 0) + 1;\n });\n\n return stats;\n }\n\n /**\n * Set global options\n */\n setOptions(newOptions) {\n this.options = { ...this.options, ...newOptions };\n\n // Recreate container if position changed\n if (newOptions.position) {\n if (this.container) {\n this.container.className = `toast-container position-fixed ${this.getPositionClasses()}`;\n }\n }\n }\n}\n\nexport default ToastService;\n","\nimport Collection from '@core/Collection.js';\nimport Model from '@core/Model.js';\n\n/**\n * Group Model - Represents an organization, team, or group entity\n *\n * Features:\n * - Hierarchical group support (parent/child relationships)\n * - Member management\n * - Search and filtering capabilities\n * - Role-based permissions within groups\n * - Metadata and settings management\n */\nclass Group extends Model {\n constructor(data = {}) {\n super(data, {\n endpoint: '/api/group'\n });\n }\n}\n\n/**\n * GroupCollection - Enhanced collection for managing groups with advanced search and filtering\n */\nclass GroupList extends Collection {\n constructor(options = {}) {\n super({\n ModelClass: Group,\n endpoint: '/api/group',\n size: 10,\n ...options\n });\n }\n}\n\nconst GroupKinds = {\n 'org': 'Organization',\n 'division': 'Division',\n 'department': 'Department',\n 'team': 'Team',\n 'merchant': 'Merchant',\n 'partner': 'Partner',\n 'client': 'Client',\n 'iso': 'ISO',\n 'sales': 'Sales',\n 'reseller': 'Reseller',\n 'location': 'Location',\n 'region': 'Region',\n 'route': 'Route',\n 'project': 'Project',\n \"inventory\": \"Inventory\",\n 'test': 'Testing',\n 'misc': 'Miscellaneous',\n 'qa': 'Quality Assurance'\n};\n\n// Convert GroupKinds to select options\nconst GroupKindOptions = Object.entries(GroupKinds).map(([key, label]) => ({\n value: key,\n label: label\n}));\n\n/**\n * Form configurations for group management\n */\nconst GroupForms = {\n create: {\n title: 'Create Group',\n fields: [\n {\n name: 'name',\n type: 'text',\n label: 'Group Name',\n required: true,\n placeholder: 'Enter group name'\n },\n {\n name: 'kind',\n type: 'select',\n label: 'Group Kind',\n required: true,\n options: GroupKindOptions\n },\n {\n type: 'collection',\n name: 'parent',\n label: 'Parent Group',\n Collection: GroupList, // Collection class\n labelField: 'name', // Field to display in dropdown\n valueField: 'id', // Field to use as value\n maxItems: 10, // Max items to show in dropdown\n placeholder: 'Search groups...',\n emptyFetch: false,\n debounceMs: 300, // Search debounce delay\n }\n ]\n },\n\n edit: {\n title: 'Edit Group',\n fields: [\n {\n name: 'name',\n type: 'text',\n label: 'Group Name',\n required: true,\n placeholder: 'Enter group name',\n },\n {\n name: 'kind',\n type: 'select',\n label: 'Group Kind',\n required: true,\n options: GroupKindOptions\n },\n {\n type: 'collection',\n name: 'parent',\n label: 'Parent Group',\n Collection: GroupList, // Collection class\n labelField: 'name', // Field to display in dropdown\n valueField: 'id', // Field to use as value\n maxItems: 10, // Max items to show in dropdown\n placeholder: 'Search groups...',\n emptyFetch: false,\n debounceMs: 300, // Search debounce delay\n },\n {\n name: 'metadata.domain',\n type: 'text',\n label: 'Default Domain',\n placeholder: 'Enter Domain',\n },\n {\n name: 'metadata.portal',\n type: 'text',\n label: 'Default Portal',\n placeholder: 'Enter Portal URL',\n },\n {\n name: 'is_active',\n type: 'switch',\n label: 'Is Active',\n cols: 4\n },\n ]\n },\n\n detailed: {\n title: 'Group Details',\n fields: [\n // Profile Header\n {\n type: 'header',\n text: 'Profile Information',\n level: 4,\n class: 'text-primary mb-3'\n },\n\n // Avatar and Basic Info\n {\n type: 'group',\n columns: { xs: 12, md: 4 },\n fields: [\n {\n type: 'image',\n name: 'avatar',\n size: 'lg',\n imageSize: { width: 200, height: 200 },\n placeholder: 'Upload your avatar',\n help: 'Square images work best',\n columns: 12\n },\n {\n name: 'is_active',\n type: 'switch',\n label: 'Is Active',\n columns: 12\n },\n ]\n },\n\n // Profile Details\n {\n type: 'group',\n columns: { xs: 12, md: 8 },\n title: 'Details',\n fields: [\n {\n name: 'name',\n type: 'text',\n label: 'Group Name',\n required: true,\n placeholder: 'Enter group name',\n columns: 12\n },\n {\n name: 'kind',\n type: 'select',\n label: 'Group Kind',\n required: true,\n columns: 12,\n options: [\n { value: 'org', label: 'Organization' },\n { value: 'team', label: 'Team' },\n { value: 'department', label: 'Department' },\n { value: 'merchant', label: 'Merchant' },\n { value: 'iso', label: 'ISO' },\n { value: 'group', label: 'Group' }\n ]\n },\n {\n type: 'collection',\n name: 'parent',\n label: 'Parent Group',\n Collection: GroupList, // Collection class\n labelField: 'name', // Field to display in dropdown\n valueField: 'id', // Field to use as value\n maxItems: 10, // Max items to show in dropdown\n placeholder: 'Search groups...',\n emptyFetch: false,\n debounceMs: 300, // Search debounce delay\n columns: 12\n }\n ]\n },\n\n // Account Settings\n {\n type: 'group',\n columns: 12,\n title: 'Account Settings',\n class: \"pt-3\",\n fields: [\n {\n type: 'select',\n name: 'metadata.timezone',\n label: 'Timezone',\n columns: 6,\n value: 'America/Los_Angeles',\n options: [\n { value: 'America/New_York', text: 'Eastern Time' },\n { value: 'America/Chicago', text: 'Central Time' },\n { value: 'America/Denver', text: 'Mountain Time' },\n { value: 'America/Los_Angeles', text: 'Pacific Time' },\n { value: 'UTC', text: 'UTC' }\n ]\n },\n {\n type: 'select',\n name: 'metadata.eod_hour',\n label: 'End of Day Hour',\n columns: 6,\n options: [\n { value: 0, text: 'Midnight' },\n { value: 1, text: '1 AM' },\n { value: 2, text: '2 AM' },\n { value: 3, text: '3 AM' },\n { value: 4, text: '4 AM' },\n { value: 5, text: '5 AM' },\n { value: 6, text: '6 AM' },\n { value: 7, text: '7 AM' },\n { value: 8, text: '8 AM' },\n { value: 9, text: '9 AM' },\n { value: 10, text: '10 AM' },\n { value: 11, text: '11 AM' },\n { value: 12, text: '12 PM' },\n { value: 13, text: '1 PM' },\n { value: 14, text: '2 PM' },\n { value: 15, text: '3 PM' },\n { value: 16, text: '4 PM' },\n { value: 17, text: '5 PM' },\n { value: 18, text: '6 PM' },\n { value: 19, text: '7 PM' },\n { value: 20, text: '8 PM' },\n { value: 21, text: '9 PM' },\n { value: 22, text: '10 PM' },\n { value: 23, text: '11 PM' }\n ]\n }\n ]\n },\n {\n type: \"text\",\n label: \"Email Template (Prefix)\",\n name: \"metadata.email_template\",\n columns: 12\n }\n ]\n },\n};\n\nGroup.EDIT_FORM = GroupForms.edit;\nGroup.ADD_FORM = GroupForms.create;\nGroup.CREATE_FORM = GroupForms.create; // Alias for compatibility\nGroup.GroupKindOptions = GroupKindOptions;\nGroup.GroupKinds = GroupKinds;\nexport { Group, GroupList, GroupForms };\n","import Collection from '@core/Collection.js';\nimport Model from '@core/Model.js';\n\nimport { GroupList } from './Group.js';\n\nclass User extends Model {\n constructor(data = {}) {\n super(data, {\n endpoint: '/api/user'\n });\n }\n\n hasPermission(permission) {\n if (this.get(\"is_superuser\")) return true;\n if (Array.isArray(permission)) {\n return permission.some(p => this.hasPermission(p));\n }\n\n // Check if permission has \"sys.\" prefix\n const isSysPermission = permission.startsWith('sys.');\n const permissionToCheck = isSysPermission ? permission.substring(4) : permission;\n\n if (this._hasPermission(permissionToCheck)) {\n return true;\n }\n\n // Only check member permissions if it's not a system permission\n if (!isSysPermission && this.member && this.member.hasPermission(permission)) {\n return true;\n }\n\n return false;\n }\n\n _hasPermission(permission) {\n const permissions = this.get(\"permissions\");\n if (!permissions) {\n return false;\n }\n return permissions[permission] == true;\n }\n\n hasPerm(p) {\n return this.hasPermission(p);\n }\n}\n\nclass UserList extends Collection {\n constructor(options = {}) {\n super({\n ModelClass: User,\n endpoint: '/api/user',\n ...options\n });\n }\n}\n\nUser.PERMISSIONS = [\n { name: \"manage_users\", label: \"Manage Users\" },\n { name: \"view_users\", label: \"View Users\" },\n { name: \"view_groups\", label: \"View Groups\" },\n { name: \"manage_groups\", label: \"Manage Groups\" },\n { name: \"view_metrics\", label: \"View System Metrics\" },\n { name: \"manage_metrics\", label: \"Manage System Metrics\" },\n { name: \"view_logs\", label: \"View Logs\" },\n { name: \"view_incidents\", label: \"View Incidents\" },\n { name: \"manage_incidents\", label: \"Manage Incidents\" },\n { name: \"view_tickets\", label: \"View Tickets\" },\n { name: \"manage_tickets\", label: \"Manage Tickets\" },\n { name: \"view_admin\", label: \"View Admin\" },\n { name: \"view_jobs\", label: \"View Jobs\" },\n { name: \"manage_jobs\", label: \"Manage Jobs\" },\n { name: \"view_global\", label: \"View Global\" },\n { name: \"manage_notifications\", label: \"Manage Notifications\" },\n { name: \"manage_files\", label: \"Manage Files\" },\n { name: \"force_single_session\", label: \"Force Single Session\" },\n { name: \"file_vault\", label: \"Access File Vault\" },\n { name: \"manage_aws\", label: \"Manage AWS\" },\n { name: \"manage_docit\", label: \"Manage DocIt\" }\n];\n\n\nUser.PERMISSION_FIELDS = [\n ...User.PERMISSIONS.map(permission => ({\n name: `permissions.${permission.name}`,\n type: 'switch',\n label: permission.label,\n columns: 4\n }))\n];\n\nconst UserForms = {\n create: {\n title: 'Create User',\n fields: [\n { name: 'email', type: 'text', label: 'Email', required: true },\n { name: 'phone_number', type: 'text', label: 'Phone number', columns: 12 },\n { name: 'display_name', type: 'text', label: 'Display Name' }\n ]\n },\n edit: {\n title: 'Edit User',\n fields: [\n { name: 'email', type: 'email', label: 'Email', columns: 12 },\n { name: 'display_name', type: 'text', label: 'Display Name', columns: 12},\n { name: 'phone_number', type: 'text', label: 'Phone number', columns: 12 },\n { type: 'collection', name: 'org', label: 'Organization', Collection: GroupList, labelField: 'name', valueField: 'id', columns: 12 },\n ]\n },\n permissions: {\n title: 'Edit Permissions',\n fields: User.PERMISSION_FIELDS\n }\n};\n\n\n// DataView configuration for User model\nconst UserDataView = {\n // Basic user profile view\n profile: {\n title: 'User Profile',\n columns: 2,\n fields: [\n {\n name: 'id',\n label: 'User ID',\n type: 'number',\n columns: 4\n },\n {\n name: 'last_login',\n label: 'Last Login',\n type: 'datetime',\n format: 'relative',\n columns: 4\n },\n {\n name: 'last_activity',\n label: 'Last Activity',\n type: 'datetime',\n format: 'relative',\n columns: 4\n },\n {\n name: 'username',\n label: 'Username',\n type: 'text',\n format: 'lowercase',\n columns: 4\n },\n {\n name: 'display_name',\n label: 'Display Name',\n type: 'text',\n columns: 4\n },\n\n {\n name: 'email',\n label: 'Email',\n type: 'email',\n columns: 12\n },\n\n {\n name: 'org.name',\n label: 'Organization',\n type: 'text',\n columns: 6\n },\n {\n name: 'phone_number',\n label: 'Phone Number',\n type: 'text',\n columns: 6\n }\n ]\n },\n\n // Activity tracking view\n activity: {\n title: 'User Activity',\n columns: 2,\n fields: [\n {\n name: 'last_login',\n label: 'Last Login',\n type: 'datetime',\n format: 'relative',\n colSize: 6\n },\n {\n name: 'last_activity',\n label: 'Last Activity',\n type: 'datetime',\n format: 'relative',\n colSize: 6\n }\n ]\n },\n\n // Comprehensive view with all data\n detailed: {\n title: 'Detailed User Information',\n columns: 2,\n showEmptyValues: true,\n emptyValueText: 'Not set',\n fields: [\n // Basic Info Section\n {\n name: 'id',\n label: 'User ID',\n type: 'number',\n colSize: 3\n },\n {\n name: 'display_name',\n label: 'Display Name',\n type: 'text',\n format: 'capitalize|default(\"Unnamed User\")',\n colSize: 9\n },\n {\n name: 'username',\n label: 'Username',\n type: 'text',\n format: 'lowercase',\n colSize: 6\n },\n {\n name: 'email',\n label: 'Email Address',\n type: 'email',\n colSize: 6\n },\n {\n name: 'phone_number',\n label: 'Phone Number',\n type: 'phone',\n format: 'phone|default(\"Not provided\")',\n colSize: 6\n },\n {\n name: 'is_active',\n label: 'Account Status',\n type: 'boolean',\n colSize: 6\n },\n\n // Activity Info\n {\n name: 'last_login',\n label: 'Last Login',\n type: 'datetime',\n format: 'relative',\n colSize: 6\n },\n {\n name: 'last_activity',\n label: 'Last Activity',\n type: 'datetime',\n format: 'relative',\n colSize: 6\n },\n\n // Avatar Info\n {\n name: 'avatar.url',\n label: 'Avatar',\n type: 'url',\n colSize: 12\n },\n\n // Complex Data (will use full width automatically)\n {\n name: 'permissions',\n label: 'User Permissions',\n type: 'dataview',\n dataViewColumns: 2,\n showEmptyValues: false\n },\n {\n name: 'metadata',\n label: 'User Metadata',\n type: 'dataview',\n dataViewColumns: 1\n },\n {\n name: 'avatar',\n label: 'Avatar Details',\n type: 'dataview',\n dataViewColumns: 1\n }\n ]\n },\n\n // Permissions-focused view\n permissions: {\n title: 'User Permissions',\n columns: 1,\n fields: [\n {\n name: 'display_name',\n label: 'User',\n type: 'text',\n format: 'capitalize',\n columns: 12\n },\n {\n name: 'permissions',\n label: 'Assigned Permissions',\n type: 'dataview',\n dataViewColumns: 3,\n showEmptyValues: false,\n colSize: 12\n }\n ]\n },\n\n // Compact summary view\n summary: {\n title: 'User Summary',\n columns: 3,\n fields: [\n {\n name: 'display_name',\n label: 'Name',\n type: 'text',\n format: 'capitalize|truncate(30)'\n },\n {\n name: 'email',\n label: 'Email',\n type: 'email'\n },\n {\n name: 'is_active',\n label: 'Status',\n type: 'boolean'\n },\n {\n name: 'last_activity',\n label: 'Last Seen',\n type: 'datetime',\n format: 'relative',\n colSize: 12\n }\n ]\n }\n};\n\nUser.DATA_VIEW = UserDataView.detailed;\nUser.EDIT_FORM = UserForms.edit;\nUser.ADD_FORM = UserForms.create;\n\n/* =========================\n * UserDevice\n * ========================= */\nclass UserDevice extends Model {\n constructor(data = {}) {\n super(data, {\n endpoint: '/api/user/device',\n });\n }\n\n static async getByDuid(duid) {\n const model = new UserDevice();\n const resp = await model.rest.GET('/api/user/device/lookup', { duid: duid });\n if (resp.success && resp.data && resp.data.data) {\n // A direct lookup should return a single object\n return new UserDevice(resp.data.data);\n }\n return null;\n }\n}\n\nclass UserDeviceList extends Collection {\n constructor(options = {}) {\n super({\n ModelClass: UserDevice,\n endpoint: '/api/user/device',\n ...options,\n });\n }\n}\n\n/* =========================\n * UserDeviceLocation\n * ========================= */\nclass UserDeviceLocation extends Model {\n constructor(data = {}) {\n super(data, {\n endpoint: '/api/user/device/location',\n });\n }\n}\n\nclass UserDeviceLocationList extends Collection {\n constructor(options = {}) {\n super({\n ModelClass: UserDeviceLocation,\n endpoint: '/api/user/device/location',\n ...options,\n });\n }\n}\n\nexport { User, UserList, UserForms, UserDataView, UserDevice, UserDeviceList, UserDeviceLocation, UserDeviceLocationList };\n"],"names":["ToastService","constructor","options","this","containerId","position","autohide","defaultDelay","maxToasts","toasts","Map","toastCounter","init","createContainer","container","document","getElementById","createElement","id","className","getPositionClasses","style","zIndex","setAttribute","body","appendChild","positionMap","success","message","show","icon","error","info","warning","plain","type","enforceMaxToasts","toastId","config","title","getDefaultTitle","getDefaultIcon","delay","dismissible","toastElement","createToastElement","bootstrap","Error","bsToast","Toast","set","element","addEventListener","cleanup","hide","console","warn","dispose","updateProgress","showView","view","createViewToastElement","cleanupView","bodyContainer","querySelector","render","progressInfo","toast","header","createToastHeader","createToastBody","innerHTML","createViewToastBody","_type","iconHtml","titleHtml","escapeHtml","timeHtml","showTime","getTimeString","closeButton","showIcon","Array","from","values","length","oldestId","keys","next","value","oldest","get","e","parentNode","removeChild","delete","hideAll","forEach","_id","clearAll","Date","toLocaleTimeString","hour","minute","str","div","textContent","getStats","stats","total","size","byType","setOptions","newOptions","Group","Model","data","super","endpoint","GroupList","Collection","ModelClass","GroupKinds","org","division","department","team","merchant","partner","client","iso","sales","reseller","location","region","route","project","inventory","test","misc","qa","GroupKindOptions","Object","entries","map","key","label","GroupForms","create","fields","name","required","placeholder","labelField","valueField","maxItems","emptyFetch","debounceMs","edit","cols","detailed","text","level","class","columns","xs","md","imageSize","width","height","help","EDIT_FORM","ADD_FORM","CREATE_FORM","User","hasPermission","permission","isArray","some","p","isSysPermission","startsWith","permissionToCheck","substring","_hasPermission","member","permissions","hasPerm","UserList","PERMISSIONS","PERMISSION_FIELDS","UserForms","UserDataView","profile","format","activity","colSize","showEmptyValues","emptyValueText","dataViewColumns","summary","DATA_VIEW","UserDevice","getByDuid","duid","model","resp","rest","GET","UserDeviceList","UserDeviceLocation","UserDeviceLocationList"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- "use strict";const e=require("./Rest-Ds9e8tN8.js");class Router{constructor(e={}){this.defaultRoute=e.defaultRoute||"home",this.routes=[],this.currentRoute=null,this.eventEmitter=e.eventEmitter||null,this.boundHandlePopState=this.handlePopState.bind(this)}start(){window.addEventListener("popstate",this.boundHandlePopState),this.handleCurrentLocation()}stop(){window.removeEventListener("popstate",this.boundHandlePopState)}addRoute(e,t){this.routes.push({pattern:this.normalizePattern(e),regex:this.patternToRegex(e),pageName:t,paramNames:this.extractParamNames(e)})}async navigate(e,t={}){const{replace:s=!1,state:r=null,trigger:i=!0}=t,{pageName:n,queryParams:o}=this.parseInput(e);i&&await this.handleRouteChange(n,o)}back(){window.history.back()}forward(){window.history.forward()}getCurrentRoute(){return this.currentRoute}getCurrentPath(){const{pageName:e,queryParams:t}=this.parseCurrentUrl();return this.buildPublicUrl(e,t)}handlePopState(e){this.allowPopState?this.handleCurrentLocation():console.warn("PopStateEvent is not allowed")}async handleCurrentLocation(){const{pageName:e,queryParams:t}=this.parseCurrentUrl();await this.handleRouteChange(e,t)}async handleRouteChange(e,t){const s="/"+e,r=this.matchRoute(s),i=this.buildPublicUrl(e,t);return r?(this.currentRoute=r,this.eventEmitter&&this.eventEmitter.emit("route:changed",{path:i,pageName:r.pageName,params:r.params,query:t,route:r}),r):(this.eventEmitter&&this.eventEmitter.emit("route:notfound",{path:i}),null)}matchRoute(e){for(const t of this.routes){const s=e.match(t.regex);if(s){const r={};return t.paramNames.forEach((e,t)=>{r[e]=s[t+1]}),{...t,params:r,path:e}}}return null}parseInput(e){let t=this.defaultRoute,s={};if(!e)return{pageName:t,queryParams:s};try{if(e.includes("?")){const[r,i]=e.split("?",2),n=new URLSearchParams(i);if(n.has("page")){t=n.get("page")||this.defaultRoute;for(const[e,t]of n)"page"!==e&&(s[e]=t)}else{t=r.startsWith("/")?r.substring(1)||this.defaultRoute:r||this.defaultRoute;for(const[e,t]of n)s[e]=t}}else t=e.startsWith("/")?e.substring(1)||this.defaultRoute:e}catch(r){console.warn("Failed to parse input:",e,r),t=this.defaultRoute,s={}}return{pageName:t,queryParams:s}}parseCurrentUrl(){const e=new URLSearchParams(window.location.search),t=e.get("page")||this.defaultRoute,s={};for(const[r,i]of e)"page"!==r&&(s[r]=i);return{pageName:t,queryParams:s}}buildPublicUrl(e,t={}){const s=new URLSearchParams;return s.set("page",e),Object.entries(t).forEach(([e,t])=>{null!=t&&""!==t&&s.set(e,String(t))}),"?"+s.toString()}updateBrowserUrl(e,t,s,r){const i=new URL(window.location.origin+window.location.pathname);i.searchParams.set("page",e),Object.entries(t).forEach(([e,t])=>{null!=t&&""!==t&&i.searchParams.set(e,String(t))});const n=i.toString();s?window.history.replaceState(r,"",n):window.history.pushState(r,"",n)}patternToRegex(e){let t=e.replace(/[-[\]{}()*+?.,\\^$|#\s]/g,"\\$&").replace(/\/:([^/?]+)\?/g,"(?:/([^/]+))?").replace(/:([^/]+)/g,"([^/]+)");return new RegExp(`^${t}$`)}extractParamNames(e){return(e.match(/:([^/?]+)\??/g)||[]).map(e=>e.replace(/[:?]/g,""))}normalizePattern(e){return e.startsWith("/")?e:`/${e}`}updateUrl(e={},t={}){const{replace:s=!1}=t,{pageName:r}=this.parseCurrentUrl();this.updateBrowserUrl(r,e,s)}buildUrl(e,t={}){return this.buildPublicUrl(e,t)}doRoutesMatch(e,t){if(!e||!t)return!1;const{pageName:s}=this.parseInput(e),{pageName:r}=this.parseInput(t);return s===r}}class EventBus{constructor(){this.listeners={},this.onceListeners={},this.maxListeners=100,this.debugMode=!1,this.eventStats={}}on(e,t){if("function"!=typeof t)throw new Error("Callback must be a function");return Array.isArray(e)?(e.forEach(e=>this.on(e,t)),this):(this.listeners[e]||(this.listeners[e]=[]),this.listeners[e].length>=this.maxListeners&&console.warn(`Max listeners (${this.maxListeners}) exceeded for event: ${e}`),this.listeners[e].push(t),this)}once(e,t){if("function"!=typeof t)throw new Error("Callback must be a function");return Array.isArray(e)?(e.forEach(e=>this.once(e,t)),this):(this.onceListeners[e]||(this.onceListeners[e]=[]),this.onceListeners[e].push(t),this)}off(e,t){if(Array.isArray(e))return e.forEach(e=>this.off(e,t)),this;if(!t)return delete this.listeners[e],delete this.onceListeners[e],this;if(this.listeners[e]){const s=this.listeners[e].indexOf(t);-1!==s&&(this.listeners[e].splice(s,1),0===this.listeners[e].length&&delete this.listeners[e])}if(this.onceListeners[e]){const s=this.onceListeners[e].indexOf(t);-1!==s&&(this.onceListeners[e].splice(s,1),0===this.onceListeners[e].length&&delete this.onceListeners[e])}return this}emit(e,t){this.updateEventStats(e),this.debugMode;const s=[];return this.listeners[e]&&s.push(...this.listeners[e]),this.listeners["*"]&&s.push(...this.listeners["*"]),this.onceListeners[e]&&(s.push(...this.onceListeners[e]),delete this.onceListeners[e]),this.onceListeners["*"]&&(s.push(...this.onceListeners["*"]),delete this.onceListeners["*"]),this.debugMode&&s.length>0&&s.length,s.forEach(s=>{try{s(t,e)&&(e.stopPropagation&&e.stopPropagation(),e.preventDefault&&e.preventDefault())}catch(r){console.error(`Error in event listener for '${e}':`,r),this.emitError(r,e,s)}}),this}async emitAsync(e,t){const s=[];this.listeners[e]&&s.push(...this.listeners[e]),this.listeners["*"]&&s.push(...this.listeners["*"]),this.onceListeners[e]&&(s.push(...this.onceListeners[e]),delete this.onceListeners[e]),this.onceListeners["*"]&&(s.push(...this.onceListeners["*"]),delete this.onceListeners["*"]);const r=s.map(s=>new Promise(r=>{try{r(s(t,e))}catch(i){console.error(`Error in async event listener for '${e}':`,i),this.emitError(i,e,s),r()}}));return await Promise.all(r),this}removeAllListeners(){return this.listeners={},this.onceListeners={},this}listenerCount(e){return(this.listeners[e]?this.listeners[e].length:0)+(this.onceListeners[e]?this.onceListeners[e].length:0)}eventNames(){const e=Object.keys(this.listeners),t=Object.keys(this.onceListeners);return[.../* @__PURE__ */new Set([...e,...t])]}setMaxListeners(e){if("number"!=typeof e||e<0)throw new Error("Max listeners must be a non-negative number");return this.maxListeners=e,this}namespace(e){const t=t=>`${e}:${t}`;return{on:(e,s)=>this.on(t(e),s),once:(e,s)=>this.once(t(e),s),off:(e,s)=>this.off(t(e),s),emit:(e,s)=>this.emit(t(e),s),emitAsync:(e,s)=>this.emitAsync(t(e),s)}}use(e){if("function"!=typeof e)throw new Error("Middleware must be a function");const t=this.emit;return this.emit=(s,r)=>{try{const i=e(s,r);if(!1===i)return this;const n=void 0!==i?i:r;return t.call(this,s,n)}catch(i){return console.error("Error in event middleware:",i),t.call(this,s,r)}},this}emitError(e,t,s){"error"!==t&&setTimeout(()=>{this.emit("error",{error:e,originalEvent:t,callback:s.toString()})},0)}waitFor(e,t=null){return new Promise((s,r)=>{let i=null;const n=e=>{i&&clearTimeout(i),s(e)};this.once(e,n),t&&(i=setTimeout(()=>{this.off(e,n),r(new Error(`Timeout waiting for event: ${e}`))},t))})}debug(e=!0){return this.debugMode=e,this}getStats(){const e=this.eventNames(),t={totalEvents:e.length,totalListeners:0,events:{},emissions:{...this.eventStats}};return e.forEach(e=>{const s=this.listenerCount(e);t.events[e]=s,t.totalListeners+=s}),t}updateEventStats(e){this.eventStats[e]||(this.eventStats[e]={count:0,firstEmission:Date.now(),lastEmission:null}),this.eventStats[e].count++,this.eventStats[e].lastEmission=Date.now()}getEventStats(e){const t=this.eventStats[e];return t?{...t,listenerCount:this.listenerCount(e),avgEmissionsPerMinute:this.calculateEmissionRate(t)}:null}calculateEmissionRate(e){if(!e.firstEmission||!e.lastEmission)return 0;const t=e.lastEmission-e.firstEmission;if(0===t)return 0;const s=t/6e4;return Math.round(e.count/s*100)/100}resetStats(){return this.eventStats={},this}getTopEvents(e=10){return Object.entries(this.eventStats).map(([e,t])=>({event:e,count:t.count,rate:this.calculateEmissionRate(t),listeners:this.listenerCount(e)})).sort((e,t)=>t.count-e.count).slice(0,e)}debugInfo(){this.debugMode,this.maxListeners;const e=this.getStats();return e.totalEvents,e.totalListeners,Object.keys(this.eventStats).length>0&&this.getTopEvents(5),this}}class WebApp{constructor(t={}){this.config=t,this.initPluginRegistry(),this.name=t.name||"MOJO App",this.version=t.version||"1.0.0",this.debug=t.debug||!1,this.container=t.container||"#app",this.layoutType=t.layout||"portal",this.layoutConfig=t.layoutConfig||{},t.sidebar&&(this.layoutConfig.sidebarConfig=t.sidebar),t.topbar&&(this.layoutConfig.topbarConfig=t.topbar),this.layout=null,this.layoutConfig.containerId=this.container||this.containerId||"#app",this.pageContainer=t.pageContainer||"#page-container",this.basePath=t.basePath||"",this.routerMode=t.routerMode||t.router?.mode||"param",this.basePath=t.basePath||t.router?.base||"",this.defaultRoute=t.defaultRoute||"home",this.session=t.session||{},this.router=null,this.navigation=t.navigation||{},this.state={currentPage:null,previousPage:null,loading:!1},this.events=new EventBus,this.rest=e.rest,t.api&&this.rest.configure(t.api),this.router=new Router({mode:"param"===this.routerMode?"params":this.routerMode,basePath:this.basePath,defaultRoute:this.defaultRoute,eventEmitter:this.events}),this.events.on("route:changed",async e=>{const{pageName:t,params:s,query:r}=e;await this.showPage(t,r,s,{fromRouter:!0})}),"undefined"!=typeof window&&(window.MOJO=window.MOJO||{},window.MOJO.router=this.router),this.setupFocusTracking(),this.pageCache=/* @__PURE__ */new Map,this.pageClasses=/* @__PURE__ */new Map,this.componentClasses=/* @__PURE__ */new Map,this.modelClasses=/* @__PURE__ */new Map,this.currentPage=null,this.isStarted=!1,window.matchUUID?window[window.matchUUID]=this:window.MOJO?window.MOJO.app=this:window.__app__=this}async start(){if(this.isStarted)console.warn("WebApp already started");else try{this.setupPageContainer(),this.validateDefaultRoute(),await this.setupRouter(),this.isStarted=!0,this.router.allowPopState=!1,this.events.emit("app:ready",{app:this})}catch(e){throw console.error(`Failed to start ${this.name}:`,e),this.showError("Failed to start application"),e}}async setupRouter(){this.router?(this.events.on("route:notfound",async e=>{console.warn(`Route not found: ${e.path}`),this._show404(e.path)}),this.router.start(),this.routerMode):console.error("Router not initialized")}setupPageContainer(){const e="string"==typeof this.container?document.querySelector(this.container):this.container;e&&!e.querySelector("#page-container")&&(e.innerHTML='<div id="page-container"></div>'),this.pageContainer="#page-container"}registerPage(e,t,s={}){if("string"!=typeof e||!e)return console.error("registerPage: pageName must be a non-empty string"),this;if("function"!=typeof t)return console.error("registerPage: PageClass must be a constructor function"),this;if(s.containerId||(s.containerId=this.pageContainer),this.pageClasses.set(e,{PageClass:t,constructorOptions:s}),this.router){let t=s.route||`/${e}`;t.startsWith("/")||(t=`/${t}`),s.route=t,this.router.addRoute(t,e)}return this}getPage(e){return this.pageCache.get(e)}getPagePermissions(e){if(this.pageCache.has(e))return this.pageCache.get(e).permissions;const t=this.pageClasses.get(e);if(!t)return null;const{PageClass:s,constructorOptions:r}=t;return r?r.permissions:null}getOrCreatePage(e){if(this.pageCache.has(e))return this.pageCache.get(e);const t=this.pageClasses.get(e);if(!t)return console.error(`Page not registered: ${e}`),null;const{PageClass:s,constructorOptions:r}=t;try{const t=new s({pageName:e,...r,app:this});return r.route&&(t.route=r.route),this.pageCache.set(e,t),t.route,t}catch(i){return console.error(`Failed to create page ${e}:`,i),null}}async showPage(e,t={},s={},r={}){const{fromRouter:i=!1,replace:n=!1,force:o=!1}=r;try{let r,n;"string"==typeof e?(n=e,r=this.getOrCreatePage(e)):e&&"object"==typeof e&&(r=e,n=e.pageName);const o=this.currentPage;if(!r)return void this._show404(n,s,t,i);if(this.events.emit("page:showing",{page:r,pageName:r.pageName,params:s,query:t,fromRouter:i}),!r.canEnter())return void this._showDeniedPage(r,s,t,i);o&&o!==r&&await this._exitOldPage(o),await r.onParams(s,t),o!==r&&await r.onEnter(),r.syncUrl(),this.events.emit("page:show",{page:r,pageName:r.pageName,params:s,query:t,fromRouter:i}),await r.render(),this.currentPage=r,r.pageName}catch(a){console.error("Error in showPage:",a),this.showError(`Failed to load page: ${a.message}`),"error"!==e&&await this.showPage("error",{},{error:a,originalPage:e},{fromRouter:i})}}async _show404(e,t,s,r){const i=this.getOrCreatePage("404");i&&(i.setInfo&&i.setInfo(e),await this._exitOldPage(this.currentPage),await i.render(),this.currentPage=i,this.events.emit("page:404",{page:null,pageName:e,params:t,query:s,fromRouter:r}))}async _showDeniedPage(e,t,s,r){const i=this.getOrCreatePage("denied");i.setDeniedPage&&i.setDeniedPage(e),await this._exitOldPage(this.currentPage),await i.render(),this.currentPage=i,this.events.emit("page:denied",{page:e,pageName:e.pageName,params:t,query:s,fromRouter:r})}async _exitOldPage(e){if(e)try{await e.onExit(),await e.unmount(),this.events.emit("page:hide",{page:e})}catch(t){console.error(`Error exiting page ${e.pageName}:`,t)}}async navigate(e,t={},s={}){if(!this.router)return void console.error("Router not initialized");let r=e;if(Object.keys(t).length>0){const s=new URLSearchParams(t).toString();r+=(e.includes("?")?"&":"?")+s}return await this.router.navigate(r,s)}async navigateToDefault(e={}){return await this.showPage(this.defaultRoute,{},{},e)}back(){this.router?this.router.back():console.warn("Router not initialized")}forward(){this.router?this.router.forward():console.warn("Router not initialized")}getCurrentPage(){return this.currentPage}getPageContainer(){return this.layout&&this.layout.getPageContainer?this.layout.getPageContainer():"string"==typeof this.pageContainer?document.querySelector(this.pageContainer):this.pageContainer}async showError(e){try{const t=(await Promise.resolve().then(()=>require("./Dialog-9FzcToYV.js"))).default;await t.alert(e,"Error",{size:"md",class:"text-danger"})}catch(t){this.events.emit("notification",{message:e,type:"error"}),"undefined"!=typeof window&&window?.console&&console.error("[WebApp] showError fallback:",t),"undefined"!=typeof window&&alert(`Error: ${e}`)}}async showSuccess(e){try{const t=(await Promise.resolve().then(()=>require("./Dialog-9FzcToYV.js"))).default;await t.alert(e,"Success",{size:"md",class:"text-success"})}catch(t){this.events.emit("notification",{message:e,type:"success"}),"undefined"!=typeof window&&window?.console&&console.warn("[WebApp] showSuccess fallback:",t),"undefined"!=typeof window&&alert(`Success: ${e}`)}}async showInfo(e){try{const t=(await Promise.resolve().then(()=>require("./Dialog-9FzcToYV.js"))).default;await t.alert(e,"Information",{size:"md",class:"text-info"})}catch(t){this.events.emit("notification",{message:e,type:"info"}),"undefined"!=typeof window&&window,"undefined"!=typeof window&&alert(`Info: ${e}`)}}async showWarning(e){try{const t=(await Promise.resolve().then(()=>require("./Dialog-9FzcToYV.js"))).default;await t.alert(e,"Warning",{size:"md",class:"text-warning"})}catch(t){this.events.emit("notification",{message:e,type:"warning"}),"undefined"!=typeof window&&window?.console&&console.warn("[WebApp] showWarning fallback:",t),"undefined"!=typeof window&&alert(`Warning: ${e}`)}}showNotification(e,t="info"){this.events.emit("notification",{message:e,type:t})}async showLoading(e={}){"string"==typeof e&&(e={message:e});try{(await Promise.resolve().then(()=>require("./Dialog-9FzcToYV.js"))).default.showBusy(e)}catch(t){"undefined"!=typeof window&&window?.console&&console.warn("[WebApp] showLoading fallback:",t,e),this.events.emit("notification",{message:e.message||"Loading...",type:"info"})}}async hideLoading(){try{(await Promise.resolve().then(()=>require("./Dialog-9FzcToYV.js"))).default.hideBusy()}catch(e){"undefined"!=typeof window&&window?.console&&console.warn("[WebApp] hideLoading fallback:",e)}}async showModelView(e,t={}){try{const s=(await Promise.resolve().then(()=>require("./Dialog-9FzcToYV.js"))).default;return await s.showModelView(e,t)}catch(s){throw"undefined"!=typeof window&&window?.console&&console.error("[WebApp] showModelForm failed:",s),s}}async showModelForm(e={}){try{const t=(await Promise.resolve().then(()=>require("./Dialog-9FzcToYV.js"))).default;return await t.showModelForm(e)}catch(t){throw"undefined"!=typeof window&&window?.console&&console.error("[WebApp] showModelForm failed:",t),t}}async showForm(e={}){try{const t=(await Promise.resolve().then(()=>require("./Dialog-9FzcToYV.js"))).default;return await t.showForm(e)}catch(t){throw"undefined"!=typeof window&&window?.console&&console.error("[WebApp] showForm failed:",t),t}}async showDialog(e={}){try{const t=(await Promise.resolve().then(()=>require("./Dialog-9FzcToYV.js"))).default;return await t.showDialog(e)}catch(t){throw"undefined"!=typeof window&&window?.console&&console.error("[WebApp] showDialog failed:",t),t}}async showAlert(e={}){try{const t=(await Promise.resolve().then(()=>require("./Dialog-9FzcToYV.js"))).default;return await t.showDialog(e)}catch(t){throw"undefined"!=typeof window&&window?.console&&console.error("[WebApp] showDialog failed:",t),t}}async confirm(e,t="Confirm",s={}){const r=(await Promise.resolve().then(()=>require("./Dialog-9FzcToYV.js"))).default;return await r.confirm(e,t,s)}setupFocusTracking(){if("undefined"==typeof window)return;this.isFocused=!document.hidden;const e=()=>{const e=this.isFocused;this.isFocused=!document.hidden,e!==this.isFocused&&(this.isFocused?this.events.emit("browser:focus"):this.events.emit("browser:blur"))},t=()=>{this.isFocused||(this.isFocused=!0,this.events.emit("browser:focus"))},s=()=>{this.isFocused&&(this.isFocused=!1,this.events.emit("browser:blur"))};document.addEventListener("visibilitychange",e),window.addEventListener("focus",t),window.addEventListener("blur",s),this._focusHandlers={visibilitychange:e,focus:t,blur:s}}setupErrorHandling(){window.addEventListener("error",e=>{console.error("Global error:",e.error),this.debug&&this.showError(`Error: ${e.error?.message||"Unknown error"}`)}),window.addEventListener("unhandledrejection",e=>{console.error("Unhandled promise rejection:",e.reason),this.debug&&this.showError(`Promise rejected: ${e.reason?.message||"Unknown error"}`)})}escapeHtml(e){return e.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&#039;")}getState(e){return e?this.state[e]:this.state}setState(e){const t={...this.state};Object.assign(this.state,e),this.events.emit("state:changed",{oldState:t,newState:this.state,updates:e})}registerComponent(e,t){this.componentClasses.set(e,t)}getComponent(e){return this.componentClasses.get(e)}registerModel(e,t){this.modelClasses.set(e,t)}getModel(e){return this.modelClasses.get(e)}setupRest(){this.rest=e.rest,e.rest.configure(this.api)}async destroy(){this.router&&this.router.stop(),this._focusHandlers&&"undefined"!=typeof window&&(document.removeEventListener("visibilitychange",this._focusHandlers.visibilitychange),window.removeEventListener("focus",this._focusHandlers.focus),window.removeEventListener("blur",this._focusHandlers.blur));const e=Array.from(this.pageCache.values());if(await Promise.allSettled(e.map(async e=>{try{e.destroy&&await e.destroy()}catch(t){console.error("Error destroying page:",t)}})),this.layout&&this.layout.destroy)try{await this.layout.destroy()}catch(t){console.error("Error destroying layout:",t)}this.pageCache.clear(),this.pageClasses.clear(),this.componentClasses.clear(),this.modelClasses.clear(),"undefined"!=typeof window&&window.MOJO&&delete window.MOJO.router,this.isStarted=!1,this.name}buildPagePath(e,t,s){let r=e.route||`/${e.pageName.toLowerCase()}`;if(Object.keys(t).forEach(e=>{"string"!=typeof t[e]&&"number"!=typeof t[e]||(r=r.replace(`:${e}`,t[e]))}),s&&Object.keys(s).length>0){const e=new URLSearchParams(s).toString();r+=(r.includes("?")?"&":"?")+e}return r}validateDefaultRoute(){this.pageClasses.has(this.defaultRoute)?this.defaultRoute:(console.warn(`⚠️ Default route '${this.defaultRoute}' is not registered!`),console.warn(` Please register a page: app.registerPage('${this.defaultRoute}', YourPageClass);`),console.warn(" Or change default route: new WebApp({ defaultRoute: 'your-page' });"))}findFallbackPage(){const e=["404","error","denied"];for(const[t]of this.pageClasses.entries())if(!e.includes(t))return t;return null}static create(e={}){return new WebApp(e)}initPluginRegistry(){"undefined"!=typeof window&&(window.MOJO||(window.MOJO={}),window.MOJO.plugins||(window.MOJO.plugins={}),window.MOJO.app=this)}static registerPlugin(e,t){"undefined"!=typeof window&&(window.MOJO||(window.MOJO={}),window.MOJO.plugins||(window.MOJO.plugins={}),window.MOJO.plugins[e]=t)}}exports.EventBus=EventBus,exports.Router=Router,exports.WebApp=WebApp;
2
- //# sourceMappingURL=WebApp-BCfA2Dlw.js.map
1
+ "use strict";const e=require("./Rest-B1eUyLX5.js");class Router{constructor(e={}){this.defaultRoute=e.defaultRoute||"home",this.routes=[],this.currentRoute=null,this.eventEmitter=e.eventEmitter||null,this.boundHandlePopState=this.handlePopState.bind(this)}start(){window.addEventListener("popstate",this.boundHandlePopState),this.handleCurrentLocation()}stop(){window.removeEventListener("popstate",this.boundHandlePopState)}addRoute(e,t){this.routes.push({pattern:this.normalizePattern(e),regex:this.patternToRegex(e),pageName:t,paramNames:this.extractParamNames(e)})}async navigate(e,t={}){const{replace:s=!1,state:r=null,trigger:i=!0}=t,{pageName:n,queryParams:o}=this.parseInput(e);i&&await this.handleRouteChange(n,o)}back(){window.history.back()}forward(){window.history.forward()}getCurrentRoute(){return this.currentRoute}getCurrentPath(){const{pageName:e,queryParams:t}=this.parseCurrentUrl();return this.buildPublicUrl(e,t)}handlePopState(e){this.allowPopState?this.handleCurrentLocation():console.warn("PopStateEvent is not allowed")}async handleCurrentLocation(){const{pageName:e,queryParams:t}=this.parseCurrentUrl();await this.handleRouteChange(e,t)}async handleRouteChange(e,t){const s="/"+e,r=this.matchRoute(s),i=this.buildPublicUrl(e,t);return r?(this.currentRoute=r,this.eventEmitter&&this.eventEmitter.emit("route:changed",{path:i,pageName:r.pageName,params:r.params,query:t,route:r}),r):(this.eventEmitter&&this.eventEmitter.emit("route:notfound",{path:i}),null)}matchRoute(e){for(const t of this.routes){const s=e.match(t.regex);if(s){const r={};return t.paramNames.forEach((e,t)=>{r[e]=s[t+1]}),{...t,params:r,path:e}}}return null}parseInput(e){let t=this.defaultRoute,s={};if(!e)return{pageName:t,queryParams:s};try{if(e.includes("?")){const[r,i]=e.split("?",2),n=new URLSearchParams(i);if(n.has("page")){t=n.get("page")||this.defaultRoute;for(const[e,t]of n)"page"!==e&&(s[e]=t)}else{t=r.startsWith("/")?r.substring(1)||this.defaultRoute:r||this.defaultRoute;for(const[e,t]of n)s[e]=t}}else t=e.startsWith("/")?e.substring(1)||this.defaultRoute:e}catch(r){console.warn("Failed to parse input:",e,r),t=this.defaultRoute,s={}}return{pageName:t,queryParams:s}}parseCurrentUrl(){const e=new URLSearchParams(window.location.search),t=e.get("page")||this.defaultRoute,s={};for(const[r,i]of e)"page"!==r&&(s[r]=i);return{pageName:t,queryParams:s}}buildPublicUrl(e,t={}){const s=new URLSearchParams;return s.set("page",e),Object.entries(t).forEach(([e,t])=>{null!=t&&""!==t&&s.set(e,String(t))}),"?"+s.toString()}updateBrowserUrl(e,t,s,r){const i=new URL(window.location.origin+window.location.pathname);i.searchParams.set("page",e),Object.entries(t).forEach(([e,t])=>{null!=t&&""!==t&&i.searchParams.set(e,String(t))});const n=i.toString();s?window.history.replaceState(r,"",n):window.history.pushState(r,"",n)}patternToRegex(e){let t=e.replace(/[-[\]{}()*+?.,\\^$|#\s]/g,"\\$&").replace(/\/:([^/?]+)\?/g,"(?:/([^/]+))?").replace(/:([^/]+)/g,"([^/]+)");return new RegExp(`^${t}$`)}extractParamNames(e){return(e.match(/:([^/?]+)\??/g)||[]).map(e=>e.replace(/[:?]/g,""))}normalizePattern(e){return e.startsWith("/")?e:`/${e}`}updateUrl(e={},t={}){const{replace:s=!1}=t,{pageName:r}=this.parseCurrentUrl();this.updateBrowserUrl(r,e,s)}buildUrl(e,t={}){return this.buildPublicUrl(e,t)}doRoutesMatch(e,t){if(!e||!t)return!1;const{pageName:s}=this.parseInput(e),{pageName:r}=this.parseInput(t);return s===r}}class EventBus{constructor(){this.listeners={},this.onceListeners={},this.maxListeners=100,this.debugMode=!1,this.eventStats={}}on(e,t){if("function"!=typeof t)throw new Error("Callback must be a function");return Array.isArray(e)?(e.forEach(e=>this.on(e,t)),this):(this.listeners[e]||(this.listeners[e]=[]),this.listeners[e].length>=this.maxListeners&&console.warn(`Max listeners (${this.maxListeners}) exceeded for event: ${e}`),this.listeners[e].push(t),this)}once(e,t){if("function"!=typeof t)throw new Error("Callback must be a function");return Array.isArray(e)?(e.forEach(e=>this.once(e,t)),this):(this.onceListeners[e]||(this.onceListeners[e]=[]),this.onceListeners[e].push(t),this)}off(e,t){if(Array.isArray(e))return e.forEach(e=>this.off(e,t)),this;if(!t)return delete this.listeners[e],delete this.onceListeners[e],this;if(this.listeners[e]){const s=this.listeners[e].indexOf(t);-1!==s&&(this.listeners[e].splice(s,1),0===this.listeners[e].length&&delete this.listeners[e])}if(this.onceListeners[e]){const s=this.onceListeners[e].indexOf(t);-1!==s&&(this.onceListeners[e].splice(s,1),0===this.onceListeners[e].length&&delete this.onceListeners[e])}return this}emit(e,t){this.updateEventStats(e),this.debugMode;const s=[];return this.listeners[e]&&s.push(...this.listeners[e]),this.listeners["*"]&&s.push(...this.listeners["*"]),this.onceListeners[e]&&(s.push(...this.onceListeners[e]),delete this.onceListeners[e]),this.onceListeners["*"]&&(s.push(...this.onceListeners["*"]),delete this.onceListeners["*"]),this.debugMode&&s.length>0&&s.length,s.forEach(s=>{try{s(t,e)&&(e.stopPropagation&&e.stopPropagation(),e.preventDefault&&e.preventDefault())}catch(r){console.error(`Error in event listener for '${e}':`,r),this.emitError(r,e,s)}}),this}async emitAsync(e,t){const s=[];this.listeners[e]&&s.push(...this.listeners[e]),this.listeners["*"]&&s.push(...this.listeners["*"]),this.onceListeners[e]&&(s.push(...this.onceListeners[e]),delete this.onceListeners[e]),this.onceListeners["*"]&&(s.push(...this.onceListeners["*"]),delete this.onceListeners["*"]);const r=s.map(s=>new Promise(r=>{try{r(s(t,e))}catch(i){console.error(`Error in async event listener for '${e}':`,i),this.emitError(i,e,s),r()}}));return await Promise.all(r),this}removeAllListeners(){return this.listeners={},this.onceListeners={},this}listenerCount(e){return(this.listeners[e]?this.listeners[e].length:0)+(this.onceListeners[e]?this.onceListeners[e].length:0)}eventNames(){const e=Object.keys(this.listeners),t=Object.keys(this.onceListeners);return[.../* @__PURE__ */new Set([...e,...t])]}setMaxListeners(e){if("number"!=typeof e||e<0)throw new Error("Max listeners must be a non-negative number");return this.maxListeners=e,this}namespace(e){const t=t=>`${e}:${t}`;return{on:(e,s)=>this.on(t(e),s),once:(e,s)=>this.once(t(e),s),off:(e,s)=>this.off(t(e),s),emit:(e,s)=>this.emit(t(e),s),emitAsync:(e,s)=>this.emitAsync(t(e),s)}}use(e){if("function"!=typeof e)throw new Error("Middleware must be a function");const t=this.emit;return this.emit=(s,r)=>{try{const i=e(s,r);if(!1===i)return this;const n=void 0!==i?i:r;return t.call(this,s,n)}catch(i){return console.error("Error in event middleware:",i),t.call(this,s,r)}},this}emitError(e,t,s){"error"!==t&&setTimeout(()=>{this.emit("error",{error:e,originalEvent:t,callback:s.toString()})},0)}waitFor(e,t=null){return new Promise((s,r)=>{let i=null;const n=e=>{i&&clearTimeout(i),s(e)};this.once(e,n),t&&(i=setTimeout(()=>{this.off(e,n),r(new Error(`Timeout waiting for event: ${e}`))},t))})}debug(e=!0){return this.debugMode=e,this}getStats(){const e=this.eventNames(),t={totalEvents:e.length,totalListeners:0,events:{},emissions:{...this.eventStats}};return e.forEach(e=>{const s=this.listenerCount(e);t.events[e]=s,t.totalListeners+=s}),t}updateEventStats(e){this.eventStats[e]||(this.eventStats[e]={count:0,firstEmission:Date.now(),lastEmission:null}),this.eventStats[e].count++,this.eventStats[e].lastEmission=Date.now()}getEventStats(e){const t=this.eventStats[e];return t?{...t,listenerCount:this.listenerCount(e),avgEmissionsPerMinute:this.calculateEmissionRate(t)}:null}calculateEmissionRate(e){if(!e.firstEmission||!e.lastEmission)return 0;const t=e.lastEmission-e.firstEmission;if(0===t)return 0;const s=t/6e4;return Math.round(e.count/s*100)/100}resetStats(){return this.eventStats={},this}getTopEvents(e=10){return Object.entries(this.eventStats).map(([e,t])=>({event:e,count:t.count,rate:this.calculateEmissionRate(t),listeners:this.listenerCount(e)})).sort((e,t)=>t.count-e.count).slice(0,e)}debugInfo(){this.debugMode,this.maxListeners;const e=this.getStats();return e.totalEvents,e.totalListeners,Object.keys(this.eventStats).length>0&&this.getTopEvents(5),this}}class WebApp{constructor(t={}){this.config=t,this.initPluginRegistry(),this.name=t.name||"MOJO App",this.version=t.version||"1.0.0",this.debug=t.debug||!1,this.container=t.container||"#app",this.layoutType=t.layout||"portal",this.layoutConfig=t.layoutConfig||{},t.sidebar&&(this.layoutConfig.sidebarConfig=t.sidebar),t.topbar&&(this.layoutConfig.topbarConfig=t.topbar),this.layout=null,this.layoutConfig.containerId=this.container||this.containerId||"#app",this.pageContainer=t.pageContainer||"#page-container",this.basePath=t.basePath||"",this.routerMode=t.routerMode||t.router?.mode||"param",this.basePath=t.basePath||t.router?.base||"",this.defaultRoute=t.defaultRoute||"home",this.session=t.session||{},this.router=null,this.navigation=t.navigation||{},this.state={currentPage:null,previousPage:null,loading:!1},this.events=new EventBus,this.rest=e.rest,t.api&&this.rest.configure(t.api),this.router=new Router({mode:"param"===this.routerMode?"params":this.routerMode,basePath:this.basePath,defaultRoute:this.defaultRoute,eventEmitter:this.events}),this.events.on("route:changed",async e=>{const{pageName:t,params:s,query:r}=e;await this.showPage(t,r,s,{fromRouter:!0})}),"undefined"!=typeof window&&(window.MOJO=window.MOJO||{},window.MOJO.router=this.router),this.setupFocusTracking(),this.pageCache=/* @__PURE__ */new Map,this.pageClasses=/* @__PURE__ */new Map,this.componentClasses=/* @__PURE__ */new Map,this.modelClasses=/* @__PURE__ */new Map,this.currentPage=null,this.isStarted=!1,window.matchUUID?window[window.matchUUID]=this:window.MOJO?window.MOJO.app=this:window.__app__=this}async start(){if(this.isStarted)console.warn("WebApp already started");else try{this.setupPageContainer(),this.validateDefaultRoute(),await this.setupRouter(),this.isStarted=!0,this.router.allowPopState=!1,this.events.emit("app:ready",{app:this})}catch(e){throw console.error(`Failed to start ${this.name}:`,e),this.showError("Failed to start application"),e}}async setupRouter(){this.router?(this.events.on("route:notfound",async e=>{console.warn(`Route not found: ${e.path}`),this._show404(e.path)}),this.router.start(),this.routerMode):console.error("Router not initialized")}setupPageContainer(){const e="string"==typeof this.container?document.querySelector(this.container):this.container;e&&!e.querySelector("#page-container")&&(e.innerHTML='<div id="page-container"></div>'),this.pageContainer="#page-container"}registerPage(e,t,s={}){if("string"!=typeof e||!e)return console.error("registerPage: pageName must be a non-empty string"),this;if("function"!=typeof t)return console.error("registerPage: PageClass must be a constructor function"),this;if(s.containerId||(s.containerId=this.pageContainer),this.pageClasses.set(e,{PageClass:t,constructorOptions:s}),this.router){let t=s.route||`/${e}`;t.startsWith("/")||(t=`/${t}`),s.route=t,this.router.addRoute(t,e)}return this}getPage(e){return this.pageCache.get(e)}getPagePermissions(e){if(this.pageCache.has(e))return this.pageCache.get(e).permissions;const t=this.pageClasses.get(e);if(!t)return null;const{PageClass:s,constructorOptions:r}=t;return r?r.permissions:null}getOrCreatePage(e){if(this.pageCache.has(e))return this.pageCache.get(e);const t=this.pageClasses.get(e);if(!t)return console.error(`Page not registered: ${e}`),null;const{PageClass:s,constructorOptions:r}=t;try{const t=new s({pageName:e,...r,app:this});return r.route&&(t.route=r.route),this.pageCache.set(e,t),t.route,t}catch(i){return console.error(`Failed to create page ${e}:`,i),null}}async showPage(e,t={},s={},r={}){const{fromRouter:i=!1,replace:n=!1,force:o=!1}=r;try{let r,n;"string"==typeof e?(n=e,r=this.getOrCreatePage(e)):e&&"object"==typeof e&&(r=e,n=e.pageName);const o=this.currentPage;if(!r)return void this._show404(n,s,t,i);if(this.events.emit("page:showing",{page:r,pageName:r.pageName,params:s,query:t,fromRouter:i}),!r.canEnter())return void this._showDeniedPage(r,s,t,i);o&&o!==r&&await this._exitOldPage(o),await r.onParams(s,t),o!==r&&await r.onEnter(),r.syncUrl(),this.events.emit("page:show",{page:r,pageName:r.pageName,params:s,query:t,fromRouter:i}),await r.render(),this.currentPage=r,r.pageName}catch(a){console.error("Error in showPage:",a),this.showError(`Failed to load page: ${a.message}`),"error"!==e&&await this.showPage("error",{},{error:a,originalPage:e},{fromRouter:i})}}async _show404(e,t,s,r){const i=this.getOrCreatePage("404");i&&(i.setInfo&&i.setInfo(e),await this._exitOldPage(this.currentPage),await i.render(),this.currentPage=i,this.events.emit("page:404",{page:null,pageName:e,params:t,query:s,fromRouter:r}))}async _showDeniedPage(e,t,s,r){const i=this.getOrCreatePage("denied");i.setDeniedPage&&i.setDeniedPage(e),await this._exitOldPage(this.currentPage),await i.render(),this.currentPage=i,this.events.emit("page:denied",{page:e,pageName:e.pageName,params:t,query:s,fromRouter:r})}async _exitOldPage(e){if(e)try{await e.onExit(),await e.unmount(),this.events.emit("page:hide",{page:e})}catch(t){console.error(`Error exiting page ${e.pageName}:`,t)}}async navigate(e,t={},s={}){if(!this.router)return void console.error("Router not initialized");let r=e;if(Object.keys(t).length>0){const s=new URLSearchParams(t).toString();r+=(e.includes("?")?"&":"?")+s}return await this.router.navigate(r,s)}async navigateToDefault(e={}){return await this.showPage(this.defaultRoute,{},{},e)}back(){this.router?this.router.back():console.warn("Router not initialized")}forward(){this.router?this.router.forward():console.warn("Router not initialized")}getCurrentPage(){return this.currentPage}getPageContainer(){return this.layout&&this.layout.getPageContainer?this.layout.getPageContainer():"string"==typeof this.pageContainer?document.querySelector(this.pageContainer):this.pageContainer}async showError(e){try{const t=(await Promise.resolve().then(()=>require("./Dialog-DW7PHzUc.js"))).default;await t.alert(e,"Error",{size:"md",class:"text-danger"})}catch(t){this.events.emit("notification",{message:e,type:"error"}),"undefined"!=typeof window&&window?.console&&console.error("[WebApp] showError fallback:",t),"undefined"!=typeof window&&alert(`Error: ${e}`)}}async showSuccess(e){try{const t=(await Promise.resolve().then(()=>require("./Dialog-DW7PHzUc.js"))).default;await t.alert(e,"Success",{size:"md",class:"text-success"})}catch(t){this.events.emit("notification",{message:e,type:"success"}),"undefined"!=typeof window&&window?.console&&console.warn("[WebApp] showSuccess fallback:",t),"undefined"!=typeof window&&alert(`Success: ${e}`)}}async showInfo(e){try{const t=(await Promise.resolve().then(()=>require("./Dialog-DW7PHzUc.js"))).default;await t.alert(e,"Information",{size:"md",class:"text-info"})}catch(t){this.events.emit("notification",{message:e,type:"info"}),"undefined"!=typeof window&&window,"undefined"!=typeof window&&alert(`Info: ${e}`)}}async showWarning(e){try{const t=(await Promise.resolve().then(()=>require("./Dialog-DW7PHzUc.js"))).default;await t.alert(e,"Warning",{size:"md",class:"text-warning"})}catch(t){this.events.emit("notification",{message:e,type:"warning"}),"undefined"!=typeof window&&window?.console&&console.warn("[WebApp] showWarning fallback:",t),"undefined"!=typeof window&&alert(`Warning: ${e}`)}}showNotification(e,t="info"){this.events.emit("notification",{message:e,type:t})}async showLoading(e={}){"string"==typeof e&&(e={message:e});try{(await Promise.resolve().then(()=>require("./Dialog-DW7PHzUc.js"))).default.showBusy(e)}catch(t){"undefined"!=typeof window&&window?.console&&console.warn("[WebApp] showLoading fallback:",t,e),this.events.emit("notification",{message:e.message||"Loading...",type:"info"})}}async hideLoading(){try{(await Promise.resolve().then(()=>require("./Dialog-DW7PHzUc.js"))).default.hideBusy()}catch(e){"undefined"!=typeof window&&window?.console&&console.warn("[WebApp] hideLoading fallback:",e)}}async showModelView(e,t={}){try{const s=(await Promise.resolve().then(()=>require("./Dialog-DW7PHzUc.js"))).default;return await s.showModelView(e,t)}catch(s){throw"undefined"!=typeof window&&window?.console&&console.error("[WebApp] showModelForm failed:",s),s}}async showModelForm(e={}){try{const t=(await Promise.resolve().then(()=>require("./Dialog-DW7PHzUc.js"))).default;return await t.showModelForm(e)}catch(t){throw"undefined"!=typeof window&&window?.console&&console.error("[WebApp] showModelForm failed:",t),t}}async showForm(e={}){try{const t=(await Promise.resolve().then(()=>require("./Dialog-DW7PHzUc.js"))).default;return await t.showForm(e)}catch(t){throw"undefined"!=typeof window&&window?.console&&console.error("[WebApp] showForm failed:",t),t}}async showDialog(e={}){try{const t=(await Promise.resolve().then(()=>require("./Dialog-DW7PHzUc.js"))).default;return await t.showDialog(e)}catch(t){throw"undefined"!=typeof window&&window?.console&&console.error("[WebApp] showDialog failed:",t),t}}async showAlert(e={}){try{const t=(await Promise.resolve().then(()=>require("./Dialog-DW7PHzUc.js"))).default;return await t.showDialog(e)}catch(t){throw"undefined"!=typeof window&&window?.console&&console.error("[WebApp] showDialog failed:",t),t}}async confirm(e,t="Confirm",s={}){const r=(await Promise.resolve().then(()=>require("./Dialog-DW7PHzUc.js"))).default;return await r.confirm(e,t,s)}setupFocusTracking(){if("undefined"==typeof window)return;this.isFocused=!document.hidden;const e=()=>{const e=this.isFocused;this.isFocused=!document.hidden,e!==this.isFocused&&(this.isFocused?this.events.emit("browser:focus"):this.events.emit("browser:blur"))},t=()=>{this.isFocused||(this.isFocused=!0,this.events.emit("browser:focus"))},s=()=>{this.isFocused&&(this.isFocused=!1,this.events.emit("browser:blur"))};document.addEventListener("visibilitychange",e),window.addEventListener("focus",t),window.addEventListener("blur",s),this._focusHandlers={visibilitychange:e,focus:t,blur:s}}setupErrorHandling(){window.addEventListener("error",e=>{console.error("Global error:",e.error),this.debug&&this.showError(`Error: ${e.error?.message||"Unknown error"}`)}),window.addEventListener("unhandledrejection",e=>{console.error("Unhandled promise rejection:",e.reason),this.debug&&this.showError(`Promise rejected: ${e.reason?.message||"Unknown error"}`)})}escapeHtml(e){return e.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&#039;")}getState(e){return e?this.state[e]:this.state}setState(e){const t={...this.state};Object.assign(this.state,e),this.events.emit("state:changed",{oldState:t,newState:this.state,updates:e})}registerComponent(e,t){this.componentClasses.set(e,t)}getComponent(e){return this.componentClasses.get(e)}registerModel(e,t){this.modelClasses.set(e,t)}getModel(e){return this.modelClasses.get(e)}setupRest(){this.rest=e.rest,e.rest.configure(this.api)}async destroy(){this.router&&this.router.stop(),this._focusHandlers&&"undefined"!=typeof window&&(document.removeEventListener("visibilitychange",this._focusHandlers.visibilitychange),window.removeEventListener("focus",this._focusHandlers.focus),window.removeEventListener("blur",this._focusHandlers.blur));const e=Array.from(this.pageCache.values());if(await Promise.allSettled(e.map(async e=>{try{e.destroy&&await e.destroy()}catch(t){console.error("Error destroying page:",t)}})),this.layout&&this.layout.destroy)try{await this.layout.destroy()}catch(t){console.error("Error destroying layout:",t)}this.pageCache.clear(),this.pageClasses.clear(),this.componentClasses.clear(),this.modelClasses.clear(),"undefined"!=typeof window&&window.MOJO&&delete window.MOJO.router,this.isStarted=!1,this.name}buildPagePath(e,t,s){let r=e.route||`/${e.pageName.toLowerCase()}`;if(Object.keys(t).forEach(e=>{"string"!=typeof t[e]&&"number"!=typeof t[e]||(r=r.replace(`:${e}`,t[e]))}),s&&Object.keys(s).length>0){const e=new URLSearchParams(s).toString();r+=(r.includes("?")?"&":"?")+e}return r}validateDefaultRoute(){this.pageClasses.has(this.defaultRoute)?this.defaultRoute:(console.warn(`⚠️ Default route '${this.defaultRoute}' is not registered!`),console.warn(` Please register a page: app.registerPage('${this.defaultRoute}', YourPageClass);`),console.warn(" Or change default route: new WebApp({ defaultRoute: 'your-page' });"))}findFallbackPage(){const e=["404","error","denied"];for(const[t]of this.pageClasses.entries())if(!e.includes(t))return t;return null}static create(e={}){return new WebApp(e)}initPluginRegistry(){"undefined"!=typeof window&&(window.MOJO||(window.MOJO={}),window.MOJO.plugins||(window.MOJO.plugins={}),window.MOJO.app=this)}static registerPlugin(e,t){"undefined"!=typeof window&&(window.MOJO||(window.MOJO={}),window.MOJO.plugins||(window.MOJO.plugins={}),window.MOJO.plugins[e]=t)}}exports.EventBus=EventBus,exports.Router=Router,exports.WebApp=WebApp;
2
+ //# sourceMappingURL=WebApp-B0m6JCjO.js.map