web-mojo 2.2.68 → 2.2.69
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/CHANGELOG.md +25 -9
- package/dist/admin.cjs.js +1 -1
- package/dist/admin.cjs.js.map +1 -1
- package/dist/admin.es.js +1 -1
- package/dist/admin.es.js.map +1 -1
- 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 +1 -1
- package/dist/chunks/ChatView-CZ3Key2k.js +2 -0
- package/dist/chunks/ChatView-CZ3Key2k.js.map +1 -0
- package/dist/chunks/ChatView-Dw-iVmht.js +2 -0
- package/dist/chunks/ChatView-Dw-iVmht.js.map +1 -0
- package/dist/chunks/{Dialog-DW7PHzUc.js → Dialog-Dhqtd9Yz.js} +2 -2
- package/dist/chunks/{Dialog-DW7PHzUc.js.map → Dialog-Dhqtd9Yz.js.map} +1 -1
- package/dist/chunks/{Dialog-jfBsXy5X.js → Dialog-t_9l2Mou.js} +2 -2
- package/dist/chunks/{Dialog-jfBsXy5X.js.map → Dialog-t_9l2Mou.js.map} +1 -1
- package/dist/chunks/Files-6eRT5k3r.js +2 -0
- package/dist/chunks/{Files-C-ChBvr5.js.map → Files-6eRT5k3r.js.map} +1 -1
- package/dist/chunks/Files-Dh_5PFBn.js +2 -0
- package/dist/chunks/{Files-DNbHDy43.js.map → Files-Dh_5PFBn.js.map} +1 -1
- package/dist/chunks/{FormView-EoB_ZdIB.js → FormView-B1CXO2t8.js} +2 -2
- package/dist/chunks/{FormView-EoB_ZdIB.js.map → FormView-B1CXO2t8.js.map} +1 -1
- package/dist/chunks/{FormView-Q_lFA0nr.js → FormView-BRHAIawp.js} +2 -2
- package/dist/chunks/{FormView-Q_lFA0nr.js.map → FormView-BRHAIawp.js.map} +1 -1
- package/dist/chunks/{MetricsMiniChartWidget-lzq4lSTF.js → MetricsMiniChartWidget-D1w608Jy.js} +2 -2
- package/dist/chunks/{MetricsMiniChartWidget-lzq4lSTF.js.map → MetricsMiniChartWidget-D1w608Jy.js.map} +1 -1
- package/dist/chunks/{MetricsMiniChartWidget-ukn-NRMR.js → MetricsMiniChartWidget-Dg1e6EQJ.js} +2 -2
- package/dist/chunks/{MetricsMiniChartWidget-ukn-NRMR.js.map → MetricsMiniChartWidget-Dg1e6EQJ.js.map} +1 -1
- package/dist/chunks/{PDFViewer-iOqYpg-6.js → PDFViewer-CDeV9OBs.js} +2 -2
- package/dist/chunks/{PDFViewer-iOqYpg-6.js.map → PDFViewer-CDeV9OBs.js.map} +1 -1
- package/dist/chunks/{PDFViewer-sFoyopz3.js → PDFViewer-D_3V8QJe.js} +2 -2
- package/dist/chunks/{PDFViewer-sFoyopz3.js.map → PDFViewer-D_3V8QJe.js.map} +1 -1
- package/dist/chunks/TableView-CI_7a-kD.js +2 -0
- package/dist/chunks/TableView-CI_7a-kD.js.map +1 -0
- package/dist/chunks/TableView-CWk5k4LQ.js +2 -0
- package/dist/chunks/TableView-CWk5k4LQ.js.map +1 -0
- package/dist/chunks/ToastService-C2tTooFn.js +3 -0
- package/dist/chunks/ToastService-C2tTooFn.js.map +1 -0
- package/dist/chunks/ToastService-nUaGVpSl.js +3 -0
- package/dist/chunks/ToastService-nUaGVpSl.js.map +1 -0
- package/dist/chunks/{TokenManager-ChNOca0K.js → TokenManager-ien2XzwO.js} +2 -2
- package/dist/chunks/{TokenManager-ChNOca0K.js.map → TokenManager-ien2XzwO.js.map} +1 -1
- package/dist/chunks/{TokenManager-DKzxBt6g.js → TokenManager-sZgt--C9.js} +2 -2
- package/dist/chunks/{TokenManager-DKzxBt6g.js.map → TokenManager-sZgt--C9.js.map} +1 -1
- package/dist/chunks/User-BL9M_PWB.js +2 -0
- package/dist/chunks/User-BL9M_PWB.js.map +1 -0
- package/dist/chunks/{User-BnlvMG5J.js → User-DqHG5Gr1.js} +2 -3
- package/dist/chunks/User-DqHG5Gr1.js.map +1 -0
- package/dist/chunks/UserProfileView-DnVMHcLH.js +2 -0
- package/dist/chunks/UserProfileView-DnVMHcLH.js.map +1 -0
- package/dist/chunks/UserProfileView-kupeq2rN.js +2 -0
- package/dist/chunks/UserProfileView-kupeq2rN.js.map +1 -0
- package/dist/chunks/{WebApp-Bsic6FPo.js → WebApp-Bti0Gqqo.js} +2 -2
- package/dist/chunks/{WebApp-Bsic6FPo.js.map → WebApp-Bti0Gqqo.js.map} +1 -1
- package/dist/chunks/{WebApp-B0m6JCjO.js → WebApp-CcVF73yg.js} +2 -2
- package/dist/chunks/{WebApp-B0m6JCjO.js.map → WebApp-CcVF73yg.js.map} +1 -1
- package/dist/chunks/index-Aq9ke4vg.js +2 -0
- package/dist/chunks/index-Aq9ke4vg.js.map +1 -0
- package/dist/chunks/index-Da9sT-tE.js +2 -0
- package/dist/chunks/index-Da9sT-tE.js.map +1 -0
- package/dist/chunks/{version-BmVUtM_7.js → version-D8JjsPW0.js} +2 -2
- package/dist/chunks/{version-BmVUtM_7.js.map → version-D8JjsPW0.js.map} +1 -1
- package/dist/chunks/{version-i7K_82Qy.js → version-XmirKYWA.js} +2 -2
- package/dist/chunks/{version-i7K_82Qy.js.map → version-XmirKYWA.js.map} +1 -1
- package/dist/css/web-mojo.css +1 -1
- package/dist/docit.cjs.js +1 -1
- package/dist/docit.cjs.js.map +1 -1
- package/dist/docit.es.js +1 -1
- package/dist/docit.es.js.map +1 -1
- package/dist/index.cjs.js +1 -1
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.es.js +1 -1
- package/dist/index.es.js.map +1 -1
- package/dist/lightbox.cjs.js +1 -1
- package/dist/lightbox.es.js +1 -1
- package/dist/map.cjs.js +1 -1
- package/dist/map.es.js +1 -1
- package/dist/user-profile.cjs.js +2 -0
- package/dist/user-profile.cjs.js.map +1 -0
- package/dist/user-profile.es.js +2 -0
- package/dist/user-profile.es.js.map +1 -0
- package/dist/web-mojo.lite.iife.js +9 -6
- package/dist/web-mojo.lite.iife.js.map +1 -1
- package/dist/web-mojo.lite.iife.min.js +11 -11
- package/dist/web-mojo.lite.iife.min.js.map +1 -1
- package/package.json +5 -1
- package/dist/chunks/ChatView-Cfe0ZGvr.js +0 -2
- package/dist/chunks/ChatView-Cfe0ZGvr.js.map +0 -1
- package/dist/chunks/ChatView-DuQVFrCY.js +0 -2
- package/dist/chunks/ChatView-DuQVFrCY.js.map +0 -1
- package/dist/chunks/Files-C-ChBvr5.js +0 -2
- package/dist/chunks/Files-DNbHDy43.js +0 -2
- package/dist/chunks/User-BnlvMG5J.js.map +0 -1
- package/dist/chunks/User-DSqcOwPL.js +0 -3
- package/dist/chunks/User-DSqcOwPL.js.map +0 -1
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
import{M as e,C as t}from"./Collection-BWKmydl5.js";import{T as s,G as a,U as o}from"./User-DSqcOwPL.js";import{V as i,d as l}from"./Rest-BJ3Mvx1L.js";class ProgressView extends i{constructor(e={}){super({template:"progress-view-template",...e}),this.filename=e.filename||"Unknown file",this.filesize=e.filesize||0,this.filesizeFormatted=l.pipe(this.filesize,"filesize"),this.progress=0,this.percentage=0,this.loaded=0,this.total=this.filesize,this.loadedFormatted="0 B",this.totalFormatted=this.filesizeFormatted,this.status="Starting upload...",this.showCancel=!1!==e.showCancel,this.onCancel=e.onCancel||null,this.cancelled=!1,this.completed=!1}getTemplate(){return'\n <div class="progress-view">\n <div class="d-flex justify-content-between align-items-start mb-2">\n <div class="flex-grow-1 min-width-0">\n <div class="fw-medium text-truncate" title="{{filename}}">\n <i class="bi bi-file-earmark me-1"></i>\n {{filename}}\n </div>\n <small class="text-muted">{{status}}</small>\n </div>\n {{#showCancel}}\n <button type="button" \n class="btn btn-sm btn-outline-secondary ms-2" \n data-action="cancel"\n {{#cancelled}}disabled{{/cancelled}}>\n <i class="bi bi-x"></i>\n </button>\n {{/showCancel}}\n </div>\n \n <div class="progress mb-2" style="height: 8px;">\n <div class="progress-bar" \n role="progressbar" \n style="width: {{percentage}}%"\n aria-valuenow="{{percentage}}" \n aria-valuemin="0" \n aria-valuemax="100">\n </div>\n </div>\n \n <div class="d-flex justify-content-between">\n <small class="text-muted">\n {{loadedFormatted}} / {{totalFormatted}}\n </small>\n <small class="text-muted">\n {{percentage}}%\n </small>\n </div>\n </div>\n '}updateProgress(e){this.cancelled||this.completed||(this.progress=e.progress,this.percentage=e.percentage,this.loaded=e.loaded,this.total=e.total||this.filesize,this.loadedFormatted=l.pipe(this.loaded,"filesize"),this.totalFormatted=l.pipe(this.total,"filesize"),this.percentage<100?this.status=`Uploading... ${this.percentage}%`:this.status="Finalizing upload...",this.render())}markCompleted(e="Upload completed!"){this.completed=!0,this.progress=1,this.percentage=100,this.status=e,this.render()}markFailed(e="Upload failed"){this.status=e,this.render()}markCancelled(){this.cancelled=!0,this.status="Upload cancelled",this.render()}async onActionCancel(e,t,s){if(!this.cancelled&&!this.completed&&(s.disabled=!0,this.markCancelled(),this.emit("cancel"),"function"==typeof this.onCancel))try{await this.onCancel()}catch(a){console.error("Error in cancel callback:",a)}}setFilename(e){this.filename=e,this.render()}setFilesize(e){this.filesize=e,this.filesizeFormatted=l.pipe(e,"filesize"),this.total=e,this.totalFormatted=this.filesizeFormatted,this.render()}getPercentage(){return this.percentage}isCompleted(){return this.completed}isCancelled(){return this.cancelled}getStats(){return{filename:this.filename,filesize:this.filesize,progress:this.progress,percentage:this.percentage,loaded:this.loaded,total:this.total,cancelled:this.cancelled,completed:this.completed,status:this.status}}}class FileUpload{constructor(e,t={}){if(this.fileModel=e,this.options={file:null,name:null,group:null,description:null,onProgress:null,onComplete:null,onError:null,showToast:!0,...t},!(this.options.file&&this.options.file instanceof File))throw new Error("FileUpload requires a valid File object");this.cancelled=!1,this.uploadRequest=null,this.progressToast=null,this.progressView=null,this.toastService=null,this.options.showToast&&(this.toastService=new s),this.promise=this._startUpload()}async _startUpload(){try{let t,s,a;this.options.showToast&&this._showProgressToast();try{t=await this._initiateUpload()}catch(e){throw new Error(`Failed to initiate upload: ${e.message}`)}if(this.cancelled)throw new Error("Upload cancelled");if(!t||!t.upload_url)throw new Error("Invalid upload response: missing upload URL");if("string"==typeof t.upload_url)s={url:t.upload_url,method:"PUT",fields:null,headers:{}};else{if(!t.upload_url||"object"!=typeof t.upload_url||!t.upload_url.upload_url)throw new Error(`Invalid upload response: unrecognised upload_url format. Server returned: ${JSON.stringify(t.upload_url)}`);s={url:t.upload_url.upload_url,method:t.upload_url.method||"POST",fields:t.upload_url.fields||null,headers:t.upload_url.headers||{}}}try{a=await this._performUpload(s)}catch(e){throw new Error(`File upload failed: ${e.message}`)}if(this.cancelled)throw new Error("Upload cancelled");try{await this._completeUpload()}catch(e){console.warn("Failed to mark upload as completed:",e)}return this._onComplete(this.fileModel),this.fileModel}catch(e){throw"Upload cancelled"!==e.message&&this._onError(e),e}}async _initiateUpload(){try{const e={filename:this.options.name||this.options.file.name,file_size:this.options.file.size,content_type:this.options.file.type};this.options.group&&(e.group=this.options.group),this.options.description&&(e.description=this.options.description);const t=await this.fileModel.rest.POST("/api/fileman/upload/initiate",e);if(!t)throw new Error("No response from upload initiation API");if(!t.data)throw new Error("Upload initiation response missing data");if(!t.data.status){const e=t.data.error||"Upload initiation failed";throw new Error(e)}if(!t.data.data)throw new Error("Upload initiation response missing data payload");return t.data.data.id&&this.fileModel.set("id",t.data.data.id),t.data.data}catch(e){if("Network Error"===e.message||"TypeError"===e.name)throw new Error("Network error during upload initiation. Please check your connection.");throw e}}async _performUpload(e){return new Promise((t,s)=>{if(!(this.options.file instanceof File))return void s(new Error("Only single File objects are supported"));const{url:a,method:o,fields:i,headers:l}=e,r="POST"===o&&null!==i,n=new XMLHttpRequest;this.uploadRequest=n,n.upload.onprogress=e=>{this.cancelled||this._onProgress({progress:e.loaded/e.total,loaded:e.loaded,total:e.total,percentage:Math.round(e.loaded/e.total*100)})},n.onload=()=>{n.status>=200&&n.status<300?t({data:n.response,status:n.status,statusText:n.statusText,xhr:n}):s(new Error(`Upload failed: ${n.status} ${n.statusText}`))},n.onerror=()=>s(new Error("Upload failed: Network error")),n.ontimeout=()=>s(new Error("Upload timed out — file may be too large or connection too slow")),n.onabort=()=>s(new Error("Upload cancelled"));let p=a;a.startsWith("/")&&!a.startsWith("/api/")&&(p="/api"+a);const d=this.fileModel.rest.buildUrl(p);if(n.open(o,d),n.timeout=3e4,r){for(const[t,s]of Object.entries(l||{}))"content-type"!==t.toLowerCase()&&n.setRequestHeader(t,s);const e=new FormData;for(const[t,s]of Object.entries(i))e.append(t,s);e.append("file",this.options.file),n.send(e)}else{n.setRequestHeader("Content-Type",this.options.file.type);for(const[e,t]of Object.entries(l||{}))"content-type"!==e.toLowerCase()&&n.setRequestHeader(e,t);n.send(this.options.file)}})}async _completeUpload(){try{const e=await this.fileModel.save({action:"mark_as_completed"});if(!e)throw new Error("No response from upload completion API");if(e.data&&!e.data.status){const t=e.data.error||"Failed to mark upload as completed";throw new Error(t)}return e}catch(e){if("Network Error"===e.message||"TypeError"===e.name)throw new Error("Network error during upload completion. The file may have uploaded successfully.");throw e}}_onProgress(e){this.progressToast&&this.progressToast.updateProgress&&this.progressToast.updateProgress(e),"function"==typeof this.options.onProgress&&this.options.onProgress(e)}_onComplete(e){this.progressView&&this.progressView.markCompleted("Upload completed successfully!"),this.progressToast&&setTimeout(()=>{try{this.progressToast&&"function"==typeof this.progressToast.hide&&this.progressToast.hide()}catch(e){console.warn("Error hiding progress toast:",e)}},2e3),"function"==typeof this.options.onComplete&&this.options.onComplete(e)}_onError(e){if(this.progressToast)try{this.progressToast.hide()}catch(t){console.warn("Error hiding progress toast on error:",t)}this.toastService&&this.toastService.error(`Upload failed: ${e.message}`),"function"==typeof this.options.onError&&this.options.onError(e)}_showProgressToast(){this.progressView=new ProgressView({filename:this.options.name||this.options.file.name,filesize:this.options.file.size,showCancel:!0,onCancel:()=>this.cancel()}),this.progressToast=this.toastService.showView(this.progressView,"info",{title:"File Upload",autohide:!1,dismissible:!1})}cancel(){return!this.cancelled&&(this.cancelled=!0,this.uploadRequest&&"function"==typeof this.uploadRequest.abort&&this.uploadRequest.abort(),this.progressView&&this.progressView.markCancelled(),this.progressToast&&setTimeout(()=>{try{this.progressToast&&"function"==typeof this.progressToast.hide&&this.progressToast.hide()}catch(e){console.warn("Error hiding progress toast on cancel:",e)}},1500),!0)}isCancelled(){return this.cancelled}then(e,t){return this.promise.then(e,t)}catch(e){return this.promise.catch(e)}finally(e){return this.promise.finally(e)}getStats(){return{filename:this.options.file.name,size:this.options.file.size,type:this.options.file.type,cancelled:this.cancelled,group:this.options.group,description:this.options.description}}}class FileManager extends e{constructor(e={}){super(e,{endpoint:"/api/fileman/manager"})}}class FileManagerList extends t{constructor(e={}){super({ModelClass:FileManager,endpoint:"/api/fileman/manager",size:10,...e})}}const r={create:{title:"Add Storage Backend",fields:[{name:"name",type:"text",label:"Display Name",placeholder:"Enter Display Name",cols:12},{name:"use",type:"text",label:"Use",placeholder:"Enter User or Leave Blank",cols:12},{name:"backend_url",type:"text",label:"Backend URL",required:!0,value:"s3://BUCKET_NAME/OPTION_FOLDER",placeholder:"s3://bucket_name/optional folder",help:"Format: service://path. Valid services: s3",cols:12},{name:"aws_region",type:"select",label:"AWS Region (optional)",value:"us-east-1",options:[{value:"",text:"System Default"},{value:"us-east-1",text:"US East (N. Virginia)"},{value:"us-east-2",text:"US East (Ohio)"},{value:"us-west-1",text:"US West (N. California)"},{value:"us-west-2",text:"US West (Oregon)"},{value:"ca-central-1",text:"Canada (Central)"},{value:"eu-west-1",text:"Europe (Ireland)"},{value:"eu-west-2",text:"Europe (London)"},{value:"eu-west-3",text:"Europe (Paris)"},{value:"eu-central-1",text:"Europe (Frankfurt)"},{value:"eu-north-1",text:"Europe (Stockholm)"},{value:"eu-south-1",text:"Europe (Milan)"},{value:"ap-southeast-2",text:"Asia Pacific (Sydney)"}],columns:12,help:"Optional. Defaults to project AWS_REGION if omitted."},{name:"aws_key",type:"text",label:"AWS Key (optional)",placeholder:"enter your AWS Key with S3 permissions",columns:12,help:"Optional, AWS Key with S3 permissions"},{name:"aws_secret",type:"text",label:"AWS Secret (optional)",placeholder:"enter your AWS Secret with S3 permissions",columns:12,help:"Optional, AWS Secret with S3 permissions"},{name:"is_default",type:"switch",label:"Is Default",cols:6},{name:"is_active",type:"switch",label:"Is Active",default:!0,cols:6}]},edit:{title:"Edit Storage Backend",fields:[{name:"name",type:"text",label:"Display Name",placeholder:"Enter Display Name",cols:12},{name:"use",type:"text",label:"Use",placeholder:"Enter User or Leave Blank",cols:12},{name:"backend_url",type:"text",label:"Backend URL",required:!0,placeholder:"s3://bucket_name/optional folder",help:"Format: service://path. Valid services: s3",cols:12},{name:"allowed_origins",type:"text",label:"Domains Who Can Upload",cols:12},{name:"is_default",type:"switch",label:"Is Default",cols:6},{name:"is_active",type:"switch",label:"Is Active",default:!0,cols:6},{name:"is_public",type:"switch",label:"Is Public",default:!0,cols:6}]},owners:{fields:[{type:"collection",name:"group",label:"Group (Owner)",Collection:a,labelField:"name",valueField:"id",maxItems:10,placeholder:"Search groups...",emptyFetch:!1,debounceMs:300},{type:"collection",name:"user",label:"User (Owner)",Collection:o,labelField:"display_name",valueField:"id",maxItems:10,placeholder:"Search users...",emptyFetch:!1,debounceMs:300}]},credentials:{fields:[{name:"aws_region",type:"select",label:"AWS Region (optional)",value:"us-east-1",options:[{value:"",text:"System Default"},{value:"us-east-1",text:"US East (N. Virginia)"},{value:"us-east-2",text:"US East (Ohio)"},{value:"us-west-1",text:"US West (N. California)"},{value:"us-west-2",text:"US West (Oregon)"},{value:"ca-central-1",text:"Canada (Central)"},{value:"eu-west-1",text:"Europe (Ireland)"},{value:"eu-west-2",text:"Europe (London)"},{value:"eu-west-3",text:"Europe (Paris)"},{value:"eu-central-1",text:"Europe (Frankfurt)"},{value:"eu-north-1",text:"Europe (Stockholm)"},{value:"eu-south-1",text:"Europe (Milan)"},{value:"ap-southeast-2",text:"Asia Pacific (Sydney)"}],columns:12,help:"Optional. Defaults to project AWS_REGION if omitted."},{name:"aws_key",type:"text",label:"AWS Key (optional)",placeholder:"enter your AWS Key with S3 permissions",columns:12,help:"Optional, AWS Key with S3 permissions"},{name:"aws_secret",type:"text",label:"AWS Secret (optional)",placeholder:"enter your AWS Secret with S3 permissions",columns:12,help:"Optional, AWS Secret with S3 permissions"}]}};let n=class extends e{constructor(e={}){super(e,{endpoint:"/api/fileman/file"})}isImage(){return"image"===this.get("category")}upload(e={}){return new FileUpload(this,e)}};class FileList extends t{constructor(e={}){super({ModelClass:n,endpoint:"/api/fileman/file",size:10,...e})}}const p={create:{title:"Add File",fields:[]},edit:{title:"Edit File Backend",fields:[]}},d=/* @__PURE__ */Object.freeze(/* @__PURE__ */Object.defineProperty({__proto__:null,File:n,FileForms:p,FileList:FileList,FileManager:FileManager,FileManagerForms:r,FileManagerList:FileManagerList},Symbol.toStringTag,{value:"Module"}));export{n as F,ProgressView as P,r as a,FileManagerList as b,p as c,FileList as d,FileManager as e,FileUpload as f,d as g};
|
|
2
|
-
//# sourceMappingURL=Files-C-ChBvr5.js.map
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
"use strict";const e=require("./Collection-CmjTsmrP.js"),t=require("./User-BnlvMG5J.js"),s=require("./Rest-B1eUyLX5.js");class ProgressView extends s.View{constructor(e={}){super({template:"progress-view-template",...e}),this.filename=e.filename||"Unknown file",this.filesize=e.filesize||0,this.filesizeFormatted=s.dataFormatter.pipe(this.filesize,"filesize"),this.progress=0,this.percentage=0,this.loaded=0,this.total=this.filesize,this.loadedFormatted="0 B",this.totalFormatted=this.filesizeFormatted,this.status="Starting upload...",this.showCancel=!1!==e.showCancel,this.onCancel=e.onCancel||null,this.cancelled=!1,this.completed=!1}getTemplate(){return'\n <div class="progress-view">\n <div class="d-flex justify-content-between align-items-start mb-2">\n <div class="flex-grow-1 min-width-0">\n <div class="fw-medium text-truncate" title="{{filename}}">\n <i class="bi bi-file-earmark me-1"></i>\n {{filename}}\n </div>\n <small class="text-muted">{{status}}</small>\n </div>\n {{#showCancel}}\n <button type="button" \n class="btn btn-sm btn-outline-secondary ms-2" \n data-action="cancel"\n {{#cancelled}}disabled{{/cancelled}}>\n <i class="bi bi-x"></i>\n </button>\n {{/showCancel}}\n </div>\n \n <div class="progress mb-2" style="height: 8px;">\n <div class="progress-bar" \n role="progressbar" \n style="width: {{percentage}}%"\n aria-valuenow="{{percentage}}" \n aria-valuemin="0" \n aria-valuemax="100">\n </div>\n </div>\n \n <div class="d-flex justify-content-between">\n <small class="text-muted">\n {{loadedFormatted}} / {{totalFormatted}}\n </small>\n <small class="text-muted">\n {{percentage}}%\n </small>\n </div>\n </div>\n '}updateProgress(e){this.cancelled||this.completed||(this.progress=e.progress,this.percentage=e.percentage,this.loaded=e.loaded,this.total=e.total||this.filesize,this.loadedFormatted=s.dataFormatter.pipe(this.loaded,"filesize"),this.totalFormatted=s.dataFormatter.pipe(this.total,"filesize"),this.percentage<100?this.status=`Uploading... ${this.percentage}%`:this.status="Finalizing upload...",this.render())}markCompleted(e="Upload completed!"){this.completed=!0,this.progress=1,this.percentage=100,this.status=e,this.render()}markFailed(e="Upload failed"){this.status=e,this.render()}markCancelled(){this.cancelled=!0,this.status="Upload cancelled",this.render()}async onActionCancel(e,t,s){if(!this.cancelled&&!this.completed&&(s.disabled=!0,this.markCancelled(),this.emit("cancel"),"function"==typeof this.onCancel))try{await this.onCancel()}catch(o){console.error("Error in cancel callback:",o)}}setFilename(e){this.filename=e,this.render()}setFilesize(e){this.filesize=e,this.filesizeFormatted=s.dataFormatter.pipe(e,"filesize"),this.total=e,this.totalFormatted=this.filesizeFormatted,this.render()}getPercentage(){return this.percentage}isCompleted(){return this.completed}isCancelled(){return this.cancelled}getStats(){return{filename:this.filename,filesize:this.filesize,progress:this.progress,percentage:this.percentage,loaded:this.loaded,total:this.total,cancelled:this.cancelled,completed:this.completed,status:this.status}}}class FileUpload{constructor(e,s={}){if(this.fileModel=e,this.options={file:null,name:null,group:null,description:null,onProgress:null,onComplete:null,onError:null,showToast:!0,...s},!(this.options.file&&this.options.file instanceof File))throw new Error("FileUpload requires a valid File object");this.cancelled=!1,this.uploadRequest=null,this.progressToast=null,this.progressView=null,this.toastService=null,this.options.showToast&&(this.toastService=new t.ToastService),this.promise=this._startUpload()}async _startUpload(){try{let t,s,o;this.options.showToast&&this._showProgressToast();try{t=await this._initiateUpload()}catch(e){throw new Error(`Failed to initiate upload: ${e.message}`)}if(this.cancelled)throw new Error("Upload cancelled");if(!t||!t.upload_url)throw new Error("Invalid upload response: missing upload URL");if("string"==typeof t.upload_url)s={url:t.upload_url,method:"PUT",fields:null,headers:{}};else{if(!t.upload_url||"object"!=typeof t.upload_url||!t.upload_url.upload_url)throw new Error(`Invalid upload response: unrecognised upload_url format. Server returned: ${JSON.stringify(t.upload_url)}`);s={url:t.upload_url.upload_url,method:t.upload_url.method||"POST",fields:t.upload_url.fields||null,headers:t.upload_url.headers||{}}}try{o=await this._performUpload(s)}catch(e){throw new Error(`File upload failed: ${e.message}`)}if(this.cancelled)throw new Error("Upload cancelled");try{await this._completeUpload()}catch(e){console.warn("Failed to mark upload as completed:",e)}return this._onComplete(this.fileModel),this.fileModel}catch(e){throw"Upload cancelled"!==e.message&&this._onError(e),e}}async _initiateUpload(){try{const e={filename:this.options.name||this.options.file.name,file_size:this.options.file.size,content_type:this.options.file.type};this.options.group&&(e.group=this.options.group),this.options.description&&(e.description=this.options.description);const t=await this.fileModel.rest.POST("/api/fileman/upload/initiate",e);if(!t)throw new Error("No response from upload initiation API");if(!t.data)throw new Error("Upload initiation response missing data");if(!t.data.status){const e=t.data.error||"Upload initiation failed";throw new Error(e)}if(!t.data.data)throw new Error("Upload initiation response missing data payload");return t.data.data.id&&this.fileModel.set("id",t.data.data.id),t.data.data}catch(e){if("Network Error"===e.message||"TypeError"===e.name)throw new Error("Network error during upload initiation. Please check your connection.");throw e}}async _performUpload(e){return new Promise((t,s)=>{if(!(this.options.file instanceof File))return void s(new Error("Only single File objects are supported"));const{url:o,method:a,fields:i,headers:l}=e,r="POST"===a&&null!==i,n=new XMLHttpRequest;this.uploadRequest=n,n.upload.onprogress=e=>{this.cancelled||this._onProgress({progress:e.loaded/e.total,loaded:e.loaded,total:e.total,percentage:Math.round(e.loaded/e.total*100)})},n.onload=()=>{n.status>=200&&n.status<300?t({data:n.response,status:n.status,statusText:n.statusText,xhr:n}):s(new Error(`Upload failed: ${n.status} ${n.statusText}`))},n.onerror=()=>s(new Error("Upload failed: Network error")),n.ontimeout=()=>s(new Error("Upload timed out — file may be too large or connection too slow")),n.onabort=()=>s(new Error("Upload cancelled"));let p=o;o.startsWith("/")&&!o.startsWith("/api/")&&(p="/api"+o);const d=this.fileModel.rest.buildUrl(p);if(n.open(a,d),n.timeout=3e4,r){for(const[t,s]of Object.entries(l||{}))"content-type"!==t.toLowerCase()&&n.setRequestHeader(t,s);const e=new FormData;for(const[t,s]of Object.entries(i))e.append(t,s);e.append("file",this.options.file),n.send(e)}else{n.setRequestHeader("Content-Type",this.options.file.type);for(const[e,t]of Object.entries(l||{}))"content-type"!==e.toLowerCase()&&n.setRequestHeader(e,t);n.send(this.options.file)}})}async _completeUpload(){try{const e=await this.fileModel.save({action:"mark_as_completed"});if(!e)throw new Error("No response from upload completion API");if(e.data&&!e.data.status){const t=e.data.error||"Failed to mark upload as completed";throw new Error(t)}return e}catch(e){if("Network Error"===e.message||"TypeError"===e.name)throw new Error("Network error during upload completion. The file may have uploaded successfully.");throw e}}_onProgress(e){this.progressToast&&this.progressToast.updateProgress&&this.progressToast.updateProgress(e),"function"==typeof this.options.onProgress&&this.options.onProgress(e)}_onComplete(e){this.progressView&&this.progressView.markCompleted("Upload completed successfully!"),this.progressToast&&setTimeout(()=>{try{this.progressToast&&"function"==typeof this.progressToast.hide&&this.progressToast.hide()}catch(e){console.warn("Error hiding progress toast:",e)}},2e3),"function"==typeof this.options.onComplete&&this.options.onComplete(e)}_onError(e){if(this.progressToast)try{this.progressToast.hide()}catch(t){console.warn("Error hiding progress toast on error:",t)}this.toastService&&this.toastService.error(`Upload failed: ${e.message}`),"function"==typeof this.options.onError&&this.options.onError(e)}_showProgressToast(){this.progressView=new ProgressView({filename:this.options.name||this.options.file.name,filesize:this.options.file.size,showCancel:!0,onCancel:()=>this.cancel()}),this.progressToast=this.toastService.showView(this.progressView,"info",{title:"File Upload",autohide:!1,dismissible:!1})}cancel(){return!this.cancelled&&(this.cancelled=!0,this.uploadRequest&&"function"==typeof this.uploadRequest.abort&&this.uploadRequest.abort(),this.progressView&&this.progressView.markCancelled(),this.progressToast&&setTimeout(()=>{try{this.progressToast&&"function"==typeof this.progressToast.hide&&this.progressToast.hide()}catch(e){console.warn("Error hiding progress toast on cancel:",e)}},1500),!0)}isCancelled(){return this.cancelled}then(e,t){return this.promise.then(e,t)}catch(e){return this.promise.catch(e)}finally(e){return this.promise.finally(e)}getStats(){return{filename:this.options.file.name,size:this.options.file.size,type:this.options.file.type,cancelled:this.cancelled,group:this.options.group,description:this.options.description}}}class FileManager extends e.Model{constructor(e={}){super(e,{endpoint:"/api/fileman/manager"})}}class FileManagerList extends e.Collection{constructor(e={}){super({ModelClass:FileManager,endpoint:"/api/fileman/manager",size:10,...e})}}const o={create:{title:"Add Storage Backend",fields:[{name:"name",type:"text",label:"Display Name",placeholder:"Enter Display Name",cols:12},{name:"use",type:"text",label:"Use",placeholder:"Enter User or Leave Blank",cols:12},{name:"backend_url",type:"text",label:"Backend URL",required:!0,value:"s3://BUCKET_NAME/OPTION_FOLDER",placeholder:"s3://bucket_name/optional folder",help:"Format: service://path. Valid services: s3",cols:12},{name:"aws_region",type:"select",label:"AWS Region (optional)",value:"us-east-1",options:[{value:"",text:"System Default"},{value:"us-east-1",text:"US East (N. Virginia)"},{value:"us-east-2",text:"US East (Ohio)"},{value:"us-west-1",text:"US West (N. California)"},{value:"us-west-2",text:"US West (Oregon)"},{value:"ca-central-1",text:"Canada (Central)"},{value:"eu-west-1",text:"Europe (Ireland)"},{value:"eu-west-2",text:"Europe (London)"},{value:"eu-west-3",text:"Europe (Paris)"},{value:"eu-central-1",text:"Europe (Frankfurt)"},{value:"eu-north-1",text:"Europe (Stockholm)"},{value:"eu-south-1",text:"Europe (Milan)"},{value:"ap-southeast-2",text:"Asia Pacific (Sydney)"}],columns:12,help:"Optional. Defaults to project AWS_REGION if omitted."},{name:"aws_key",type:"text",label:"AWS Key (optional)",placeholder:"enter your AWS Key with S3 permissions",columns:12,help:"Optional, AWS Key with S3 permissions"},{name:"aws_secret",type:"text",label:"AWS Secret (optional)",placeholder:"enter your AWS Secret with S3 permissions",columns:12,help:"Optional, AWS Secret with S3 permissions"},{name:"is_default",type:"switch",label:"Is Default",cols:6},{name:"is_active",type:"switch",label:"Is Active",default:!0,cols:6}]},edit:{title:"Edit Storage Backend",fields:[{name:"name",type:"text",label:"Display Name",placeholder:"Enter Display Name",cols:12},{name:"use",type:"text",label:"Use",placeholder:"Enter User or Leave Blank",cols:12},{name:"backend_url",type:"text",label:"Backend URL",required:!0,placeholder:"s3://bucket_name/optional folder",help:"Format: service://path. Valid services: s3",cols:12},{name:"allowed_origins",type:"text",label:"Domains Who Can Upload",cols:12},{name:"is_default",type:"switch",label:"Is Default",cols:6},{name:"is_active",type:"switch",label:"Is Active",default:!0,cols:6},{name:"is_public",type:"switch",label:"Is Public",default:!0,cols:6}]},owners:{fields:[{type:"collection",name:"group",label:"Group (Owner)",Collection:t.GroupList,labelField:"name",valueField:"id",maxItems:10,placeholder:"Search groups...",emptyFetch:!1,debounceMs:300},{type:"collection",name:"user",label:"User (Owner)",Collection:t.UserList,labelField:"display_name",valueField:"id",maxItems:10,placeholder:"Search users...",emptyFetch:!1,debounceMs:300}]},credentials:{fields:[{name:"aws_region",type:"select",label:"AWS Region (optional)",value:"us-east-1",options:[{value:"",text:"System Default"},{value:"us-east-1",text:"US East (N. Virginia)"},{value:"us-east-2",text:"US East (Ohio)"},{value:"us-west-1",text:"US West (N. California)"},{value:"us-west-2",text:"US West (Oregon)"},{value:"ca-central-1",text:"Canada (Central)"},{value:"eu-west-1",text:"Europe (Ireland)"},{value:"eu-west-2",text:"Europe (London)"},{value:"eu-west-3",text:"Europe (Paris)"},{value:"eu-central-1",text:"Europe (Frankfurt)"},{value:"eu-north-1",text:"Europe (Stockholm)"},{value:"eu-south-1",text:"Europe (Milan)"},{value:"ap-southeast-2",text:"Asia Pacific (Sydney)"}],columns:12,help:"Optional. Defaults to project AWS_REGION if omitted."},{name:"aws_key",type:"text",label:"AWS Key (optional)",placeholder:"enter your AWS Key with S3 permissions",columns:12,help:"Optional, AWS Key with S3 permissions"},{name:"aws_secret",type:"text",label:"AWS Secret (optional)",placeholder:"enter your AWS Secret with S3 permissions",columns:12,help:"Optional, AWS Secret with S3 permissions"}]}};let a=class extends e.Model{constructor(e={}){super(e,{endpoint:"/api/fileman/file"})}isImage(){return"image"===this.get("category")}upload(e={}){return new FileUpload(this,e)}};class FileList extends e.Collection{constructor(e={}){super({ModelClass:a,endpoint:"/api/fileman/file",size:10,...e})}}const i={create:{title:"Add File",fields:[]},edit:{title:"Edit File Backend",fields:[]}},l=/* @__PURE__ */Object.freeze(/* @__PURE__ */Object.defineProperty({__proto__:null,File:a,FileForms:i,FileList:FileList,FileManager:FileManager,FileManagerForms:o,FileManagerList:FileManagerList},Symbol.toStringTag,{value:"Module"}));exports.File=a,exports.FileForms=i,exports.FileList=FileList,exports.FileManager=FileManager,exports.FileManagerForms=o,exports.FileManagerList=FileManagerList,exports.FileUpload=FileUpload,exports.Files=l,exports.ProgressView=ProgressView;
|
|
2
|
-
//# sourceMappingURL=Files-DNbHDy43.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"User-BnlvMG5J.js","sources":["../../src/core/models/Group.js","../../src/core/models/User.js","../../src/core/services/ToastService.js"],"sourcesContent":["\nimport Collection from '@core/Collection.js';\nimport Model from '@core/Model.js';\n\n/**\n * Group Model - Represents an organization, team, or group entity\n *\n * Features:\n * - Hierarchical group support (parent/child relationships)\n * - Member management\n * - Search and filtering capabilities\n * - Role-based permissions within groups\n * - Metadata and settings management\n */\nclass Group extends Model {\n constructor(data = {}) {\n super(data, {\n endpoint: '/api/group'\n });\n }\n}\n\n/**\n * GroupCollection - Enhanced collection for managing groups with advanced search and filtering\n */\nclass GroupList extends Collection {\n constructor(options = {}) {\n super({\n ModelClass: Group,\n endpoint: '/api/group',\n size: 10,\n ...options\n });\n }\n}\n\nconst GroupKinds = {\n 'org': 'Organization',\n 'division': 'Division',\n 'department': 'Department',\n 'team': 'Team',\n 'merchant': 'Merchant',\n 'partner': 'Partner',\n 'client': 'Client',\n 'iso': 'ISO',\n 'sales': 'Sales',\n 'reseller': 'Reseller',\n 'location': 'Location',\n 'region': 'Region',\n 'route': 'Route',\n 'project': 'Project',\n \"inventory\": \"Inventory\",\n 'test': 'Testing',\n 'misc': 'Miscellaneous',\n 'qa': 'Quality Assurance'\n};\n\n// Convert GroupKinds to select options\nconst GroupKindOptions = Object.entries(GroupKinds).map(([key, label]) => ({\n value: key,\n label: label\n}));\n\n/**\n * Form configurations for group management\n */\nconst GroupForms = {\n create: {\n title: 'Create Group',\n fields: [\n {\n name: 'name',\n type: 'text',\n label: 'Group Name',\n required: true,\n placeholder: 'Enter group name'\n },\n {\n name: 'kind',\n type: 'select',\n label: 'Group Kind',\n required: true,\n options: GroupKindOptions\n },\n {\n type: 'collection',\n name: 'parent',\n label: 'Parent Group',\n Collection: GroupList, // Collection class\n labelField: 'name', // Field to display in dropdown\n valueField: 'id', // Field to use as value\n maxItems: 10, // Max items to show in dropdown\n placeholder: 'Search groups...',\n emptyFetch: false,\n debounceMs: 300, // Search debounce delay\n }\n ]\n },\n\n edit: {\n title: 'Edit Group',\n fields: [\n {\n name: 'name',\n type: 'text',\n label: 'Group Name',\n required: true,\n placeholder: 'Enter group name',\n },\n {\n name: 'kind',\n type: 'select',\n label: 'Group Kind',\n required: true,\n options: GroupKindOptions\n },\n {\n type: 'collection',\n name: 'parent',\n label: 'Parent Group',\n Collection: GroupList, // Collection class\n labelField: 'name', // Field to display in dropdown\n valueField: 'id', // Field to use as value\n maxItems: 10, // Max items to show in dropdown\n placeholder: 'Search groups...',\n emptyFetch: false,\n debounceMs: 300, // Search debounce delay\n },\n {\n name: 'metadata.domain',\n type: 'text',\n label: 'Default Domain',\n placeholder: 'Enter Domain',\n },\n {\n name: 'metadata.portal',\n type: 'text',\n label: 'Default Portal',\n placeholder: 'Enter Portal URL',\n },\n {\n name: 'is_active',\n type: 'switch',\n label: 'Is Active',\n cols: 4\n },\n ]\n },\n\n detailed: {\n title: 'Group Details',\n fields: [\n // Profile Header\n {\n type: 'header',\n text: 'Profile Information',\n level: 4,\n class: 'text-primary mb-3'\n },\n\n // Avatar and Basic Info\n {\n type: 'group',\n columns: { xs: 12, md: 4 },\n fields: [\n {\n type: 'image',\n name: 'avatar',\n size: 'lg',\n imageSize: { width: 200, height: 200 },\n placeholder: 'Upload your avatar',\n help: 'Square images work best',\n columns: 12\n },\n {\n name: 'is_active',\n type: 'switch',\n label: 'Is Active',\n columns: 12\n },\n ]\n },\n\n // Profile Details\n {\n type: 'group',\n columns: { xs: 12, md: 8 },\n title: 'Details',\n fields: [\n {\n name: 'name',\n type: 'text',\n label: 'Group Name',\n required: true,\n placeholder: 'Enter group name',\n columns: 12\n },\n {\n name: 'kind',\n type: 'select',\n label: 'Group Kind',\n required: true,\n columns: 12,\n options: [\n { value: 'org', label: 'Organization' },\n { value: 'team', label: 'Team' },\n { value: 'department', label: 'Department' },\n { value: 'merchant', label: 'Merchant' },\n { value: 'iso', label: 'ISO' },\n { value: 'group', label: 'Group' }\n ]\n },\n {\n type: 'collection',\n name: 'parent',\n label: 'Parent Group',\n Collection: GroupList, // Collection class\n labelField: 'name', // Field to display in dropdown\n valueField: 'id', // Field to use as value\n maxItems: 10, // Max items to show in dropdown\n placeholder: 'Search groups...',\n emptyFetch: false,\n debounceMs: 300, // Search debounce delay\n columns: 12\n }\n ]\n },\n\n // Account Settings\n {\n type: 'group',\n columns: 12,\n title: 'Account Settings',\n class: \"pt-3\",\n fields: [\n {\n type: 'select',\n name: 'metadata.timezone',\n label: 'Timezone',\n columns: 6,\n value: 'America/Los_Angeles',\n options: [\n { value: 'America/New_York', text: 'Eastern Time' },\n { value: 'America/Chicago', text: 'Central Time' },\n { value: 'America/Denver', text: 'Mountain Time' },\n { value: 'America/Los_Angeles', text: 'Pacific Time' },\n { value: 'UTC', text: 'UTC' }\n ]\n },\n {\n type: 'select',\n name: 'metadata.eod_hour',\n label: 'End of Day Hour',\n columns: 6,\n options: [\n { value: 0, text: 'Midnight' },\n { value: 1, text: '1 AM' },\n { value: 2, text: '2 AM' },\n { value: 3, text: '3 AM' },\n { value: 4, text: '4 AM' },\n { value: 5, text: '5 AM' },\n { value: 6, text: '6 AM' },\n { value: 7, text: '7 AM' },\n { value: 8, text: '8 AM' },\n { value: 9, text: '9 AM' },\n { value: 10, text: '10 AM' },\n { value: 11, text: '11 AM' },\n { value: 12, text: '12 PM' },\n { value: 13, text: '1 PM' },\n { value: 14, text: '2 PM' },\n { value: 15, text: '3 PM' },\n { value: 16, text: '4 PM' },\n { value: 17, text: '5 PM' },\n { value: 18, text: '6 PM' },\n { value: 19, text: '7 PM' },\n { value: 20, text: '8 PM' },\n { value: 21, text: '9 PM' },\n { value: 22, text: '10 PM' },\n { value: 23, text: '11 PM' }\n ]\n }\n ]\n },\n {\n type: \"text\",\n label: \"Email Template (Prefix)\",\n name: \"metadata.email_template\",\n columns: 12\n }\n ]\n },\n};\n\nGroup.EDIT_FORM = GroupForms.edit;\nGroup.ADD_FORM = GroupForms.create;\nGroup.CREATE_FORM = GroupForms.create; // Alias for compatibility\nGroup.GroupKindOptions = GroupKindOptions;\nGroup.GroupKinds = GroupKinds;\nexport { Group, GroupList, GroupForms };\n","import Collection from '@core/Collection.js';\nimport Model from '@core/Model.js';\n\nimport { GroupList } from './Group.js';\n\nclass User extends Model {\n constructor(data = {}) {\n super(data, {\n endpoint: '/api/user'\n });\n }\n\n hasPermission(permission) {\n if (this.get(\"is_superuser\")) return true;\n if (Array.isArray(permission)) {\n return permission.some(p => this.hasPermission(p));\n }\n\n // Check if permission has \"sys.\" prefix\n const isSysPermission = permission.startsWith('sys.');\n const permissionToCheck = isSysPermission ? permission.substring(4) : permission;\n\n if (this._hasPermission(permissionToCheck)) {\n return true;\n }\n\n // Only check member permissions if it's not a system permission\n if (!isSysPermission && this.member && this.member.hasPermission(permission)) {\n return true;\n }\n\n return false;\n }\n\n _hasPermission(permission) {\n const permissions = this.get(\"permissions\");\n if (!permissions) {\n return false;\n }\n return permissions[permission] == true;\n }\n\n hasPerm(p) {\n return this.hasPermission(p);\n }\n}\n\nclass UserList extends Collection {\n constructor(options = {}) {\n super({\n ModelClass: User,\n endpoint: '/api/user',\n ...options\n });\n }\n}\n\nUser.PERMISSIONS = [\n { name: \"manage_users\", label: \"Manage Users\" },\n { name: \"view_users\", label: \"View Users\" },\n { name: \"view_groups\", label: \"View Groups\" },\n { name: \"manage_groups\", label: \"Manage Groups\" },\n { name: \"view_metrics\", label: \"View System Metrics\" },\n { name: \"manage_metrics\", label: \"Manage System Metrics\" },\n { name: \"view_logs\", label: \"View Logs\" },\n { name: \"view_incidents\", label: \"View Incidents\" },\n { name: \"manage_incidents\", label: \"Manage Incidents\" },\n { name: \"view_tickets\", label: \"View Tickets\" },\n { name: \"manage_tickets\", label: \"Manage Tickets\" },\n { name: \"view_admin\", label: \"View Admin\" },\n { name: \"view_jobs\", label: \"View Jobs\" },\n { name: \"manage_jobs\", label: \"Manage Jobs\" },\n { name: \"view_global\", label: \"View Global\" },\n { name: \"manage_notifications\", label: \"Manage Notifications\" },\n { name: \"manage_files\", label: \"Manage Files\" },\n { name: \"force_single_session\", label: \"Force Single Session\" },\n { name: \"file_vault\", label: \"Access File Vault\" },\n { name: \"manage_aws\", label: \"Manage AWS\" },\n { name: \"manage_docit\", label: \"Manage DocIt\" }\n];\n\n\nUser.PERMISSION_FIELDS = [\n ...User.PERMISSIONS.map(permission => ({\n name: `permissions.${permission.name}`,\n type: 'switch',\n label: permission.label,\n columns: 4\n }))\n];\n\nconst UserForms = {\n create: {\n title: 'Create User',\n fields: [\n { name: 'email', type: 'text', label: 'Email', required: true },\n { name: 'phone_number', type: 'text', label: 'Phone number', columns: 12 },\n { name: 'display_name', type: 'text', label: 'Display Name' }\n ]\n },\n edit: {\n title: 'Edit User',\n fields: [\n { name: 'email', type: 'email', label: 'Email', columns: 12 },\n { name: 'display_name', type: 'text', label: 'Display Name', columns: 12},\n { name: 'phone_number', type: 'text', label: 'Phone number', columns: 12 },\n { type: 'collection', name: 'org', label: 'Organization', Collection: GroupList, labelField: 'name', valueField: 'id', columns: 12 },\n ]\n },\n permissions: {\n title: 'Edit Permissions',\n fields: User.PERMISSION_FIELDS\n }\n};\n\n\n// DataView configuration for User model\nconst UserDataView = {\n // Basic user profile view\n profile: {\n title: 'User Profile',\n columns: 2,\n fields: [\n {\n name: 'id',\n label: 'User ID',\n type: 'number',\n columns: 4\n },\n {\n name: 'last_login',\n label: 'Last Login',\n type: 'datetime',\n format: 'relative',\n columns: 4\n },\n {\n name: 'last_activity',\n label: 'Last Activity',\n type: 'datetime',\n format: 'relative',\n columns: 4\n },\n {\n name: 'username',\n label: 'Username',\n type: 'text',\n format: 'lowercase',\n columns: 4\n },\n {\n name: 'display_name',\n label: 'Display Name',\n type: 'text',\n columns: 4\n },\n\n {\n name: 'email',\n label: 'Email',\n type: 'email',\n columns: 12\n },\n\n {\n name: 'org.name',\n label: 'Organization',\n type: 'text',\n columns: 6\n },\n {\n name: 'phone_number',\n label: 'Phone Number',\n type: 'text',\n columns: 6\n }\n ]\n },\n\n // Activity tracking view\n activity: {\n title: 'User Activity',\n columns: 2,\n fields: [\n {\n name: 'last_login',\n label: 'Last Login',\n type: 'datetime',\n format: 'relative',\n colSize: 6\n },\n {\n name: 'last_activity',\n label: 'Last Activity',\n type: 'datetime',\n format: 'relative',\n colSize: 6\n }\n ]\n },\n\n // Comprehensive view with all data\n detailed: {\n title: 'Detailed User Information',\n columns: 2,\n showEmptyValues: true,\n emptyValueText: 'Not set',\n fields: [\n // Basic Info Section\n {\n name: 'id',\n label: 'User ID',\n type: 'number',\n colSize: 3\n },\n {\n name: 'display_name',\n label: 'Display Name',\n type: 'text',\n format: 'capitalize|default(\"Unnamed User\")',\n colSize: 9\n },\n {\n name: 'username',\n label: 'Username',\n type: 'text',\n format: 'lowercase',\n colSize: 6\n },\n {\n name: 'email',\n label: 'Email Address',\n type: 'email',\n colSize: 6\n },\n {\n name: 'phone_number',\n label: 'Phone Number',\n type: 'phone',\n format: 'phone|default(\"Not provided\")',\n colSize: 6\n },\n {\n name: 'is_active',\n label: 'Account Status',\n type: 'boolean',\n colSize: 6\n },\n\n // Activity Info\n {\n name: 'last_login',\n label: 'Last Login',\n type: 'datetime',\n format: 'relative',\n colSize: 6\n },\n {\n name: 'last_activity',\n label: 'Last Activity',\n type: 'datetime',\n format: 'relative',\n colSize: 6\n },\n\n // Avatar Info\n {\n name: 'avatar.url',\n label: 'Avatar',\n type: 'url',\n colSize: 12\n },\n\n // Complex Data (will use full width automatically)\n {\n name: 'permissions',\n label: 'User Permissions',\n type: 'dataview',\n dataViewColumns: 2,\n showEmptyValues: false\n },\n {\n name: 'metadata',\n label: 'User Metadata',\n type: 'dataview',\n dataViewColumns: 1\n },\n {\n name: 'avatar',\n label: 'Avatar Details',\n type: 'dataview',\n dataViewColumns: 1\n }\n ]\n },\n\n // Permissions-focused view\n permissions: {\n title: 'User Permissions',\n columns: 1,\n fields: [\n {\n name: 'display_name',\n label: 'User',\n type: 'text',\n format: 'capitalize',\n columns: 12\n },\n {\n name: 'permissions',\n label: 'Assigned Permissions',\n type: 'dataview',\n dataViewColumns: 3,\n showEmptyValues: false,\n colSize: 12\n }\n ]\n },\n\n // Compact summary view\n summary: {\n title: 'User Summary',\n columns: 3,\n fields: [\n {\n name: 'display_name',\n label: 'Name',\n type: 'text',\n format: 'capitalize|truncate(30)'\n },\n {\n name: 'email',\n label: 'Email',\n type: 'email'\n },\n {\n name: 'is_active',\n label: 'Status',\n type: 'boolean'\n },\n {\n name: 'last_activity',\n label: 'Last Seen',\n type: 'datetime',\n format: 'relative',\n colSize: 12\n }\n ]\n }\n};\n\nUser.DATA_VIEW = UserDataView.detailed;\nUser.EDIT_FORM = UserForms.edit;\nUser.ADD_FORM = UserForms.create;\n\n/* =========================\n * UserDevice\n * ========================= */\nclass UserDevice extends Model {\n constructor(data = {}) {\n super(data, {\n endpoint: '/api/user/device',\n });\n }\n\n static async getByDuid(duid) {\n const model = new UserDevice();\n const resp = await model.rest.GET('/api/user/device/lookup', { duid: duid });\n if (resp.success && resp.data && resp.data.data) {\n // A direct lookup should return a single object\n return new UserDevice(resp.data.data);\n }\n return null;\n }\n}\n\nclass UserDeviceList extends Collection {\n constructor(options = {}) {\n super({\n ModelClass: UserDevice,\n endpoint: '/api/user/device',\n ...options,\n });\n }\n}\n\n/* =========================\n * UserDeviceLocation\n * ========================= */\nclass UserDeviceLocation extends Model {\n constructor(data = {}) {\n super(data, {\n endpoint: '/api/user/device/location',\n });\n }\n}\n\nclass UserDeviceLocationList extends Collection {\n constructor(options = {}) {\n super({\n ModelClass: UserDeviceLocation,\n endpoint: '/api/user/device/location',\n ...options,\n });\n }\n}\n\nexport { User, UserList, UserForms, UserDataView, UserDevice, UserDeviceList, UserDeviceLocation, UserDeviceLocationList };\n","/**\n * ToastService - Bootstrap 5 Toast Notification Service\n * Provides methods to display toast notifications with different types and options\n *\n * Features:\n * - Bootstrap 5 toast integration\n * - Multiple toast types (success, error, info, warning)\n * - Auto-dismiss with customizable delays\n * - Toast container management\n * - Event integration\n * - Proper cleanup and memory management\n *\n * @example\n * const toastService = new ToastService();\n * toastService.success('Operation completed successfully!');\n * toastService.error('Something went wrong');\n * toastService.info('FYI: This is informational');\n * toastService.warning('Please be careful');\n */\n\nclass ToastService {\n constructor(options = {}) {\n this.options = {\n containerId: 'toast-container',\n position: 'top-end', // top-start, top-center, top-end, middle-start, etc.\n autohide: true,\n defaultDelay: 5000, // 5 seconds\n maxToasts: 5, // Maximum number of toasts to show at once\n ...options\n };\n\n this.toasts = new Map(); // Track active toasts\n this.toastCounter = 0; // For unique IDs\n\n this.init();\n }\n\n /**\n * Initialize the toast service\n */\n init() {\n this.createContainer();\n }\n\n /**\n * Create the toast container if it doesn't exist\n */\n createContainer() {\n let container = document.getElementById(this.options.containerId);\n\n if (!container) {\n container = document.createElement('div');\n container.id = this.options.containerId;\n container.className = `toast-container position-fixed ${this.getPositionClasses()}`;\n container.style.zIndex = '1070'; // Bootstrap toast z-index\n container.setAttribute('aria-live', 'polite');\n container.setAttribute('aria-atomic', 'true');\n\n document.body.appendChild(container);\n }\n\n this.container = container;\n }\n\n /**\n * Get CSS classes for toast positioning\n */\n getPositionClasses() {\n const positionMap = {\n 'top-start': 'top-0 start-0 p-3',\n 'top-center': 'top-0 start-50 translate-middle-x p-3',\n 'top-end': 'top-0 end-0 p-3',\n 'middle-start': 'top-50 start-0 translate-middle-y p-3',\n 'middle-center': 'top-50 start-50 translate-middle p-3',\n 'middle-end': 'top-50 end-0 translate-middle-y p-3',\n 'bottom-start': 'bottom-0 start-0 p-3',\n 'bottom-center': 'bottom-0 start-50 translate-middle-x p-3',\n 'bottom-end': 'bottom-0 end-0 p-3'\n };\n\n return positionMap[this.options.position] || positionMap['top-end'];\n }\n\n\n\n /**\n * Show a success toast\n * @param {string} message - The message to display\n * @param {object} options - Additional options\n */\n success(message, options = {}) {\n return this.show(message, 'success', {\n icon: 'bi-check-circle-fill',\n ...options\n });\n }\n\n /**\n * Show an error toast\n * @param {string} message - The message to display\n * @param {object} options - Additional options\n */\n error(message, options = {}) {\n return this.show(message, 'error', {\n icon: 'bi-exclamation-triangle-fill',\n autohide: true, // Keep error toasts visible until manually dismissed\n ...options\n });\n }\n\n /**\n * Show an info toast\n * @param {string} message - The message to display\n * @param {object} options - Additional options\n */\n info(message, options = {}) {\n return this.show(message, 'info', {\n icon: 'bi-info-circle-fill',\n ...options\n });\n }\n\n /**\n * Show a warning toast\n * @param {string} message - The message to display\n * @param {object} options - Additional options\n */\n warning(message, options = {}) {\n return this.show(message, 'warning', {\n icon: 'bi-exclamation-triangle-fill',\n ...options\n });\n }\n\n /**\n * Show a plain toast without specific styling\n * @param {string} message - The message to display\n * @param {object} options - Additional options\n */\n plain(message, options = {}) {\n return this.show(message, 'plain', {\n ...options\n });\n }\n\n /**\n * Show a toast with specified type and options\n * @param {string} message - The message to display\n * @param {string} type - Toast type (success, error, info, warning)\n * @param {object} options - Additional options\n */\n show(message, type = 'info', options = {}) {\n // Enforce max toasts limit\n this.enforceMaxToasts();\n\n const toastId = `toast-${++this.toastCounter}`;\n const config = {\n title: this.getDefaultTitle(type),\n icon: this.getDefaultIcon(type),\n autohide: this.options.autohide,\n delay: this.options.defaultDelay,\n dismissible: true,\n ...options\n };\n\n const toastElement = this.createToastElement(toastId, message, type, config);\n this.container.appendChild(toastElement);\n\n // Initialize Bootstrap toast\n if (typeof bootstrap === 'undefined') {\n throw new Error('Bootstrap is required for ToastService. Make sure Bootstrap 5 is loaded.');\n }\n const bsToast = new bootstrap.Toast(toastElement, {\n autohide: config.autohide,\n delay: config.delay\n });\n\n // Store toast reference\n this.toasts.set(toastId, {\n element: toastElement,\n bootstrap: bsToast,\n type: type,\n message: message\n });\n\n // Setup cleanup on hide\n toastElement.addEventListener('hidden.bs.toast', () => {\n this.cleanup(toastId);\n });\n\n // Show the toast\n bsToast.show();\n\n return {\n id: toastId,\n hide: () => {\n try {\n bsToast.hide();\n } catch (error) {\n console.warn('Error hiding toast:', error);\n }\n },\n dispose: () => this.cleanup(toastId),\n updateProgress: options.updateProgress || null\n };\n }\n\n /**\n * Show a toast with a View component in the body\n * @param {View} view - The View component to display\n * @param {string} type - Toast type (success, error, info, warning, plain)\n * @param {object} options - Additional options\n */\n showView(view, type = 'info', options = {}) {\n // Enforce max toasts limit\n this.enforceMaxToasts();\n\n const toastId = `toast-${++this.toastCounter}`;\n const config = {\n title: options.title || this.getDefaultTitle(type),\n icon: options.icon || this.getDefaultIcon(type),\n autohide: this.options.autohide,\n delay: this.options.defaultDelay,\n dismissible: true,\n ...options\n };\n\n const toastElement = this.createViewToastElement(toastId, view, type, config);\n this.container.appendChild(toastElement);\n\n // Initialize Bootstrap toast\n if (typeof bootstrap === 'undefined') {\n throw new Error('Bootstrap is required for ToastService. Make sure Bootstrap 5 is loaded.');\n }\n const bsToast = new bootstrap.Toast(toastElement, {\n autohide: config.autohide,\n delay: config.delay\n });\n\n // Store toast reference with view\n this.toasts.set(toastId, {\n element: toastElement,\n bootstrap: bsToast,\n type: type,\n view: view,\n message: 'View toast'\n });\n\n // Setup cleanup on hide - dispose view properly\n toastElement.addEventListener('hidden.bs.toast', () => {\n this.cleanupView(toastId);\n });\n\n // Mount and render the view\n const bodyContainer = toastElement.querySelector('.toast-view-body');\n if (bodyContainer && view) {\n view.render(true, bodyContainer);\n }\n\n // Show the toast\n bsToast.show();\n\n return {\n id: toastId,\n view: view,\n hide: () => {\n try {\n bsToast.hide();\n } catch (error) {\n console.warn('Error hiding view toast:', error);\n }\n },\n dispose: () => this.cleanupView(toastId),\n updateProgress: (progressInfo) => {\n if (view && typeof view.updateProgress === 'function') {\n view.updateProgress(progressInfo);\n }\n }\n };\n }\n\n /**\n * Create toast DOM element\n */\n createToastElement(id, message, type, config) {\n const toast = document.createElement('div');\n toast.id = id;\n toast.className = `toast toast-service-${type}`;\n toast.setAttribute('role', 'alert');\n toast.setAttribute('aria-live', 'assertive');\n toast.setAttribute('aria-atomic', 'true');\n\n const header = config.title || config.icon ? this.createToastHeader(config, type) : '';\n const body = this.createToastBody(message, config.icon && !config.title);\n\n toast.innerHTML = `\n ${header}\n ${body}\n `;\n\n return toast;\n }\n\n /**\n * Create toast DOM element for View component\n */\n createViewToastElement(id, view, type, config) {\n const toast = document.createElement('div');\n toast.id = id;\n toast.className = `toast toast-service-${type}`;\n toast.setAttribute('role', 'alert');\n toast.setAttribute('aria-live', 'assertive');\n toast.setAttribute('aria-atomic', 'true');\n\n const header = config.title || config.icon ? this.createToastHeader(config, type) : '';\n const body = this.createViewToastBody();\n\n toast.innerHTML = `\n ${header}\n ${body}\n `;\n\n return toast;\n }\n\n /**\n * Create toast body for View component\n */\n createViewToastBody() {\n return `\n <div class=\"toast-body p-0\">\n <div class=\"toast-view-body p-3\"></div>\n </div>\n `;\n }\n\n /**\n * Create toast header with title and icon\n */\n createToastHeader(config, _type) {\n const iconHtml = config.icon ?\n `<i class=\"${config.icon} toast-service-icon me-2\"></i>` : '';\n\n const titleHtml = config.title ?\n `<strong class=\"me-auto\">${iconHtml}${this.escapeHtml(config.title)}</strong>` : '';\n\n const timeHtml = config.showTime ?\n `<small class=\"text-muted\">${this.getTimeString()}</small>` : '';\n\n const closeButton = config.dismissible ?\n `<button type=\"button\" class=\"btn-close toast-service-close\" data-bs-dismiss=\"toast\" aria-label=\"Close\"></button>` : '';\n\n if (!titleHtml && !timeHtml && !closeButton) {\n return '';\n }\n\n return `\n <div class=\"toast-header\">\n ${titleHtml}\n ${timeHtml}\n ${closeButton}\n </div>\n `;\n }\n\n /**\n * Create toast body with message\n */\n createToastBody(message, showIcon = false) {\n const iconHtml = showIcon ?\n `<i class=\"${this.getDefaultIcon('info')} toast-service-icon me-2\"></i>` : '';\n\n return `\n <div class=\"toast-body d-flex align-items-center\">\n ${iconHtml}\n <span>${this.escapeHtml(message)}</span>\n </div>\n `;\n }\n\n /**\n * Get default title for toast type\n */\n getDefaultTitle(type) {\n const titles = {\n success: 'Success',\n error: 'Error',\n warning: 'Warning',\n info: 'Information',\n plain: ''\n };\n return titles[type] || 'Notification';\n }\n\n /**\n * Get default icon for toast type\n */\n getDefaultIcon(type) {\n const icons = {\n success: 'bi-check-circle-fill',\n error: 'bi-exclamation-triangle-fill',\n warning: 'bi-exclamation-triangle-fill',\n info: 'bi-info-circle-fill',\n plain: ''\n };\n return icons[type] || 'bi-info-circle-fill';\n }\n\n /**\n * Enforce maximum number of toasts\n */\n enforceMaxToasts() {\n const activeToasts = Array.from(this.toasts.values());\n\n if (activeToasts.length >= this.options.maxToasts) {\n // Remove oldest toast\n const oldestId = this.toasts.keys().next().value;\n const oldest = this.toasts.get(oldestId);\n\n if (oldest) {\n oldest.bootstrap.hide();\n }\n }\n }\n\n /**\n * Clean up toast resources\n */\n cleanup(toastId) {\n const toast = this.toasts.get(toastId);\n\n if (toast) {\n // Dispose Bootstrap toast\n try {\n toast.bootstrap.dispose();\n } catch (e) {\n console.warn('Error disposing toast:', e);\n }\n\n // Remove from DOM\n if (toast.element && toast.element.parentNode) {\n toast.element.parentNode.removeChild(toast.element);\n }\n\n // Remove from tracking\n this.toasts.delete(toastId);\n }\n }\n\n /**\n * Clean up view toast resources with proper view disposal\n */\n cleanupView(toastId) {\n const toast = this.toasts.get(toastId);\n\n if (toast) {\n // Dispose view first if it exists\n if (toast.view && typeof toast.view.dispose === 'function') {\n try {\n toast.view.dispose();\n } catch (e) {\n console.warn('Error disposing view in toast:', e);\n }\n }\n\n // Dispose Bootstrap toast\n try {\n toast.bootstrap.dispose();\n } catch (e) {\n console.warn('Error disposing toast:', e);\n }\n\n // Remove from DOM\n if (toast.element && toast.element.parentNode) {\n toast.element.parentNode.removeChild(toast.element);\n }\n\n // Remove from tracking\n this.toasts.delete(toastId);\n }\n }\n\n /**\n * Hide all active toasts\n */\n hideAll() {\n this.toasts.forEach((toast, _id) => {\n toast.bootstrap.hide();\n });\n }\n\n /**\n * Clear all toasts immediately\n */\n clearAll() {\n this.toasts.forEach((toast, id) => {\n this.cleanup(id);\n });\n }\n\n /**\n * Get current time string\n */\n getTimeString() {\n return new Date().toLocaleTimeString([], {\n hour: '2-digit',\n minute: '2-digit'\n });\n }\n\n /**\n * Escape HTML to prevent XSS\n */\n escapeHtml(str) {\n const div = document.createElement('div');\n div.textContent = str;\n return div.innerHTML;\n }\n\n /**\n * Dispose of the entire toast service\n */\n dispose() {\n this.clearAll();\n\n if (this.container && this.container.parentNode) {\n this.container.parentNode.removeChild(this.container);\n }\n }\n\n /**\n * Get statistics about active toasts\n */\n getStats() {\n const stats = {\n total: this.toasts.size,\n byType: {}\n };\n\n this.toasts.forEach(toast => {\n stats.byType[toast.type] = (stats.byType[toast.type] || 0) + 1;\n });\n\n return stats;\n }\n\n /**\n * Set global options\n */\n setOptions(newOptions) {\n this.options = { ...this.options, ...newOptions };\n\n // Recreate container if position changed\n if (newOptions.position) {\n if (this.container) {\n this.container.className = `toast-container position-fixed ${this.getPositionClasses()}`;\n }\n }\n }\n}\n\nexport default ToastService;\n"],"names":["Group","Model","constructor","data","super","endpoint","GroupList","Collection","options","ModelClass","size","GroupKinds","org","division","department","team","merchant","partner","client","iso","sales","reseller","location","region","route","project","inventory","test","misc","qa","GroupKindOptions","Object","entries","map","key","label","value","GroupForms","create","title","fields","name","type","required","placeholder","labelField","valueField","maxItems","emptyFetch","debounceMs","edit","cols","detailed","text","level","class","columns","xs","md","imageSize","width","height","help","EDIT_FORM","ADD_FORM","CREATE_FORM","User","hasPermission","permission","this","get","Array","isArray","some","p","isSysPermission","startsWith","permissionToCheck","substring","_hasPermission","member","permissions","hasPerm","UserList","PERMISSIONS","PERMISSION_FIELDS","UserForms","UserDataView","profile","format","activity","colSize","showEmptyValues","emptyValueText","dataViewColumns","summary","DATA_VIEW","UserDevice","getByDuid","duid","model","resp","rest","GET","success","UserDeviceList","UserDeviceLocation","UserDeviceLocationList","containerId","position","autohide","defaultDelay","maxToasts","toasts","Map","toastCounter","init","createContainer","container","document","getElementById","createElement","id","className","getPositionClasses","style","zIndex","setAttribute","body","appendChild","positionMap","message","show","icon","error","info","warning","plain","enforceMaxToasts","toastId","config","getDefaultTitle","getDefaultIcon","delay","dismissible","toastElement","createToastElement","bootstrap","Error","bsToast","Toast","set","element","addEventListener","cleanup","hide","console","warn","dispose","updateProgress","showView","view","createViewToastElement","cleanupView","bodyContainer","querySelector","render","progressInfo","toast","header","createToastHeader","createToastBody","innerHTML","createViewToastBody","_type","iconHtml","titleHtml","escapeHtml","timeHtml","showTime","getTimeString","closeButton","showIcon","from","values","length","oldestId","keys","next","oldest","e","parentNode","removeChild","delete","hideAll","forEach","_id","clearAll","Date","toLocaleTimeString","hour","minute","str","div","textContent","getStats","stats","total","byType","setOptions","newOptions"],"mappings":"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"}
|
|
@@ -1,3 +0,0 @@
|
|
|
1
|
-
import{C as e,M as t}from"./Collection-BWKmydl5.js";class ToastService{constructor(e={}){this.options={containerId:"toast-container",position:"top-end",autohide:!0,defaultDelay:5e3,maxToasts:5,...e},this.toasts=/* @__PURE__ */new Map,this.toastCounter=0,this.init()}init(){this.createContainer()}createContainer(){let e=document.getElementById(this.options.containerId);e||(e=document.createElement("div"),e.id=this.options.containerId,e.className=`toast-container position-fixed ${this.getPositionClasses()}`,e.style.zIndex="1070",e.setAttribute("aria-live","polite"),e.setAttribute("aria-atomic","true"),document.body.appendChild(e)),this.container=e}getPositionClasses(){const e={"top-start":"top-0 start-0 p-3","top-center":"top-0 start-50 translate-middle-x p-3","top-end":"top-0 end-0 p-3","middle-start":"top-50 start-0 translate-middle-y p-3","middle-center":"top-50 start-50 translate-middle p-3","middle-end":"top-50 end-0 translate-middle-y p-3","bottom-start":"bottom-0 start-0 p-3","bottom-center":"bottom-0 start-50 translate-middle-x p-3","bottom-end":"bottom-0 end-0 p-3"};return e[this.options.position]||e["top-end"]}success(e,t={}){return this.show(e,"success",{icon:"bi-check-circle-fill",...t})}error(e,t={}){return this.show(e,"error",{icon:"bi-exclamation-triangle-fill",autohide:!0,...t})}info(e,t={}){return this.show(e,"info",{icon:"bi-info-circle-fill",...t})}warning(e,t={}){return this.show(e,"warning",{icon:"bi-exclamation-triangle-fill",...t})}plain(e,t={}){return this.show(e,"plain",{...t})}show(e,t="info",a={}){this.enforceMaxToasts();const s="toast-"+ ++this.toastCounter,i={title:this.getDefaultTitle(t),icon:this.getDefaultIcon(t),autohide:this.options.autohide,delay:this.options.defaultDelay,dismissible:!0,...a},o=this.createToastElement(s,e,t,i);if(this.container.appendChild(o),"undefined"==typeof bootstrap)throw new Error("Bootstrap is required for ToastService. Make sure Bootstrap 5 is loaded.");const n=new bootstrap.Toast(o,{autohide:i.autohide,delay:i.delay});return this.toasts.set(s,{element:o,bootstrap:n,type:t,message:e}),o.addEventListener("hidden.bs.toast",()=>{this.cleanup(s)}),n.show(),{id:s,hide:()=>{try{n.hide()}catch(e){console.warn("Error hiding toast:",e)}},dispose:()=>this.cleanup(s),updateProgress:a.updateProgress||null}}showView(e,t="info",a={}){this.enforceMaxToasts();const s="toast-"+ ++this.toastCounter,i={title:a.title||this.getDefaultTitle(t),icon:a.icon||this.getDefaultIcon(t),autohide:this.options.autohide,delay:this.options.defaultDelay,dismissible:!0,...a},o=this.createViewToastElement(s,e,t,i);if(this.container.appendChild(o),"undefined"==typeof bootstrap)throw new Error("Bootstrap is required for ToastService. Make sure Bootstrap 5 is loaded.");const n=new bootstrap.Toast(o,{autohide:i.autohide,delay:i.delay});this.toasts.set(s,{element:o,bootstrap:n,type:t,view:e,message:"View toast"}),o.addEventListener("hidden.bs.toast",()=>{this.cleanupView(s)});const l=o.querySelector(".toast-view-body");return l&&e&&e.render(!0,l),n.show(),{id:s,view:e,hide:()=>{try{n.hide()}catch(e){console.warn("Error hiding view toast:",e)}},dispose:()=>this.cleanupView(s),updateProgress:t=>{e&&"function"==typeof e.updateProgress&&e.updateProgress(t)}}}createToastElement(e,t,a,s){const i=document.createElement("div");i.id=e,i.className=`toast toast-service-${a}`,i.setAttribute("role","alert"),i.setAttribute("aria-live","assertive"),i.setAttribute("aria-atomic","true");const o=s.title||s.icon?this.createToastHeader(s,a):"",n=this.createToastBody(t,s.icon&&!s.title);return i.innerHTML=`\n ${o}\n ${n}\n `,i}createViewToastElement(e,t,a,s){const i=document.createElement("div");i.id=e,i.className=`toast toast-service-${a}`,i.setAttribute("role","alert"),i.setAttribute("aria-live","assertive"),i.setAttribute("aria-atomic","true");const o=s.title||s.icon?this.createToastHeader(s,a):"",n=this.createViewToastBody();return i.innerHTML=`\n ${o}\n ${n}\n `,i}createViewToastBody(){return'\n <div class="toast-body p-0">\n <div class="toast-view-body p-3"></div>\n </div>\n '}createToastHeader(e,t){const a=e.icon?`<i class="${e.icon} toast-service-icon me-2"></i>`:"",s=e.title?`<strong class="me-auto">${a}${this.escapeHtml(e.title)}</strong>`:"",i=e.showTime?`<small class="text-muted">${this.getTimeString()}</small>`:"",o=e.dismissible?'<button type="button" class="btn-close toast-service-close" data-bs-dismiss="toast" aria-label="Close"></button>':"";return s||i||o?`\n <div class="toast-header">\n ${s}\n ${i}\n ${o}\n </div>\n `:""}createToastBody(e,t=!1){return`\n <div class="toast-body d-flex align-items-center">\n ${t?`<i class="${this.getDefaultIcon("info")} toast-service-icon me-2"></i>`:""}\n <span>${this.escapeHtml(e)}</span>\n </div>\n `}getDefaultTitle(e){return{success:"Success",error:"Error",warning:"Warning",info:"Information",plain:""}[e]||"Notification"}getDefaultIcon(e){return{success:"bi-check-circle-fill",error:"bi-exclamation-triangle-fill",warning:"bi-exclamation-triangle-fill",info:"bi-info-circle-fill",plain:""}[e]||"bi-info-circle-fill"}enforceMaxToasts(){if(Array.from(this.toasts.values()).length>=this.options.maxToasts){const e=this.toasts.keys().next().value,t=this.toasts.get(e);t&&t.bootstrap.hide()}}cleanup(e){const t=this.toasts.get(e);if(t){try{t.bootstrap.dispose()}catch(a){console.warn("Error disposing toast:",a)}t.element&&t.element.parentNode&&t.element.parentNode.removeChild(t.element),this.toasts.delete(e)}}cleanupView(e){const t=this.toasts.get(e);if(t){if(t.view&&"function"==typeof t.view.dispose)try{t.view.dispose()}catch(a){console.warn("Error disposing view in toast:",a)}try{t.bootstrap.dispose()}catch(a){console.warn("Error disposing toast:",a)}t.element&&t.element.parentNode&&t.element.parentNode.removeChild(t.element),this.toasts.delete(e)}}hideAll(){this.toasts.forEach((e,t)=>{e.bootstrap.hide()})}clearAll(){this.toasts.forEach((e,t)=>{this.cleanup(t)})}getTimeString(){/* @__PURE__ */
|
|
2
|
-
return(new Date).toLocaleTimeString([],{hour:"2-digit",minute:"2-digit"})}escapeHtml(e){const t=document.createElement("div");return t.textContent=e,t.innerHTML}dispose(){this.clearAll(),this.container&&this.container.parentNode&&this.container.parentNode.removeChild(this.container)}getStats(){const e={total:this.toasts.size,byType:{}};return this.toasts.forEach(t=>{e.byType[t.type]=(e.byType[t.type]||0)+1}),e}setOptions(e){this.options={...this.options,...e},e.position&&this.container&&(this.container.className=`toast-container position-fixed ${this.getPositionClasses()}`)}}class Group extends t{constructor(e={}){super(e,{endpoint:"/api/group"})}}class GroupList extends e{constructor(e={}){super({ModelClass:Group,endpoint:"/api/group",size:10,...e})}}const a={org:"Organization",division:"Division",department:"Department",team:"Team",merchant:"Merchant",partner:"Partner",client:"Client",iso:"ISO",sales:"Sales",reseller:"Reseller",location:"Location",region:"Region",route:"Route",project:"Project",inventory:"Inventory",test:"Testing",misc:"Miscellaneous",qa:"Quality Assurance"},s=Object.entries(a).map(([e,t])=>({value:e,label:t})),i={create:{title:"Create Group",fields:[{name:"name",type:"text",label:"Group Name",required:!0,placeholder:"Enter group name"},{name:"kind",type:"select",label:"Group Kind",required:!0,options:s},{type:"collection",name:"parent",label:"Parent Group",Collection:GroupList,labelField:"name",valueField:"id",maxItems:10,placeholder:"Search groups...",emptyFetch:!1,debounceMs:300}]},edit:{title:"Edit Group",fields:[{name:"name",type:"text",label:"Group Name",required:!0,placeholder:"Enter group name"},{name:"kind",type:"select",label:"Group Kind",required:!0,options:s},{type:"collection",name:"parent",label:"Parent Group",Collection:GroupList,labelField:"name",valueField:"id",maxItems:10,placeholder:"Search groups...",emptyFetch:!1,debounceMs:300},{name:"metadata.domain",type:"text",label:"Default Domain",placeholder:"Enter Domain"},{name:"metadata.portal",type:"text",label:"Default Portal",placeholder:"Enter Portal URL"},{name:"is_active",type:"switch",label:"Is Active",cols:4}]},detailed:{title:"Group Details",fields:[{type:"header",text:"Profile Information",level:4,class:"text-primary mb-3"},{type:"group",columns:{xs:12,md:4},fields:[{type:"image",name:"avatar",size:"lg",imageSize:{width:200,height:200},placeholder:"Upload your avatar",help:"Square images work best",columns:12},{name:"is_active",type:"switch",label:"Is Active",columns:12}]},{type:"group",columns:{xs:12,md:8},title:"Details",fields:[{name:"name",type:"text",label:"Group Name",required:!0,placeholder:"Enter group name",columns:12},{name:"kind",type:"select",label:"Group Kind",required:!0,columns:12,options:[{value:"org",label:"Organization"},{value:"team",label:"Team"},{value:"department",label:"Department"},{value:"merchant",label:"Merchant"},{value:"iso",label:"ISO"},{value:"group",label:"Group"}]},{type:"collection",name:"parent",label:"Parent Group",Collection:GroupList,labelField:"name",valueField:"id",maxItems:10,placeholder:"Search groups...",emptyFetch:!1,debounceMs:300,columns:12}]},{type:"group",columns:12,title:"Account Settings",class:"pt-3",fields:[{type:"select",name:"metadata.timezone",label:"Timezone",columns:6,value:"America/Los_Angeles",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:"metadata.eod_hour",label:"End of Day Hour",columns:6,options:[{value:0,text:"Midnight"},{value:1,text:"1 AM"},{value:2,text:"2 AM"},{value:3,text:"3 AM"},{value:4,text:"4 AM"},{value:5,text:"5 AM"},{value:6,text:"6 AM"},{value:7,text:"7 AM"},{value:8,text:"8 AM"},{value:9,text:"9 AM"},{value:10,text:"10 AM"},{value:11,text:"11 AM"},{value:12,text:"12 PM"},{value:13,text:"1 PM"},{value:14,text:"2 PM"},{value:15,text:"3 PM"},{value:16,text:"4 PM"},{value:17,text:"5 PM"},{value:18,text:"6 PM"},{value:19,text:"7 PM"},{value:20,text:"8 PM"},{value:21,text:"9 PM"},{value:22,text:"10 PM"},{value:23,text:"11 PM"}]}]},{type:"text",label:"Email Template (Prefix)",name:"metadata.email_template",columns:12}]}};Group.EDIT_FORM=i.edit,Group.ADD_FORM=i.create,Group.CREATE_FORM=i.create,Group.GroupKindOptions=s,Group.GroupKinds=a;const o=/* @__PURE__ */Object.freeze(/* @__PURE__ */Object.defineProperty({__proto__:null,Group:Group,GroupForms:i,GroupList:GroupList},Symbol.toStringTag,{value:"Module"}));class User extends t{constructor(e={}){super(e,{endpoint:"/api/user"})}hasPermission(e){if(this.get("is_superuser"))return!0;if(Array.isArray(e))return e.some(e=>this.hasPermission(e));const t=e.startsWith("sys."),a=t?e.substring(4):e;return!!this._hasPermission(a)||!(t||!this.member||!this.member.hasPermission(e))}_hasPermission(e){const t=this.get("permissions");return!!t&&1==t[e]}hasPerm(e){return this.hasPermission(e)}}class UserList extends e{constructor(e={}){super({ModelClass:User,endpoint:"/api/user",...e})}}User.PERMISSIONS=[{name:"manage_users",label:"Manage Users"},{name:"view_users",label:"View Users"},{name:"view_groups",label:"View Groups"},{name:"manage_groups",label:"Manage Groups"},{name:"view_metrics",label:"View System Metrics"},{name:"manage_metrics",label:"Manage System Metrics"},{name:"view_logs",label:"View Logs"},{name:"view_incidents",label:"View Incidents"},{name:"manage_incidents",label:"Manage Incidents"},{name:"view_tickets",label:"View Tickets"},{name:"manage_tickets",label:"Manage Tickets"},{name:"view_admin",label:"View Admin"},{name:"view_jobs",label:"View Jobs"},{name:"manage_jobs",label:"Manage Jobs"},{name:"view_global",label:"View Global"},{name:"manage_notifications",label:"Manage Notifications"},{name:"manage_files",label:"Manage Files"},{name:"force_single_session",label:"Force Single Session"},{name:"file_vault",label:"Access File Vault"},{name:"manage_aws",label:"Manage AWS"},{name:"manage_docit",label:"Manage DocIt"}],User.PERMISSION_FIELDS=[...User.PERMISSIONS.map(e=>({name:`permissions.${e.name}`,type:"switch",label:e.label,columns:4}))];const n={create:{title:"Create User",fields:[{name:"email",type:"text",label:"Email",required:!0},{name:"phone_number",type:"text",label:"Phone number",columns:12},{name:"display_name",type:"text",label:"Display Name"}]},edit:{title:"Edit User",fields:[{name:"email",type:"email",label:"Email",columns:12},{name:"display_name",type:"text",label:"Display Name",columns:12},{name:"phone_number",type:"text",label:"Phone number",columns:12},{type:"collection",name:"org",label:"Organization",Collection:GroupList,labelField:"name",valueField:"id",columns:12}]},permissions:{title:"Edit Permissions",fields:User.PERMISSION_FIELDS}},l={profile:{title:"User Profile",columns:2,fields:[{name:"id",label:"User ID",type:"number",columns:4},{name:"last_login",label:"Last Login",type:"datetime",format:"relative",columns:4},{name:"last_activity",label:"Last Activity",type:"datetime",format:"relative",columns:4},{name:"username",label:"Username",type:"text",format:"lowercase",columns:4},{name:"display_name",label:"Display Name",type:"text",columns:4},{name:"email",label:"Email",type:"email",columns:12},{name:"org.name",label:"Organization",type:"text",columns:6},{name:"phone_number",label:"Phone Number",type:"text",columns:6}]},activity:{title:"User Activity",columns:2,fields:[{name:"last_login",label:"Last Login",type:"datetime",format:"relative",colSize:6},{name:"last_activity",label:"Last Activity",type:"datetime",format:"relative",colSize:6}]},detailed:{title:"Detailed User Information",columns:2,showEmptyValues:!0,emptyValueText:"Not set",fields:[{name:"id",label:"User ID",type:"number",colSize:3},{name:"display_name",label:"Display Name",type:"text",format:'capitalize|default("Unnamed User")',colSize:9},{name:"username",label:"Username",type:"text",format:"lowercase",colSize:6},{name:"email",label:"Email Address",type:"email",colSize:6},{name:"phone_number",label:"Phone Number",type:"phone",format:'phone|default("Not provided")',colSize:6},{name:"is_active",label:"Account Status",type:"boolean",colSize:6},{name:"last_login",label:"Last Login",type:"datetime",format:"relative",colSize:6},{name:"last_activity",label:"Last Activity",type:"datetime",format:"relative",colSize:6},{name:"avatar.url",label:"Avatar",type:"url",colSize:12},{name:"permissions",label:"User Permissions",type:"dataview",dataViewColumns:2,showEmptyValues:!1},{name:"metadata",label:"User Metadata",type:"dataview",dataViewColumns:1},{name:"avatar",label:"Avatar Details",type:"dataview",dataViewColumns:1}]},permissions:{title:"User Permissions",columns:1,fields:[{name:"display_name",label:"User",type:"text",format:"capitalize",columns:12},{name:"permissions",label:"Assigned Permissions",type:"dataview",dataViewColumns:3,showEmptyValues:!1,colSize:12}]},summary:{title:"User Summary",columns:3,fields:[{name:"display_name",label:"Name",type:"text",format:"capitalize|truncate(30)"},{name:"email",label:"Email",type:"email"},{name:"is_active",label:"Status",type:"boolean"},{name:"last_activity",label:"Last Seen",type:"datetime",format:"relative",colSize:12}]}};User.DATA_VIEW=l.detailed,User.EDIT_FORM=n.edit,User.ADD_FORM=n.create;class UserDevice extends t{constructor(e={}){super(e,{endpoint:"/api/user/device"})}static async getByDuid(e){const t=new UserDevice,a=await t.rest.GET("/api/user/device/lookup",{duid:e});return a.success&&a.data&&a.data.data?new UserDevice(a.data.data):null}}class UserDeviceList extends e{constructor(e={}){super({ModelClass:UserDevice,endpoint:"/api/user/device",...e})}}class UserDeviceLocation extends t{constructor(e={}){super(e,{endpoint:"/api/user/device/location"})}}class UserDeviceLocationList extends e{constructor(e={}){super({ModelClass:UserDeviceLocation,endpoint:"/api/user/device/location",...e})}}export{GroupList as G,ToastService as T,UserList as U,User as a,l as b,UserDeviceList as c,UserDeviceLocationList as d,n as e,Group as f,i as g,UserDevice as h,UserDeviceLocation as i,o as j};
|
|
3
|
-
//# sourceMappingURL=User-DSqcOwPL.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"User-DSqcOwPL.js","sources":["../../src/core/services/ToastService.js","../../src/core/models/Group.js","../../src/core/models/User.js"],"sourcesContent":["/**\n * ToastService - Bootstrap 5 Toast Notification Service\n * Provides methods to display toast notifications with different types and options\n *\n * Features:\n * - Bootstrap 5 toast integration\n * - Multiple toast types (success, error, info, warning)\n * - Auto-dismiss with customizable delays\n * - Toast container management\n * - Event integration\n * - Proper cleanup and memory management\n *\n * @example\n * const toastService = new ToastService();\n * toastService.success('Operation completed successfully!');\n * toastService.error('Something went wrong');\n * toastService.info('FYI: This is informational');\n * toastService.warning('Please be careful');\n */\n\nclass ToastService {\n constructor(options = {}) {\n this.options = {\n containerId: 'toast-container',\n position: 'top-end', // top-start, top-center, top-end, middle-start, etc.\n autohide: true,\n defaultDelay: 5000, // 5 seconds\n maxToasts: 5, // Maximum number of toasts to show at once\n ...options\n };\n\n this.toasts = new Map(); // Track active toasts\n this.toastCounter = 0; // For unique IDs\n\n this.init();\n }\n\n /**\n * Initialize the toast service\n */\n init() {\n this.createContainer();\n }\n\n /**\n * Create the toast container if it doesn't exist\n */\n createContainer() {\n let container = document.getElementById(this.options.containerId);\n\n if (!container) {\n container = document.createElement('div');\n container.id = this.options.containerId;\n container.className = `toast-container position-fixed ${this.getPositionClasses()}`;\n container.style.zIndex = '1070'; // Bootstrap toast z-index\n container.setAttribute('aria-live', 'polite');\n container.setAttribute('aria-atomic', 'true');\n\n document.body.appendChild(container);\n }\n\n this.container = container;\n }\n\n /**\n * Get CSS classes for toast positioning\n */\n getPositionClasses() {\n const positionMap = {\n 'top-start': 'top-0 start-0 p-3',\n 'top-center': 'top-0 start-50 translate-middle-x p-3',\n 'top-end': 'top-0 end-0 p-3',\n 'middle-start': 'top-50 start-0 translate-middle-y p-3',\n 'middle-center': 'top-50 start-50 translate-middle p-3',\n 'middle-end': 'top-50 end-0 translate-middle-y p-3',\n 'bottom-start': 'bottom-0 start-0 p-3',\n 'bottom-center': 'bottom-0 start-50 translate-middle-x p-3',\n 'bottom-end': 'bottom-0 end-0 p-3'\n };\n\n return positionMap[this.options.position] || positionMap['top-end'];\n }\n\n\n\n /**\n * Show a success toast\n * @param {string} message - The message to display\n * @param {object} options - Additional options\n */\n success(message, options = {}) {\n return this.show(message, 'success', {\n icon: 'bi-check-circle-fill',\n ...options\n });\n }\n\n /**\n * Show an error toast\n * @param {string} message - The message to display\n * @param {object} options - Additional options\n */\n error(message, options = {}) {\n return this.show(message, 'error', {\n icon: 'bi-exclamation-triangle-fill',\n autohide: true, // Keep error toasts visible until manually dismissed\n ...options\n });\n }\n\n /**\n * Show an info toast\n * @param {string} message - The message to display\n * @param {object} options - Additional options\n */\n info(message, options = {}) {\n return this.show(message, 'info', {\n icon: 'bi-info-circle-fill',\n ...options\n });\n }\n\n /**\n * Show a warning toast\n * @param {string} message - The message to display\n * @param {object} options - Additional options\n */\n warning(message, options = {}) {\n return this.show(message, 'warning', {\n icon: 'bi-exclamation-triangle-fill',\n ...options\n });\n }\n\n /**\n * Show a plain toast without specific styling\n * @param {string} message - The message to display\n * @param {object} options - Additional options\n */\n plain(message, options = {}) {\n return this.show(message, 'plain', {\n ...options\n });\n }\n\n /**\n * Show a toast with specified type and options\n * @param {string} message - The message to display\n * @param {string} type - Toast type (success, error, info, warning)\n * @param {object} options - Additional options\n */\n show(message, type = 'info', options = {}) {\n // Enforce max toasts limit\n this.enforceMaxToasts();\n\n const toastId = `toast-${++this.toastCounter}`;\n const config = {\n title: this.getDefaultTitle(type),\n icon: this.getDefaultIcon(type),\n autohide: this.options.autohide,\n delay: this.options.defaultDelay,\n dismissible: true,\n ...options\n };\n\n const toastElement = this.createToastElement(toastId, message, type, config);\n this.container.appendChild(toastElement);\n\n // Initialize Bootstrap toast\n if (typeof bootstrap === 'undefined') {\n throw new Error('Bootstrap is required for ToastService. Make sure Bootstrap 5 is loaded.');\n }\n const bsToast = new bootstrap.Toast(toastElement, {\n autohide: config.autohide,\n delay: config.delay\n });\n\n // Store toast reference\n this.toasts.set(toastId, {\n element: toastElement,\n bootstrap: bsToast,\n type: type,\n message: message\n });\n\n // Setup cleanup on hide\n toastElement.addEventListener('hidden.bs.toast', () => {\n this.cleanup(toastId);\n });\n\n // Show the toast\n bsToast.show();\n\n return {\n id: toastId,\n hide: () => {\n try {\n bsToast.hide();\n } catch (error) {\n console.warn('Error hiding toast:', error);\n }\n },\n dispose: () => this.cleanup(toastId),\n updateProgress: options.updateProgress || null\n };\n }\n\n /**\n * Show a toast with a View component in the body\n * @param {View} view - The View component to display\n * @param {string} type - Toast type (success, error, info, warning, plain)\n * @param {object} options - Additional options\n */\n showView(view, type = 'info', options = {}) {\n // Enforce max toasts limit\n this.enforceMaxToasts();\n\n const toastId = `toast-${++this.toastCounter}`;\n const config = {\n title: options.title || this.getDefaultTitle(type),\n icon: options.icon || this.getDefaultIcon(type),\n autohide: this.options.autohide,\n delay: this.options.defaultDelay,\n dismissible: true,\n ...options\n };\n\n const toastElement = this.createViewToastElement(toastId, view, type, config);\n this.container.appendChild(toastElement);\n\n // Initialize Bootstrap toast\n if (typeof bootstrap === 'undefined') {\n throw new Error('Bootstrap is required for ToastService. Make sure Bootstrap 5 is loaded.');\n }\n const bsToast = new bootstrap.Toast(toastElement, {\n autohide: config.autohide,\n delay: config.delay\n });\n\n // Store toast reference with view\n this.toasts.set(toastId, {\n element: toastElement,\n bootstrap: bsToast,\n type: type,\n view: view,\n message: 'View toast'\n });\n\n // Setup cleanup on hide - dispose view properly\n toastElement.addEventListener('hidden.bs.toast', () => {\n this.cleanupView(toastId);\n });\n\n // Mount and render the view\n const bodyContainer = toastElement.querySelector('.toast-view-body');\n if (bodyContainer && view) {\n view.render(true, bodyContainer);\n }\n\n // Show the toast\n bsToast.show();\n\n return {\n id: toastId,\n view: view,\n hide: () => {\n try {\n bsToast.hide();\n } catch (error) {\n console.warn('Error hiding view toast:', error);\n }\n },\n dispose: () => this.cleanupView(toastId),\n updateProgress: (progressInfo) => {\n if (view && typeof view.updateProgress === 'function') {\n view.updateProgress(progressInfo);\n }\n }\n };\n }\n\n /**\n * Create toast DOM element\n */\n createToastElement(id, message, type, config) {\n const toast = document.createElement('div');\n toast.id = id;\n toast.className = `toast toast-service-${type}`;\n toast.setAttribute('role', 'alert');\n toast.setAttribute('aria-live', 'assertive');\n toast.setAttribute('aria-atomic', 'true');\n\n const header = config.title || config.icon ? this.createToastHeader(config, type) : '';\n const body = this.createToastBody(message, config.icon && !config.title);\n\n toast.innerHTML = `\n ${header}\n ${body}\n `;\n\n return toast;\n }\n\n /**\n * Create toast DOM element for View component\n */\n createViewToastElement(id, view, type, config) {\n const toast = document.createElement('div');\n toast.id = id;\n toast.className = `toast toast-service-${type}`;\n toast.setAttribute('role', 'alert');\n toast.setAttribute('aria-live', 'assertive');\n toast.setAttribute('aria-atomic', 'true');\n\n const header = config.title || config.icon ? this.createToastHeader(config, type) : '';\n const body = this.createViewToastBody();\n\n toast.innerHTML = `\n ${header}\n ${body}\n `;\n\n return toast;\n }\n\n /**\n * Create toast body for View component\n */\n createViewToastBody() {\n return `\n <div class=\"toast-body p-0\">\n <div class=\"toast-view-body p-3\"></div>\n </div>\n `;\n }\n\n /**\n * Create toast header with title and icon\n */\n createToastHeader(config, _type) {\n const iconHtml = config.icon ?\n `<i class=\"${config.icon} toast-service-icon me-2\"></i>` : '';\n\n const titleHtml = config.title ?\n `<strong class=\"me-auto\">${iconHtml}${this.escapeHtml(config.title)}</strong>` : '';\n\n const timeHtml = config.showTime ?\n `<small class=\"text-muted\">${this.getTimeString()}</small>` : '';\n\n const closeButton = config.dismissible ?\n `<button type=\"button\" class=\"btn-close toast-service-close\" data-bs-dismiss=\"toast\" aria-label=\"Close\"></button>` : '';\n\n if (!titleHtml && !timeHtml && !closeButton) {\n return '';\n }\n\n return `\n <div class=\"toast-header\">\n ${titleHtml}\n ${timeHtml}\n ${closeButton}\n </div>\n `;\n }\n\n /**\n * Create toast body with message\n */\n createToastBody(message, showIcon = false) {\n const iconHtml = showIcon ?\n `<i class=\"${this.getDefaultIcon('info')} toast-service-icon me-2\"></i>` : '';\n\n return `\n <div class=\"toast-body d-flex align-items-center\">\n ${iconHtml}\n <span>${this.escapeHtml(message)}</span>\n </div>\n `;\n }\n\n /**\n * Get default title for toast type\n */\n getDefaultTitle(type) {\n const titles = {\n success: 'Success',\n error: 'Error',\n warning: 'Warning',\n info: 'Information',\n plain: ''\n };\n return titles[type] || 'Notification';\n }\n\n /**\n * Get default icon for toast type\n */\n getDefaultIcon(type) {\n const icons = {\n success: 'bi-check-circle-fill',\n error: 'bi-exclamation-triangle-fill',\n warning: 'bi-exclamation-triangle-fill',\n info: 'bi-info-circle-fill',\n plain: ''\n };\n return icons[type] || 'bi-info-circle-fill';\n }\n\n /**\n * Enforce maximum number of toasts\n */\n enforceMaxToasts() {\n const activeToasts = Array.from(this.toasts.values());\n\n if (activeToasts.length >= this.options.maxToasts) {\n // Remove oldest toast\n const oldestId = this.toasts.keys().next().value;\n const oldest = this.toasts.get(oldestId);\n\n if (oldest) {\n oldest.bootstrap.hide();\n }\n }\n }\n\n /**\n * Clean up toast resources\n */\n cleanup(toastId) {\n const toast = this.toasts.get(toastId);\n\n if (toast) {\n // Dispose Bootstrap toast\n try {\n toast.bootstrap.dispose();\n } catch (e) {\n console.warn('Error disposing toast:', e);\n }\n\n // Remove from DOM\n if (toast.element && toast.element.parentNode) {\n toast.element.parentNode.removeChild(toast.element);\n }\n\n // Remove from tracking\n this.toasts.delete(toastId);\n }\n }\n\n /**\n * Clean up view toast resources with proper view disposal\n */\n cleanupView(toastId) {\n const toast = this.toasts.get(toastId);\n\n if (toast) {\n // Dispose view first if it exists\n if (toast.view && typeof toast.view.dispose === 'function') {\n try {\n toast.view.dispose();\n } catch (e) {\n console.warn('Error disposing view in toast:', e);\n }\n }\n\n // Dispose Bootstrap toast\n try {\n toast.bootstrap.dispose();\n } catch (e) {\n console.warn('Error disposing toast:', e);\n }\n\n // Remove from DOM\n if (toast.element && toast.element.parentNode) {\n toast.element.parentNode.removeChild(toast.element);\n }\n\n // Remove from tracking\n this.toasts.delete(toastId);\n }\n }\n\n /**\n * Hide all active toasts\n */\n hideAll() {\n this.toasts.forEach((toast, _id) => {\n toast.bootstrap.hide();\n });\n }\n\n /**\n * Clear all toasts immediately\n */\n clearAll() {\n this.toasts.forEach((toast, id) => {\n this.cleanup(id);\n });\n }\n\n /**\n * Get current time string\n */\n getTimeString() {\n return new Date().toLocaleTimeString([], {\n hour: '2-digit',\n minute: '2-digit'\n });\n }\n\n /**\n * Escape HTML to prevent XSS\n */\n escapeHtml(str) {\n const div = document.createElement('div');\n div.textContent = str;\n return div.innerHTML;\n }\n\n /**\n * Dispose of the entire toast service\n */\n dispose() {\n this.clearAll();\n\n if (this.container && this.container.parentNode) {\n this.container.parentNode.removeChild(this.container);\n }\n }\n\n /**\n * Get statistics about active toasts\n */\n getStats() {\n const stats = {\n total: this.toasts.size,\n byType: {}\n };\n\n this.toasts.forEach(toast => {\n stats.byType[toast.type] = (stats.byType[toast.type] || 0) + 1;\n });\n\n return stats;\n }\n\n /**\n * Set global options\n */\n setOptions(newOptions) {\n this.options = { ...this.options, ...newOptions };\n\n // Recreate container if position changed\n if (newOptions.position) {\n if (this.container) {\n this.container.className = `toast-container position-fixed ${this.getPositionClasses()}`;\n }\n }\n }\n}\n\nexport default ToastService;\n","\nimport Collection from '@core/Collection.js';\nimport Model from '@core/Model.js';\n\n/**\n * Group Model - Represents an organization, team, or group entity\n *\n * Features:\n * - Hierarchical group support (parent/child relationships)\n * - Member management\n * - Search and filtering capabilities\n * - Role-based permissions within groups\n * - Metadata and settings management\n */\nclass Group extends Model {\n constructor(data = {}) {\n super(data, {\n endpoint: '/api/group'\n });\n }\n}\n\n/**\n * GroupCollection - Enhanced collection for managing groups with advanced search and filtering\n */\nclass GroupList extends Collection {\n constructor(options = {}) {\n super({\n ModelClass: Group,\n endpoint: '/api/group',\n size: 10,\n ...options\n });\n }\n}\n\nconst GroupKinds = {\n 'org': 'Organization',\n 'division': 'Division',\n 'department': 'Department',\n 'team': 'Team',\n 'merchant': 'Merchant',\n 'partner': 'Partner',\n 'client': 'Client',\n 'iso': 'ISO',\n 'sales': 'Sales',\n 'reseller': 'Reseller',\n 'location': 'Location',\n 'region': 'Region',\n 'route': 'Route',\n 'project': 'Project',\n \"inventory\": \"Inventory\",\n 'test': 'Testing',\n 'misc': 'Miscellaneous',\n 'qa': 'Quality Assurance'\n};\n\n// Convert GroupKinds to select options\nconst GroupKindOptions = Object.entries(GroupKinds).map(([key, label]) => ({\n value: key,\n label: label\n}));\n\n/**\n * Form configurations for group management\n */\nconst GroupForms = {\n create: {\n title: 'Create Group',\n fields: [\n {\n name: 'name',\n type: 'text',\n label: 'Group Name',\n required: true,\n placeholder: 'Enter group name'\n },\n {\n name: 'kind',\n type: 'select',\n label: 'Group Kind',\n required: true,\n options: GroupKindOptions\n },\n {\n type: 'collection',\n name: 'parent',\n label: 'Parent Group',\n Collection: GroupList, // Collection class\n labelField: 'name', // Field to display in dropdown\n valueField: 'id', // Field to use as value\n maxItems: 10, // Max items to show in dropdown\n placeholder: 'Search groups...',\n emptyFetch: false,\n debounceMs: 300, // Search debounce delay\n }\n ]\n },\n\n edit: {\n title: 'Edit Group',\n fields: [\n {\n name: 'name',\n type: 'text',\n label: 'Group Name',\n required: true,\n placeholder: 'Enter group name',\n },\n {\n name: 'kind',\n type: 'select',\n label: 'Group Kind',\n required: true,\n options: GroupKindOptions\n },\n {\n type: 'collection',\n name: 'parent',\n label: 'Parent Group',\n Collection: GroupList, // Collection class\n labelField: 'name', // Field to display in dropdown\n valueField: 'id', // Field to use as value\n maxItems: 10, // Max items to show in dropdown\n placeholder: 'Search groups...',\n emptyFetch: false,\n debounceMs: 300, // Search debounce delay\n },\n {\n name: 'metadata.domain',\n type: 'text',\n label: 'Default Domain',\n placeholder: 'Enter Domain',\n },\n {\n name: 'metadata.portal',\n type: 'text',\n label: 'Default Portal',\n placeholder: 'Enter Portal URL',\n },\n {\n name: 'is_active',\n type: 'switch',\n label: 'Is Active',\n cols: 4\n },\n ]\n },\n\n detailed: {\n title: 'Group Details',\n fields: [\n // Profile Header\n {\n type: 'header',\n text: 'Profile Information',\n level: 4,\n class: 'text-primary mb-3'\n },\n\n // Avatar and Basic Info\n {\n type: 'group',\n columns: { xs: 12, md: 4 },\n fields: [\n {\n type: 'image',\n name: 'avatar',\n size: 'lg',\n imageSize: { width: 200, height: 200 },\n placeholder: 'Upload your avatar',\n help: 'Square images work best',\n columns: 12\n },\n {\n name: 'is_active',\n type: 'switch',\n label: 'Is Active',\n columns: 12\n },\n ]\n },\n\n // Profile Details\n {\n type: 'group',\n columns: { xs: 12, md: 8 },\n title: 'Details',\n fields: [\n {\n name: 'name',\n type: 'text',\n label: 'Group Name',\n required: true,\n placeholder: 'Enter group name',\n columns: 12\n },\n {\n name: 'kind',\n type: 'select',\n label: 'Group Kind',\n required: true,\n columns: 12,\n options: [\n { value: 'org', label: 'Organization' },\n { value: 'team', label: 'Team' },\n { value: 'department', label: 'Department' },\n { value: 'merchant', label: 'Merchant' },\n { value: 'iso', label: 'ISO' },\n { value: 'group', label: 'Group' }\n ]\n },\n {\n type: 'collection',\n name: 'parent',\n label: 'Parent Group',\n Collection: GroupList, // Collection class\n labelField: 'name', // Field to display in dropdown\n valueField: 'id', // Field to use as value\n maxItems: 10, // Max items to show in dropdown\n placeholder: 'Search groups...',\n emptyFetch: false,\n debounceMs: 300, // Search debounce delay\n columns: 12\n }\n ]\n },\n\n // Account Settings\n {\n type: 'group',\n columns: 12,\n title: 'Account Settings',\n class: \"pt-3\",\n fields: [\n {\n type: 'select',\n name: 'metadata.timezone',\n label: 'Timezone',\n columns: 6,\n value: 'America/Los_Angeles',\n options: [\n { value: 'America/New_York', text: 'Eastern Time' },\n { value: 'America/Chicago', text: 'Central Time' },\n { value: 'America/Denver', text: 'Mountain Time' },\n { value: 'America/Los_Angeles', text: 'Pacific Time' },\n { value: 'UTC', text: 'UTC' }\n ]\n },\n {\n type: 'select',\n name: 'metadata.eod_hour',\n label: 'End of Day Hour',\n columns: 6,\n options: [\n { value: 0, text: 'Midnight' },\n { value: 1, text: '1 AM' },\n { value: 2, text: '2 AM' },\n { value: 3, text: '3 AM' },\n { value: 4, text: '4 AM' },\n { value: 5, text: '5 AM' },\n { value: 6, text: '6 AM' },\n { value: 7, text: '7 AM' },\n { value: 8, text: '8 AM' },\n { value: 9, text: '9 AM' },\n { value: 10, text: '10 AM' },\n { value: 11, text: '11 AM' },\n { value: 12, text: '12 PM' },\n { value: 13, text: '1 PM' },\n { value: 14, text: '2 PM' },\n { value: 15, text: '3 PM' },\n { value: 16, text: '4 PM' },\n { value: 17, text: '5 PM' },\n { value: 18, text: '6 PM' },\n { value: 19, text: '7 PM' },\n { value: 20, text: '8 PM' },\n { value: 21, text: '9 PM' },\n { value: 22, text: '10 PM' },\n { value: 23, text: '11 PM' }\n ]\n }\n ]\n },\n {\n type: \"text\",\n label: \"Email Template (Prefix)\",\n name: \"metadata.email_template\",\n columns: 12\n }\n ]\n },\n};\n\nGroup.EDIT_FORM = GroupForms.edit;\nGroup.ADD_FORM = GroupForms.create;\nGroup.CREATE_FORM = GroupForms.create; // Alias for compatibility\nGroup.GroupKindOptions = GroupKindOptions;\nGroup.GroupKinds = GroupKinds;\nexport { Group, GroupList, GroupForms };\n","import Collection from '@core/Collection.js';\nimport Model from '@core/Model.js';\n\nimport { GroupList } from './Group.js';\n\nclass User extends Model {\n constructor(data = {}) {\n super(data, {\n endpoint: '/api/user'\n });\n }\n\n hasPermission(permission) {\n if (this.get(\"is_superuser\")) return true;\n if (Array.isArray(permission)) {\n return permission.some(p => this.hasPermission(p));\n }\n\n // Check if permission has \"sys.\" prefix\n const isSysPermission = permission.startsWith('sys.');\n const permissionToCheck = isSysPermission ? permission.substring(4) : permission;\n\n if (this._hasPermission(permissionToCheck)) {\n return true;\n }\n\n // Only check member permissions if it's not a system permission\n if (!isSysPermission && this.member && this.member.hasPermission(permission)) {\n return true;\n }\n\n return false;\n }\n\n _hasPermission(permission) {\n const permissions = this.get(\"permissions\");\n if (!permissions) {\n return false;\n }\n return permissions[permission] == true;\n }\n\n hasPerm(p) {\n return this.hasPermission(p);\n }\n}\n\nclass UserList extends Collection {\n constructor(options = {}) {\n super({\n ModelClass: User,\n endpoint: '/api/user',\n ...options\n });\n }\n}\n\nUser.PERMISSIONS = [\n { name: \"manage_users\", label: \"Manage Users\" },\n { name: \"view_users\", label: \"View Users\" },\n { name: \"view_groups\", label: \"View Groups\" },\n { name: \"manage_groups\", label: \"Manage Groups\" },\n { name: \"view_metrics\", label: \"View System Metrics\" },\n { name: \"manage_metrics\", label: \"Manage System Metrics\" },\n { name: \"view_logs\", label: \"View Logs\" },\n { name: \"view_incidents\", label: \"View Incidents\" },\n { name: \"manage_incidents\", label: \"Manage Incidents\" },\n { name: \"view_tickets\", label: \"View Tickets\" },\n { name: \"manage_tickets\", label: \"Manage Tickets\" },\n { name: \"view_admin\", label: \"View Admin\" },\n { name: \"view_jobs\", label: \"View Jobs\" },\n { name: \"manage_jobs\", label: \"Manage Jobs\" },\n { name: \"view_global\", label: \"View Global\" },\n { name: \"manage_notifications\", label: \"Manage Notifications\" },\n { name: \"manage_files\", label: \"Manage Files\" },\n { name: \"force_single_session\", label: \"Force Single Session\" },\n { name: \"file_vault\", label: \"Access File Vault\" },\n { name: \"manage_aws\", label: \"Manage AWS\" },\n { name: \"manage_docit\", label: \"Manage DocIt\" }\n];\n\n\nUser.PERMISSION_FIELDS = [\n ...User.PERMISSIONS.map(permission => ({\n name: `permissions.${permission.name}`,\n type: 'switch',\n label: permission.label,\n columns: 4\n }))\n];\n\nconst UserForms = {\n create: {\n title: 'Create User',\n fields: [\n { name: 'email', type: 'text', label: 'Email', required: true },\n { name: 'phone_number', type: 'text', label: 'Phone number', columns: 12 },\n { name: 'display_name', type: 'text', label: 'Display Name' }\n ]\n },\n edit: {\n title: 'Edit User',\n fields: [\n { name: 'email', type: 'email', label: 'Email', columns: 12 },\n { name: 'display_name', type: 'text', label: 'Display Name', columns: 12},\n { name: 'phone_number', type: 'text', label: 'Phone number', columns: 12 },\n { type: 'collection', name: 'org', label: 'Organization', Collection: GroupList, labelField: 'name', valueField: 'id', columns: 12 },\n ]\n },\n permissions: {\n title: 'Edit Permissions',\n fields: User.PERMISSION_FIELDS\n }\n};\n\n\n// DataView configuration for User model\nconst UserDataView = {\n // Basic user profile view\n profile: {\n title: 'User Profile',\n columns: 2,\n fields: [\n {\n name: 'id',\n label: 'User ID',\n type: 'number',\n columns: 4\n },\n {\n name: 'last_login',\n label: 'Last Login',\n type: 'datetime',\n format: 'relative',\n columns: 4\n },\n {\n name: 'last_activity',\n label: 'Last Activity',\n type: 'datetime',\n format: 'relative',\n columns: 4\n },\n {\n name: 'username',\n label: 'Username',\n type: 'text',\n format: 'lowercase',\n columns: 4\n },\n {\n name: 'display_name',\n label: 'Display Name',\n type: 'text',\n columns: 4\n },\n\n {\n name: 'email',\n label: 'Email',\n type: 'email',\n columns: 12\n },\n\n {\n name: 'org.name',\n label: 'Organization',\n type: 'text',\n columns: 6\n },\n {\n name: 'phone_number',\n label: 'Phone Number',\n type: 'text',\n columns: 6\n }\n ]\n },\n\n // Activity tracking view\n activity: {\n title: 'User Activity',\n columns: 2,\n fields: [\n {\n name: 'last_login',\n label: 'Last Login',\n type: 'datetime',\n format: 'relative',\n colSize: 6\n },\n {\n name: 'last_activity',\n label: 'Last Activity',\n type: 'datetime',\n format: 'relative',\n colSize: 6\n }\n ]\n },\n\n // Comprehensive view with all data\n detailed: {\n title: 'Detailed User Information',\n columns: 2,\n showEmptyValues: true,\n emptyValueText: 'Not set',\n fields: [\n // Basic Info Section\n {\n name: 'id',\n label: 'User ID',\n type: 'number',\n colSize: 3\n },\n {\n name: 'display_name',\n label: 'Display Name',\n type: 'text',\n format: 'capitalize|default(\"Unnamed User\")',\n colSize: 9\n },\n {\n name: 'username',\n label: 'Username',\n type: 'text',\n format: 'lowercase',\n colSize: 6\n },\n {\n name: 'email',\n label: 'Email Address',\n type: 'email',\n colSize: 6\n },\n {\n name: 'phone_number',\n label: 'Phone Number',\n type: 'phone',\n format: 'phone|default(\"Not provided\")',\n colSize: 6\n },\n {\n name: 'is_active',\n label: 'Account Status',\n type: 'boolean',\n colSize: 6\n },\n\n // Activity Info\n {\n name: 'last_login',\n label: 'Last Login',\n type: 'datetime',\n format: 'relative',\n colSize: 6\n },\n {\n name: 'last_activity',\n label: 'Last Activity',\n type: 'datetime',\n format: 'relative',\n colSize: 6\n },\n\n // Avatar Info\n {\n name: 'avatar.url',\n label: 'Avatar',\n type: 'url',\n colSize: 12\n },\n\n // Complex Data (will use full width automatically)\n {\n name: 'permissions',\n label: 'User Permissions',\n type: 'dataview',\n dataViewColumns: 2,\n showEmptyValues: false\n },\n {\n name: 'metadata',\n label: 'User Metadata',\n type: 'dataview',\n dataViewColumns: 1\n },\n {\n name: 'avatar',\n label: 'Avatar Details',\n type: 'dataview',\n dataViewColumns: 1\n }\n ]\n },\n\n // Permissions-focused view\n permissions: {\n title: 'User Permissions',\n columns: 1,\n fields: [\n {\n name: 'display_name',\n label: 'User',\n type: 'text',\n format: 'capitalize',\n columns: 12\n },\n {\n name: 'permissions',\n label: 'Assigned Permissions',\n type: 'dataview',\n dataViewColumns: 3,\n showEmptyValues: false,\n colSize: 12\n }\n ]\n },\n\n // Compact summary view\n summary: {\n title: 'User Summary',\n columns: 3,\n fields: [\n {\n name: 'display_name',\n label: 'Name',\n type: 'text',\n format: 'capitalize|truncate(30)'\n },\n {\n name: 'email',\n label: 'Email',\n type: 'email'\n },\n {\n name: 'is_active',\n label: 'Status',\n type: 'boolean'\n },\n {\n name: 'last_activity',\n label: 'Last Seen',\n type: 'datetime',\n format: 'relative',\n colSize: 12\n }\n ]\n }\n};\n\nUser.DATA_VIEW = UserDataView.detailed;\nUser.EDIT_FORM = UserForms.edit;\nUser.ADD_FORM = UserForms.create;\n\n/* =========================\n * UserDevice\n * ========================= */\nclass UserDevice extends Model {\n constructor(data = {}) {\n super(data, {\n endpoint: '/api/user/device',\n });\n }\n\n static async getByDuid(duid) {\n const model = new UserDevice();\n const resp = await model.rest.GET('/api/user/device/lookup', { duid: duid });\n if (resp.success && resp.data && resp.data.data) {\n // A direct lookup should return a single object\n return new UserDevice(resp.data.data);\n }\n return null;\n }\n}\n\nclass UserDeviceList extends Collection {\n constructor(options = {}) {\n super({\n ModelClass: UserDevice,\n endpoint: '/api/user/device',\n ...options,\n });\n }\n}\n\n/* =========================\n * UserDeviceLocation\n * ========================= */\nclass UserDeviceLocation extends Model {\n constructor(data = {}) {\n super(data, {\n endpoint: '/api/user/device/location',\n });\n }\n}\n\nclass UserDeviceLocationList extends Collection {\n constructor(options = {}) {\n super({\n ModelClass: UserDeviceLocation,\n endpoint: '/api/user/device/location',\n ...options,\n });\n }\n}\n\nexport { User, UserList, UserForms, UserDataView, UserDevice, UserDeviceList, UserDeviceLocation, UserDeviceLocationList };\n"],"names":["ToastService","constructor","options","this","containerId","position","autohide","defaultDelay","maxToasts","toasts","Map","toastCounter","init","createContainer","container","document","getElementById","createElement","id","className","getPositionClasses","style","zIndex","setAttribute","body","appendChild","positionMap","success","message","show","icon","error","info","warning","plain","type","enforceMaxToasts","toastId","config","title","getDefaultTitle","getDefaultIcon","delay","dismissible","toastElement","createToastElement","bootstrap","Error","bsToast","Toast","set","element","addEventListener","cleanup","hide","console","warn","dispose","updateProgress","showView","view","createViewToastElement","cleanupView","bodyContainer","querySelector","render","progressInfo","toast","header","createToastHeader","createToastBody","innerHTML","createViewToastBody","_type","iconHtml","titleHtml","escapeHtml","timeHtml","showTime","getTimeString","closeButton","showIcon","Array","from","values","length","oldestId","keys","next","value","oldest","get","e","parentNode","removeChild","delete","hideAll","forEach","_id","clearAll","Date","toLocaleTimeString","hour","minute","str","div","textContent","getStats","stats","total","size","byType","setOptions","newOptions","Group","Model","data","super","endpoint","GroupList","Collection","ModelClass","GroupKinds","org","division","department","team","merchant","partner","client","iso","sales","reseller","location","region","route","project","inventory","test","misc","qa","GroupKindOptions","Object","entries","map","key","label","GroupForms","create","fields","name","required","placeholder","labelField","valueField","maxItems","emptyFetch","debounceMs","edit","cols","detailed","text","level","class","columns","xs","md","imageSize","width","height","help","EDIT_FORM","ADD_FORM","CREATE_FORM","User","hasPermission","permission","isArray","some","p","isSysPermission","startsWith","permissionToCheck","substring","_hasPermission","member","permissions","hasPerm","UserList","PERMISSIONS","PERMISSION_FIELDS","UserForms","UserDataView","profile","format","activity","colSize","showEmptyValues","emptyValueText","dataViewColumns","summary","DATA_VIEW","UserDevice","getByDuid","duid","model","resp","rest","GET","UserDeviceList","UserDeviceLocation","UserDeviceLocationList"],"mappings":"oDAoBA,MAAMA,aACJ,WAAAC,CAAYC,EAAU,IACpBC,KAAKD,QAAU,CACbE,YAAa,kBACbC,SAAU,UACVC,UAAU,EACVC,aAAc,IACdC,UAAW,KACRN,GAGLC,KAAKM,0BAAaC,IAClBP,KAAKQ,aAAe,EAEpBR,KAAKS,MACP,CAKA,IAAAA,GACET,KAAKU,iBACP,CAKA,eAAAA,GACE,IAAIC,EAAYC,SAASC,eAAeb,KAAKD,QAAQE,aAEhDU,IACHA,EAAYC,SAASE,cAAc,OACnCH,EAAUI,GAAKf,KAAKD,QAAQE,YAC5BU,EAAUK,UAAY,kCAAkChB,KAAKiB,uBAC7DN,EAAUO,MAAMC,OAAS,OACzBR,EAAUS,aAAa,YAAa,UACpCT,EAAUS,aAAa,cAAe,QAEtCR,SAASS,KAAKC,YAAYX,IAG5BX,KAAKW,UAAYA,CACnB,CAKA,kBAAAM,GACE,MAAMM,EAAc,CAClB,YAAa,oBACb,aAAc,wCACd,UAAW,kBACX,eAAgB,wCAChB,gBAAiB,uCACjB,aAAc,sCACd,eAAgB,uBAChB,gBAAiB,2CACjB,aAAc,sBAGhB,OAAOA,EAAYvB,KAAKD,QAAQG,WAAaqB,EAAY,UAC3D,CASA,OAAAC,CAAQC,EAAS1B,EAAU,IACzB,OAAOC,KAAK0B,KAAKD,EAAS,UAAW,CACnCE,KAAM,0BACH5B,GAEP,CAOA,KAAA6B,CAAMH,EAAS1B,EAAU,IACvB,OAAOC,KAAK0B,KAAKD,EAAS,QAAS,CACjCE,KAAM,+BACNxB,UAAU,KACPJ,GAEP,CAOA,IAAA8B,CAAKJ,EAAS1B,EAAU,IACtB,OAAOC,KAAK0B,KAAKD,EAAS,OAAQ,CAChCE,KAAM,yBACH5B,GAEP,CAOA,OAAA+B,CAAQL,EAAS1B,EAAU,IACzB,OAAOC,KAAK0B,KAAKD,EAAS,UAAW,CACnCE,KAAM,kCACH5B,GAEP,CAOA,KAAAgC,CAAMN,EAAS1B,EAAU,IACvB,OAAOC,KAAK0B,KAAKD,EAAS,QAAS,IAC9B1B,GAEP,CAQA,IAAA2B,CAAKD,EAASO,EAAO,OAAQjC,EAAU,CAAA,GAErCC,KAAKiC,mBAEL,MAAMC,EAAU,YAAWlC,KAAKQ,aAC1B2B,EAAS,CACbC,MAAOpC,KAAKqC,gBAAgBL,GAC5BL,KAAM3B,KAAKsC,eAAeN,GAC1B7B,SAAUH,KAAKD,QAAQI,SACvBoC,MAAOvC,KAAKD,QAAQK,aACpBoC,aAAa,KACVzC,GAGC0C,EAAezC,KAAK0C,mBAAmBR,EAAST,EAASO,EAAMG,GAIrE,GAHAnC,KAAKW,UAAUW,YAAYmB,GAGF,oBAAdE,UACT,MAAM,IAAIC,MAAM,4EAElB,MAAMC,EAAU,IAAIF,UAAUG,MAAML,EAAc,CAChDtC,SAAUgC,EAAOhC,SACjBoC,MAAOJ,EAAOI,QAmBhB,OAfAvC,KAAKM,OAAOyC,IAAIb,EAAS,CACvBc,QAASP,EACTE,UAAWE,EACXb,OACAP,YAIFgB,EAAaQ,iBAAiB,kBAAmB,KAC/CjD,KAAKkD,QAAQhB,KAIfW,EAAQnB,OAED,CACLX,GAAImB,EACJiB,KAAM,KACJ,IACEN,EAAQM,MACV,OAASvB,GACPwB,QAAQC,KAAK,sBAAuBzB,EACtC,GAEF0B,QAAS,IAAMtD,KAAKkD,QAAQhB,GAC5BqB,eAAgBxD,EAAQwD,gBAAkB,KAE9C,CAQA,QAAAC,CAASC,EAAMzB,EAAO,OAAQjC,EAAU,CAAA,GAEtCC,KAAKiC,mBAEL,MAAMC,EAAU,YAAWlC,KAAKQ,aAC1B2B,EAAS,CACbC,MAAOrC,EAAQqC,OAASpC,KAAKqC,gBAAgBL,GAC7CL,KAAM5B,EAAQ4B,MAAQ3B,KAAKsC,eAAeN,GAC1C7B,SAAUH,KAAKD,QAAQI,SACvBoC,MAAOvC,KAAKD,QAAQK,aACpBoC,aAAa,KACVzC,GAGC0C,EAAezC,KAAK0D,uBAAuBxB,EAASuB,EAAMzB,EAAMG,GAItE,GAHAnC,KAAKW,UAAUW,YAAYmB,GAGF,oBAAdE,UACT,MAAM,IAAIC,MAAM,4EAElB,MAAMC,EAAU,IAAIF,UAAUG,MAAML,EAAc,CAChDtC,SAAUgC,EAAOhC,SACjBoC,MAAOJ,EAAOI,QAIhBvC,KAAKM,OAAOyC,IAAIb,EAAS,CACvBc,QAASP,EACTE,UAAWE,EACXb,OACAyB,OACAhC,QAAS,eAIXgB,EAAaQ,iBAAiB,kBAAmB,KAC/CjD,KAAK2D,YAAYzB,KAInB,MAAM0B,EAAgBnB,EAAaoB,cAAc,oBAQjD,OAPID,GAAiBH,GACnBA,EAAKK,QAAO,EAAMF,GAIpBf,EAAQnB,OAED,CACLX,GAAImB,EACJuB,OACAN,KAAM,KACJ,IACEN,EAAQM,MACV,OAASvB,GACPwB,QAAQC,KAAK,2BAA4BzB,EAC3C,GAEF0B,QAAS,IAAMtD,KAAK2D,YAAYzB,GAChCqB,eAAiBQ,IACXN,GAAuC,mBAAxBA,EAAKF,gBACtBE,EAAKF,eAAeQ,IAI5B,CAKA,kBAAArB,CAAmB3B,EAAIU,EAASO,EAAMG,GACpC,MAAM6B,EAAQpD,SAASE,cAAc,OACrCkD,EAAMjD,GAAKA,EACXiD,EAAMhD,UAAY,uBAAuBgB,IACzCgC,EAAM5C,aAAa,OAAQ,SAC3B4C,EAAM5C,aAAa,YAAa,aAChC4C,EAAM5C,aAAa,cAAe,QAElC,MAAM6C,EAAS9B,EAAOC,OAASD,EAAOR,KAAO3B,KAAKkE,kBAAkB/B,EAAQH,GAAQ,GAC9EX,EAAOrB,KAAKmE,gBAAgB1C,EAASU,EAAOR,OAASQ,EAAOC,OAOlE,OALA4B,EAAMI,UAAY,WACdH,YACA5C,UAGG2C,CACT,CAKA,sBAAAN,CAAuB3C,EAAI0C,EAAMzB,EAAMG,GACrC,MAAM6B,EAAQpD,SAASE,cAAc,OACrCkD,EAAMjD,GAAKA,EACXiD,EAAMhD,UAAY,uBAAuBgB,IACzCgC,EAAM5C,aAAa,OAAQ,SAC3B4C,EAAM5C,aAAa,YAAa,aAChC4C,EAAM5C,aAAa,cAAe,QAElC,MAAM6C,EAAS9B,EAAOC,OAASD,EAAOR,KAAO3B,KAAKkE,kBAAkB/B,EAAQH,GAAQ,GAC9EX,EAAOrB,KAAKqE,sBAOlB,OALAL,EAAMI,UAAY,WACdH,YACA5C,UAGG2C,CACT,CAKA,mBAAAK,GACE,MAAO,2GAKT,CAKA,iBAAAH,CAAkB/B,EAAQmC,GACxB,MAAMC,EAAWpC,EAAOR,KACtB,aAAaQ,EAAOR,qCAAuC,GAEvD6C,EAAYrC,EAAOC,MACvB,2BAA2BmC,IAAWvE,KAAKyE,WAAWtC,EAAOC,kBAAoB,GAE7EsC,EAAWvC,EAAOwC,SACtB,6BAA6B3E,KAAK4E,0BAA4B,GAE1DC,EAAc1C,EAAOK,YACzB,mHAAqH,GAEvH,OAAKgC,GAAcE,GAAaG,EAIzB,+CAEDL,cACAE,cACAG,wBAPG,EAUX,CAKA,eAAAV,CAAgB1C,EAASqD,GAAW,GAIlC,MAAO,uEAHUA,EACf,aAAa9E,KAAKsC,eAAe,wCAA0C,qBAKjEtC,KAAKyE,WAAWhD,+BAG9B,CAKA,eAAAY,CAAgBL,GAQd,MAPe,CACbR,QAAS,UACTI,MAAO,QACPE,QAAS,UACTD,KAAM,cACNE,MAAO,IAEKC,IAAS,cACzB,CAKA,cAAAM,CAAeN,GAQb,MAPc,CACZR,QAAS,uBACTI,MAAO,+BACPE,QAAS,+BACTD,KAAM,sBACNE,MAAO,IAEIC,IAAS,qBACxB,CAKA,gBAAAC,GAGE,GAFqB8C,MAAMC,KAAKhF,KAAKM,OAAO2E,UAE3BC,QAAUlF,KAAKD,QAAQM,UAAW,CAEjD,MAAM8E,EAAWnF,KAAKM,OAAO8E,OAAOC,OAAOC,MACrCC,EAASvF,KAAKM,OAAOkF,IAAIL,GAE3BI,GACFA,EAAO5C,UAAUQ,MAErB,CACF,CAKA,OAAAD,CAAQhB,GACN,MAAM8B,EAAQhE,KAAKM,OAAOkF,IAAItD,GAE9B,GAAI8B,EAAO,CAET,IACEA,EAAMrB,UAAUW,SAClB,OAASmC,GACPrC,QAAQC,KAAK,yBAA0BoC,EACzC,CAGIzB,EAAMhB,SAAWgB,EAAMhB,QAAQ0C,YACjC1B,EAAMhB,QAAQ0C,WAAWC,YAAY3B,EAAMhB,SAI7ChD,KAAKM,OAAOsF,OAAO1D,EACrB,CACF,CAKA,WAAAyB,CAAYzB,GACV,MAAM8B,EAAQhE,KAAKM,OAAOkF,IAAItD,GAE9B,GAAI8B,EAAO,CAET,GAAIA,EAAMP,MAAsC,mBAAvBO,EAAMP,KAAKH,QAClC,IACEU,EAAMP,KAAKH,SACb,OAASmC,GACPrC,QAAQC,KAAK,iCAAkCoC,EACjD,CAIF,IACEzB,EAAMrB,UAAUW,SAClB,OAASmC,GACPrC,QAAQC,KAAK,yBAA0BoC,EACzC,CAGIzB,EAAMhB,SAAWgB,EAAMhB,QAAQ0C,YACjC1B,EAAMhB,QAAQ0C,WAAWC,YAAY3B,EAAMhB,SAI7ChD,KAAKM,OAAOsF,OAAO1D,EACrB,CACF,CAKA,OAAA2D,GACE7F,KAAKM,OAAOwF,QAAQ,CAAC9B,EAAO+B,KAC1B/B,EAAMrB,UAAUQ,QAEpB,CAKA,QAAA6C,GACEhG,KAAKM,OAAOwF,QAAQ,CAAC9B,EAAOjD,KAC1Bf,KAAKkD,QAAQnC,IAEjB,CAKA,aAAA6D;AACE,OAAA,IAAWqB,MAAOC,mBAAmB,GAAI,CACvCC,KAAM,UACNC,OAAQ,WAEZ,CAKA,UAAA3B,CAAW4B,GACT,MAAMC,EAAM1F,SAASE,cAAc,OAEnC,OADAwF,EAAIC,YAAcF,EACXC,EAAIlC,SACb,CAKA,OAAAd,GACEtD,KAAKgG,WAEDhG,KAAKW,WAAaX,KAAKW,UAAU+E,YACnC1F,KAAKW,UAAU+E,WAAWC,YAAY3F,KAAKW,UAE/C,CAKA,QAAA6F,GACE,MAAMC,EAAQ,CACZC,MAAO1G,KAAKM,OAAOqG,KACnBC,OAAQ,CAAA,GAOV,OAJA5G,KAAKM,OAAOwF,QAAQ9B,IAClByC,EAAMG,OAAO5C,EAAMhC,OAASyE,EAAMG,OAAO5C,EAAMhC,OAAS,GAAK,IAGxDyE,CACT,CAKA,UAAAI,CAAWC,GACT9G,KAAKD,QAAU,IAAKC,KAAKD,WAAY+G,GAGjCA,EAAW5G,UACTF,KAAKW,YACPX,KAAKW,UAAUK,UAAY,kCAAkChB,KAAKiB,uBAGxE,EChiBF,MAAM8F,cAAcC,EAChB,WAAAlH,CAAYmH,EAAO,IACfC,MAAMD,EAAM,CACRE,SAAU,cAElB,EAMJ,MAAMC,kBAAkBC,EACpB,WAAAvH,CAAYC,EAAU,IAClBmH,MAAM,CACFI,WAAYP,MACZI,SAAU,aACVR,KAAM,MACH5G,GAEX,EAGJ,MAAMwH,EAAa,CACfC,IAAO,eACPC,SAAY,WACZC,WAAc,aACdC,KAAQ,OACRC,SAAY,WACZC,QAAW,UACXC,OAAU,SACVC,IAAO,MACPC,MAAS,QACTC,SAAY,WACZC,SAAY,WACZC,OAAU,SACVC,MAAS,QACTC,QAAW,UACXC,UAAa,YACbC,KAAQ,UACRC,KAAQ,gBACRC,GAAM,qBAIJC,EAAmBC,OAAOC,QAAQrB,GAAYsB,IAAI,EAAEC,EAAKC,MAAK,CAChEzD,MAAOwD,EACPC,WAMEC,EAAa,CACfC,OAAQ,CACJ7G,MAAO,eACP8G,OAAQ,CACJ,CACIC,KAAM,OACNnH,KAAM,OACN+G,MAAO,aACPK,UAAU,EACVC,YAAa,oBAEjB,CACIF,KAAM,OACNnH,KAAM,SACN+G,MAAO,aACPK,UAAU,EACVrJ,QAAS2I,GAEb,CACI1G,KAAM,aACNmH,KAAM,SACNJ,MAAO,eACP1B,WAAYD,UACZkC,WAAY,OACZC,WAAY,KACZC,SAAU,GACVH,YAAa,mBACbI,YAAY,EACZC,WAAY,OAKxBC,KAAM,CACFvH,MAAO,aACP8G,OAAQ,CACJ,CACIC,KAAM,OACNnH,KAAM,OACN+G,MAAO,aACPK,UAAU,EACVC,YAAa,oBAEjB,CACIF,KAAM,OACNnH,KAAM,SACN+G,MAAO,aACPK,UAAU,EACVrJ,QAAS2I,GAEb,CACI1G,KAAM,aACNmH,KAAM,SACNJ,MAAO,eACP1B,WAAYD,UACZkC,WAAY,OACZC,WAAY,KACZC,SAAU,GACVH,YAAa,mBACbI,YAAY,EACZC,WAAY,KAEhB,CACIP,KAAM,kBACNnH,KAAM,OACN+G,MAAO,iBACPM,YAAa,gBAEjB,CACIF,KAAM,kBACNnH,KAAM,OACN+G,MAAO,iBACPM,YAAa,oBAEjB,CACIF,KAAM,YACNnH,KAAM,SACN+G,MAAO,YACPa,KAAM,KAKlBC,SAAU,CACNzH,MAAO,gBACP8G,OAAQ,CAEJ,CACIlH,KAAM,SACN8H,KAAM,sBACNC,MAAO,EACPC,MAAO,qBAIX,CACIhI,KAAM,QACNiI,QAAS,CAAEC,GAAI,GAAIC,GAAI,GACvBjB,OAAQ,CACJ,CACIlH,KAAM,QACNmH,KAAM,SACNxC,KAAM,KACNyD,UAAW,CAAEC,MAAO,IAAKC,OAAQ,KACjCjB,YAAa,qBACbkB,KAAM,0BACNN,QAAS,IAEb,CACId,KAAM,YACNnH,KAAM,SACN+G,MAAO,YACPkB,QAAS,MAMrB,CACIjI,KAAM,QACNiI,QAAS,CAAEC,GAAI,GAAIC,GAAI,GACvB/H,MAAO,UACP8G,OAAQ,CACJ,CACIC,KAAM,OACNnH,KAAM,OACN+G,MAAO,aACPK,UAAU,EACVC,YAAa,mBACbY,QAAS,IAEb,CACId,KAAM,OACNnH,KAAM,SACN+G,MAAO,aACPK,UAAU,EACVa,QAAS,GACTlK,QAAS,CACL,CAAEuF,MAAO,MAAOyD,MAAO,gBACvB,CAAEzD,MAAO,OAAQyD,MAAO,QACxB,CAAEzD,MAAO,aAAcyD,MAAO,cAC9B,CAAEzD,MAAO,WAAYyD,MAAO,YAC5B,CAAEzD,MAAO,MAAOyD,MAAO,OACvB,CAAEzD,MAAO,QAASyD,MAAO,WAGjC,CACI/G,KAAM,aACNmH,KAAM,SACNJ,MAAO,eACP1B,WAAYD,UACZkC,WAAY,OACZC,WAAY,KACZC,SAAU,GACVH,YAAa,mBACbI,YAAY,EACZC,WAAY,IACZO,QAAS,MAMrB,CACIjI,KAAM,QACNiI,QAAS,GACT7H,MAAO,mBACP4H,MAAO,OACPd,OAAQ,CACJ,CACIlH,KAAM,SACNmH,KAAM,oBACNJ,MAAO,WACPkB,QAAS,EACT3E,MAAO,sBACPvF,QAAS,CACL,CAAEuF,MAAO,mBAAoBwE,KAAM,gBACnC,CAAExE,MAAO,kBAAmBwE,KAAM,gBAClC,CAAExE,MAAO,iBAAkBwE,KAAM,iBACjC,CAAExE,MAAO,sBAAuBwE,KAAM,gBACtC,CAAExE,MAAO,MAAOwE,KAAM,SAG9B,CACI9H,KAAM,SACNmH,KAAM,oBACNJ,MAAO,kBACPkB,QAAS,EACTlK,QAAS,CACL,CAAEuF,MAAO,EAAGwE,KAAM,YAClB,CAAExE,MAAO,EAAGwE,KAAM,QAClB,CAAExE,MAAO,EAAGwE,KAAM,QAClB,CAAExE,MAAO,EAAGwE,KAAM,QAClB,CAAExE,MAAO,EAAGwE,KAAM,QAClB,CAAExE,MAAO,EAAGwE,KAAM,QAClB,CAAExE,MAAO,EAAGwE,KAAM,QAClB,CAAExE,MAAO,EAAGwE,KAAM,QAClB,CAAExE,MAAO,EAAGwE,KAAM,QAClB,CAAExE,MAAO,EAAGwE,KAAM,QAClB,CAAExE,MAAO,GAAIwE,KAAM,SACnB,CAAExE,MAAO,GAAIwE,KAAM,SACnB,CAAExE,MAAO,GAAIwE,KAAM,SACnB,CAAExE,MAAO,GAAIwE,KAAM,QACnB,CAAExE,MAAO,GAAIwE,KAAM,QACnB,CAAExE,MAAO,GAAIwE,KAAM,QACnB,CAAExE,MAAO,GAAIwE,KAAM,QACnB,CAAExE,MAAO,GAAIwE,KAAM,QACnB,CAAExE,MAAO,GAAIwE,KAAM,QACnB,CAAExE,MAAO,GAAIwE,KAAM,QACnB,CAAExE,MAAO,GAAIwE,KAAM,QACnB,CAAExE,MAAO,GAAIwE,KAAM,QACnB,CAAExE,MAAO,GAAIwE,KAAM,SACnB,CAAExE,MAAO,GAAIwE,KAAM,aAKnC,CACI9H,KAAM,OACN+G,MAAO,0BACPI,KAAM,0BACNc,QAAS,OAMzBlD,MAAMyD,UAAYxB,EAAWW,KAC7B5C,MAAM0D,SAAWzB,EAAWC,OAC5BlC,MAAM2D,YAAc1B,EAAWC,OAC/BlC,MAAM2B,iBAAmBA,EACzB3B,MAAMQ,WAAaA,gLCpSnB,MAAMoD,aAAa3D,EACf,WAAAlH,CAAYmH,EAAO,IACfC,MAAMD,EAAM,CACRE,SAAU,aAElB,CAEA,aAAAyD,CAAcC,GACV,GAAI7K,KAAKwF,IAAI,gBAAiB,OAAO,EACrC,GAAIT,MAAM+F,QAAQD,GACd,OAAOA,EAAWE,KAAKC,GAAKhL,KAAK4K,cAAcI,IAInD,MAAMC,EAAkBJ,EAAWK,WAAW,QACxCC,EAAoBF,EAAkBJ,EAAWO,UAAU,GAAKP,EAEtE,QAAI7K,KAAKqL,eAAeF,MAKnBF,IAAmBjL,KAAKsL,SAAUtL,KAAKsL,OAAOV,cAAcC,GAKrE,CAEA,cAAAQ,CAAeR,GACX,MAAMU,EAAcvL,KAAKwF,IAAI,eAC7B,QAAK+F,GAG6B,GAA3BA,EAAYV,EACvB,CAEA,OAAAW,CAAQR,GACJ,OAAOhL,KAAK4K,cAAcI,EAC9B,EAGJ,MAAMS,iBAAiBpE,EACnB,WAAAvH,CAAYC,EAAU,IAClBmH,MAAM,CACFI,WAAYqD,KACZxD,SAAU,eACPpH,GAEX,EAGJ4K,KAAKe,YAAc,CACf,CAAEvC,KAAM,eAAgBJ,MAAO,gBAC/B,CAAEI,KAAM,aAAcJ,MAAO,cAC7B,CAAEI,KAAM,cAAeJ,MAAO,eAC9B,CAAEI,KAAM,gBAAiBJ,MAAO,iBAChC,CAAEI,KAAM,eAAgBJ,MAAO,uBAC/B,CAAEI,KAAM,iBAAkBJ,MAAO,yBACjC,CAAEI,KAAM,YAAaJ,MAAO,aAC5B,CAAEI,KAAM,iBAAkBJ,MAAO,kBACjC,CAAEI,KAAM,mBAAoBJ,MAAO,oBACnC,CAAEI,KAAM,eAAgBJ,MAAO,gBAC/B,CAAEI,KAAM,iBAAkBJ,MAAO,kBACjC,CAAEI,KAAM,aAAcJ,MAAO,cAC7B,CAAEI,KAAM,YAAaJ,MAAO,aAC5B,CAAEI,KAAM,cAAeJ,MAAO,eAC9B,CAAEI,KAAM,cAAeJ,MAAO,eAC9B,CAAEI,KAAM,uBAAwBJ,MAAO,wBACvC,CAAEI,KAAM,eAAgBJ,MAAO,gBAC/B,CAAEI,KAAM,uBAAwBJ,MAAO,wBACvC,CAAEI,KAAM,aAAcJ,MAAO,qBAC7B,CAAEI,KAAM,aAAcJ,MAAO,cAC7B,CAAEI,KAAM,eAAgBJ,MAAO,iBAInC4B,KAAKgB,kBAAoB,IAClBhB,KAAKe,YAAY7C,IAAIgC,IAAA,CACpB1B,KAAM,eAAe0B,EAAW1B,OAChCnH,KAAM,SACN+G,MAAO8B,EAAW9B,MAClBkB,QAAS,MAIZ,MAAC2B,EAAY,CACd3C,OAAQ,CACJ7G,MAAO,cACP8G,OAAQ,CACJ,CAAEC,KAAM,QAASnH,KAAM,OAAQ+G,MAAO,QAASK,UAAU,GACzD,CAAED,KAAM,eAAgBnH,KAAM,OAAQ+G,MAAO,eAAgBkB,QAAS,IACtE,CAAEd,KAAM,eAAgBnH,KAAM,OAAQ+G,MAAO,kBAGrDY,KAAM,CACFvH,MAAO,YACP8G,OAAQ,CACJ,CAAEC,KAAM,QAASnH,KAAM,QAAS+G,MAAO,QAASkB,QAAS,IACzD,CAAEd,KAAM,eAAgBnH,KAAM,OAAQ+G,MAAO,eAAgBkB,QAAS,IACtE,CAAEd,KAAM,eAAgBnH,KAAM,OAAQ+G,MAAO,eAAgBkB,QAAS,IACtE,CAAEjI,KAAM,aAAcmH,KAAM,MAAOJ,MAAO,eAAgB1B,WAAYD,UAAWkC,WAAY,OAAQC,WAAY,KAAMU,QAAS,MAGxIsB,YAAa,CACTnJ,MAAO,mBACP8G,OAAQyB,KAAKgB,oBAMfE,EAAe,CAEjBC,QAAS,CACL1J,MAAO,eACP6H,QAAS,EACTf,OAAQ,CACJ,CACIC,KAAM,KACNJ,MAAO,UACP/G,KAAM,SACNiI,QAAS,GAEb,CACId,KAAM,aACNJ,MAAO,aACP/G,KAAM,WACN+J,OAAQ,WACR9B,QAAS,GAEb,CACId,KAAM,gBACNJ,MAAO,gBACP/G,KAAM,WACN+J,OAAQ,WACR9B,QAAS,GAEb,CACId,KAAM,WACNJ,MAAO,WACP/G,KAAM,OACN+J,OAAQ,YACR9B,QAAS,GAEb,CACId,KAAM,eACNJ,MAAO,eACP/G,KAAM,OACNiI,QAAS,GAGb,CACId,KAAM,QACNJ,MAAO,QACP/G,KAAM,QACNiI,QAAS,IAGb,CACId,KAAM,WACNJ,MAAO,eACP/G,KAAM,OACNiI,QAAS,GAEb,CACId,KAAM,eACNJ,MAAO,eACP/G,KAAM,OACNiI,QAAS,KAMrB+B,SAAU,CACN5J,MAAO,gBACP6H,QAAS,EACTf,OAAQ,CACJ,CACIC,KAAM,aACNJ,MAAO,aACP/G,KAAM,WACN+J,OAAQ,WACRE,QAAS,GAEb,CACI9C,KAAM,gBACNJ,MAAO,gBACP/G,KAAM,WACN+J,OAAQ,WACRE,QAAS,KAMrBpC,SAAU,CACNzH,MAAO,4BACP6H,QAAS,EACTiC,iBAAiB,EACjBC,eAAgB,UAChBjD,OAAQ,CAEJ,CACIC,KAAM,KACNJ,MAAO,UACP/G,KAAM,SACNiK,QAAS,GAEb,CACI9C,KAAM,eACNJ,MAAO,eACP/G,KAAM,OACN+J,OAAQ,qCACRE,QAAS,GAEb,CACI9C,KAAM,WACNJ,MAAO,WACP/G,KAAM,OACN+J,OAAQ,YACRE,QAAS,GAEb,CACI9C,KAAM,QACNJ,MAAO,gBACP/G,KAAM,QACNiK,QAAS,GAEb,CACI9C,KAAM,eACNJ,MAAO,eACP/G,KAAM,QACN+J,OAAQ,gCACRE,QAAS,GAEb,CACI9C,KAAM,YACNJ,MAAO,iBACP/G,KAAM,UACNiK,QAAS,GAIb,CACI9C,KAAM,aACNJ,MAAO,aACP/G,KAAM,WACN+J,OAAQ,WACRE,QAAS,GAEb,CACI9C,KAAM,gBACNJ,MAAO,gBACP/G,KAAM,WACN+J,OAAQ,WACRE,QAAS,GAIb,CACI9C,KAAM,aACNJ,MAAO,SACP/G,KAAM,MACNiK,QAAS,IAIb,CACI9C,KAAM,cACNJ,MAAO,mBACP/G,KAAM,WACNoK,gBAAiB,EACjBF,iBAAiB,GAErB,CACI/C,KAAM,WACNJ,MAAO,gBACP/G,KAAM,WACNoK,gBAAiB,GAErB,CACIjD,KAAM,SACNJ,MAAO,iBACP/G,KAAM,WACNoK,gBAAiB,KAM7Bb,YAAa,CACTnJ,MAAO,mBACP6H,QAAS,EACTf,OAAQ,CACJ,CACIC,KAAM,eACNJ,MAAO,OACP/G,KAAM,OACN+J,OAAQ,aACR9B,QAAS,IAEb,CACId,KAAM,cACNJ,MAAO,uBACP/G,KAAM,WACNoK,gBAAiB,EACjBF,iBAAiB,EACjBD,QAAS,MAMrBI,QAAS,CACLjK,MAAO,eACP6H,QAAS,EACTf,OAAQ,CACJ,CACIC,KAAM,eACNJ,MAAO,OACP/G,KAAM,OACN+J,OAAQ,2BAEZ,CACI5C,KAAM,QACNJ,MAAO,QACP/G,KAAM,SAEV,CACImH,KAAM,YACNJ,MAAO,SACP/G,KAAM,WAEV,CACImH,KAAM,gBACNJ,MAAO,YACP/G,KAAM,WACN+J,OAAQ,WACRE,QAAS,OAMzBtB,KAAK2B,UAAYT,EAAahC,SAC9Bc,KAAKH,UAAYoB,EAAUjC,KAC3BgB,KAAKF,SAAWmB,EAAU3C,OAK1B,MAAMsD,mBAAmBvF,EACrB,WAAAlH,CAAYmH,EAAO,IACfC,MAAMD,EAAM,CACRE,SAAU,oBAElB,CAEA,sBAAaqF,CAAUC,GACnB,MAAMC,EAAQ,IAAIH,WACZI,QAAaD,EAAME,KAAKC,IAAI,0BAA2B,CAAEJ,SAC/D,OAAIE,EAAKnL,SAAWmL,EAAK1F,MAAQ0F,EAAK1F,KAAKA,KAEhC,IAAIsF,WAAWI,EAAK1F,KAAKA,MAE7B,IACX,EAGJ,MAAM6F,uBAAuBzF,EACzB,WAAAvH,CAAYC,EAAU,IAClBmH,MAAM,CACFI,WAAYiF,WACZpF,SAAU,sBACPpH,GAEX,EAMJ,MAAMgN,2BAA2B/F,EAC7B,WAAAlH,CAAYmH,EAAO,IACfC,MAAMD,EAAM,CACRE,SAAU,6BAElB,EAGJ,MAAM6F,+BAA+B3F,EACjC,WAAAvH,CAAYC,EAAU,IAClBmH,MAAM,CACFI,WAAYyF,mBACZ5F,SAAU,+BACPpH,GAEX"}
|