web-mojo 2.2.2 → 2.2.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/admin.cjs.js +1 -1
- package/dist/admin.es.js +12 -12
- package/dist/auth.cjs.js +1 -1
- package/dist/auth.es.js +1 -1
- package/dist/charts.cjs.js +1 -1
- package/dist/charts.es.js +4 -4
- package/dist/chunks/{ChatView-CWNoGk-B.js → ChatView-DZ7f2Rl5.js} +7 -7
- package/dist/chunks/{ChatView-CWNoGk-B.js.map → ChatView-DZ7f2Rl5.js.map} +1 -1
- package/dist/chunks/{ChatView-DSEEMnNt.js → ChatView-DoA8h81E.js} +2 -2
- package/dist/chunks/{ChatView-DSEEMnNt.js.map → ChatView-DoA8h81E.js.map} +1 -1
- package/dist/chunks/{Collection-CqLcHgQG.js → Collection-CREl6Fa9.js} +2 -2
- package/dist/chunks/{Collection-CqLcHgQG.js.map → Collection-CREl6Fa9.js.map} +1 -1
- package/dist/chunks/{Collection-C7rteLDn.js → Collection-DJaa8dhS.js} +2 -2
- package/dist/chunks/{Collection-C7rteLDn.js.map → Collection-DJaa8dhS.js.map} +1 -1
- package/dist/chunks/{ContextMenu-JJ51hS-a.js → ContextMenu-CvLNRuJb.js} +3 -3
- package/dist/chunks/{ContextMenu-JJ51hS-a.js.map → ContextMenu-CvLNRuJb.js.map} +1 -1
- package/dist/chunks/{ContextMenu-BY3BgxM5.js → ContextMenu-DvsDXgOe.js} +2 -2
- package/dist/chunks/{ContextMenu-BY3BgxM5.js.map → ContextMenu-DvsDXgOe.js.map} +1 -1
- package/dist/chunks/{DataView-CsYXM9vF.js → DataView-Bm8dffDn.js} +2 -2
- package/dist/chunks/{DataView-CsYXM9vF.js.map → DataView-Bm8dffDn.js.map} +1 -1
- package/dist/chunks/{DataView-CHvoEI4M.js → DataView-gc1VouWJ.js} +2 -2
- package/dist/chunks/{DataView-CHvoEI4M.js.map → DataView-gc1VouWJ.js.map} +1 -1
- package/dist/chunks/{Dialog-BKPwBCDC.js → Dialog-Cl_rBFSh.js} +2 -2
- package/dist/chunks/{Dialog-BKPwBCDC.js.map → Dialog-Cl_rBFSh.js.map} +1 -1
- package/dist/chunks/{Dialog-D4DsB-N1.js → Dialog-LPU__Q7Z.js} +5 -5
- package/dist/chunks/{Dialog-D4DsB-N1.js.map → Dialog-LPU__Q7Z.js.map} +1 -1
- package/dist/chunks/{FormView-DYX_yeho.js → FormView-Cc5iagqS.js} +2 -2
- package/dist/chunks/{FormView-DYX_yeho.js.map → FormView-Cc5iagqS.js.map} +1 -1
- package/dist/chunks/{FormView-B9nIO_AX.js → FormView-DMMUiciW.js} +2 -2
- package/dist/chunks/{FormView-B9nIO_AX.js.map → FormView-DMMUiciW.js.map} +1 -1
- package/dist/chunks/{ListView-DWaowghQ.js → ListView-8FqhYWRU.js} +3 -3
- package/dist/chunks/{ListView-DWaowghQ.js.map → ListView-8FqhYWRU.js.map} +1 -1
- package/dist/chunks/{ListView-D2vt0koT.js → ListView-Xcsfu4IL.js} +2 -2
- package/dist/chunks/{ListView-D2vt0koT.js.map → ListView-Xcsfu4IL.js.map} +1 -1
- package/dist/chunks/{MetricsMiniChartWidget-BfZ-dcbW.js → MetricsMiniChartWidget-BuvhT5NG.js} +2 -2
- package/dist/chunks/{MetricsMiniChartWidget-BfZ-dcbW.js.map → MetricsMiniChartWidget-BuvhT5NG.js.map} +1 -1
- package/dist/chunks/{MetricsMiniChartWidget-Cl-TA-Q9.js → MetricsMiniChartWidget-CsawNLeS.js} +4 -4
- package/dist/chunks/{MetricsMiniChartWidget-Cl-TA-Q9.js.map → MetricsMiniChartWidget-CsawNLeS.js.map} +1 -1
- package/dist/chunks/{PDFViewer-Cgr3T15i.js → PDFViewer-Bg06w3Cu.js} +2 -2
- package/dist/chunks/{PDFViewer-Cgr3T15i.js.map → PDFViewer-Bg06w3Cu.js.map} +1 -1
- package/dist/chunks/{PDFViewer-Bzifr-dn.js → PDFViewer-Dr72gJt1.js} +3 -3
- package/dist/chunks/{PDFViewer-Bzifr-dn.js.map → PDFViewer-Dr72gJt1.js.map} +1 -1
- package/dist/chunks/Rest-29RtA7pe.js +2 -0
- package/dist/chunks/Rest-29RtA7pe.js.map +1 -0
- package/dist/chunks/{Rest-C3fPzCIA.js → Rest-BoKp2Hj4.js} +34 -1
- package/dist/chunks/Rest-BoKp2Hj4.js.map +1 -0
- package/dist/chunks/TokenManager-Bh1WshcR.js +2 -0
- package/dist/chunks/TokenManager-Bh1WshcR.js.map +1 -0
- package/dist/chunks/{TokenManager-CoHKTGNX.js → TokenManager-BoolOcxQ.js} +26 -11
- package/dist/chunks/TokenManager-BoolOcxQ.js.map +1 -0
- package/dist/chunks/{WebSocketClient-Dzwprd15.js → WebSocketClient-DcJBT-iB.js} +2 -2
- package/dist/chunks/{WebSocketClient-Dzwprd15.js.map → WebSocketClient-DcJBT-iB.js.map} +1 -1
- package/dist/chunks/{WebSocketClient-CkAL55qy.js → WebSocketClient-Do0CazHx.js} +2 -2
- package/dist/chunks/{WebSocketClient-CkAL55qy.js.map → WebSocketClient-Do0CazHx.js.map} +1 -1
- package/dist/chunks/{version-CJnLNR-g.js → version-Bado0p82.js} +2 -2
- package/dist/chunks/{version-CJnLNR-g.js.map → version-Bado0p82.js.map} +1 -1
- package/dist/chunks/{version-Bl3PlRrV.js → version-_FYWwpG_.js} +4 -4
- package/dist/chunks/{version-Bl3PlRrV.js.map → version-_FYWwpG_.js.map} +1 -1
- package/dist/docit.cjs.js +1 -1
- package/dist/docit.es.js +6 -6
- package/dist/index.cjs.js +1 -1
- package/dist/index.es.js +15 -15
- package/dist/lightbox.cjs.js +1 -1
- package/dist/lightbox.es.js +5 -5
- package/dist/map.cjs.js +1 -1
- package/dist/map.es.js +2 -2
- package/dist/timeline.cjs.js +1 -1
- package/dist/timeline.es.js +4 -4
- package/package.json +1 -1
- package/dist/chunks/Rest-C3fPzCIA.js.map +0 -1
- package/dist/chunks/Rest-DYPLEzNy.js +0 -2
- package/dist/chunks/Rest-DYPLEzNy.js.map +0 -1
- package/dist/chunks/TokenManager-CoHKTGNX.js.map +0 -1
- package/dist/chunks/TokenManager-DSyRWlvc.js +0 -2
- package/dist/chunks/TokenManager-DSyRWlvc.js.map +0 -1
package/dist/index.cjs.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});const e=require("./chunks/version-CJnLNR-g.js"),t=require("./chunks/Rest-DYPLEzNy.js"),s=require("./chunks/ContextMenu-BY3BgxM5.js"),i=require("./chunks/Dialog-BKPwBCDC.js"),n=require("./chunks/Collection-CqLcHgQG.js"),a=require("./chunks/ChatView-DSEEMnNt.js"),r=require("./chunks/TokenManager-DSyRWlvc.js"),o=require("./chunks/ListView-D2vt0koT.js"),l=require("./chunks/DataView-CsYXM9vF.js"),c=require("./chunks/FormView-B9nIO_AX.js"),d=require("./chunks/WebSocketClient-Dzwprd15.js");var h="undefined"!=typeof document?document.currentScript:null;const u={BASE_URL:"/",DEV:!1,MODE:"production",PROD:!0,SSR:!1},p=Object.freeze({silent:0,error:1,warn:2,info:3,log:3,debug:4,trace:5,all:5}),g=(()=>{try{if(void 0!=={url:"undefined"==typeof document?require("url").pathToFileURL(__filename).href:h&&"SCRIPT"===h.tagName.toUpperCase()&&h.src||new URL("index.cjs.js",document.baseURI).href}&&("undefined"==typeof document?require("url").pathToFileURL(__filename).href:h&&"SCRIPT"===h.tagName.toUpperCase()&&h.src||new URL("index.cjs.js",document.baseURI).href,1)&&u)return!1}catch{}if("undefined"!=typeof globalThis&&void 0!==globalThis.__DEV__)try{return!!globalThis.__DEV__}catch{}return!("undefined"==typeof process||!process||"object"!=typeof process.env||"string"!=typeof process.env.NODE_ENV)&&"production"!==process.env.NODE_ENV})(),m="undefined"!=typeof window&&"undefined"!=typeof document,b="undefined"!=typeof globalThis?globalThis:"undefined"!=typeof window?window:global,v=b.console||{},f={};let w=!1,y=null;function x(e){if("number"==typeof e){const t=p.silent,s=p.trace;return Math.min(Math.max(e,t),s)}if("string"==typeof e){const t=e.toLowerCase();if(Object.prototype.hasOwnProperty.call(p,t))return p[t]}return null}function S(e,t){const s=f[e]||v[e]||(()=>{});return function(...e){if(y>=t)return s.apply(v,e)}}const L={install(e={}){if(w)return e&&void 0!==e.level&&this.setLevel(e.level,{persist:!!e.persist}),this;if(!b||!v)return w=!0,this;y=function(e){const t=x(e);if(null!==t)return t;const s=function(){if(!m||"undefined"==typeof location||!location.search)return null;try{const e=new URLSearchParams(location.search),t=["logLevel","loglevel","mojoLog"];for(const s of t){const t=e.get(s);if(null!=t){const e=x(t);if(null!==e)return e}}}catch{}return null}();if(null!==s)return s;const i=function(){if(!m||!("localStorage"in b))return null;try{const e=b.localStorage.getItem("MOJO_LOG_LEVEL");if(null!=e){const t=x(e);if(null!==t)return t}}catch{}return null}();return null!==i?i:x(g?"debug":"warn")}(e.level);const t=function(){const e={...v},t={error:p.error,warn:p.warn,info:p.info,log:p.info,dir:p.info,table:p.info,debug:p.debug,group:p.debug,groupCollapsed:p.debug,groupEnd:p.debug,time:p.debug,timeEnd:p.debug,timeLog:p.debug,trace:p.trace};for(const s of Object.keys(t))f[s]=v[s]||(()=>{}),e[s]=S(s,t[s]);return f.assert=v.assert||(()=>{}),e.assert=function(){const e=f.assert||v.assert||(()=>{});return function(t,...s){if(!t)return y>=p.error?e.apply(v,[t,...s]):void 0}}(),e}();return b.console=t,w=!0,b.MOJOConsoleSilencer=this,this},uninstall(){if(!w)return this;try{b.console=v}catch{}return w=!1,this},setLevel(e,{persist:t=!1}={}){const s=x(e);return null===s||(y=s,t&&function(e){if(m&&"localStorage"in b)try{const t="string"==typeof e?e:null===e?null:Object.entries(p).find(([,t])=>t===e)?.[0]??null;t?b.localStorage.setItem("MOJO_LOG_LEVEL",t):b.localStorage.removeItem("MOJO_LOG_LEVEL")}catch{}}(e)),this},getLevel:()=>y,getLevelName(){const e=Object.entries(p).find(([,e])=>e===y);return e?e[0]:null},criticalOnly({persist:e=!1}={}){return this.setLevel("warn",{persist:e})},errorsOnly({persist:e=!1}={}){return this.setLevel("error",{persist:e})},silent({persist:e=!1}={}){return this.setLevel("silent",{persist:e})},verbose({persist:e=!1}={}){return this.setLevel(g?"debug":"info",{persist:e})},allowAll({persist:e=!1}={}){return this.setLevel("trace",{persist:e})},withTemporaryLevel(e,t){const s=y,i=x(e);if(null===i||"function"!=typeof t)return t?.();y=i;try{return t()}finally{y=s}},LEVELS:p};class GroupSearchView extends r.SimpleSearchView{constructor(e={}){super({...e,className:`group-search-view ${e.className||""}`.trim()}),this.showKind=void 0===e.showKind||e.showKind,this.parentField=e.parentField||"parent",this.kindField=e.kindField||"kind",this.treeData=[],this.flattenedItems=[],this.showLines=void 0===e.showLines||e.showLines}buildTreeHierarchy(e){if(!e||0===e.length)return[];const t=/* @__PURE__ */new Map;e.forEach(e=>{t.has(e.id)||t.set(e.id,{...e,children:[],level:0,hasChildren:!1});const s=e[this.parentField];s&&s.id&&!t.has(s.id)&&t.set(s.id,{...s,children:[],level:0,hasChildren:!1})});const s=[];t.forEach((i,n)=>{const a=e.find(e=>e.id===n)||i,r=a[this.parentField]?.id;if(r&&t.has(r)){const e=t.get(r);e.children.push(i),e.hasChildren=!0}else s.push(i)});const i=(e,t=0)=>{e.forEach(e=>{e.level=t,e.children.length>0&&(e.children.sort((e,t)=>(e.name||"").localeCompare(t.name||"")),i(e.children,t+1))})};return s.sort((e,t)=>(e.name||"").localeCompare(t.name||"")),i(s),s}flattenTree(e,t=[],s=[]){return e.forEach((i,n)=>{i._isLastChild=n===e.length-1,i._ancestorLastFlags=[...s];const a=s.every(e=>e);if(i._isLastDescendant=a&&i._isLastChild&&(!i.children||0===i.children.length),t.push(i),i.children&&i.children.length>0){const e=[...s,i._isLastChild];this.flattenTree(i.children,t,e)}}),t}computeVerticalLines(e){for(let t=0;t<e.length;t++){const s=e[t];s._continueVertical=[];for(let i=0;i<s.level;i++){let n=!1;for(let s=t+1;s<e.length;s++){const t=e[s];if(t.level===i+1){n=!0;break}if(t.level<=i)break}s._continueVertical[i]=n}}}updateFilteredItems(){if(!this.collection)return this.filteredItems=[],this.treeData=[],void(this.flattenedItems=[]);const e=this.collection.toJSON();this.treeData=this.buildTreeHierarchy(e),this.flattenedItems=this.flattenTree(this.treeData),this.computeVerticalLines(this.flattenedItems),this.filteredItems=this.flattenedItems,this.updateResultsView()}getDefaultItemTemplate(){return'\n <div class="tree-item-content">\n <div class="tree-item-name">{{name}}</div>\n {{#showKind}}\n <div class="tree-item-kind">{{kind}}</div>\n {{/showKind}}\n </div>\n '}processItemTemplate(e){let t=this.itemTemplate;t=t.replace(/\{\{(\w+)\}\}/g,(t,s)=>"showKind"===s?this.showKind?"true":"":this.getNestedValue(e,s)||""),t=this.showKind?t.replace(/\{\{#showKind\}\}(.*?)\{\{\/showKind\}\}/gs,"$1"):t.replace(/\{\{#showKind\}\}.*?\{\{\/showKind\}\}/gs,"");let s="";if(this.showLines&&e.level>0)for(let i=0;i<e.level;i++)i===e.level-1?s+=`<span class="${e._isLastChild?"tree-seg tree-seg-last":"tree-seg tree-seg-mid"}"></span>`:s+=e._continueVertical&&e._continueVertical[i]?'<span class="tree-seg tree-seg-vert"></span>':'<span class="tree-seg"></span>';return`\n <div class="tree-item-wrapper${e.hasChildren?" has-children":""}${e._isLastChild?" is-last-child":""}" data-tree-level="${e.level}">\n <div class="tree-lines">\n ${s}\n </div>\n <div class="tree-item-body flex-grow-1">\n ${t}\n </div>\n </div>\n `}getRootItems(){return this.treeData}getNodeChildren(e){const t=(e,s)=>{for(const i of e){if(i.id===s)return i.children;if(i.children.length>0){const e=t(i.children,s);if(e)return e}}return null};return t(this.treeData,e)||[]}}class Sidebar extends t.View{constructor(e={}){super({tagName:"nav",className:"sidebar",id:"sidebar",...e}),this.menus=/* @__PURE__ */new Map,this.activeMenuName=null,this.currentRoute=null,this.showToggle=e.showToggle,this.isCollapsed=!1,this.sidebarTheme=e.theme||"sidebar-light",this.customView=null,this.options.groupHeader&&(this.groupHeader=this.options.groupHeader),this.groupSelectorMode=e.groupSelectorMode||"inline",this.groupSelectorDialog=null,this.sidebarTheme&&this.addClass(this.sidebarTheme),this.initializeMenus(e),this.setupRouteListeners(),!1!==e.autoCollapseMobile&&this.setupResponsiveBehavior()}groupHeader='\n {{#group.parent}}\n <div class="sidebar-parent-bar" data-action="select-group-parent">\n <div class="parent-info">\n <span class="parent-label">{{group.parent.kind}}:</span>\n <span class="parent-name collapsed-hidden">{{group.parent.name}}</span>\n </div>\n <i class="bi bi-chevron-down parent-expand collapsed-hidden"></i>\n </div>\n {{/group.parent}}\n <div class="sidebar-selected-group-row" data-action="show-group-search">\n <div class="selected-group-info">\n <div class=\'selected-group-name collapsed-hidden\'>{{group.name}}</div>\n <div class=\'selected-group-meta collapsed-hidden\'>\n <span class="selected-group-kind">{{group.kind}}</span>\n </div>\n </div>\n <i class="bi bi-chevron-down selected-group-chevron collapsed-hidden"></i>\n </div>\n ';async onInit(){await super.onInit();const e=this.getApp(),t=e?.router;if(t){const e=t.getCurrentPath();e&&this.autoSwitchToMenuForRoute(e)}this.initializeTooltips(),this.searchView=new GroupSearchView({noAppend:!0,showExitButton:!0,headerText:"Select Group",containerId:"sidebar-search-container",Collection:s.GroupList,itemTemplate:'\n <div class="p-3 border-bottom">\n <div class="fw-semibold text-dark">{{name}}</div>\n <small class="text-muted">#{{id}} {{kind}}</small>\n </div>\n '}),this.addChild(this.searchView),this.searchView.on("item:selected",e=>{this.getApp().setActiveGroup(e.model)}),this.searchView.on("exit",e=>{this.hideGroupSearch()})}showGroupSearch(){"dialog"===this.groupSelectorMode?this.showGroupSearchDialog():(this.setClass("sidebar"),this.showSearch=!0,this.render())}hideGroupSearch(){"dialog"===this.groupSelectorMode?this.groupSelectorDialog&&this.groupSelectorDialog.hide():(this.setClass("sidebar"),this.showSearch=!1,this.render())}onActionShowGroupSearch(){this.showGroupSearch()}async onActionSelectGroupParent(){const e=this.getApp().activeGroup;if(await i.Dialog.confirm(`Are you sure you want to navigate to the '${e.get("parent.name")}'?`)){this.getApp().showLoading();let t=new s.Group({id:e.get("parent.id")});await t.fetch(),this.getApp().setActiveGroup(t),this.getApp().hideLoading()}}async showGroupSearchDialog(){const e=new s.GroupList,t=new GroupSearchView({Collection:s.GroupList,collection:e,searchFields:["name"],headerText:null,searchPlaceholder:"Search groups...",headerIcon:null,maxHeight:Math.min(600,window.innerHeight-200),showExitButton:!1,showKind:!0,parentField:"parent",kindField:"kind",autoExpandRoot:!0,autoExpandAll:!1,indentSize:20,showLines:!0});this.groupSelectorDialog=new i.Dialog({body:t,size:"md",header:null,noBodyPadding:!0,scrollable:!1,buttons:[],closeButton:!0}),t.on("item:selected",e=>{this.getApp().setActiveGroup(e.model),this.groupSelectorDialog&&this.groupSelectorDialog.hide()}),this.groupSelectorDialog.on("hidden",()=>{this.groupSelectorDialog.destroy(),this.groupSelectorDialog=null}),await this.groupSelectorDialog.render(!0,document.body),this.groupSelectorDialog.show()}autoSwitchToMenuForRoute(e){for(const[t,s]of this.menus)if((!s.groupKind||this.getApp().activeGroup)&&this.menuContainsRoute(s,e))return this._setActiveMenu(t),this.currentRoute=e,this.clearAllActiveStates(),this.setActiveItemByRoute(e),this.render(),this.emit("menu-auto-switched",{menuName:t,route:e,config:s,sidebar:this}),!0;return!1}clearAllActiveStates(){for(const[e,t]of this.menus)for(const s of t.items||[])if(s.active=!1,s.children)for(const e of s.children)e.active=!1}setActiveItemByRoute(e){const t=e=>{if(!e)return"/";const t=decodeURIComponent(e);return t.startsWith("/")?t:`/${t}`},s=t(e);for(const[i,n]of this.menus)if(!n.groupKind||this.getApp().activeGroup)for(const e of n.items||[]){if(e.route){const i=t(e.route);if(this.routesMatch(s,i))return e.active=!0,this.activeMenuItem=e,!0}if(e.children)for(const i of e.children)if(i.route){const n=t(i.route);if(this.routesMatch(s,n))return i.active=!0,e.active=!0,!0}}return!1}menuContainsRoute(e,t){const s=e=>{if(!e)return"/";const t=decodeURIComponent(e);return t.startsWith("/")?t:`/${t}`},i=s(t);for(const n of e.items||[]){if(n.route){const e=s(n.route);if(this.routesMatch(i,e))return!0}if(n.children)for(const e of n.children)if(e.route){const t=s(e.route);if(this.routesMatch(i,t))return!0}}return!1}routesMatch(e,t){return this.getApp().router.doRoutesMatch(e,t)}getTemplate(){return this.customView?'<div class="sidebar-container" id="sidebar-custom-view-container"></div>':this.showSearch?this.getSearchTemplate():this.getMenuTemplate()}getSearchTemplate(){return'\n <div class="sidebar-container" id="sidebar-search-container">\n </div>\n '}getMenuTemplate(){return'\n <div class="sidebar-container">\n {{#data.currentMenu}}\n \x3c!-- Header --\x3e\n {{#header}}\n <div class="sidebar-header">\n {{{header}}}\n {{#showToggle}}\n <button class="sidebar-toggle" data-action="toggle-sidebar"\n aria-label="Toggle Sidebar">\n <i class="bi bi-chevron-left toggle-icon"></i>\n <i class="bi bi-chevron-right toggle-icon"></i>\n </button>\n {{/showToggle}}\n </div>\n {{/header}}\n\n \x3c!-- Navigation Items --\x3e\n <div class="sidebar-body">\n <ul class="nav nav-pills flex-column sidebar-nav" id="sidebar-nav-menu">\n {{#items}}\n {{>nav-item}}\n {{/items}}\n </ul>\n </div>\n\n \x3c!-- Footer --\x3e\n {{#footer}}\n <div class="sidebar-footer">\n {{{footer}}}\n </div>\n {{/footer}}\n {{/data.currentMenu}}\n\n {{^data.currentMenu}}\n <div class="sidebar-empty">\n <p class="text-danger text-center">No menu configured</p>\n </div>\n {{/data.currentMenu}}\n </div>\n '}getPartials(){return{"nav-item":'\n {{#isDivider}}\n {{>nav-divider}}\n {{/isDivider}}\n {{#isSpacer}}\n {{>nav-spacer}}\n {{/isSpacer}}\n {{#isLabel}}\n {{>nav-label}}\n {{/isLabel}}\n\n {{^isDivider}}\n {{^isSpacer}}\n {{^isLabel}}\n <li class="nav-item">\n {{#hasChildren}}\n \x3c!-- Item with submenu --\x3e\n <a class="nav-link {{#active}}active{{/active}} has-children collapsed"\n data-bs-toggle="collapse"\n href="#collapse-{{id}}"\n role="button"\n aria-expanded="{{#active}}true{{/active}}{{^active}}false{{/active}}"\n data-action="toggle-submenu">\n {{#icon}}<i class="{{icon}} me-2"></i>{{/icon}}\n <span class="nav-text">{{text}}</span>\n {{#badge}}\n <span class="{{badge.class}} ms-auto">{{badge.text}}</span>\n {{/badge}}\n <i class="bi bi-chevron-down nav-arrow ms-auto"></i>\n </a>\n <div class="collapse {{#active}}show{{/active}}" id="collapse-{{id}}" data-bs-parent="#sidebar-nav-menu">\n <ul class="nav flex-column nav-submenu">\n {{#children}}\n <li class="nav-item">\n <a class="nav-link {{#active}}active{{/active}}"\n {{#action}}data-action="{{action}}"{{/action}}\n {{#href}}href="{{href}}"{{/href}}>\n {{#icon}}<i class="{{icon}} me-2"></i>{{/icon}}\n <span class="nav-text">{{text}}</span>\n {{#badge}}\n <span class="{{badge.class}} ms-auto">{{badge.text}}</span>\n {{/badge}}\n </a>\n </li>\n {{/children}}\n </ul>\n </div>\n {{/hasChildren}}\n {{^hasChildren}}\n \x3c!-- Simple item --\x3e\n <a class="nav-link {{#active}}active{{/active}} {{#disabled}}disabled{{/disabled}}"\n {{#action}}{{^disabled}}data-action="{{action}}"{{/disabled}}{{/action}}\n {{#href}}{{^disabled}}href="{{href}}"{{/disabled}}{{/href}}>\n {{#icon}}<i class="{{icon}} me-2"></i>{{/icon}}\n <span class="nav-text">{{text}}</span>\n {{#badge}}\n <span class="{{badge.class}} ms-auto">{{badge.text}}</span>\n {{/badge}}\n </a>\n {{/hasChildren}}\n </li>\n {{/isLabel}}\n {{/isSpacer}}\n {{/isDivider}}\n ',"nav-divider":'\n <li class="nav-divider-item">\n <hr class="nav-divider-line">\n </li>\n ',"nav-spacer":'\n <li class="nav-spacer-item"></li>\n ',"nav-label":'\n <li class="nav-item {{className}}">\n <div class="nav-text px-3">{{text}}</div>\n </li>\n '}}getGroupHeader(){return this.groupHeader}addMenu(e,t){return t.groupKind&&!t.header&&(t.header=this.getGroupHeader()),this.menus.set(e,{name:e,groupKind:t.groupKind||null,header:t.header||null,footer:t.footer||null,items:t.items||[],data:t.data||{},className:t.className||"sidebar sidebar-dark"}),this.activeMenuName||this._setActiveMenu(e),this}_setActiveMenu(e){this.showSearch=!1,this.activeMenuName=e;const t=this.getCurrentMenuConfig();t.className?this.setClass(t.className):this.setClass("sidebar")}async setActiveMenu(e){if(!this.menus.has(e))return console.warn(`Menu '${e}' not found`),this;const t=this.menus.get(e);if(!t.groupKind||(this.lastGroupMenu=t,this.getApp().activeGroup))return this._setActiveMenu(e),await this.render(),this.emit("menu-changed",{menuName:e,config:t,sidebar:this}),this;this.showGroupSearch()}getGroupMenu(e){if(!e)return console.warn("No group provided"),null;let t=this.lastGroupMenu,s=null;if(e._.kind)for(const[i,n]of this.menus){if(this._groupKindMatches(n.groupKind,e._.kind)){t=n;break}"any"===n.groupKind&&(s=n)}return t||s}_groupKindMatches(e,t){return!(!e||!t)&&(Array.isArray(e)?e.includes(t):e===t)}showMenuForGroup(e){if(!e)return void console.warn("No group provided");let t=this.getGroupMenu(e);if(t)return this._setActiveMenu(t.name),this.render(),this.emit("menu-changed",{menuName:t.name,config:t,sidebar:this}),this;console.warn(`No menu found for group kind: ${e.kind}`)}getMenuConfig(e){return this.menus.get(e)||null}getCurrentMenuConfig(){return this.activeMenuName?this.menus.get(this.activeMenuName):null}updateMenu(e,t){const s=this.menus.get(e);return s?(Object.assign(s,t),this.activeMenuName===e&&this.render(),this):(console.warn(`Menu '${e}' not found`),this)}removeMenu(e){if(this.menus.delete(e),this.activeMenuName===e){const e=Array.from(this.menus.keys());this.activeMenuName=e.length>0?e[0]:null,this.render()}return this}async onBeforeRender(){const e=this.getCurrentMenuConfig();if(!e)return{currentMenu:null};let t={version:this.getApp().version||null,group:this.getApp().activeGroup||null,user:this.getApp.activeUser||null};this.data={currentMenu:{header:this.renderTemplateString(e.header||"",t),footer:this.renderTemplateString(e.footer||"",t),items:this.processNavItems(e.items,e.groupKind),data:e.data,showToggle:this.showToggle}}}async onAfterRender(){this.isCollapsedState()?setTimeout(()=>this.initializeTooltips(),50):this.destroyTooltips()}setCustomView(e){return this.customView&&this.removeChild(this.customView.id),this.customView=e,e&&(e.containerId="sidebar-custom-view-container",this.addChild(e)),this.render(),this}clearCustomView(){return this.customView&&(this.removeChild(this.customView.id),this.customView=null),this.render(),this}processNavItems(e,t){const s=this.getApp(),i=s?.activeUser,n=s?.activeGroup,a=e=>{if(t&&n&&n.id){const t=e.includes("?")?"&":"?";return`${e}${t}group=${n.id}`}return e};return e.map((e,t)=>{if(""===e||"object"==typeof e&&e.divider)return{isDivider:!0,id:`divider-${t}`};if("object"==typeof e&&e.spacer)return{isSpacer:!0,id:`spacer-${t}`};const s={...e};if(s.permissions&&(!i||!i.hasPermission(s.permissions)))return null;if(s.requiresGroupKind){const e=n?._.kind||n?.kind;if(!e||!this._groupKindMatches(s.requiresGroupKind,e))return null}if("label"===s.kind)return s.isLabel=!0,s.id||(s.id=`nav-label-${t}`),s;if(s.id||(s.id=`nav-${t}`),s.route)s.href=a(s.route);else if(s.page){const e=s.page.startsWith("/")?s.page:`/${s.page}`;s.href=a(e),s.route=s.href}return s.children?(s.children=s.children.map(e=>{const t={...e};if(t.permissions&&i&&!i.hasPermission(t.permissions))return null;if(t.requiresGroupKind){const e=n?._.kind||n?.kind;if(!e||!this._groupKindMatches(t.requiresGroupKind,e))return null}if(t.route)t.href=a(t.route);else if(t.page){const e=t.page.startsWith("/")?t.page:`/${t.page}`;t.href=a(e),t.route=t.href}return t}).filter(e=>null!==e),s.hasChildren=!!(s.children&&s.children.length>0)):s.hasChildren=!1,s}).filter(e=>null!==e)}isItemActive(e){if(!e.route||!this.currentRoute)return!1;const t=e=>{if(!e)return"/";const t=decodeURIComponent(e);return t.startsWith("/")?t:`/${t}`},s=t(e.route),i=t(this.currentRoute);return"/"===s&&"/"===i||"/"!==s&&"/"!==i&&(i.startsWith(s)||i===s)}async updateActiveItem(e){return this.currentRoute=e,this.clearAllActiveStates(),this.setActiveItemByRoute(e),await this.render(),this}async handleActionToggleSubmenu(e,t){const s=t.querySelector(".nav-arrow");s&&s.classList.toggle("rotated")}async handleActionToggleSidebar(e,t){this.toggleSidebar()}onActionShowGroupMenu(e,t,s){return this.setActiveMenu("group_default"),!1}async onActionDefault(e,t,s){const i=this.getCurrentMenuConfig();if(i){for(const n of i.items)if(n.action==e&&n.handler)return n.handler(e,t,s),!0;return!1}}getMenuNames(){return Array.from(this.menus.keys())}hasMenu(e){return this.menus.has(e)}clearMenus(){return this.menus.clear(),this.activeMenuName=null,this.render(),this}setMenuData(e){const t=this.getCurrentMenuConfig();return t&&(t.data={...t.data,...e},this.render()),this}getMenuData(){const e=this.getCurrentMenuConfig();return e?e.data:{}}setupRouteListeners(){const e=this.getApp();e&&e.events&&(e.events.on(["page:showing"],e=>{this.onRouteChanged(e)}),e.events.on("group:changed",e=>{this.showMenuForGroup(e.group)}),e.events.on("portal:user-changed",e=>{this.render()}))}onRouteChanged(e){if(e.page&&e.page.route){const t=e.page.route;if(this.activeMenuItem&&this.routesMatch(t,this.activeMenuItem.route))return;this.autoSwitchToMenuForRoute(t)||(this.clearAllActiveStates(),this.setActiveItemByRoute(t),this.updateActiveItem(t))}}toggleSidebar(){const e=document.querySelector(".portal-container");if(!e)return;this.hideAllTooltips();const t=e.classList.contains("collapse-sidebar");return e.classList.contains("hide-sidebar")?(e.classList.remove("hide-sidebar"),this.isCollapsed=!1,this.destroyTooltips()):t?(e.classList.remove("collapse-sidebar"),this.isCollapsed=!1,this.destroyTooltips()):(e.classList.add("collapse-sidebar"),this.isCollapsed=!0,setTimeout(()=>this.initializeTooltips(),150)),this}setSidebarState(e){const t=document.querySelector(".portal-container");if(!t)return this;switch(t.classList.remove("collapse-sidebar","hide-sidebar"),e){case"collapsed":t.classList.add("collapse-sidebar"),this.isCollapsed=!0;break;case"hidden":t.classList.add("hide-sidebar"),this.isCollapsed=!1;break;default:this.isCollapsed=!1}return this.isCollapsed?(this.hideAllTooltips(),setTimeout(()=>this.initializeTooltips(),100)):this.destroyTooltips(),this}initializeTooltips(){return this.destroyTooltips(),this.isCollapsedState()?(this.element.querySelectorAll(".sidebar-nav .nav-link").forEach(e=>{const t=e.querySelector(".nav-text");if(t&&t.textContent.trim()){const s=t.textContent.trim();if(e.setAttribute("data-bs-toggle","tooltip"),e.setAttribute("data-bs-placement","right"),e.setAttribute("data-bs-title",s),e.setAttribute("data-bs-container","body"),window.bootstrap&&window.bootstrap.Tooltip){const t=e.getAttribute("data-tooltip-theme"),s=e.getAttribute("data-tooltip-size");let i="";t&&(i+=`tooltip-${t} `),s&&(i+=`tooltip-${s}`);const n={placement:"right",container:"body",trigger:"hover",delay:{show:500,hide:100},fallbackPlacements:["top","bottom","left"]},a=i.trim();a&&(n.customClass=a);const r=new window.bootstrap.Tooltip(e,n);e._tooltipInstance=r,e.addEventListener("click",()=>{r.hide()}),e.addEventListener("blur",()=>{r.hide()})}}}),this.addTooltipHideListeners(),this):this}destroyTooltips(){return this.removeTooltipHideListeners(),this.element.querySelectorAll('.sidebar-nav .nav-link[data-bs-toggle="tooltip"]').forEach(e=>{const t=e._tooltipInstance||window.bootstrap?.Tooltip?.getInstance(e);t&&(t.hide(),t.dispose()),delete e._tooltipInstance,e.removeAttribute("data-bs-toggle"),e.removeAttribute("data-bs-placement"),e.removeAttribute("data-bs-title"),e.removeAttribute("data-bs-container")}),this}getSidebarState(){const e=document.querySelector(".portal-container");return e?e.classList.contains("hide-sidebar")?"hidden":e.classList.contains("collapse-sidebar")?"collapsed":"normal":"normal"}isCollapsedState(){return"collapsed"===this.getSidebarState()}setToggleEnabled(e){return this.showToggle=e,this.render(),this}initializeMenus(e){if(e.menus)for(const t of e.menus)this.addMenu(t.name,t);else e.menu&&(e.menu.name=e.menu.name||"default",this.addMenu(e.menu.name,e.menu))}addTooltipHideListeners(){this._tooltipScrollHandler=()=>this.hideAllTooltips(),this.element.addEventListener("scroll",this._tooltipScrollHandler,{passive:!0}),this._tooltipRouteHandler=()=>this.hideAllTooltips(),this.getApp(),this._tooltipBlurHandler=()=>this.hideAllTooltips(),window.addEventListener("blur",this._tooltipBlurHandler),this._tooltipEscapeHandler=e=>{"Escape"===e.key&&this.hideAllTooltips()},document.addEventListener("keydown",this._tooltipEscapeHandler)}removeTooltipHideListeners(){this._tooltipScrollHandler&&(this.element.removeEventListener("scroll",this._tooltipScrollHandler),delete this._tooltipScrollHandler),this._tooltipBlurHandler&&(window.removeEventListener("blur",this._tooltipBlurHandler),delete this._tooltipBlurHandler),this._tooltipEscapeHandler&&(document.removeEventListener("keydown",this._tooltipEscapeHandler),delete this._tooltipEscapeHandler)}hideAllTooltips(){this.element.querySelectorAll('.sidebar-nav .nav-link[data-bs-toggle="tooltip"]').forEach(e=>{const t=e._tooltipInstance||window.bootstrap?.Tooltip?.getInstance(e);t&&t.hide()}),document.querySelectorAll(".tooltip.show").forEach(e=>{e.remove()})}async onBeforeDestroy(){this.destroyTooltips(),await super.onBeforeDestroy()}setupResponsiveBehavior(){const e=()=>{const e=window.innerWidth<=768,t=document.querySelector(".portal-container");t&&(e?t.classList.add("sidebar-mobile"):t.classList.remove("sidebar-mobile","sidebar-open"))};e(),window.addEventListener("resize",e)}static createDefault(e={}){return new Sidebar({theme:"sidebar-clean",showToggle:!0,autoCollapseMobile:!0,...e})}static createMinimal(e={}){return new Sidebar({theme:"sidebar-clean",showToggle:!1,autoCollapseMobile:!1,...e})}setSidebarTheme(e){return this.removeClass("sidebar-light sidebar-dark sidebar-clean"),this.sidebarTheme=e,this.addClass(e),this}show(){return this.setSidebarState("normal")}hide(){return this.setSidebarState("hidden")}collapse(){return this.setSidebarState("collapsed")}expand(){return this.setSidebarState("normal")}pulseToggle(){const e=this.element.querySelector(".sidebar-toggle");if(e){e.classList.add("pulse");const t=()=>{e.classList.remove("pulse"),e.removeEventListener("click",t)};e.addEventListener("click",t,{once:!0}),setTimeout(t,3e3)}return this}addSimpleMenuItem(e,t,s,i="bi-circle"){const n=this.menus.get(e);return n&&(n.items=n.items||[],n.items.push({text:t,route:s,icon:i}),this.activeMenuName===e&&this.render()),this}setSimpleMenu(e,t,s){const i={name:e,header:t,items:s};return this.addMenu(e,i),this.setActiveMenu(e),this}}class PageHeader extends t.View{constructor(e={}){super({tagName:"div",className:"page-header",...e}),this.style=e.style||"default",this.size=e.size||"md",this.showIcon=!1!==e.showIcon,this.showDescription=!1!==e.showDescription,this.showBreadcrumbs=e.showBreadcrumbs||!1,this.currentPage=null}async getTemplate(){return"minimal"===this.style?this.getMinimalTemplate():"breadcrumb"===this.style?this.getBreadcrumbTemplate():this.getDefaultTemplate()}getDefaultTemplate(){return'\n {{#data.hasPage}}\n <div class="page-header-content page-header-{{data.size}}">\n <div class="page-header-main">\n <div class="page-header-info">\n {{#data.showIcon}}\n {{#data.pageIcon}}\n <div class="page-icon">\n <i class="{{data.pageIcon}}"></i>\n </div>\n {{/data.pageIcon}}\n {{/data.showIcon}}\n \n <div class="page-title-group">\n <h1 class="page-title">{{data.pageTitle}}</h1>\n {{#data.showDescription}}\n {{#data.pageDescription}}\n <p class="page-description text-muted">{{data.pageDescription}}</p>\n {{/data.pageDescription}}\n {{/data.showDescription}}\n </div>\n </div>\n\n {{#data.hasActions}}\n <div class="page-actions">\n {{#data.actions}}\n <button class="btn {{buttonClass}}" \n data-action="{{action}}"\n type="button">\n {{#icon}}<i class="{{icon}} me-1"></i>{{/icon}}\n {{label}}\n </button>\n {{/data.actions}}\n </div>\n {{/data.hasActions}}\n </div>\n </div>\n {{/data.hasPage}}\n '}getMinimalTemplate(){return'\n {{#data.hasPage}}\n <div class="page-header-content page-header-minimal">\n <h1 class="page-title">\n {{#data.showIcon}}\n {{#data.pageIcon}}<i class="{{data.pageIcon}} me-2"></i>{{/data.pageIcon}}\n {{/data.showIcon}}\n {{data.pageTitle}}\n </h1>\n </div>\n {{/data.hasPage}}\n '}getBreadcrumbTemplate(){return'\n {{#data.hasPage}}\n <div class="page-header-content page-header-breadcrumb">\n {{#data.showBreadcrumbs}}\n <nav aria-label="breadcrumb">\n <ol class="breadcrumb mb-2">\n {{#data.breadcrumbs}}\n <li class="breadcrumb-item {{#active}}active{{/active}}">\n {{#href}}<a href="{{href}}">{{label}}</a>{{/href}}\n {{^href}}{{label}}{{/href}}\n </li>\n {{/data.breadcrumbs}}\n </ol>\n </nav>\n {{/data.showBreadcrumbs}}\n \n <div class="d-flex justify-content-between align-items-start">\n <h1 class="page-title">\n {{#data.showIcon}}\n {{#data.pageIcon}}<i class="{{data.pageIcon}} me-2"></i>{{/data.pageIcon}}\n {{/data.showIcon}}\n {{data.pageTitle}}\n </h1>\n \n {{#data.hasActions}}\n <div class="page-actions">\n {{#data.actions}}\n <button class="btn {{buttonClass}}" \n data-action="{{action}}"\n type="button">\n {{#icon}}<i class="{{icon}} me-1"></i>{{/icon}}\n {{label}}\n </button>\n {{/data.actions}}\n </div>\n {{/data.hasActions}}\n </div>\n \n {{#data.showDescription}}\n {{#data.pageDescription}}\n <p class="page-description text-muted mt-2">{{data.pageDescription}}</p>\n {{/data.pageDescription}}\n {{/data.showDescription}}\n </div>\n {{/data.hasPage}}\n '}async onBeforeRender(){await super.onBeforeRender();const e=this.currentPage,t=!!e,s=e?.options?.headerActions||e?.headerActions||e?.constructor?.prototype?.headerActions||[];this.data={hasPage:t,pageTitle:e?.title||e?.name||"",pageIcon:e?.icon||e?.pageIcon||"",pageDescription:e?.description||"",showIcon:this.showIcon,showDescription:this.showDescription,showBreadcrumbs:this.showBreadcrumbs,breadcrumbs:e?.options?.breadcrumbs||e?.breadcrumbs||[],actions:s,hasActions:s.length>0,size:this.size}}setPage(e){this.currentPage=e,this.mounted&&this.render()}getPage(){return this.currentPage}async onActionDefault(e,t,s){return this.currentPage&&"function"==typeof this.currentPage.onHeaderAction?(await this.currentPage.onHeaderAction(e,t,s),!0):(this.emit("action",{action:e,event:t,element:s,page:this.currentPage}),!1)}}class DeniedPage extends s.Page{constructor(e={}){super({pageName:"Access Denied",route:"/denied",title:"Access Denied",pageIcon:"bi bi-shield-x",template:'\n <div class="container mt-5">\n <div class="row justify-content-center">\n <div class="col-md-8 col-lg-6">\n <div class="text-center mb-4">\n <i class="bi bi-shield-x text-muted" style="font-size: 3rem;"></i>\n <h2 class="mt-3 mb-2">Access Denied</h2>\n <p class="text-muted">You don\'t have permission to access this page.</p>\n </div>\n\n {{#deniedPage}}\n <div class="card border-0 shadow-sm mb-4">\n <div class="card-body">\n <h6 class="card-subtitle mb-2 text-muted">Requested Page</h6>\n <h5 class="card-title">\n <i class="{{pageIcon}} me-2"></i>\n {{displayName}}\n </h5>\n {{#route}}\n <p class="card-text text-muted small">{{route}}</p>\n {{/route}}\n {{#description}}\n <p class="card-text">{{description}}</p>\n {{/description}}\n\n {{#requiredPermissions}}\n <div class="mt-3">\n <h6 class="mb-2">Required Permissions:</h6>\n {{#permissions}}\n <span class="badge bg-light text-dark me-1 mb-1">{{.}}</span>\n {{/permissions}}\n {{^permissions}}\n <span class="text-muted small">Authentication required</span>\n {{/permissions}}\n </div>\n {{/requiredPermissions}}\n </div>\n </div>\n {{/deniedPage}}\n\n <div class="d-grid gap-2 d-md-flex justify-content-md-center">\n <button type="button" class="btn btn-primary" data-action="go-back">\n <i class="bi bi-arrow-left me-1"></i>\n Go Back\n </button>\n <button type="button" class="btn btn-outline-secondary" data-action="go-home">\n <i class="bi bi-house me-1"></i>\n Home\n </button>\n {{#showLogin}}\n <button type="button" class="btn btn-outline-primary" data-action="login">\n <i class="bi bi-box-arrow-in-right me-1"></i>\n Login\n </button>\n {{/showLogin}}\n </div>\n\n {{#currentUser}}\n <div class="text-center mt-4">\n <small class="text-muted">\n Logged in as <strong>{{username}}</strong>\n </small>\n </div>\n {{/currentUser}}\n </div>\n </div>\n </div>\n ',...e}),this.deniedPage=null,this.deniedPageOptions=null}async onParams(e={},t={}){await super.onParams(e,t),e.page?(this.deniedPage=e.page,this.deniedPageOptions=e.page.options||e.page.pageOptions||{}):t.page&&(this.deniedPageName=t.page)}setDeniedPage(e){return this.deniedPage=e,this.deniedPageOptions=e?.options||e?.pageOptions||{},this}async getViewData(){const e=this.getApp(),t=e?.activeUser||e?.getCurrentUser?.()||null;let s=null;if(this.deniedPage){const e=this.deniedPageOptions?.permissions||this.deniedPage.options?.permissions||this.deniedPage.pageOptions?.permissions;s={displayName:this.deniedPage.displayName||this.deniedPage.pageName||this.deniedPage.title||"Unknown Page",pageName:this.deniedPage.pageName,route:this.deniedPage.route,description:this.deniedPage.pageDescription||this.deniedPage.description,pageIcon:this.deniedPage.pageIcon||"bi bi-file-text",requiredPermissions:e?{permissions:Array.isArray(e)?e:[e]}:null}}else this.deniedPageName&&(s={displayName:this.deniedPageName,pageName:this.deniedPageName,pageIcon:"bi bi-file-text"});return{deniedPage:s,currentUser:t?{username:t.username||t.name||t.email||"Unknown User",name:t.name,email:t.email}:null,showLogin:!t}}async handleActionGoBack(e,t){e.preventDefault(),window.history.length>1?window.history.back():await this.handleActionGoHome(e,t)}async handleActionGoHome(e,t){e.preventDefault();const s=this.getApp();s?await s.navigateToDefault():window.location.href="/"}async handleActionLogin(e,t){e.preventDefault();const s=this.getApp();if(s)try{await s.showPage("login")}catch(i){try{await s.navigate("/login")}catch(n){this.emit("login-required",{returnUrl:this.deniedPage?.route||window.location.pathname}),setTimeout(()=>{s?.showInfo?.("Please contact your administrator for access.")},100)}}}async onEnter(){await super.onEnter();const e=this.deniedPage?.pageName||this.deniedPageName;e&&this.setMeta({title:`Access Denied - ${e}`}),console.warn("Access denied to page:",{page:this.deniedPage?.pageName||this.deniedPageName,route:this.deniedPage?.route,permissions:this.deniedPageOptions?.permissions,timestamp:/* @__PURE__ */(new Date).toISOString()})}static showForPage(e,t){const s=new DeniedPage;return s.setDeniedPage(t),e.showPage(s)}}class NotFoundPage extends s.Page{constructor(e={}){super({pageName:"404",route:"/404",title:"404 - Page Not Found",pageIcon:"bi bi-search",template:'\n <div class="container mt-5">\n <div class="row justify-content-center">\n <div class="col-md-8 col-lg-6">\n <div class="text-center mb-4">\n <i class="bi bi-search text-muted" style="font-size: 3rem;"></i>\n <h2 class="mt-3 mb-2">Page Not Found</h2>\n <p class="text-muted">The page you\'re looking for doesn\'t exist.</p>\n </div>\n\n {{#path}}\n <div class="card border-0 shadow-sm mb-4">\n <div class="card-body text-center">\n <h6 class="card-subtitle mb-2 text-muted">Requested Path</h6>\n <code class="text-primary">{{path}}</code>\n </div>\n </div>\n {{/path}}\n\n <div class="d-grid gap-2 d-md-flex justify-content-md-center">\n <button type="button" class="btn btn-primary" data-action="go-back">\n <i class="bi bi-arrow-left me-1"></i>\n Go Back\n </button>\n <button type="button" class="btn btn-outline-secondary" data-action="go-home">\n <i class="bi bi-house me-1"></i>\n Home\n </button>\n </div>\n </div>\n </div>\n </div>\n ',...e}),this.path=null}async onParams(e={},t={}){await super.onParams(e,t),e.path&&(this.path=e.path),t.path&&(this.path=t.path)}setInfo(e){return this.path=e||null,this}async handleActionGoBack(e,t){e.preventDefault(),window.history.length>1?window.history.back():await this.handleActionGoHome(e,t)}async handleActionGoHome(e,t){e.preventDefault();const s=this.getApp();s?await s.navigateToDefault():window.location.href="/"}async onEnter(){await super.onEnter(),this.path&&this.setMeta({title:`404 - ${this.path} Not Found`}),console.warn("404 Not Found:",{path:this.path,timestamp:/* @__PURE__ */(new Date).toISOString()})}static showForPath(e,t){const s=new NotFoundPage;return s.setInfo(t),s.render()}}class PortalApp extends i.WebApp{constructor(e={}){super(e),this.sidebarConfig=e.sidebar,this.topbarConfig=e.topbar||{},e.topnav&&!e.topbar&&(this.topbarConfig=e.topnav),this.showPageHeader=e.showPageHeader||!1,this.pageHeaderConfig=e.pageHeader||{},this.sidebar=null,this.topbar=null,this.topnav=null,this.pageHeader=null,this.tokenManager=new r.TokenManager,this.activeGroup=null,this.isMobile()?this.sidebarCollapsed=this.sidebarConfig.defaultCollapsed||!1:this.sidebarCollapsed=this.loadSidebarState()??(this.sidebarConfig.defaultCollapsed||!1),this.setupPageContainer(),this.toast=new s.ToastService,this.Dialog=i.Dialog,this.registerPage("denied",DeniedPage),this.registerPage("404",NotFoundPage)}async start(){await this.checkAuthStatus(),this.events.on("auth:unauthorized",()=>{this.tokenManager.clearTokens(),this.rest.clearAuth(),this.setActiveUser(null)}),this.events.on("auth:logout",()=>{this.tokenManager.clearTokens(),this.rest.clearAuth(),this.setActiveUser(null)}),this.events.on("browser:focus",()=>{this.activeUser&&this.tokenManager.checkAndRefreshTokens(this)}),this.events.on("portal:action",this.onPortalAction.bind(this)),this.activeUser&&await this.checkActiveGroup(),await this.setupRouter(),this.isStarted=!0,this.events.emit("app:ready",{app:this})}async checkAuthStatus(){const e=this.tokenManager.checkTokenStatus();if("logout"===e.action)return this.events.emit("auth:unauthorized",{app:this}),!1;if("refresh"===e.action&&!(await this.tokenManager.checkAndRefreshTokens(this)))return!1;const t=this.tokenManager.getTokenInstance();if(this.activeUser)return this.tokenManager.startAutoRefresh(this),!0;this.rest.setAuthToken(t.token);const i=new s.User({id:t.getUserId()}),n=await i.fetch();return n.success?(this.setActiveUser(i),this.tokenManager.startAutoRefresh(this),!0):(this.tokenManager.clearTokens(),this.events.emit("auth:unauthorized",{app:this,error:n.error}),!1)}async checkActiveGroup(){const e=new URLSearchParams(window.location.search).get("group"),t=e||this.loadActiveGroupId();if(t)try{const i=new s.Group({id:t}),n=await i.fetch();if(!n.success||!n.data.status)return this.clearActiveGroup(),void console.warn("Failed to load active group:",n.statusText);this.activeGroup=i,e&&this.saveActiveGroupId(t),this.activeUser&&(this.activeUser.member=new a.Member,await this.activeUser.member.fetchForGroup(i.id)),this.events.emit("group:loaded",{group:this.activeGroup})}catch(i){if(console.warn("Failed to load active group:",i),e&&!this.loadActiveGroupId())this.clearActiveGroupId();else if(e){const t=this.loadActiveGroupId();if(t&&t!==e)try{const e=new s.Group({id:t});await e.fetch(),this.activeGroup=e,this.events.emit("group:loaded",{group:this.activeGroup})}catch(n){console.warn("Fallback to stored group also failed:",n),this.clearActiveGroupId()}}}}async setActiveGroup(e){const t=this.activeGroup;this.activeGroup=e,e&&e.get("id")?this.saveActiveGroupId(e.get("id")):this.clearActiveGroupId(),this.activeUser&&(this.activeUser.member=new a.Member,await this.activeUser.member.fetchForGroup(e.id)),this.events.emit("group:changed",{group:e,previousGroup:t,app:this});const s=this.getCurrentPage();return s&&s.onGroupChange&&s.onGroupChange(e),this.router.updateUrl({group:e.id},{replace:!0}),this}getActiveGroup(){return this.activeGroup}async clearActiveGroup(){const e=this.activeGroup;return this.activeGroup=null,this.clearActiveGroupId(),this.events.emit("group:cleared",{previousGroup:e,app:this}),this}saveActiveGroupId(e){try{const t=this.getActiveGroupStorageKey();localStorage.setItem(t,e.toString())}catch(t){console.warn("Failed to save active group ID:",t)}}loadActiveGroupId(){try{const e=this.getActiveGroupStorageKey();return localStorage.getItem(e)}catch(e){return console.warn("Failed to load active group ID:",e),null}}clearActiveGroupId(){try{const e=this.getActiveGroupStorageKey();localStorage.removeItem(e)}catch(e){console.warn("Failed to clear active group ID:",e)}}getActiveGroupStorageKey(){return"active_group_id"}setPortalProfile(e){try{localStorage.setItem("portal_profile",e)}catch(t){console.warn("Failed to save portal profile:",t)}}needsGroupSelection(){return!this.activeGroup}setupPageContainer(){const e="string"==typeof this.container?document.querySelector(this.container):this.container;if(!e)throw new Error(`Portal container not found: ${this.container}`);const t=this.sidebarConfig&&Object.keys(this.sidebarConfig).length>0,s=this.topbarConfig&&Object.keys(this.topbarConfig).length>0,i=this.showPageHeader?'\n <div class="portal-content" id="portal-content">\n <div id="page-header"></div>\n <div id="page-container">\n \x3c!-- Pages render here --\x3e\n </div>\n </div>\n ':'\n <div class="portal-content" id="page-container">\n \x3c!-- Pages render here --\x3e\n </div>\n ';e.innerHTML=`\n <div class="portal-layout hide-sidebar">\n ${t?'<div id="portal-sidebar"></div>':""}\n <div class="portal-body">\n ${s?'<div id="portal-topnav"></div>':""}\n ${i}\n </div>\n </div>\n `,this.pageContainer="#page-container",e.classList.add("portal-container"),this.setupPortalComponents(),this.applySidebarState(e)}async setupPortalComponents(){await this.setupSidebar(),await this.setupTopbar(),await this.setupPageHeader(),this.setupPortalEvents()}async setupSidebar(){this.sidebarConfig&&0!==Object.keys(this.sidebarConfig).length&&(this.sidebar=new Sidebar({containerId:"portal-sidebar",...this.sidebarConfig}),await this.sidebar.render())}async setupTopbar(){this.topbarConfig&&0!==Object.keys(this.topbarConfig).length&&(this.topbar=new r.TopNav({containerId:"portal-topnav",brandText:this.topbarConfig.brand||this.brand||this.title,brandRoute:this.topbarConfig.brandRoute||"/",brandIcon:this.topbarConfig.brandIcon||this.brandIcon,navItems:this.topbarConfig.leftItems||[],rightItems:this.topbarConfig.rightItems||[],displayMode:this.topbarConfig.displayMode||"both",showSidebarToggle:this.topbarConfig.showSidebarToggle||!1,...this.topbarConfig}),await this.topbar.render(),this.topnav=this.topbar)}async setupPageHeader(){if(!this.showPageHeader)return;this.pageHeader=new PageHeader({containerId:"page-header",style:this.pageHeaderConfig.style||"default",showIcon:!1!==this.pageHeaderConfig.showIcon,showDescription:!1!==this.pageHeaderConfig.showDescription,showBreadcrumbs:this.pageHeaderConfig.showBreadcrumbs||!1,...this.pageHeaderConfig});const e=document.getElementById("page-header");e&&await this.pageHeader.render(!0,e)}setupPortalEvents(){if(document.addEventListener("click",e=>{e.target.closest('[data-action="toggle-sidebar"]')&&(e.preventDefault(),this.toggleSidebar())}),window.ResizeObserver){const e=new ResizeObserver(()=>{this.handleResponsive()});e.observe(document.body),this._resizeObserver=e}else this._resizeHandler=()=>this.handleResponsive(),window.addEventListener("resize",this._resizeHandler);this.handleResponsive()}toggleSidebar(){if(!this.sidebar)return;const e=document.querySelector(".portal-container"),t=this.isMobile();t?e.classList.toggle("hide-sidebar"):(e.classList.toggle("collapse-sidebar"),this.sidebarCollapsed=!this.sidebarCollapsed,this.saveSidebarState(this.sidebarCollapsed)),this.events.emit("sidebar:toggled",{collapsed:this.sidebarCollapsed,mobile:t})}handleResponsive(){const e=document.querySelector(".portal-container");if(!e)return;const t=this.isMobile();t?(e.classList.add("mobile-layout"),e.classList.contains("hide-sidebar")||e.classList.add("hide-sidebar")):e.classList.remove("mobile-layout","hide-sidebar"),this.events.emit("responsive:changed",{mobile:t})}getPortalContainer(){return document.querySelector(".portal-container")}isMobile(){return window.innerWidth<768}hasMobileLayout(){return this.getPortalContainer().classList.contains("mobile-layout")}async showPage(e,t={},s={},i={}){const n=await super.showPage(e,t,s,i);return this.hasMobileLayout()&&this.getPortalContainer().classList.add("hide-sidebar"),this.currentPage&&this.updateNavigation(this.currentPage),n}updateNavigation(e){this.sidebar&&this.sidebar.setActivePage&&this.sidebar.setActivePage(e.route),this.topbar&&this.topbar.setActivePage&&this.topbar.setActivePage(e.route),this.pageHeader&&this.pageHeader.setPage(e),this.events.emit("portal:page-changed",{page:e})}setActiveUser(e){this.activeUser=e,this.topbar&&this.topbar.setUser(e),this.events.emit("portal:user-changed",{user:e})}getActiveUser(){return this.activeUser}saveSidebarState(e){try{const t=this.getSidebarStorageKey();localStorage.setItem(t,JSON.stringify(e))}catch(t){console.warn("Failed to save sidebar state:",t)}}loadSidebarState(){try{const e=this.getSidebarStorageKey(),t=localStorage.getItem(e);return null!==t?JSON.parse(t):null}catch(e){return console.warn("Failed to load sidebar state:",e),null}}getSidebarStorageKey(){return`${this.title?this.title.replace(/\s+/g,"_").toLowerCase():"portal_app"}_sidebar_collapsed`}applySidebarState(e=null){e||(e=document.querySelector(".portal-container")),e&&(this.sidebarCollapsed?e.classList.add("collapse-sidebar"):e.classList.remove("collapse-sidebar"))}clearSidebarState(){try{const e=this.getSidebarStorageKey();localStorage.removeItem(e)}catch(e){console.warn("Failed to clear sidebar state:",e)}}async changePassword(){const e=await this.showForm({title:"Change Password",fields:[{name:"current_password",type:"password",label:"Current Password",required:!0,showToggle:!0,strengthMeter:!0,capsLockWarning:!0},{name:"new_password",type:"password",label:"New Password",required:!0,showToggle:!0,passwordUsage:"new",strengthMeter:!0,capsLockWarning:!0,attributes:{autocomplete:"new-password"}},{name:"confirm_password",type:"password",label:"Confirm Password",required:!0,showToggle:!0,passwordUsage:"new",strengthMeter:!0,capsLockWarning:!0,attributes:{}}],submitLabel:"Change Password"});e&&(e.new_password===e.confirm_password?200===(await this.activeUser.save(e)).status?this.toast.success("Password changed successfully"):this.toast.error("Failed to change password"):this.toast.error("Passwords do not match"))}onPortalAction(e){switch(e.action){case"logout":this.tokenManager.clearTokens(),this.rest.clearAuth(),this.setActiveUser(null);break;case"profile":this.showProfile();break;case"change-password":this.changePassword();break;default:console.warn(`Unknown portal action: ${e}`)}}async showProfile(){if(this.activeUser)try{const e=await i.Dialog.showModelForm({title:"Edit Profile",size:"lg",fileHandling:"base64",model:this.activeUser,fields:[{type:"header",text:"Profile Information",level:4,class:"text-primary mb-3"},{type:"group",columns:{xs:12,md:4},title:"Avatar",fields:[{type:"image",name:"avatar",size:"lg",imageSize:{width:200,height:200},placeholder:"Upload your avatar",help:"Square images work best"}]},{type:"group",columns:{xs:12,md:8},title:"Details",fields:[{type:"text",name:"display_name",label:"Display Name",required:!0,columns:12,placeholder:"Enter first name"},{type:"email",name:"email",label:"Email Address",required:!0,columns:8,placeholder:"your.email@example.com"},{type:"tel",name:"phone_number",label:"Phone Number",columns:4,placeholder:"(555) 123-4567"}]},{type:"group",columns:12,title:"Account Settings",class:"pt-3",fields:[{type:"select",name:"timezone",label:"Timezone",columns:6,options:[{value:"America/New_York",text:"Eastern Time"},{value:"America/Chicago",text:"Central Time"},{value:"America/Denver",text:"Mountain Time"},{value:"America/Los_Angeles",text:"Pacific Time"},{value:"UTC",text:"UTC"}]},{type:"select",name:"language",label:"Language",columns:6,options:[{value:"en",text:"English"},{value:"es",text:"Spanish"},{value:"fr",text:"French"},{value:"de",text:"German"}]},{type:"switch",name:"email_notifications",label:"Email Notifications",columns:4},{type:"switch",name:"two_factor_enabled",label:"Two-Factor Authentication",columns:4},{type:"switch",name:"profile_public",label:"Public Profile",columns:4}]}],submitText:"Save Profile",cancelText:"Cancel"});e&&e.success?this.showSuccess("Profile updated successfully!"):e&&e.success}catch(e){console.error("Error showing profile form:",e),this.showError("Failed to load profile form")}else this.showError("No user is currently logged in")}async destroy(){this.activeGroup=null,this._resizeObserver&&this._resizeObserver.disconnect(),this._resizeHandler&&window.removeEventListener("resize",this._resizeHandler),this.topbar&&(await this.topbar.destroy(),this.topbar=null,this.topnav=null),this.sidebar&&(await this.sidebar.destroy(),this.sidebar=null),await super.destroy()}static create(e={}){return new PortalApp(e)}}const P=new class{constructor(){this.formatter=t.dataFormatter,this.compiledTemplates=/* @__PURE__ */new Map}render(e,s,i={}){return t.Mustache.render(e,s,i)}compile(e){const s=t.Mustache.parse(e);return this.compiledTemplates.set(e,s),s}renderCompiled(e,s,i={}){return t.Mustache.render(e,s,i)}clearCache(){this.compiledTemplates.clear(),t.Mustache.clearCache()}cache(e,t){return{key:e,template:t,compiled:this.compile(t)}}getCached(e){for(const[t,s]of this.compiledTemplates)if(t===e||s===e)return{key:e,template:t,compiled:s};return null}registerFormatter(e,t){return this.formatter.register(e,t),this}hasPipes(e){return/\{\{[{]?[^}|]+\|[^}]+\}[}]?\}/.test(e)}processData(e,t){const s={...e};for(const[i,n]of Object.entries(t))if(e&&"function"==typeof e.get)s[i]=e.get(`${i}|${n}`);else{const t=this.getValueFromPath(e,i);s[i]=this.formatter.pipe(t,n)}return s}getValueFromPath(e,t){if(!e||!t)return;if(e&&"function"==typeof e.get)return e.get(t);const s=t.split(".");let i=e;for(const n of s){if(null==i)return;i=!isNaN(n)&&Array.isArray(i)?i[parseInt(n)]:i[n]}return i}processTemplate(e,t){return{template:e,data:t}}};L.install({level:"warn"});const M="MOJO",A="web-mojo",T={FRAMEWORK_NAME:M,PACKAGE_NAME:A};exports.BUILD_TIME=e.BUILD_TIME,exports.VERSION=e.VERSION,exports.VERSION_INFO=e.VERSION_INFO,exports.VERSION_MAJOR=e.VERSION_MAJOR,exports.VERSION_MINOR=e.VERSION_MINOR,exports.VERSION_REVISION=e.VERSION_REVISION,exports.DataWrapper=t.DataWrapper,exports.EventDelegate=t.EventDelegate,exports.MOJOUtils=t.MOJOUtils,exports.Rest=t.rest,exports.View=t.View,exports.dataFormatter=t.dataFormatter,exports.ContextMenu=s.ContextMenu,exports.Group=s.Group,exports.GroupForms=s.GroupForms,exports.GroupList=s.GroupList,exports.Page=s.Page,exports.ToastService=s.ToastService,exports.User=s.User,exports.UserDataView=s.UserDataView,exports.UserDevice=s.UserDevice,exports.UserDeviceList=s.UserDeviceList,exports.UserDeviceLocation=s.UserDeviceLocation,exports.UserDeviceLocationList=s.UserDeviceLocationList,exports.UserForms=s.UserForms,exports.UserList=s.UserList,exports.Dialog=i.Dialog,exports.EventBus=i.EventBus,exports.Router=i.Router,exports.WebApp=i.WebApp,exports.Collection=n.Collection,exports.Model=n.Model,exports.BundleByOptions=a.BundleByOptions,exports.ChatInputView=a.ChatInputView,exports.ChatMessageView=a.ChatMessageView,exports.ChatView=a.ChatView,exports.CommonEventFields=a.CommonEventFields,exports.ComparatorOptions=a.ComparatorOptions,exports.EmailDomain=a.EmailDomain,exports.EmailDomainForms=a.EmailDomainForms,exports.EmailDomainList=a.EmailDomainList,exports.EmailTemplate=a.EmailTemplate,exports.EmailTemplateForms=a.EmailTemplateForms,exports.EmailTemplateList=a.EmailTemplateList,exports.File=a.File,exports.FileForms=a.FileForms,exports.FileList=a.FileList,exports.FileManager=a.FileManager,exports.FileManagerForms=a.FileManagerForms,exports.FileManagerList=a.FileManagerList,exports.FilePreviewView=a.FilePreviewView,exports.FileUpload=a.FileUpload,exports.GeoLocatedIP=a.GeoLocatedIP,exports.GeoLocatedIPList=a.GeoLocatedIPList,exports.Incident=a.Incident,exports.IncidentEvent=a.IncidentEvent,exports.IncidentEventForms=a.IncidentEventForms,exports.IncidentEventList=a.IncidentEventList,exports.IncidentForms=a.IncidentForms,exports.IncidentHistory=a.IncidentHistory,exports.IncidentHistoryList=a.IncidentHistoryList,exports.IncidentList=a.IncidentList,exports.IncidentRule=a.IncidentRule,exports.IncidentRuleList=a.IncidentRuleList,exports.IncidentRuleSet=a.IncidentRuleSet,exports.IncidentRuleSetList=a.IncidentRuleSetList,exports.IncidentStats=a.IncidentStats,exports.Job=a.Job,exports.JobEvent=a.JobEvent,exports.JobEventList=a.JobEventList,exports.JobForms=a.JobForms,exports.JobList=a.JobList,exports.JobLog=a.JobLog,exports.JobLogList=a.JobLogList,exports.JobRunner=a.JobRunner,exports.JobRunnerForms=a.JobRunnerForms,exports.JobRunnerList=a.JobRunnerList,exports.JobsEngineStats=a.JobsEngineStats,exports.Log=a.Log,exports.LogList=a.LogList,exports.Mailbox=a.Mailbox,exports.MailboxForms=a.MailboxForms,exports.MailboxList=a.MailboxList,exports.MatchByOptions=a.MatchByOptions,exports.Member=a.Member,exports.MemberForms=a.MemberForms,exports.MemberList=a.MemberList,exports.MetricsForms=a.MetricsForms,exports.MetricsPermission=a.MetricsPermission,exports.MetricsPermissionList=a.MetricsPermissionList,exports.ProgressView=a.ProgressView,exports.PushConfig=a.PushConfig,exports.PushConfigForms=a.PushConfigForms,exports.PushConfigList=a.PushConfigList,exports.PushDelivery=a.PushDelivery,exports.PushDeliveryList=a.PushDeliveryList,exports.PushDevice=a.PushDevice,exports.PushDeviceList=a.PushDeviceList,exports.PushTemplate=a.PushTemplate,exports.PushTemplateForms=a.PushTemplateForms,exports.PushTemplateList=a.PushTemplateList,exports.Rule=a.Rule,exports.RuleForms=a.RuleForms,exports.RuleList=a.RuleList,exports.RuleSet=a.RuleSet,exports.RuleSetForms=a.RuleSetForms,exports.RuleSetList=a.RuleSetList,exports.S3Bucket=a.S3Bucket,exports.S3BucketForms=a.S3BucketForms,exports.S3BucketList=a.S3BucketList,exports.SentMessage=a.SentMessage,exports.SentMessageForms=a.SentMessageForms,exports.SentMessageList=a.SentMessageList,exports.TabView=a.TabView,exports.TablePage=a.TablePage,exports.TableRow=a.TableRow,exports.TableView=a.TableView,exports.Ticket=a.Ticket,exports.TicketCategories=a.TicketCategories,exports.TicketForms=a.TicketForms,exports.TicketList=a.TicketList,exports.TicketNote=a.TicketNote,exports.TicketNoteList=a.TicketNoteList,exports.ValueTypeOptions=a.ValueTypeOptions,exports.SimpleSearchView=r.SimpleSearchView,exports.TokenManager=r.TokenManager,exports.TopNav=r.TopNav,exports.ListView=o.ListView,exports.ListViewItem=o.ListViewItem,exports.DataView=l.default,exports.FormView=c.FormView,exports.applyFileDropMixin=c.applyFileDropMixin,exports.WebSocketClient=d.WebSocketClient,exports.ConsoleSilencer=L,exports.FRAMEWORK_NAME=M,exports.MustacheFormatter=P,exports.PACKAGE_NAME=A,exports.PortalApp=PortalApp,exports.Sidebar=Sidebar,exports.default=T,exports.installConsoleSilencer=e=>L.install(e);
|
|
1
|
+
"use strict";Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});const e=require("./chunks/version-Bado0p82.js"),t=require("./chunks/Rest-29RtA7pe.js"),s=require("./chunks/ContextMenu-DvsDXgOe.js"),i=require("./chunks/Dialog-Cl_rBFSh.js"),n=require("./chunks/Collection-CREl6Fa9.js"),a=require("./chunks/ChatView-DoA8h81E.js"),r=require("./chunks/TokenManager-Bh1WshcR.js"),o=require("./chunks/ListView-Xcsfu4IL.js"),l=require("./chunks/DataView-Bm8dffDn.js"),c=require("./chunks/FormView-DMMUiciW.js"),d=require("./chunks/WebSocketClient-DcJBT-iB.js");var h="undefined"!=typeof document?document.currentScript:null;const u={BASE_URL:"/",DEV:!1,MODE:"production",PROD:!0,SSR:!1},p=Object.freeze({silent:0,error:1,warn:2,info:3,log:3,debug:4,trace:5,all:5}),g=(()=>{try{if(void 0!=={url:"undefined"==typeof document?require("url").pathToFileURL(__filename).href:h&&"SCRIPT"===h.tagName.toUpperCase()&&h.src||new URL("index.cjs.js",document.baseURI).href}&&("undefined"==typeof document?require("url").pathToFileURL(__filename).href:h&&"SCRIPT"===h.tagName.toUpperCase()&&h.src||new URL("index.cjs.js",document.baseURI).href,1)&&u)return!1}catch{}if("undefined"!=typeof globalThis&&void 0!==globalThis.__DEV__)try{return!!globalThis.__DEV__}catch{}return!("undefined"==typeof process||!process||"object"!=typeof process.env||"string"!=typeof process.env.NODE_ENV)&&"production"!==process.env.NODE_ENV})(),m="undefined"!=typeof window&&"undefined"!=typeof document,b="undefined"!=typeof globalThis?globalThis:"undefined"!=typeof window?window:global,v=b.console||{},f={};let w=!1,y=null;function x(e){if("number"==typeof e){const t=p.silent,s=p.trace;return Math.min(Math.max(e,t),s)}if("string"==typeof e){const t=e.toLowerCase();if(Object.prototype.hasOwnProperty.call(p,t))return p[t]}return null}function S(e,t){const s=f[e]||v[e]||(()=>{});return function(...e){if(y>=t)return s.apply(v,e)}}const L={install(e={}){if(w)return e&&void 0!==e.level&&this.setLevel(e.level,{persist:!!e.persist}),this;if(!b||!v)return w=!0,this;y=function(e){const t=x(e);if(null!==t)return t;const s=function(){if(!m||"undefined"==typeof location||!location.search)return null;try{const e=new URLSearchParams(location.search),t=["logLevel","loglevel","mojoLog"];for(const s of t){const t=e.get(s);if(null!=t){const e=x(t);if(null!==e)return e}}}catch{}return null}();if(null!==s)return s;const i=function(){if(!m||!("localStorage"in b))return null;try{const e=b.localStorage.getItem("MOJO_LOG_LEVEL");if(null!=e){const t=x(e);if(null!==t)return t}}catch{}return null}();return null!==i?i:x(g?"debug":"warn")}(e.level);const t=function(){const e={...v},t={error:p.error,warn:p.warn,info:p.info,log:p.info,dir:p.info,table:p.info,debug:p.debug,group:p.debug,groupCollapsed:p.debug,groupEnd:p.debug,time:p.debug,timeEnd:p.debug,timeLog:p.debug,trace:p.trace};for(const s of Object.keys(t))f[s]=v[s]||(()=>{}),e[s]=S(s,t[s]);return f.assert=v.assert||(()=>{}),e.assert=function(){const e=f.assert||v.assert||(()=>{});return function(t,...s){if(!t)return y>=p.error?e.apply(v,[t,...s]):void 0}}(),e}();return b.console=t,w=!0,b.MOJOConsoleSilencer=this,this},uninstall(){if(!w)return this;try{b.console=v}catch{}return w=!1,this},setLevel(e,{persist:t=!1}={}){const s=x(e);return null===s||(y=s,t&&function(e){if(m&&"localStorage"in b)try{const t="string"==typeof e?e:null===e?null:Object.entries(p).find(([,t])=>t===e)?.[0]??null;t?b.localStorage.setItem("MOJO_LOG_LEVEL",t):b.localStorage.removeItem("MOJO_LOG_LEVEL")}catch{}}(e)),this},getLevel:()=>y,getLevelName(){const e=Object.entries(p).find(([,e])=>e===y);return e?e[0]:null},criticalOnly({persist:e=!1}={}){return this.setLevel("warn",{persist:e})},errorsOnly({persist:e=!1}={}){return this.setLevel("error",{persist:e})},silent({persist:e=!1}={}){return this.setLevel("silent",{persist:e})},verbose({persist:e=!1}={}){return this.setLevel(g?"debug":"info",{persist:e})},allowAll({persist:e=!1}={}){return this.setLevel("trace",{persist:e})},withTemporaryLevel(e,t){const s=y,i=x(e);if(null===i||"function"!=typeof t)return t?.();y=i;try{return t()}finally{y=s}},LEVELS:p};class GroupSearchView extends r.SimpleSearchView{constructor(e={}){super({...e,className:`group-search-view ${e.className||""}`.trim()}),this.showKind=void 0===e.showKind||e.showKind,this.parentField=e.parentField||"parent",this.kindField=e.kindField||"kind",this.treeData=[],this.flattenedItems=[],this.showLines=void 0===e.showLines||e.showLines}buildTreeHierarchy(e){if(!e||0===e.length)return[];const t=/* @__PURE__ */new Map;e.forEach(e=>{t.has(e.id)||t.set(e.id,{...e,children:[],level:0,hasChildren:!1});const s=e[this.parentField];s&&s.id&&!t.has(s.id)&&t.set(s.id,{...s,children:[],level:0,hasChildren:!1})});const s=[];t.forEach((i,n)=>{const a=e.find(e=>e.id===n)||i,r=a[this.parentField]?.id;if(r&&t.has(r)){const e=t.get(r);e.children.push(i),e.hasChildren=!0}else s.push(i)});const i=(e,t=0)=>{e.forEach(e=>{e.level=t,e.children.length>0&&(e.children.sort((e,t)=>(e.name||"").localeCompare(t.name||"")),i(e.children,t+1))})};return s.sort((e,t)=>(e.name||"").localeCompare(t.name||"")),i(s),s}flattenTree(e,t=[],s=[]){return e.forEach((i,n)=>{i._isLastChild=n===e.length-1,i._ancestorLastFlags=[...s];const a=s.every(e=>e);if(i._isLastDescendant=a&&i._isLastChild&&(!i.children||0===i.children.length),t.push(i),i.children&&i.children.length>0){const e=[...s,i._isLastChild];this.flattenTree(i.children,t,e)}}),t}computeVerticalLines(e){for(let t=0;t<e.length;t++){const s=e[t];s._continueVertical=[];for(let i=0;i<s.level;i++){let n=!1;for(let s=t+1;s<e.length;s++){const t=e[s];if(t.level===i+1){n=!0;break}if(t.level<=i)break}s._continueVertical[i]=n}}}updateFilteredItems(){if(!this.collection)return this.filteredItems=[],this.treeData=[],void(this.flattenedItems=[]);const e=this.collection.toJSON();this.treeData=this.buildTreeHierarchy(e),this.flattenedItems=this.flattenTree(this.treeData),this.computeVerticalLines(this.flattenedItems),this.filteredItems=this.flattenedItems,this.updateResultsView()}getDefaultItemTemplate(){return'\n <div class="tree-item-content">\n <div class="tree-item-name">{{name}}</div>\n {{#showKind}}\n <div class="tree-item-kind">{{kind}}</div>\n {{/showKind}}\n </div>\n '}processItemTemplate(e){let t=this.itemTemplate;t=t.replace(/\{\{(\w+)\}\}/g,(t,s)=>"showKind"===s?this.showKind?"true":"":this.getNestedValue(e,s)||""),t=this.showKind?t.replace(/\{\{#showKind\}\}(.*?)\{\{\/showKind\}\}/gs,"$1"):t.replace(/\{\{#showKind\}\}.*?\{\{\/showKind\}\}/gs,"");let s="";if(this.showLines&&e.level>0)for(let i=0;i<e.level;i++)i===e.level-1?s+=`<span class="${e._isLastChild?"tree-seg tree-seg-last":"tree-seg tree-seg-mid"}"></span>`:s+=e._continueVertical&&e._continueVertical[i]?'<span class="tree-seg tree-seg-vert"></span>':'<span class="tree-seg"></span>';return`\n <div class="tree-item-wrapper${e.hasChildren?" has-children":""}${e._isLastChild?" is-last-child":""}" data-tree-level="${e.level}">\n <div class="tree-lines">\n ${s}\n </div>\n <div class="tree-item-body flex-grow-1">\n ${t}\n </div>\n </div>\n `}getRootItems(){return this.treeData}getNodeChildren(e){const t=(e,s)=>{for(const i of e){if(i.id===s)return i.children;if(i.children.length>0){const e=t(i.children,s);if(e)return e}}return null};return t(this.treeData,e)||[]}}class Sidebar extends t.View{constructor(e={}){super({tagName:"nav",className:"sidebar",id:"sidebar",...e}),this.menus=/* @__PURE__ */new Map,this.activeMenuName=null,this.currentRoute=null,this.showToggle=e.showToggle,this.isCollapsed=!1,this.sidebarTheme=e.theme||"sidebar-light",this.customView=null,this.options.groupHeader&&(this.groupHeader=this.options.groupHeader),this.groupSelectorMode=e.groupSelectorMode||"inline",this.groupSelectorDialog=null,this.sidebarTheme&&this.addClass(this.sidebarTheme),this.initializeMenus(e),this.setupRouteListeners(),!1!==e.autoCollapseMobile&&this.setupResponsiveBehavior()}groupHeader='\n {{#group.parent}}\n <div class="sidebar-parent-bar" data-action="select-group-parent">\n <div class="parent-info">\n <span class="parent-label">{{group.parent.kind}}:</span>\n <span class="parent-name collapsed-hidden">{{group.parent.name}}</span>\n </div>\n <i class="bi bi-chevron-down parent-expand collapsed-hidden"></i>\n </div>\n {{/group.parent}}\n <div class="sidebar-selected-group-row" data-action="show-group-search">\n <div class="selected-group-info">\n <div class=\'selected-group-name collapsed-hidden\'>{{group.name}}</div>\n <div class=\'selected-group-meta collapsed-hidden\'>\n <span class="selected-group-kind">{{group.kind}}</span>\n </div>\n </div>\n <i class="bi bi-chevron-down selected-group-chevron collapsed-hidden"></i>\n </div>\n ';async onInit(){await super.onInit();const e=this.getApp(),t=e?.router;if(t){const e=t.getCurrentPath();e&&this.autoSwitchToMenuForRoute(e)}this.initializeTooltips(),this.searchView=new GroupSearchView({noAppend:!0,showExitButton:!0,headerText:"Select Group",containerId:"sidebar-search-container",Collection:s.GroupList,itemTemplate:'\n <div class="p-3 border-bottom">\n <div class="fw-semibold text-dark">{{name}}</div>\n <small class="text-muted">#{{id}} {{kind}}</small>\n </div>\n '}),this.addChild(this.searchView),this.searchView.on("item:selected",e=>{this.getApp().setActiveGroup(e.model)}),this.searchView.on("exit",e=>{this.hideGroupSearch()})}showGroupSearch(){"dialog"===this.groupSelectorMode?this.showGroupSearchDialog():(this.setClass("sidebar"),this.showSearch=!0,this.render())}hideGroupSearch(){"dialog"===this.groupSelectorMode?this.groupSelectorDialog&&this.groupSelectorDialog.hide():(this.setClass("sidebar"),this.showSearch=!1,this.render())}onActionShowGroupSearch(){this.showGroupSearch()}async onActionSelectGroupParent(){const e=this.getApp().activeGroup;if(await i.Dialog.confirm(`Are you sure you want to navigate to the '${e.get("parent.name")}'?`)){this.getApp().showLoading();let t=new s.Group({id:e.get("parent.id")});await t.fetch(),this.getApp().setActiveGroup(t),this.getApp().hideLoading()}}async showGroupSearchDialog(){const e=new s.GroupList,t=new GroupSearchView({Collection:s.GroupList,collection:e,searchFields:["name"],headerText:null,searchPlaceholder:"Search groups...",headerIcon:null,maxHeight:Math.min(600,window.innerHeight-200),showExitButton:!1,showKind:!0,parentField:"parent",kindField:"kind",autoExpandRoot:!0,autoExpandAll:!1,indentSize:20,showLines:!0});this.groupSelectorDialog=new i.Dialog({body:t,size:"md",header:null,noBodyPadding:!0,scrollable:!1,buttons:[],closeButton:!0}),t.on("item:selected",e=>{this.getApp().setActiveGroup(e.model),this.groupSelectorDialog&&this.groupSelectorDialog.hide()}),this.groupSelectorDialog.on("hidden",()=>{this.groupSelectorDialog.destroy(),this.groupSelectorDialog=null}),await this.groupSelectorDialog.render(!0,document.body),this.groupSelectorDialog.show()}autoSwitchToMenuForRoute(e){for(const[t,s]of this.menus)if((!s.groupKind||this.getApp().activeGroup)&&this.menuContainsRoute(s,e))return this._setActiveMenu(t),this.currentRoute=e,this.clearAllActiveStates(),this.setActiveItemByRoute(e),this.render(),this.emit("menu-auto-switched",{menuName:t,route:e,config:s,sidebar:this}),!0;return!1}clearAllActiveStates(){for(const[e,t]of this.menus)for(const s of t.items||[])if(s.active=!1,s.children)for(const e of s.children)e.active=!1}setActiveItemByRoute(e){const t=e=>{if(!e)return"/";const t=decodeURIComponent(e);return t.startsWith("/")?t:`/${t}`},s=t(e);for(const[i,n]of this.menus)if(!n.groupKind||this.getApp().activeGroup)for(const e of n.items||[]){if(e.route){const i=t(e.route);if(this.routesMatch(s,i))return e.active=!0,this.activeMenuItem=e,!0}if(e.children)for(const i of e.children)if(i.route){const n=t(i.route);if(this.routesMatch(s,n))return i.active=!0,e.active=!0,!0}}return!1}menuContainsRoute(e,t){const s=e=>{if(!e)return"/";const t=decodeURIComponent(e);return t.startsWith("/")?t:`/${t}`},i=s(t);for(const n of e.items||[]){if(n.route){const e=s(n.route);if(this.routesMatch(i,e))return!0}if(n.children)for(const e of n.children)if(e.route){const t=s(e.route);if(this.routesMatch(i,t))return!0}}return!1}routesMatch(e,t){return this.getApp().router.doRoutesMatch(e,t)}getTemplate(){return this.customView?'<div class="sidebar-container" id="sidebar-custom-view-container"></div>':this.showSearch?this.getSearchTemplate():this.getMenuTemplate()}getSearchTemplate(){return'\n <div class="sidebar-container" id="sidebar-search-container">\n </div>\n '}getMenuTemplate(){return'\n <div class="sidebar-container">\n {{#data.currentMenu}}\n \x3c!-- Header --\x3e\n {{#header}}\n <div class="sidebar-header">\n {{{header}}}\n {{#showToggle}}\n <button class="sidebar-toggle" data-action="toggle-sidebar"\n aria-label="Toggle Sidebar">\n <i class="bi bi-chevron-left toggle-icon"></i>\n <i class="bi bi-chevron-right toggle-icon"></i>\n </button>\n {{/showToggle}}\n </div>\n {{/header}}\n\n \x3c!-- Navigation Items --\x3e\n <div class="sidebar-body">\n <ul class="nav nav-pills flex-column sidebar-nav" id="sidebar-nav-menu">\n {{#items}}\n {{>nav-item}}\n {{/items}}\n </ul>\n </div>\n\n \x3c!-- Footer --\x3e\n {{#footer}}\n <div class="sidebar-footer">\n {{{footer}}}\n </div>\n {{/footer}}\n {{/data.currentMenu}}\n\n {{^data.currentMenu}}\n <div class="sidebar-empty">\n <p class="text-danger text-center">No menu configured</p>\n </div>\n {{/data.currentMenu}}\n </div>\n '}getPartials(){return{"nav-item":'\n {{#isDivider}}\n {{>nav-divider}}\n {{/isDivider}}\n {{#isSpacer}}\n {{>nav-spacer}}\n {{/isSpacer}}\n {{#isLabel}}\n {{>nav-label}}\n {{/isLabel}}\n\n {{^isDivider}}\n {{^isSpacer}}\n {{^isLabel}}\n <li class="nav-item">\n {{#hasChildren}}\n \x3c!-- Item with submenu --\x3e\n <a class="nav-link {{#active}}active{{/active}} has-children collapsed"\n data-bs-toggle="collapse"\n href="#collapse-{{id}}"\n role="button"\n aria-expanded="{{#active}}true{{/active}}{{^active}}false{{/active}}"\n data-action="toggle-submenu">\n {{#icon}}<i class="{{icon}} me-2"></i>{{/icon}}\n <span class="nav-text">{{text}}</span>\n {{#badge}}\n <span class="{{badge.class}} ms-auto">{{badge.text}}</span>\n {{/badge}}\n <i class="bi bi-chevron-down nav-arrow ms-auto"></i>\n </a>\n <div class="collapse {{#active}}show{{/active}}" id="collapse-{{id}}" data-bs-parent="#sidebar-nav-menu">\n <ul class="nav flex-column nav-submenu">\n {{#children}}\n <li class="nav-item">\n <a class="nav-link {{#active}}active{{/active}}"\n {{#action}}data-action="{{action}}"{{/action}}\n {{#href}}href="{{href}}"{{/href}}>\n {{#icon}}<i class="{{icon}} me-2"></i>{{/icon}}\n <span class="nav-text">{{text}}</span>\n {{#badge}}\n <span class="{{badge.class}} ms-auto">{{badge.text}}</span>\n {{/badge}}\n </a>\n </li>\n {{/children}}\n </ul>\n </div>\n {{/hasChildren}}\n {{^hasChildren}}\n \x3c!-- Simple item --\x3e\n <a class="nav-link {{#active}}active{{/active}} {{#disabled}}disabled{{/disabled}}"\n {{#action}}{{^disabled}}data-action="{{action}}"{{/disabled}}{{/action}}\n {{#href}}{{^disabled}}href="{{href}}"{{/disabled}}{{/href}}>\n {{#icon}}<i class="{{icon}} me-2"></i>{{/icon}}\n <span class="nav-text">{{text}}</span>\n {{#badge}}\n <span class="{{badge.class}} ms-auto">{{badge.text}}</span>\n {{/badge}}\n </a>\n {{/hasChildren}}\n </li>\n {{/isLabel}}\n {{/isSpacer}}\n {{/isDivider}}\n ',"nav-divider":'\n <li class="nav-divider-item">\n <hr class="nav-divider-line">\n </li>\n ',"nav-spacer":'\n <li class="nav-spacer-item"></li>\n ',"nav-label":'\n <li class="nav-item {{className}}">\n <div class="nav-text px-3">{{text}}</div>\n </li>\n '}}getGroupHeader(){return this.groupHeader}addMenu(e,t){return t.groupKind&&!t.header&&(t.header=this.getGroupHeader()),this.menus.set(e,{name:e,groupKind:t.groupKind||null,header:t.header||null,footer:t.footer||null,items:t.items||[],data:t.data||{},className:t.className||"sidebar sidebar-dark"}),this.activeMenuName||this._setActiveMenu(e),this}_setActiveMenu(e){this.showSearch=!1,this.activeMenuName=e;const t=this.getCurrentMenuConfig();t.className?this.setClass(t.className):this.setClass("sidebar")}async setActiveMenu(e){if(!this.menus.has(e))return console.warn(`Menu '${e}' not found`),this;const t=this.menus.get(e);if(!t.groupKind||(this.lastGroupMenu=t,this.getApp().activeGroup))return this._setActiveMenu(e),await this.render(),this.emit("menu-changed",{menuName:e,config:t,sidebar:this}),this;this.showGroupSearch()}getGroupMenu(e){if(!e)return console.warn("No group provided"),null;let t=this.lastGroupMenu,s=null;if(e._.kind)for(const[i,n]of this.menus){if(this._groupKindMatches(n.groupKind,e._.kind)){t=n;break}"any"===n.groupKind&&(s=n)}return t||s}_groupKindMatches(e,t){return!(!e||!t)&&(Array.isArray(e)?e.includes(t):e===t)}showMenuForGroup(e){if(!e)return void console.warn("No group provided");let t=this.getGroupMenu(e);if(t)return this._setActiveMenu(t.name),this.render(),this.emit("menu-changed",{menuName:t.name,config:t,sidebar:this}),this;console.warn(`No menu found for group kind: ${e.kind}`)}getMenuConfig(e){return this.menus.get(e)||null}getCurrentMenuConfig(){return this.activeMenuName?this.menus.get(this.activeMenuName):null}updateMenu(e,t){const s=this.menus.get(e);return s?(Object.assign(s,t),this.activeMenuName===e&&this.render(),this):(console.warn(`Menu '${e}' not found`),this)}removeMenu(e){if(this.menus.delete(e),this.activeMenuName===e){const e=Array.from(this.menus.keys());this.activeMenuName=e.length>0?e[0]:null,this.render()}return this}async onBeforeRender(){const e=this.getCurrentMenuConfig();if(!e)return{currentMenu:null};let t={version:this.getApp().version||null,group:this.getApp().activeGroup||null,user:this.getApp.activeUser||null};this.data={currentMenu:{header:this.renderTemplateString(e.header||"",t),footer:this.renderTemplateString(e.footer||"",t),items:this.processNavItems(e.items,e.groupKind),data:e.data,showToggle:this.showToggle}}}async onAfterRender(){this.isCollapsedState()?setTimeout(()=>this.initializeTooltips(),50):this.destroyTooltips()}setCustomView(e){return this.customView&&this.removeChild(this.customView.id),this.customView=e,e&&(e.containerId="sidebar-custom-view-container",this.addChild(e)),this.render(),this}clearCustomView(){return this.customView&&(this.removeChild(this.customView.id),this.customView=null),this.render(),this}processNavItems(e,t){const s=this.getApp(),i=s?.activeUser,n=s?.activeGroup,a=e=>{if(t&&n&&n.id){const t=e.includes("?")?"&":"?";return`${e}${t}group=${n.id}`}return e};return e.map((e,t)=>{if(""===e||"object"==typeof e&&e.divider)return{isDivider:!0,id:`divider-${t}`};if("object"==typeof e&&e.spacer)return{isSpacer:!0,id:`spacer-${t}`};const s={...e};if(s.permissions&&(!i||!i.hasPermission(s.permissions)))return null;if(s.requiresGroupKind){const e=n?._.kind||n?.kind;if(!e||!this._groupKindMatches(s.requiresGroupKind,e))return null}if("label"===s.kind)return s.isLabel=!0,s.id||(s.id=`nav-label-${t}`),s;if(s.id||(s.id=`nav-${t}`),s.route)s.href=a(s.route);else if(s.page){const e=s.page.startsWith("/")?s.page:`/${s.page}`;s.href=a(e),s.route=s.href}return s.children?(s.children=s.children.map(e=>{const t={...e};if(t.permissions&&i&&!i.hasPermission(t.permissions))return null;if(t.requiresGroupKind){const e=n?._.kind||n?.kind;if(!e||!this._groupKindMatches(t.requiresGroupKind,e))return null}if(t.route)t.href=a(t.route);else if(t.page){const e=t.page.startsWith("/")?t.page:`/${t.page}`;t.href=a(e),t.route=t.href}return t}).filter(e=>null!==e),s.hasChildren=!!(s.children&&s.children.length>0)):s.hasChildren=!1,s}).filter(e=>null!==e)}isItemActive(e){if(!e.route||!this.currentRoute)return!1;const t=e=>{if(!e)return"/";const t=decodeURIComponent(e);return t.startsWith("/")?t:`/${t}`},s=t(e.route),i=t(this.currentRoute);return"/"===s&&"/"===i||"/"!==s&&"/"!==i&&(i.startsWith(s)||i===s)}async updateActiveItem(e){return this.currentRoute=e,this.clearAllActiveStates(),this.setActiveItemByRoute(e),await this.render(),this}async handleActionToggleSubmenu(e,t){const s=t.querySelector(".nav-arrow");s&&s.classList.toggle("rotated")}async handleActionToggleSidebar(e,t){this.toggleSidebar()}onActionShowGroupMenu(e,t,s){return this.setActiveMenu("group_default"),!1}async onActionDefault(e,t,s){const i=this.getCurrentMenuConfig();if(i){for(const n of i.items)if(n.action==e&&n.handler)return n.handler(e,t,s),!0;return!1}}getMenuNames(){return Array.from(this.menus.keys())}hasMenu(e){return this.menus.has(e)}clearMenus(){return this.menus.clear(),this.activeMenuName=null,this.render(),this}setMenuData(e){const t=this.getCurrentMenuConfig();return t&&(t.data={...t.data,...e},this.render()),this}getMenuData(){const e=this.getCurrentMenuConfig();return e?e.data:{}}setupRouteListeners(){const e=this.getApp();e&&e.events&&(e.events.on(["page:showing"],e=>{this.onRouteChanged(e)}),e.events.on("group:changed",e=>{this.showMenuForGroup(e.group)}),e.events.on("portal:user-changed",e=>{this.render()}))}onRouteChanged(e){if(e.page&&e.page.route){const t=e.page.route;if(this.activeMenuItem&&this.routesMatch(t,this.activeMenuItem.route))return;this.autoSwitchToMenuForRoute(t)||(this.clearAllActiveStates(),this.setActiveItemByRoute(t),this.updateActiveItem(t))}}toggleSidebar(){const e=document.querySelector(".portal-container");if(!e)return;this.hideAllTooltips();const t=e.classList.contains("collapse-sidebar");return e.classList.contains("hide-sidebar")?(e.classList.remove("hide-sidebar"),this.isCollapsed=!1,this.destroyTooltips()):t?(e.classList.remove("collapse-sidebar"),this.isCollapsed=!1,this.destroyTooltips()):(e.classList.add("collapse-sidebar"),this.isCollapsed=!0,setTimeout(()=>this.initializeTooltips(),150)),this}setSidebarState(e){const t=document.querySelector(".portal-container");if(!t)return this;switch(t.classList.remove("collapse-sidebar","hide-sidebar"),e){case"collapsed":t.classList.add("collapse-sidebar"),this.isCollapsed=!0;break;case"hidden":t.classList.add("hide-sidebar"),this.isCollapsed=!1;break;default:this.isCollapsed=!1}return this.isCollapsed?(this.hideAllTooltips(),setTimeout(()=>this.initializeTooltips(),100)):this.destroyTooltips(),this}initializeTooltips(){return this.destroyTooltips(),this.isCollapsedState()?(this.element.querySelectorAll(".sidebar-nav .nav-link").forEach(e=>{const t=e.querySelector(".nav-text");if(t&&t.textContent.trim()){const s=t.textContent.trim();if(e.setAttribute("data-bs-toggle","tooltip"),e.setAttribute("data-bs-placement","right"),e.setAttribute("data-bs-title",s),e.setAttribute("data-bs-container","body"),window.bootstrap&&window.bootstrap.Tooltip){const t=e.getAttribute("data-tooltip-theme"),s=e.getAttribute("data-tooltip-size");let i="";t&&(i+=`tooltip-${t} `),s&&(i+=`tooltip-${s}`);const n={placement:"right",container:"body",trigger:"hover",delay:{show:500,hide:100},fallbackPlacements:["top","bottom","left"]},a=i.trim();a&&(n.customClass=a);const r=new window.bootstrap.Tooltip(e,n);e._tooltipInstance=r,e.addEventListener("click",()=>{r.hide()}),e.addEventListener("blur",()=>{r.hide()})}}}),this.addTooltipHideListeners(),this):this}destroyTooltips(){return this.removeTooltipHideListeners(),this.element.querySelectorAll('.sidebar-nav .nav-link[data-bs-toggle="tooltip"]').forEach(e=>{const t=e._tooltipInstance||window.bootstrap?.Tooltip?.getInstance(e);t&&(t.hide(),t.dispose()),delete e._tooltipInstance,e.removeAttribute("data-bs-toggle"),e.removeAttribute("data-bs-placement"),e.removeAttribute("data-bs-title"),e.removeAttribute("data-bs-container")}),this}getSidebarState(){const e=document.querySelector(".portal-container");return e?e.classList.contains("hide-sidebar")?"hidden":e.classList.contains("collapse-sidebar")?"collapsed":"normal":"normal"}isCollapsedState(){return"collapsed"===this.getSidebarState()}setToggleEnabled(e){return this.showToggle=e,this.render(),this}initializeMenus(e){if(e.menus)for(const t of e.menus)this.addMenu(t.name,t);else e.menu&&(e.menu.name=e.menu.name||"default",this.addMenu(e.menu.name,e.menu))}addTooltipHideListeners(){this._tooltipScrollHandler=()=>this.hideAllTooltips(),this.element.addEventListener("scroll",this._tooltipScrollHandler,{passive:!0}),this._tooltipRouteHandler=()=>this.hideAllTooltips(),this.getApp(),this._tooltipBlurHandler=()=>this.hideAllTooltips(),window.addEventListener("blur",this._tooltipBlurHandler),this._tooltipEscapeHandler=e=>{"Escape"===e.key&&this.hideAllTooltips()},document.addEventListener("keydown",this._tooltipEscapeHandler)}removeTooltipHideListeners(){this._tooltipScrollHandler&&(this.element.removeEventListener("scroll",this._tooltipScrollHandler),delete this._tooltipScrollHandler),this._tooltipBlurHandler&&(window.removeEventListener("blur",this._tooltipBlurHandler),delete this._tooltipBlurHandler),this._tooltipEscapeHandler&&(document.removeEventListener("keydown",this._tooltipEscapeHandler),delete this._tooltipEscapeHandler)}hideAllTooltips(){this.element.querySelectorAll('.sidebar-nav .nav-link[data-bs-toggle="tooltip"]').forEach(e=>{const t=e._tooltipInstance||window.bootstrap?.Tooltip?.getInstance(e);t&&t.hide()}),document.querySelectorAll(".tooltip.show").forEach(e=>{e.remove()})}async onBeforeDestroy(){this.destroyTooltips(),await super.onBeforeDestroy()}setupResponsiveBehavior(){const e=()=>{const e=window.innerWidth<=768,t=document.querySelector(".portal-container");t&&(e?t.classList.add("sidebar-mobile"):t.classList.remove("sidebar-mobile","sidebar-open"))};e(),window.addEventListener("resize",e)}static createDefault(e={}){return new Sidebar({theme:"sidebar-clean",showToggle:!0,autoCollapseMobile:!0,...e})}static createMinimal(e={}){return new Sidebar({theme:"sidebar-clean",showToggle:!1,autoCollapseMobile:!1,...e})}setSidebarTheme(e){return this.removeClass("sidebar-light sidebar-dark sidebar-clean"),this.sidebarTheme=e,this.addClass(e),this}show(){return this.setSidebarState("normal")}hide(){return this.setSidebarState("hidden")}collapse(){return this.setSidebarState("collapsed")}expand(){return this.setSidebarState("normal")}pulseToggle(){const e=this.element.querySelector(".sidebar-toggle");if(e){e.classList.add("pulse");const t=()=>{e.classList.remove("pulse"),e.removeEventListener("click",t)};e.addEventListener("click",t,{once:!0}),setTimeout(t,3e3)}return this}addSimpleMenuItem(e,t,s,i="bi-circle"){const n=this.menus.get(e);return n&&(n.items=n.items||[],n.items.push({text:t,route:s,icon:i}),this.activeMenuName===e&&this.render()),this}setSimpleMenu(e,t,s){const i={name:e,header:t,items:s};return this.addMenu(e,i),this.setActiveMenu(e),this}}class PageHeader extends t.View{constructor(e={}){super({tagName:"div",className:"page-header",...e}),this.style=e.style||"default",this.size=e.size||"md",this.showIcon=!1!==e.showIcon,this.showDescription=!1!==e.showDescription,this.showBreadcrumbs=e.showBreadcrumbs||!1,this.currentPage=null}async getTemplate(){return"minimal"===this.style?this.getMinimalTemplate():"breadcrumb"===this.style?this.getBreadcrumbTemplate():this.getDefaultTemplate()}getDefaultTemplate(){return'\n {{#data.hasPage}}\n <div class="page-header-content page-header-{{data.size}}">\n <div class="page-header-main">\n <div class="page-header-info">\n {{#data.showIcon}}\n {{#data.pageIcon}}\n <div class="page-icon">\n <i class="{{data.pageIcon}}"></i>\n </div>\n {{/data.pageIcon}}\n {{/data.showIcon}}\n \n <div class="page-title-group">\n <h1 class="page-title">{{data.pageTitle}}</h1>\n {{#data.showDescription}}\n {{#data.pageDescription}}\n <p class="page-description text-muted">{{data.pageDescription}}</p>\n {{/data.pageDescription}}\n {{/data.showDescription}}\n </div>\n </div>\n\n {{#data.hasActions}}\n <div class="page-actions">\n {{#data.actions}}\n <button class="btn {{buttonClass}}" \n data-action="{{action}}"\n type="button">\n {{#icon}}<i class="{{icon}} me-1"></i>{{/icon}}\n {{label}}\n </button>\n {{/data.actions}}\n </div>\n {{/data.hasActions}}\n </div>\n </div>\n {{/data.hasPage}}\n '}getMinimalTemplate(){return'\n {{#data.hasPage}}\n <div class="page-header-content page-header-minimal">\n <h1 class="page-title">\n {{#data.showIcon}}\n {{#data.pageIcon}}<i class="{{data.pageIcon}} me-2"></i>{{/data.pageIcon}}\n {{/data.showIcon}}\n {{data.pageTitle}}\n </h1>\n </div>\n {{/data.hasPage}}\n '}getBreadcrumbTemplate(){return'\n {{#data.hasPage}}\n <div class="page-header-content page-header-breadcrumb">\n {{#data.showBreadcrumbs}}\n <nav aria-label="breadcrumb">\n <ol class="breadcrumb mb-2">\n {{#data.breadcrumbs}}\n <li class="breadcrumb-item {{#active}}active{{/active}}">\n {{#href}}<a href="{{href}}">{{label}}</a>{{/href}}\n {{^href}}{{label}}{{/href}}\n </li>\n {{/data.breadcrumbs}}\n </ol>\n </nav>\n {{/data.showBreadcrumbs}}\n \n <div class="d-flex justify-content-between align-items-start">\n <h1 class="page-title">\n {{#data.showIcon}}\n {{#data.pageIcon}}<i class="{{data.pageIcon}} me-2"></i>{{/data.pageIcon}}\n {{/data.showIcon}}\n {{data.pageTitle}}\n </h1>\n \n {{#data.hasActions}}\n <div class="page-actions">\n {{#data.actions}}\n <button class="btn {{buttonClass}}" \n data-action="{{action}}"\n type="button">\n {{#icon}}<i class="{{icon}} me-1"></i>{{/icon}}\n {{label}}\n </button>\n {{/data.actions}}\n </div>\n {{/data.hasActions}}\n </div>\n \n {{#data.showDescription}}\n {{#data.pageDescription}}\n <p class="page-description text-muted mt-2">{{data.pageDescription}}</p>\n {{/data.pageDescription}}\n {{/data.showDescription}}\n </div>\n {{/data.hasPage}}\n '}async onBeforeRender(){await super.onBeforeRender();const e=this.currentPage,t=!!e,s=e?.options?.headerActions||e?.headerActions||e?.constructor?.prototype?.headerActions||[];this.data={hasPage:t,pageTitle:e?.title||e?.name||"",pageIcon:e?.icon||e?.pageIcon||"",pageDescription:e?.description||"",showIcon:this.showIcon,showDescription:this.showDescription,showBreadcrumbs:this.showBreadcrumbs,breadcrumbs:e?.options?.breadcrumbs||e?.breadcrumbs||[],actions:s,hasActions:s.length>0,size:this.size}}setPage(e){this.currentPage=e,this.mounted&&this.render()}getPage(){return this.currentPage}async onActionDefault(e,t,s){return this.currentPage&&"function"==typeof this.currentPage.onHeaderAction?(await this.currentPage.onHeaderAction(e,t,s),!0):(this.emit("action",{action:e,event:t,element:s,page:this.currentPage}),!1)}}class DeniedPage extends s.Page{constructor(e={}){super({pageName:"Access Denied",route:"/denied",title:"Access Denied",pageIcon:"bi bi-shield-x",template:'\n <div class="container mt-5">\n <div class="row justify-content-center">\n <div class="col-md-8 col-lg-6">\n <div class="text-center mb-4">\n <i class="bi bi-shield-x text-muted" style="font-size: 3rem;"></i>\n <h2 class="mt-3 mb-2">Access Denied</h2>\n <p class="text-muted">You don\'t have permission to access this page.</p>\n </div>\n\n {{#deniedPage}}\n <div class="card border-0 shadow-sm mb-4">\n <div class="card-body">\n <h6 class="card-subtitle mb-2 text-muted">Requested Page</h6>\n <h5 class="card-title">\n <i class="{{pageIcon}} me-2"></i>\n {{displayName}}\n </h5>\n {{#route}}\n <p class="card-text text-muted small">{{route}}</p>\n {{/route}}\n {{#description}}\n <p class="card-text">{{description}}</p>\n {{/description}}\n\n {{#requiredPermissions}}\n <div class="mt-3">\n <h6 class="mb-2">Required Permissions:</h6>\n {{#permissions}}\n <span class="badge bg-light text-dark me-1 mb-1">{{.}}</span>\n {{/permissions}}\n {{^permissions}}\n <span class="text-muted small">Authentication required</span>\n {{/permissions}}\n </div>\n {{/requiredPermissions}}\n </div>\n </div>\n {{/deniedPage}}\n\n <div class="d-grid gap-2 d-md-flex justify-content-md-center">\n <button type="button" class="btn btn-primary" data-action="go-back">\n <i class="bi bi-arrow-left me-1"></i>\n Go Back\n </button>\n <button type="button" class="btn btn-outline-secondary" data-action="go-home">\n <i class="bi bi-house me-1"></i>\n Home\n </button>\n {{#showLogin}}\n <button type="button" class="btn btn-outline-primary" data-action="login">\n <i class="bi bi-box-arrow-in-right me-1"></i>\n Login\n </button>\n {{/showLogin}}\n </div>\n\n {{#currentUser}}\n <div class="text-center mt-4">\n <small class="text-muted">\n Logged in as <strong>{{username}}</strong>\n </small>\n </div>\n {{/currentUser}}\n </div>\n </div>\n </div>\n ',...e}),this.deniedPage=null,this.deniedPageOptions=null}async onParams(e={},t={}){await super.onParams(e,t),e.page?(this.deniedPage=e.page,this.deniedPageOptions=e.page.options||e.page.pageOptions||{}):t.page&&(this.deniedPageName=t.page)}setDeniedPage(e){return this.deniedPage=e,this.deniedPageOptions=e?.options||e?.pageOptions||{},this}async getViewData(){const e=this.getApp(),t=e?.activeUser||e?.getCurrentUser?.()||null;let s=null;if(this.deniedPage){const e=this.deniedPageOptions?.permissions||this.deniedPage.options?.permissions||this.deniedPage.pageOptions?.permissions;s={displayName:this.deniedPage.displayName||this.deniedPage.pageName||this.deniedPage.title||"Unknown Page",pageName:this.deniedPage.pageName,route:this.deniedPage.route,description:this.deniedPage.pageDescription||this.deniedPage.description,pageIcon:this.deniedPage.pageIcon||"bi bi-file-text",requiredPermissions:e?{permissions:Array.isArray(e)?e:[e]}:null}}else this.deniedPageName&&(s={displayName:this.deniedPageName,pageName:this.deniedPageName,pageIcon:"bi bi-file-text"});return{deniedPage:s,currentUser:t?{username:t.username||t.name||t.email||"Unknown User",name:t.name,email:t.email}:null,showLogin:!t}}async handleActionGoBack(e,t){e.preventDefault(),window.history.length>1?window.history.back():await this.handleActionGoHome(e,t)}async handleActionGoHome(e,t){e.preventDefault();const s=this.getApp();s?await s.navigateToDefault():window.location.href="/"}async handleActionLogin(e,t){e.preventDefault();const s=this.getApp();if(s)try{await s.showPage("login")}catch(i){try{await s.navigate("/login")}catch(n){this.emit("login-required",{returnUrl:this.deniedPage?.route||window.location.pathname}),setTimeout(()=>{s?.showInfo?.("Please contact your administrator for access.")},100)}}}async onEnter(){await super.onEnter();const e=this.deniedPage?.pageName||this.deniedPageName;e&&this.setMeta({title:`Access Denied - ${e}`}),console.warn("Access denied to page:",{page:this.deniedPage?.pageName||this.deniedPageName,route:this.deniedPage?.route,permissions:this.deniedPageOptions?.permissions,timestamp:/* @__PURE__ */(new Date).toISOString()})}static showForPage(e,t){const s=new DeniedPage;return s.setDeniedPage(t),e.showPage(s)}}class NotFoundPage extends s.Page{constructor(e={}){super({pageName:"404",route:"/404",title:"404 - Page Not Found",pageIcon:"bi bi-search",template:'\n <div class="container mt-5">\n <div class="row justify-content-center">\n <div class="col-md-8 col-lg-6">\n <div class="text-center mb-4">\n <i class="bi bi-search text-muted" style="font-size: 3rem;"></i>\n <h2 class="mt-3 mb-2">Page Not Found</h2>\n <p class="text-muted">The page you\'re looking for doesn\'t exist.</p>\n </div>\n\n {{#path}}\n <div class="card border-0 shadow-sm mb-4">\n <div class="card-body text-center">\n <h6 class="card-subtitle mb-2 text-muted">Requested Path</h6>\n <code class="text-primary">{{path}}</code>\n </div>\n </div>\n {{/path}}\n\n <div class="d-grid gap-2 d-md-flex justify-content-md-center">\n <button type="button" class="btn btn-primary" data-action="go-back">\n <i class="bi bi-arrow-left me-1"></i>\n Go Back\n </button>\n <button type="button" class="btn btn-outline-secondary" data-action="go-home">\n <i class="bi bi-house me-1"></i>\n Home\n </button>\n </div>\n </div>\n </div>\n </div>\n ',...e}),this.path=null}async onParams(e={},t={}){await super.onParams(e,t),e.path&&(this.path=e.path),t.path&&(this.path=t.path)}setInfo(e){return this.path=e||null,this}async handleActionGoBack(e,t){e.preventDefault(),window.history.length>1?window.history.back():await this.handleActionGoHome(e,t)}async handleActionGoHome(e,t){e.preventDefault();const s=this.getApp();s?await s.navigateToDefault():window.location.href="/"}async onEnter(){await super.onEnter(),this.path&&this.setMeta({title:`404 - ${this.path} Not Found`}),console.warn("404 Not Found:",{path:this.path,timestamp:/* @__PURE__ */(new Date).toISOString()})}static showForPath(e,t){const s=new NotFoundPage;return s.setInfo(t),s.render()}}class PortalApp extends i.WebApp{constructor(e={}){super(e),this.sidebarConfig=e.sidebar,this.topbarConfig=e.topbar||{},e.topnav&&!e.topbar&&(this.topbarConfig=e.topnav),this.showPageHeader=e.showPageHeader||!1,this.pageHeaderConfig=e.pageHeader||{},this.sidebar=null,this.topbar=null,this.topnav=null,this.pageHeader=null,this.tokenManager=new r.TokenManager,this.activeGroup=null,this.isMobile()?this.sidebarCollapsed=this.sidebarConfig.defaultCollapsed||!1:this.sidebarCollapsed=this.loadSidebarState()??(this.sidebarConfig.defaultCollapsed||!1),this.setupPageContainer(),this.toast=new s.ToastService,this.Dialog=i.Dialog,this.registerPage("denied",DeniedPage),this.registerPage("404",NotFoundPage)}async start(){await this.checkAuthStatus(),this.events.on("auth:unauthorized",()=>{this.tokenManager.clearTokens(),this.rest.clearAuth(),this.setActiveUser(null)}),this.events.on("auth:logout",()=>{this.tokenManager.clearTokens(),this.rest.clearAuth(),this.setActiveUser(null)}),this.events.on("browser:focus",()=>{this.activeUser&&this.tokenManager.checkAndRefreshTokens(this)}),this.events.on("portal:action",this.onPortalAction.bind(this)),this.activeUser&&await this.checkActiveGroup(),await this.setupRouter(),this.isStarted=!0,this.events.emit("app:ready",{app:this})}async checkAuthStatus(){const e=this.tokenManager.checkTokenStatus();if("logout"===e.action)return this.events.emit("auth:unauthorized",{app:this}),!1;if("refresh"===e.action&&!(await this.tokenManager.checkAndRefreshTokens(this)))return!1;const t=this.tokenManager.getTokenInstance();if(this.activeUser)return this.tokenManager.startAutoRefresh(this),!0;this.rest.setAuthToken(t.token);const i=new s.User({id:t.getUserId()}),n=await i.fetch();return n.success?(this.setActiveUser(i),this.tokenManager.startAutoRefresh(this),!0):(this.tokenManager.clearTokens(),this.events.emit("auth:unauthorized",{app:this,error:n.error}),!1)}async checkActiveGroup(){const e=new URLSearchParams(window.location.search).get("group"),t=e||this.loadActiveGroupId();if(t)try{const i=new s.Group({id:t}),n=await i.fetch();if(!n.success||!n.data.status)return this.clearActiveGroup(),void console.warn("Failed to load active group:",n.statusText);this.activeGroup=i,e&&this.saveActiveGroupId(t),this.activeUser&&(this.activeUser.member=new a.Member,await this.activeUser.member.fetchForGroup(i.id)),this.events.emit("group:loaded",{group:this.activeGroup})}catch(i){if(console.warn("Failed to load active group:",i),e&&!this.loadActiveGroupId())this.clearActiveGroupId();else if(e){const t=this.loadActiveGroupId();if(t&&t!==e)try{const e=new s.Group({id:t});await e.fetch(),this.activeGroup=e,this.events.emit("group:loaded",{group:this.activeGroup})}catch(n){console.warn("Fallback to stored group also failed:",n),this.clearActiveGroupId()}}}}async setActiveGroup(e){const t=this.activeGroup;this.activeGroup=e,e&&e.get("id")?this.saveActiveGroupId(e.get("id")):this.clearActiveGroupId(),this.activeUser&&(this.activeUser.member=new a.Member,await this.activeUser.member.fetchForGroup(e.id)),this.events.emit("group:changed",{group:e,previousGroup:t,app:this});const s=this.getCurrentPage();return s&&s.onGroupChange&&s.onGroupChange(e),this.router.updateUrl({group:e.id},{replace:!0}),this}getActiveGroup(){return this.activeGroup}async clearActiveGroup(){const e=this.activeGroup;return this.activeGroup=null,this.clearActiveGroupId(),this.events.emit("group:cleared",{previousGroup:e,app:this}),this}saveActiveGroupId(e){try{const t=this.getActiveGroupStorageKey();localStorage.setItem(t,e.toString())}catch(t){console.warn("Failed to save active group ID:",t)}}loadActiveGroupId(){try{const e=this.getActiveGroupStorageKey();return localStorage.getItem(e)}catch(e){return console.warn("Failed to load active group ID:",e),null}}clearActiveGroupId(){try{const e=this.getActiveGroupStorageKey();localStorage.removeItem(e)}catch(e){console.warn("Failed to clear active group ID:",e)}}getActiveGroupStorageKey(){return"active_group_id"}setPortalProfile(e){try{localStorage.setItem("portal_profile",e)}catch(t){console.warn("Failed to save portal profile:",t)}}needsGroupSelection(){return!this.activeGroup}setupPageContainer(){const e="string"==typeof this.container?document.querySelector(this.container):this.container;if(!e)throw new Error(`Portal container not found: ${this.container}`);const t=this.sidebarConfig&&Object.keys(this.sidebarConfig).length>0,s=this.topbarConfig&&Object.keys(this.topbarConfig).length>0,i=this.showPageHeader?'\n <div class="portal-content" id="portal-content">\n <div id="page-header"></div>\n <div id="page-container">\n \x3c!-- Pages render here --\x3e\n </div>\n </div>\n ':'\n <div class="portal-content" id="page-container">\n \x3c!-- Pages render here --\x3e\n </div>\n ';e.innerHTML=`\n <div class="portal-layout hide-sidebar">\n ${t?'<div id="portal-sidebar"></div>':""}\n <div class="portal-body">\n ${s?'<div id="portal-topnav"></div>':""}\n ${i}\n </div>\n </div>\n `,this.pageContainer="#page-container",e.classList.add("portal-container"),this.setupPortalComponents(),this.applySidebarState(e)}async setupPortalComponents(){await this.setupSidebar(),await this.setupTopbar(),await this.setupPageHeader(),this.setupPortalEvents()}async setupSidebar(){this.sidebarConfig&&0!==Object.keys(this.sidebarConfig).length&&(this.sidebar=new Sidebar({containerId:"portal-sidebar",...this.sidebarConfig}),await this.sidebar.render())}async setupTopbar(){this.topbarConfig&&0!==Object.keys(this.topbarConfig).length&&(this.topbar=new r.TopNav({containerId:"portal-topnav",brandText:this.topbarConfig.brand||this.brand||this.title,brandRoute:this.topbarConfig.brandRoute||"/",brandIcon:this.topbarConfig.brandIcon||this.brandIcon,navItems:this.topbarConfig.leftItems||[],rightItems:this.topbarConfig.rightItems||[],displayMode:this.topbarConfig.displayMode||"both",showSidebarToggle:this.topbarConfig.showSidebarToggle||!1,...this.topbarConfig}),await this.topbar.render(),this.topnav=this.topbar)}async setupPageHeader(){if(!this.showPageHeader)return;this.pageHeader=new PageHeader({containerId:"page-header",style:this.pageHeaderConfig.style||"default",showIcon:!1!==this.pageHeaderConfig.showIcon,showDescription:!1!==this.pageHeaderConfig.showDescription,showBreadcrumbs:this.pageHeaderConfig.showBreadcrumbs||!1,...this.pageHeaderConfig});const e=document.getElementById("page-header");e&&await this.pageHeader.render(!0,e)}setupPortalEvents(){if(document.addEventListener("click",e=>{e.target.closest('[data-action="toggle-sidebar"]')&&(e.preventDefault(),this.toggleSidebar())}),window.ResizeObserver){const e=new ResizeObserver(()=>{this.handleResponsive()});e.observe(document.body),this._resizeObserver=e}else this._resizeHandler=()=>this.handleResponsive(),window.addEventListener("resize",this._resizeHandler);this.handleResponsive()}toggleSidebar(){if(!this.sidebar)return;const e=document.querySelector(".portal-container"),t=this.isMobile();t?e.classList.toggle("hide-sidebar"):(e.classList.toggle("collapse-sidebar"),this.sidebarCollapsed=!this.sidebarCollapsed,this.saveSidebarState(this.sidebarCollapsed)),this.events.emit("sidebar:toggled",{collapsed:this.sidebarCollapsed,mobile:t})}handleResponsive(){const e=document.querySelector(".portal-container");if(!e)return;const t=this.isMobile();t?(e.classList.add("mobile-layout"),e.classList.contains("hide-sidebar")||e.classList.add("hide-sidebar")):e.classList.remove("mobile-layout","hide-sidebar"),this.events.emit("responsive:changed",{mobile:t})}getPortalContainer(){return document.querySelector(".portal-container")}isMobile(){return window.innerWidth<768}hasMobileLayout(){return this.getPortalContainer().classList.contains("mobile-layout")}async showPage(e,t={},s={},i={}){const n=await super.showPage(e,t,s,i);return this.hasMobileLayout()&&this.getPortalContainer().classList.add("hide-sidebar"),this.currentPage&&this.updateNavigation(this.currentPage),n}updateNavigation(e){this.sidebar&&this.sidebar.setActivePage&&this.sidebar.setActivePage(e.route),this.topbar&&this.topbar.setActivePage&&this.topbar.setActivePage(e.route),this.pageHeader&&this.pageHeader.setPage(e),this.events.emit("portal:page-changed",{page:e})}setActiveUser(e){this.activeUser=e,this.topbar&&this.topbar.setUser(e),this.events.emit("portal:user-changed",{user:e})}getActiveUser(){return this.activeUser}saveSidebarState(e){try{const t=this.getSidebarStorageKey();localStorage.setItem(t,JSON.stringify(e))}catch(t){console.warn("Failed to save sidebar state:",t)}}loadSidebarState(){try{const e=this.getSidebarStorageKey(),t=localStorage.getItem(e);return null!==t?JSON.parse(t):null}catch(e){return console.warn("Failed to load sidebar state:",e),null}}getSidebarStorageKey(){return`${this.title?this.title.replace(/\s+/g,"_").toLowerCase():"portal_app"}_sidebar_collapsed`}applySidebarState(e=null){e||(e=document.querySelector(".portal-container")),e&&(this.sidebarCollapsed?e.classList.add("collapse-sidebar"):e.classList.remove("collapse-sidebar"))}clearSidebarState(){try{const e=this.getSidebarStorageKey();localStorage.removeItem(e)}catch(e){console.warn("Failed to clear sidebar state:",e)}}async changePassword(){const e=await this.showForm({title:"Change Password",fields:[{name:"current_password",type:"password",label:"Current Password",required:!0,showToggle:!0,strengthMeter:!0,capsLockWarning:!0},{name:"new_password",type:"password",label:"New Password",required:!0,showToggle:!0,passwordUsage:"new",strengthMeter:!0,capsLockWarning:!0,attributes:{autocomplete:"new-password"}},{name:"confirm_password",type:"password",label:"Confirm Password",required:!0,showToggle:!0,passwordUsage:"new",strengthMeter:!0,capsLockWarning:!0,attributes:{}}],submitLabel:"Change Password"});e&&(e.new_password===e.confirm_password?200===(await this.activeUser.save(e)).status?this.toast.success("Password changed successfully"):this.toast.error("Failed to change password"):this.toast.error("Passwords do not match"))}onPortalAction(e){switch(e.action){case"logout":this.tokenManager.clearTokens(),this.rest.clearAuth(),this.setActiveUser(null);break;case"profile":this.showProfile();break;case"change-password":this.changePassword();break;default:console.warn(`Unknown portal action: ${e}`)}}async showProfile(){if(this.activeUser)try{const e=await i.Dialog.showModelForm({title:"Edit Profile",size:"lg",fileHandling:"base64",model:this.activeUser,fields:[{type:"header",text:"Profile Information",level:4,class:"text-primary mb-3"},{type:"group",columns:{xs:12,md:4},title:"Avatar",fields:[{type:"image",name:"avatar",size:"lg",imageSize:{width:200,height:200},placeholder:"Upload your avatar",help:"Square images work best"}]},{type:"group",columns:{xs:12,md:8},title:"Details",fields:[{type:"text",name:"display_name",label:"Display Name",required:!0,columns:12,placeholder:"Enter first name"},{type:"email",name:"email",label:"Email Address",required:!0,columns:8,placeholder:"your.email@example.com"},{type:"tel",name:"phone_number",label:"Phone Number",columns:4,placeholder:"(555) 123-4567"}]},{type:"group",columns:12,title:"Account Settings",class:"pt-3",fields:[{type:"select",name:"timezone",label:"Timezone",columns:6,options:[{value:"America/New_York",text:"Eastern Time"},{value:"America/Chicago",text:"Central Time"},{value:"America/Denver",text:"Mountain Time"},{value:"America/Los_Angeles",text:"Pacific Time"},{value:"UTC",text:"UTC"}]},{type:"select",name:"language",label:"Language",columns:6,options:[{value:"en",text:"English"},{value:"es",text:"Spanish"},{value:"fr",text:"French"},{value:"de",text:"German"}]},{type:"switch",name:"email_notifications",label:"Email Notifications",columns:4},{type:"switch",name:"two_factor_enabled",label:"Two-Factor Authentication",columns:4},{type:"switch",name:"profile_public",label:"Public Profile",columns:4}]}],submitText:"Save Profile",cancelText:"Cancel"});e&&e.success?this.showSuccess("Profile updated successfully!"):e&&e.success}catch(e){console.error("Error showing profile form:",e),this.showError("Failed to load profile form")}else this.showError("No user is currently logged in")}async destroy(){this.activeGroup=null,this._resizeObserver&&this._resizeObserver.disconnect(),this._resizeHandler&&window.removeEventListener("resize",this._resizeHandler),this.topbar&&(await this.topbar.destroy(),this.topbar=null,this.topnav=null),this.sidebar&&(await this.sidebar.destroy(),this.sidebar=null),await super.destroy()}static create(e={}){return new PortalApp(e)}}const P=new class{constructor(){this.formatter=t.dataFormatter,this.compiledTemplates=/* @__PURE__ */new Map}render(e,s,i={}){return t.Mustache.render(e,s,i)}compile(e){const s=t.Mustache.parse(e);return this.compiledTemplates.set(e,s),s}renderCompiled(e,s,i={}){return t.Mustache.render(e,s,i)}clearCache(){this.compiledTemplates.clear(),t.Mustache.clearCache()}cache(e,t){return{key:e,template:t,compiled:this.compile(t)}}getCached(e){for(const[t,s]of this.compiledTemplates)if(t===e||s===e)return{key:e,template:t,compiled:s};return null}registerFormatter(e,t){return this.formatter.register(e,t),this}hasPipes(e){return/\{\{[{]?[^}|]+\|[^}]+\}[}]?\}/.test(e)}processData(e,t){const s={...e};for(const[i,n]of Object.entries(t))if(e&&"function"==typeof e.get)s[i]=e.get(`${i}|${n}`);else{const t=this.getValueFromPath(e,i);s[i]=this.formatter.pipe(t,n)}return s}getValueFromPath(e,t){if(!e||!t)return;if(e&&"function"==typeof e.get)return e.get(t);const s=t.split(".");let i=e;for(const n of s){if(null==i)return;i=!isNaN(n)&&Array.isArray(i)?i[parseInt(n)]:i[n]}return i}processTemplate(e,t){return{template:e,data:t}}};L.install({level:"warn"});const M="MOJO",A="web-mojo",T={FRAMEWORK_NAME:M,PACKAGE_NAME:A};exports.BUILD_TIME=e.BUILD_TIME,exports.VERSION=e.VERSION,exports.VERSION_INFO=e.VERSION_INFO,exports.VERSION_MAJOR=e.VERSION_MAJOR,exports.VERSION_MINOR=e.VERSION_MINOR,exports.VERSION_REVISION=e.VERSION_REVISION,exports.DataWrapper=t.DataWrapper,exports.EventDelegate=t.EventDelegate,exports.MOJOUtils=t.MOJOUtils,exports.Rest=t.rest,exports.View=t.View,exports.dataFormatter=t.dataFormatter,exports.ContextMenu=s.ContextMenu,exports.Group=s.Group,exports.GroupForms=s.GroupForms,exports.GroupList=s.GroupList,exports.Page=s.Page,exports.ToastService=s.ToastService,exports.User=s.User,exports.UserDataView=s.UserDataView,exports.UserDevice=s.UserDevice,exports.UserDeviceList=s.UserDeviceList,exports.UserDeviceLocation=s.UserDeviceLocation,exports.UserDeviceLocationList=s.UserDeviceLocationList,exports.UserForms=s.UserForms,exports.UserList=s.UserList,exports.Dialog=i.Dialog,exports.EventBus=i.EventBus,exports.Router=i.Router,exports.WebApp=i.WebApp,exports.Collection=n.Collection,exports.Model=n.Model,exports.BundleByOptions=a.BundleByOptions,exports.ChatInputView=a.ChatInputView,exports.ChatMessageView=a.ChatMessageView,exports.ChatView=a.ChatView,exports.CommonEventFields=a.CommonEventFields,exports.ComparatorOptions=a.ComparatorOptions,exports.EmailDomain=a.EmailDomain,exports.EmailDomainForms=a.EmailDomainForms,exports.EmailDomainList=a.EmailDomainList,exports.EmailTemplate=a.EmailTemplate,exports.EmailTemplateForms=a.EmailTemplateForms,exports.EmailTemplateList=a.EmailTemplateList,exports.File=a.File,exports.FileForms=a.FileForms,exports.FileList=a.FileList,exports.FileManager=a.FileManager,exports.FileManagerForms=a.FileManagerForms,exports.FileManagerList=a.FileManagerList,exports.FilePreviewView=a.FilePreviewView,exports.FileUpload=a.FileUpload,exports.GeoLocatedIP=a.GeoLocatedIP,exports.GeoLocatedIPList=a.GeoLocatedIPList,exports.Incident=a.Incident,exports.IncidentEvent=a.IncidentEvent,exports.IncidentEventForms=a.IncidentEventForms,exports.IncidentEventList=a.IncidentEventList,exports.IncidentForms=a.IncidentForms,exports.IncidentHistory=a.IncidentHistory,exports.IncidentHistoryList=a.IncidentHistoryList,exports.IncidentList=a.IncidentList,exports.IncidentRule=a.IncidentRule,exports.IncidentRuleList=a.IncidentRuleList,exports.IncidentRuleSet=a.IncidentRuleSet,exports.IncidentRuleSetList=a.IncidentRuleSetList,exports.IncidentStats=a.IncidentStats,exports.Job=a.Job,exports.JobEvent=a.JobEvent,exports.JobEventList=a.JobEventList,exports.JobForms=a.JobForms,exports.JobList=a.JobList,exports.JobLog=a.JobLog,exports.JobLogList=a.JobLogList,exports.JobRunner=a.JobRunner,exports.JobRunnerForms=a.JobRunnerForms,exports.JobRunnerList=a.JobRunnerList,exports.JobsEngineStats=a.JobsEngineStats,exports.Log=a.Log,exports.LogList=a.LogList,exports.Mailbox=a.Mailbox,exports.MailboxForms=a.MailboxForms,exports.MailboxList=a.MailboxList,exports.MatchByOptions=a.MatchByOptions,exports.Member=a.Member,exports.MemberForms=a.MemberForms,exports.MemberList=a.MemberList,exports.MetricsForms=a.MetricsForms,exports.MetricsPermission=a.MetricsPermission,exports.MetricsPermissionList=a.MetricsPermissionList,exports.ProgressView=a.ProgressView,exports.PushConfig=a.PushConfig,exports.PushConfigForms=a.PushConfigForms,exports.PushConfigList=a.PushConfigList,exports.PushDelivery=a.PushDelivery,exports.PushDeliveryList=a.PushDeliveryList,exports.PushDevice=a.PushDevice,exports.PushDeviceList=a.PushDeviceList,exports.PushTemplate=a.PushTemplate,exports.PushTemplateForms=a.PushTemplateForms,exports.PushTemplateList=a.PushTemplateList,exports.Rule=a.Rule,exports.RuleForms=a.RuleForms,exports.RuleList=a.RuleList,exports.RuleSet=a.RuleSet,exports.RuleSetForms=a.RuleSetForms,exports.RuleSetList=a.RuleSetList,exports.S3Bucket=a.S3Bucket,exports.S3BucketForms=a.S3BucketForms,exports.S3BucketList=a.S3BucketList,exports.SentMessage=a.SentMessage,exports.SentMessageForms=a.SentMessageForms,exports.SentMessageList=a.SentMessageList,exports.TabView=a.TabView,exports.TablePage=a.TablePage,exports.TableRow=a.TableRow,exports.TableView=a.TableView,exports.Ticket=a.Ticket,exports.TicketCategories=a.TicketCategories,exports.TicketForms=a.TicketForms,exports.TicketList=a.TicketList,exports.TicketNote=a.TicketNote,exports.TicketNoteList=a.TicketNoteList,exports.ValueTypeOptions=a.ValueTypeOptions,exports.SimpleSearchView=r.SimpleSearchView,exports.TokenManager=r.TokenManager,exports.TopNav=r.TopNav,exports.ListView=o.ListView,exports.ListViewItem=o.ListViewItem,exports.DataView=l.default,exports.FormView=c.FormView,exports.applyFileDropMixin=c.applyFileDropMixin,exports.WebSocketClient=d.WebSocketClient,exports.ConsoleSilencer=L,exports.FRAMEWORK_NAME=M,exports.MustacheFormatter=P,exports.PACKAGE_NAME=A,exports.PortalApp=PortalApp,exports.Sidebar=Sidebar,exports.default=T,exports.installConsoleSilencer=e=>L.install(e);
|
|
2
2
|
//# sourceMappingURL=index.cjs.js.map
|
package/dist/index.es.js
CHANGED
|
@@ -1,18 +1,18 @@
|
|
|
1
|
-
import { B, a, V, b, c, d } from "./chunks/version-
|
|
2
|
-
import { V as View, d as dataFormatter, a as Mustache } from "./chunks/Rest-
|
|
3
|
-
import { D, b as b2, M, r } from "./chunks/Rest-
|
|
4
|
-
import { G as GroupList, a as Group, P as Page, T as ToastService, U as User } from "./chunks/ContextMenu-
|
|
5
|
-
import { C, b as b3, e, f, g, h, i, d as d2, c as c2 } from "./chunks/ContextMenu-
|
|
6
|
-
import { D as Dialog, W as WebApp } from "./chunks/Dialog-
|
|
7
|
-
import { E, R } from "./chunks/Dialog-
|
|
8
|
-
import { C as C2, M as M2 } from "./chunks/Collection-
|
|
9
|
-
import { M as Member } from "./chunks/ChatView-
|
|
10
|
-
import { Z, e as e2, d as d3, C as C3, a1, $, E as E2, j, i as i2, q, s, r as r2, w, y, x, t, v, u, F, f as f2, au, av, B as B2, I, A, z, G, N, O, D as D2, K, L, H, J, Y, a2, a7, a8, a4, a3, a5, a6, aa, ac, ab, a9, ad, ae, k, m, l, _, ag, af, aj, ah, ai, P, ao, as, ap, aq, ar, ak, al, am, at, an, V as V2, X, W, R as R2, U, Q, S, h as h2, g as g2, n, p, o, c as c3, b as b4, a as a10, T, aw, aB, aA, ax, ay, az, a0 } from "./chunks/ChatView-
|
|
11
|
-
import { S as SimpleSearchView, T as TokenManager, a as TopNav } from "./chunks/TokenManager-
|
|
12
|
-
import { a as a11, L as L2 } from "./chunks/ListView-
|
|
13
|
-
import { default as default2 } from "./chunks/DataView-
|
|
14
|
-
import { F as F2, a as a12 } from "./chunks/FormView-
|
|
15
|
-
import { W as W2 } from "./chunks/WebSocketClient-
|
|
1
|
+
import { B, a, V, b, c, d } from "./chunks/version-_FYWwpG_.js";
|
|
2
|
+
import { V as View, d as dataFormatter, a as Mustache } from "./chunks/Rest-BoKp2Hj4.js";
|
|
3
|
+
import { D, b as b2, M, r } from "./chunks/Rest-BoKp2Hj4.js";
|
|
4
|
+
import { G as GroupList, a as Group, P as Page, T as ToastService, U as User } from "./chunks/ContextMenu-CvLNRuJb.js";
|
|
5
|
+
import { C, b as b3, e, f, g, h, i, d as d2, c as c2 } from "./chunks/ContextMenu-CvLNRuJb.js";
|
|
6
|
+
import { D as Dialog, W as WebApp } from "./chunks/Dialog-LPU__Q7Z.js";
|
|
7
|
+
import { E, R } from "./chunks/Dialog-LPU__Q7Z.js";
|
|
8
|
+
import { C as C2, M as M2 } from "./chunks/Collection-DJaa8dhS.js";
|
|
9
|
+
import { M as Member } from "./chunks/ChatView-DZ7f2Rl5.js";
|
|
10
|
+
import { Z, e as e2, d as d3, C as C3, a1, $, E as E2, j, i as i2, q, s, r as r2, w, y, x, t, v, u, F, f as f2, au, av, B as B2, I, A, z, G, N, O, D as D2, K, L, H, J, Y, a2, a7, a8, a4, a3, a5, a6, aa, ac, ab, a9, ad, ae, k, m, l, _, ag, af, aj, ah, ai, P, ao, as, ap, aq, ar, ak, al, am, at, an, V as V2, X, W, R as R2, U, Q, S, h as h2, g as g2, n, p, o, c as c3, b as b4, a as a10, T, aw, aB, aA, ax, ay, az, a0 } from "./chunks/ChatView-DZ7f2Rl5.js";
|
|
11
|
+
import { S as SimpleSearchView, T as TokenManager, a as TopNav } from "./chunks/TokenManager-BoolOcxQ.js";
|
|
12
|
+
import { a as a11, L as L2 } from "./chunks/ListView-8FqhYWRU.js";
|
|
13
|
+
import { default as default2 } from "./chunks/DataView-gc1VouWJ.js";
|
|
14
|
+
import { F as F2, a as a12 } from "./chunks/FormView-Cc5iagqS.js";
|
|
15
|
+
import { W as W2 } from "./chunks/WebSocketClient-Do0CazHx.js";
|
|
16
16
|
const __vite_import_meta_env__ = { "BASE_URL": "/", "DEV": false, "MODE": "production", "PROD": true, "SSR": false };
|
|
17
17
|
const LEVELS = Object.freeze({
|
|
18
18
|
silent: 0,
|