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.
Files changed (96) hide show
  1. package/CHANGELOG.md +25 -9
  2. package/dist/admin.cjs.js +1 -1
  3. package/dist/admin.cjs.js.map +1 -1
  4. package/dist/admin.es.js +1 -1
  5. package/dist/admin.es.js.map +1 -1
  6. package/dist/auth.cjs.js +1 -1
  7. package/dist/auth.es.js +1 -1
  8. package/dist/charts.cjs.js +1 -1
  9. package/dist/charts.es.js +1 -1
  10. package/dist/chunks/ChatView-CZ3Key2k.js +2 -0
  11. package/dist/chunks/ChatView-CZ3Key2k.js.map +1 -0
  12. package/dist/chunks/ChatView-Dw-iVmht.js +2 -0
  13. package/dist/chunks/ChatView-Dw-iVmht.js.map +1 -0
  14. package/dist/chunks/{Dialog-DW7PHzUc.js → Dialog-Dhqtd9Yz.js} +2 -2
  15. package/dist/chunks/{Dialog-DW7PHzUc.js.map → Dialog-Dhqtd9Yz.js.map} +1 -1
  16. package/dist/chunks/{Dialog-jfBsXy5X.js → Dialog-t_9l2Mou.js} +2 -2
  17. package/dist/chunks/{Dialog-jfBsXy5X.js.map → Dialog-t_9l2Mou.js.map} +1 -1
  18. package/dist/chunks/Files-6eRT5k3r.js +2 -0
  19. package/dist/chunks/{Files-C-ChBvr5.js.map → Files-6eRT5k3r.js.map} +1 -1
  20. package/dist/chunks/Files-Dh_5PFBn.js +2 -0
  21. package/dist/chunks/{Files-DNbHDy43.js.map → Files-Dh_5PFBn.js.map} +1 -1
  22. package/dist/chunks/{FormView-EoB_ZdIB.js → FormView-B1CXO2t8.js} +2 -2
  23. package/dist/chunks/{FormView-EoB_ZdIB.js.map → FormView-B1CXO2t8.js.map} +1 -1
  24. package/dist/chunks/{FormView-Q_lFA0nr.js → FormView-BRHAIawp.js} +2 -2
  25. package/dist/chunks/{FormView-Q_lFA0nr.js.map → FormView-BRHAIawp.js.map} +1 -1
  26. package/dist/chunks/{MetricsMiniChartWidget-lzq4lSTF.js → MetricsMiniChartWidget-D1w608Jy.js} +2 -2
  27. package/dist/chunks/{MetricsMiniChartWidget-lzq4lSTF.js.map → MetricsMiniChartWidget-D1w608Jy.js.map} +1 -1
  28. package/dist/chunks/{MetricsMiniChartWidget-ukn-NRMR.js → MetricsMiniChartWidget-Dg1e6EQJ.js} +2 -2
  29. package/dist/chunks/{MetricsMiniChartWidget-ukn-NRMR.js.map → MetricsMiniChartWidget-Dg1e6EQJ.js.map} +1 -1
  30. package/dist/chunks/{PDFViewer-iOqYpg-6.js → PDFViewer-CDeV9OBs.js} +2 -2
  31. package/dist/chunks/{PDFViewer-iOqYpg-6.js.map → PDFViewer-CDeV9OBs.js.map} +1 -1
  32. package/dist/chunks/{PDFViewer-sFoyopz3.js → PDFViewer-D_3V8QJe.js} +2 -2
  33. package/dist/chunks/{PDFViewer-sFoyopz3.js.map → PDFViewer-D_3V8QJe.js.map} +1 -1
  34. package/dist/chunks/TableView-CI_7a-kD.js +2 -0
  35. package/dist/chunks/TableView-CI_7a-kD.js.map +1 -0
  36. package/dist/chunks/TableView-CWk5k4LQ.js +2 -0
  37. package/dist/chunks/TableView-CWk5k4LQ.js.map +1 -0
  38. package/dist/chunks/ToastService-C2tTooFn.js +3 -0
  39. package/dist/chunks/ToastService-C2tTooFn.js.map +1 -0
  40. package/dist/chunks/ToastService-nUaGVpSl.js +3 -0
  41. package/dist/chunks/ToastService-nUaGVpSl.js.map +1 -0
  42. package/dist/chunks/{TokenManager-ChNOca0K.js → TokenManager-ien2XzwO.js} +2 -2
  43. package/dist/chunks/{TokenManager-ChNOca0K.js.map → TokenManager-ien2XzwO.js.map} +1 -1
  44. package/dist/chunks/{TokenManager-DKzxBt6g.js → TokenManager-sZgt--C9.js} +2 -2
  45. package/dist/chunks/{TokenManager-DKzxBt6g.js.map → TokenManager-sZgt--C9.js.map} +1 -1
  46. package/dist/chunks/User-BL9M_PWB.js +2 -0
  47. package/dist/chunks/User-BL9M_PWB.js.map +1 -0
  48. package/dist/chunks/{User-BnlvMG5J.js → User-DqHG5Gr1.js} +2 -3
  49. package/dist/chunks/User-DqHG5Gr1.js.map +1 -0
  50. package/dist/chunks/UserProfileView-DnVMHcLH.js +2 -0
  51. package/dist/chunks/UserProfileView-DnVMHcLH.js.map +1 -0
  52. package/dist/chunks/UserProfileView-kupeq2rN.js +2 -0
  53. package/dist/chunks/UserProfileView-kupeq2rN.js.map +1 -0
  54. package/dist/chunks/{WebApp-Bsic6FPo.js → WebApp-Bti0Gqqo.js} +2 -2
  55. package/dist/chunks/{WebApp-Bsic6FPo.js.map → WebApp-Bti0Gqqo.js.map} +1 -1
  56. package/dist/chunks/{WebApp-B0m6JCjO.js → WebApp-CcVF73yg.js} +2 -2
  57. package/dist/chunks/{WebApp-B0m6JCjO.js.map → WebApp-CcVF73yg.js.map} +1 -1
  58. package/dist/chunks/index-Aq9ke4vg.js +2 -0
  59. package/dist/chunks/index-Aq9ke4vg.js.map +1 -0
  60. package/dist/chunks/index-Da9sT-tE.js +2 -0
  61. package/dist/chunks/index-Da9sT-tE.js.map +1 -0
  62. package/dist/chunks/{version-BmVUtM_7.js → version-D8JjsPW0.js} +2 -2
  63. package/dist/chunks/{version-BmVUtM_7.js.map → version-D8JjsPW0.js.map} +1 -1
  64. package/dist/chunks/{version-i7K_82Qy.js → version-XmirKYWA.js} +2 -2
  65. package/dist/chunks/{version-i7K_82Qy.js.map → version-XmirKYWA.js.map} +1 -1
  66. package/dist/css/web-mojo.css +1 -1
  67. package/dist/docit.cjs.js +1 -1
  68. package/dist/docit.cjs.js.map +1 -1
  69. package/dist/docit.es.js +1 -1
  70. package/dist/docit.es.js.map +1 -1
  71. package/dist/index.cjs.js +1 -1
  72. package/dist/index.cjs.js.map +1 -1
  73. package/dist/index.es.js +1 -1
  74. package/dist/index.es.js.map +1 -1
  75. package/dist/lightbox.cjs.js +1 -1
  76. package/dist/lightbox.es.js +1 -1
  77. package/dist/map.cjs.js +1 -1
  78. package/dist/map.es.js +1 -1
  79. package/dist/user-profile.cjs.js +2 -0
  80. package/dist/user-profile.cjs.js.map +1 -0
  81. package/dist/user-profile.es.js +2 -0
  82. package/dist/user-profile.es.js.map +1 -0
  83. package/dist/web-mojo.lite.iife.js +9 -6
  84. package/dist/web-mojo.lite.iife.js.map +1 -1
  85. package/dist/web-mojo.lite.iife.min.js +11 -11
  86. package/dist/web-mojo.lite.iife.min.js.map +1 -1
  87. package/package.json +5 -1
  88. package/dist/chunks/ChatView-Cfe0ZGvr.js +0 -2
  89. package/dist/chunks/ChatView-Cfe0ZGvr.js.map +0 -1
  90. package/dist/chunks/ChatView-DuQVFrCY.js +0 -2
  91. package/dist/chunks/ChatView-DuQVFrCY.js.map +0 -1
  92. package/dist/chunks/Files-C-ChBvr5.js +0 -2
  93. package/dist/chunks/Files-DNbHDy43.js +0 -2
  94. package/dist/chunks/User-BnlvMG5J.js.map +0 -1
  95. package/dist/chunks/User-DSqcOwPL.js +0 -3
  96. package/dist/chunks/User-DSqcOwPL.js.map +0 -1
@@ -0,0 +1,2 @@
1
+ import{M as e,C as t}from"./Collection-BWKmydl5.js";import{r as a,V as s}from"./Rest-BJ3Mvx1L.js";import{G as n,U as i}from"./User-BL9M_PWB.js";import{P as l}from"./ContextMenu-DBw0WMTO.js";import o from"./Dialog-t_9l2Mou.js";import{T as r,p as c}from"./TableView-CWk5k4LQ.js";import{a as d}from"./FormView-BRHAIawp.js";import{F as u}from"./Files-6eRT5k3r.js";class S3Bucket extends e{constructor(e={}){super(e,{endpoint:"/api/aws/s3/bucket"})}}class S3BucketList extends t{constructor(e={}){super({ModelClass:S3Bucket,endpoint:"/api/aws/s3/bucket",size:10,...e})}}const p={create:{title:"Add S3 Bucket",fields:[{name:"bucket_name",type:"text",label:"Name",placeholder:"bucket name",help:"Enter a universally unique name for the bucket",required:!0,cols:12},{name:"is_public",type:"switch",label:"Is Public",cols:12}]},edit:{title:"Edit S3 Bucket",fields:[{name:"bucket_name",type:"text",label:"Name",placeholder:"bucket name",help:"Enter a universally unique name for the bucket",required:!0,cols:12},{name:"is_public",type:"switch",label:"Is Public",cols:12}]}};class EmailDomain extends e{constructor(e={},t={}){super(e,{endpoint:"/api/aws/email/domain",...t})}async onboard(e={},t={}){if(!this.id)return await this.showError("Cannot onboard domain without ID"),{success:!1,status:400,error:"Missing domain id"};try{const a=`${this.buildUrl(this.id)}/onboard`;return await this.rest.POST(a,e,t.params)}catch(a){return{success:!1,status:a?.status||500,error:a?.message||"Failed to onboard domain"}}}async audit(e={}){if(!this.id)return await this.showError("Cannot audit domain without ID"),{success:!1,status:400,error:"Missing domain id"};const t=(e.method||"GET").toUpperCase(),a=`${this.buildUrl(this.id)}/audit`;try{return"POST"===t?await this.rest.POST(a,e.data||{},e.params):await this.rest.GET(a,e.params)}catch(s){return{success:!1,status:s?.status||500,error:s?.message||"Failed to audit domain"}}}async reconcile(e={},t={}){if(!this.id)return await this.showError("Cannot reconcile domain without ID"),{success:!1,status:400,error:"Missing domain id"};try{const a=`${this.buildUrl(this.id)}/reconcile`;return await this.rest.POST(a,e,t.params)}catch(a){return{success:!1,status:a?.status||500,error:a?.message||"Failed to reconcile domain"}}}static async onboardById(e,t={},a={}){const s=new EmailDomain({id:e},a);return await s.onboard(t,a)}static async auditById(e,t={}){const a=new EmailDomain({id:e},t);return await a.audit(t)}static async reconcileById(e,t={},a={}){const s=new EmailDomain({id:e},a);return await s.reconcile(t,a)}}class EmailDomainList extends t{constructor(e={}){super({ModelClass:EmailDomain,endpoint:"/api/aws/email/domain",size:10,...e})}}const h={create:{title:"Add Email Domain",fields:[{name:"name",type:"text",label:"Domain Name",placeholder:"example.com",required:!0,columns:12,help:"Enter the root domain to verify with SES (no protocol)."},{name:"region",type:"text",label:"AWS Region (optional)",placeholder:"us-east-1",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 SES permissions",columns:12,help:"Optional, AWS Key with SES permissions"},{name:"aws_secret",type:"text",label:"AWS Secret (optional)",placeholder:"enter your AWS Secret with SES permissions",columns:12,help:"Optional, AWS Secret with SES permissions"},{name:"receiving_enabled",type:"switch",label:"Enable Inbound Receiving",columns:12,help:"Catch-all SES receipt rule to S3 + SNS; routing is done in-app."}]},edit:{title:"Edit Email Domain",fields:[{name:"name",type:"text",label:"Domain Name",placeholder:"example.com",required:!0,columns:12,readonly:!0,help:"Domain name cannot be changed after creation."},{name:"region",type:"text",label:"AWS Region",placeholder:"us-east-1",columns:12},{name:"receiving_enabled",type:"switch",label:"Enable Inbound Receiving",columns:12},{name:"s3_inbound_bucket",type:"text",label:"Inbound S3 Bucket",placeholder:"my-inbound-bucket",columns:12},{name:"s3_inbound_prefix",type:"text",label:"Inbound S3 Prefix",placeholder:"inbound/example.com/",columns:12},{name:"dns_mode",type:"select",label:"DNS Mode",options:[{value:"manual",text:"Manual (show records)"},{value:"godaddy",text:"GoDaddy (apply via API)"}],columns:12}]},credentials:{fields:[{name:"region",type:"select",label:"AWS Region (optional)",placeholder:"us-east-1",options:[{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 SES permissions",columns:12,help:"Optional, AWS Key with SES permissions"},{name:"aws_secret",type:"text",label:"AWS Secret (optional)",placeholder:"enter your AWS Secret with SES permissions",columns:12,help:"Optional, AWS Secret with SES permissions"}]},onboard:{title:"Onboard Domain",fields:[{type:"header",text:"Receiving",level:6,className:"mt-2"},{name:"receiving_enabled",type:"switch",label:"Enable Inbound Receiving",columns:12},{name:"s3_inbound_bucket",type:"text",label:"Inbound S3 Bucket",placeholder:"my-inbound-bucket",columns:12,help:"Required if receiving is enabled."},{name:"s3_inbound_prefix",type:"text",label:"Inbound S3 Prefix",placeholder:"inbound/example.com/",columns:12},{type:"header",text:"MAIL FROM (optional)",level:6,className:"mt-3"},{name:"ensure_mail_from",type:"switch",label:"Ensure MAIL FROM Setup",columns:12},{name:"mail_from_subdomain",type:"text",label:"MAIL FROM Subdomain",placeholder:"feedback",columns:12},{type:"header",text:"DNS",level:6,className:"mt-3"},{name:"dns_mode",type:"select",label:"DNS Mode",options:[{value:"manual",text:"Manual (show records)"},{value:"godaddy",text:"GoDaddy (apply via API)"}],value:"manual",columns:12},{name:"godaddy_key",type:"text",label:"GoDaddy API Key",columns:12,help:"Required when DNS Mode = GoDaddy."},{name:"godaddy_secret",type:"password",label:"GoDaddy API Secret",columns:12},{type:"header",text:"Webhook Endpoints",level:6,className:"mt-3"},{name:"endpoints.bounce",type:"text",label:"Bounce Endpoint",placeholder:"https://portal.example.com/api/aws/sns/bounce",columns:12},{name:"endpoints.complaint",type:"text",label:"Complaint Endpoint",placeholder:"https://portal.example.com/api/aws/sns/complaint",columns:12},{name:"endpoints.delivery",type:"text",label:"Delivery Endpoint",placeholder:"https://portal.example.com/api/aws/sns/delivery",columns:12},{name:"endpoints.inbound",type:"text",label:"Inbound Endpoint",placeholder:"https://portal.example.com/api/aws/sns/inbound",columns:12}]}};class Mailbox extends e{constructor(e={},t={}){super(e,{endpoint:"/api/aws/email/mailbox",...t})}}Mailbox.sendEmail=async function(e){return await a.POST("/api/aws/email/send",e)};class MailboxList extends t{constructor(e={}){super({ModelClass:Mailbox,endpoint:"/api/aws/email/mailbox",size:10,...e})}}const m={create:{title:"Add Mailbox",fields:[{type:"collection",name:"domain",label:"Domain",Collection:EmailDomainList,labelField:"name",valueField:"id",maxItems:10,placeholder:"Search domains...",emptyFetch:!1,required:!0,debounceMs:300,columns:12},{name:"email",type:"email",label:"Email Address",placeholder:"support@example.com",required:!0,columns:12},{name:"allow_inbound",type:"switch",label:"Allow Inbound",columns:6},{name:"allow_outbound",type:"switch",label:"Allow Outbound",defaultValue:!0,columns:6},{name:"is_system_default",type:"switch",label:"System Default",columns:6},{name:"is_domain_default",type:"switch",label:"Domain Default",columns:6},{name:"async_handler",type:"text",label:"Async Handler (optional)",placeholder:"myapp.handlers.process_support",columns:12,help:"Module:function to process inbound messages via task system"}]},edit:{title:"Edit Mailbox",fields:[{name:"email",type:"email",label:"Email Address",required:!0,columns:12},{name:"allow_inbound",type:"switch",label:"Allow Inbound",columns:6},{name:"allow_outbound",type:"switch",label:"Allow Outbound",columns:6},{name:"is_system_default",type:"switch",label:"System Default",columns:6},{name:"is_domain_default",type:"switch",label:"Domain Default",columns:6},{name:"async_handler",type:"text",label:"Async Handler (optional)",placeholder:"myapp.handlers.process_support",columns:12}]}};class SentMessage extends e{constructor(e={},t={}){super(e,{endpoint:"/api/aws/email/sent",...t})}}class SentMessageList extends t{constructor(e={}){super({ModelClass:SentMessage,endpoint:"/api/aws/email/sent",size:10,...e})}}const b={view:{title:"Sent Message Details",fields:[{name:"id",type:"text",label:"ID",readonly:!0,cols:6},{name:"ses_message_id",type:"text",label:"SES Message ID",readonly:!0,cols:6},{name:"from_email",type:"text",label:"From",readonly:!0,cols:12},{name:"to",type:"textarea",label:"To",readonly:!0,rows:2,cols:12},{name:"cc",type:"textarea",label:"CC",readonly:!0,rows:2,cols:12},{name:"bcc",type:"textarea",label:"BCC",readonly:!0,rows:2,cols:12},{name:"subject",type:"text",label:"Subject",readonly:!0,cols:12},{name:"status",type:"text",label:"Status",readonly:!0,cols:6},{name:"status_reason",type:"textarea",label:"Status Reason",readonly:!0,rows:3,cols:12},{name:"created",type:"text",label:"Created",readonly:!0,cols:6}]}};class EmailTemplate extends e{constructor(e={},t={}){super(e,{endpoint:"/api/aws/email/template",...t})}}class EmailTemplateList extends t{constructor(e={}){super({ModelClass:EmailTemplate,endpoint:"/api/aws/email/template",size:10,...e})}}const y={create:{title:"Add Email Template",fields:[{name:"name",type:"text",label:"Name",required:!0,cols:12},{name:"subject_template",type:"text",label:"Subject Template",cols:12},{type:"tabset",name:"settingsTabs",tabs:[{label:"HTML",fields:[{name:"html_template",type:"htmlpreview",label:"HTML Template",rows:16,cols:12}]},{label:"TEXT",fields:[{name:"text_template",type:"textarea",label:"Text Template",rows:16,cols:12}]}]}]},edit:{title:"Edit Email Template",fields:[{name:"name",type:"text",label:"Name",required:!0,cols:12},{name:"subject_template",type:"text",label:"Subject Template",cols:12},{type:"tabset",name:"settingsTabs",tabs:[{label:"HTML",fields:[{name:"html_template",type:"textarea",label:"HTML Template",rows:16,cols:12}]},{label:"TEXT",fields:[{name:"text_template",type:"textarea",label:"Text Template",rows:16,cols:12}]}]}]}};class IncidentStats extends e{constructor(e={}){super(e,{endpoint:"/api/incident/stats",requiresId:!1})}}class IncidentEvent extends e{constructor(e={}){super(e,{endpoint:"/api/incident/event"})}}class IncidentEventList extends t{constructor(e={}){super({ModelClass:IncidentEvent,endpoint:"/api/incident/event",size:10,...e})}}const g={edit:{title:"Edit Incident Event",fields:[{name:"category",type:"select",label:"Category",placeholder:"Select category",options:()=>Incident.COMPONENTS,editable:!0,force_top:!0,cols:6},{name:"incident",type:"text",label:"Incident",placeholder:"Enter Incident ID",cols:6},{name:"description",type:"textarea",label:"Description",placeholder:"Enter Description",cols:12},{name:"details",type:"textarea",label:"Details",placeholder:"Enter Details",cols:12},{name:"component",type:"text",label:"Component",placeholder:"Enter Component",cols:8},{name:"component_id",type:"text",label:"Component ID",placeholder:"Enter Component ID",cols:4}]}};class Incident extends e{constructor(e={}){super(e,{endpoint:"/api/incident/incident"})}}class IncidentList extends t{constructor(e={}){super({ModelClass:Incident,endpoint:"/api/incident/incident",size:10,...e})}}const v={create:{title:"Create Incident",fields:[{type:"tabset",name:"settingsTabs",tabs:[{label:"General",fields:[{name:"title",type:"text",label:"Title",required:!0,columns:12},{name:"details",type:"textarea",label:"Details",required:!0,columns:12}]},{label:"Advanced",fields:[{name:"priority",type:"select",label:"Priority",options:["1","2","3","4","5","6","7","8","9","10"],value:5,columns:6},{name:"status",type:"select",label:"Status",value:"open",options:["open","investigating","resolved","closed","paused","ignored"],columns:6},{name:"category",type:"text",label:"Category",value:"manual",columns:6}]},{label:"Metadata",fields:[{name:"metadata",type:"json",label:"Metadata",value:{example:"hello world"},rows:15,columns:12}]}]}]},edit:{title:"Edit Incident",fields:[{name:"category",type:"text",label:"Category",cols:6},{name:"state",type:"select",label:"State",placeholder:"Select State",options:["new","opened","paused","ignore","resolved"],cols:3},{name:"priority",type:"text",label:"Priority"},{name:"details",type:"textarea",label:"Description",placeholder:"Enter Name",cols:12},{name:"model_name",type:"text",label:"Model",placeholder:"Enter Model",cols:8},{name:"model_id",type:"text",label:"Model ID",placeholder:"Enter Model ID",cols:4}]}};class IncidentRuleSet extends e{constructor(e={}){super(e,{endpoint:"/api/incident/event/ruleset"})}}class IncidentRuleSetList extends t{constructor(e={}){super({ModelClass:IncidentRuleSet,endpoint:"/api/incident/event/ruleset",size:10,...e})}}class IncidentRule extends e{constructor(e={}){super(e,{endpoint:"/api/incident/event/ruleset/rule"})}}class IncidentRuleList extends t{constructor(e={}){super({ModelClass:IncidentRule,endpoint:"/api/incident/event/ruleset/rule",size:10,...e})}}class IncidentHistory extends e{constructor(e={}){super(e,{endpoint:"/api/incident/incident/history"})}}class IncidentHistoryList extends t{constructor(e={}){super({ModelClass:IncidentHistory,endpoint:"/api/incident/incident/history",size:10,...e})}}const w=[{value:0,label:"No Bundling"},{value:1,label:"By Hostname"},{value:2,label:"By Model Name"},{value:3,label:"By Model Name + ID"},{value:4,label:"By Source IP"},{value:5,label:"By Hostname + Model Name"},{value:6,label:"By Hostname + Model Name + ID"},{value:7,label:"By Source IP + Model Name"},{value:8,label:"By Source IP + Model Name + ID"},{value:9,label:"By Source IP + Hostname"}],f=[{value:0,label:"ALL (must match all rules)"},{value:1,label:"ANY (match any rule)"}],S=[{value:"==",label:"Equal (==)"},{value:"eq",label:"Equal (eq)"},{value:">",label:"Greater Than (>)"},{value:">=",label:"Greater Than or Equal (>=)"},{value:"<",label:"Less Than (<)"},{value:"<=",label:"Less Than or Equal (<=)"},{value:"contains",label:"Contains"},{value:"regex",label:"Regular Expression"}],x=[{value:"str",label:"String"},{value:"int",label:"Integer"},{value:"float",label:"Float"},{value:"bool",label:"Boolean"}],T=[{value:"level",label:"Level",description:"Event level (error, warning, info, debug)",meta:{type:"str"}},{value:"source_ip",label:"Source IP Address",description:"IP address of the event source",meta:{type:"str"}},{value:"rule_id",label:"Rule ID",description:"Numeric rule identifier",meta:{type:"int"}},{value:"hostname",label:"Hostname",description:"Hostname where event occurred",meta:{type:"str"}},{value:"component",label:"Component",description:"System component name",meta:{type:"str"}},{value:"component_id",label:"Component ID",description:"Component identifier",meta:{type:"str"}},{value:"category",label:"Category",description:"Event category (ossec, auth, api_error, etc.)",meta:{type:"str"}},{value:"description",label:"Description",description:"Event description text",meta:{type:"str"}},{value:"details",label:"Details",description:"Additional event details",meta:{type:"str"}},{value:"alert_id",label:"Alert ID",description:"Numeric alert identifier",meta:{type:"int"}},{value:"severity",label:"Severity",description:"Numeric severity level",meta:{type:"int"}},{value:"user",label:"User",description:"Username associated with event",meta:{type:"str"}},{value:"action",label:"Action",description:"Action that triggered the event",meta:{type:"str"}},{value:"status",label:"Status",description:"Status value or code",meta:{type:"str"}},{value:"status_code",label:"Status Code",description:"Numeric status code (e.g., HTTP status)",meta:{type:"int"}},{value:"message",label:"Message",description:"Event message text",meta:{type:"str"}},{value:"path",label:"Path",description:"File path or URL path",meta:{type:"str"}},{value:"title",label:"Title",description:"OSSEC Title",meta:{type:"str"}},{value:"country_code",label:"Country Code",description:"Country code associated with event",meta:{type:"str"}},{value:"region",label:"Region",description:"Region associated with event",meta:{type:"str"}},{value:"city",label:"City",description:"City associated with event",meta:{type:"str"}},{value:"http_user_agent",label:"HTTP User Agent",description:"User agent string associated with event",meta:{type:"str"}},{value:"request_path",label:"Request Path",description:"Request path associated with event",meta:{type:"str"}},{value:"method",label:"Method",description:"HTTP method or function name",meta:{type:"str"}}],_=[{value:"global",label:"Global"},{value:"account",label:"Account"},{value:"incident",label:"Incident"},{value:"ossec",label:"OSSEC"},{value:"fileman",label:"File Manager"},{value:"metrics",label:"Metrics"},{value:"jobs",label:"Jobs"},{value:"realtime",label:"Realtime"},{value:"aws",label:"AWS"}];class RuleSet extends e{constructor(e={}){super(e,{endpoint:"/api/incident/event/ruleset"})}}class RuleSetList extends t{constructor(e={}){super({ModelClass:RuleSet,endpoint:"/api/incident/event/ruleset",...e})}}const C={create:{title:"Create RuleSet",size:"lg",fields:[{name:"name",type:"text",label:"Name",required:!0,placeholder:"Enter ruleset name",cols:12},{name:"category",type:"combo",label:"Scope",required:!0,options:_,placeholder:"e.g., ossec, auth, api_error",cols:6},{name:"priority",type:"number",label:"Priority",value:10,required:!0,cols:6},{name:"match_by",type:"select",label:"Match Logic",value:0,options:f,cols:12},{name:"bundle_by",type:"select",label:"Bundle By",value:0,options:w,cols:12},{name:"bundle_minutes",type:"number",label:"Bundle Minutes",value:10,placeholder:"Time window for bundling",cols:12},{name:"handler",type:"text",label:"Handler",placeholder:"e.g., email://user@company.com, task://name",cols:12},{name:"is_active",type:"switch",label:"Is Active",value:!0,cols:6},{name:"bundle_by_rule_set",type:"switch",label:"Bundle by Rule Set",value:!0,cols:6}]},edit:{title:"Edit RuleSet",size:"lg",fields:[{name:"name",type:"text",label:"Name",required:!0,placeholder:"Enter ruleset name",cols:12},{name:"category",type:"combo",label:"Scope",options:_,required:!0,placeholder:"e.g., ossec, auth, api_error",cols:6},{name:"priority",type:"number",label:"Priority",required:!0,cols:6},{name:"match_by",type:"select",label:"Match Logic",options:f,cols:12},{name:"bundle_by",type:"select",label:"Bundle By",options:w,cols:12},{name:"bundle_minutes",type:"select",label:"Bundle Minutes",placeholder:"Time window for bundling",options:[{value:0,label:"Disabled - don't bundle by time"},{value:5,label:"5 minutes"},{value:10,label:"10 minutes"},{value:15,label:"15 minutes"},{value:30,label:"30 minutes"},{value:60,label:"1 hour"},{value:120,label:"2 hours"},{value:360,label:"6 hours"},{value:720,label:"12 hours"},{value:1440,label:"1 day"},{value:null,label:"No limit - bundle forever"}],cols:12},{name:"handler",type:"text",label:"Handler",placeholder:"e.g., email://user@company.com, task://name",cols:12},{name:"is_active",type:"switch",label:"Is Active",value:!0,cols:6},{name:"bundle_by_rule_set",type:"switch",label:"Bundle by Rule Set",value:!0,cols:6}]}};class Rule extends e{constructor(e={}){super(e,{endpoint:"/api/incident/event/ruleset/rule"})}}class RuleList extends t{constructor(e={}){super({ModelClass:Rule,endpoint:"/api/incident/event/ruleset/rule",...e})}}const E={create:{title:"Create Rule",fields:[{name:"name",type:"text",label:"Name",required:!0,placeholder:"Enter rule name",cols:12},{name:"field_name",type:"combo",label:"Field Name",required:!0,placeholder:"Select or enter field name...",options:T,allowCustom:!0,showDescription:!0,help:"Select a common field or type a custom field name",cols:8},{name:"index",type:"select",label:"Index",required:!0,start:0,end:14,step:1,cols:4},{name:"comparator",type:"select",label:"Comparator",required:!0,options:S,cols:6},{name:"value_type",type:"select",label:"Value Type",required:!0,options:x,value:"str",cols:6},{name:"value",type:"textarea",label:"Value",required:!0,placeholder:"Enter comparison value",cols:12}]},edit:{title:"Edit Rule",fields:[{name:"name",type:"text",label:"Name",required:!0,placeholder:"Enter rule name",cols:12},{name:"field_name",type:"combo",label:"Field Name",required:!0,placeholder:"Select or enter field name...",options:T,allowCustom:!0,showDescription:!0,help:"Select a common field or type a custom field name",cols:12},{name:"comparator",type:"select",label:"Comparator",required:!0,options:S,cols:6},{name:"value_type",type:"select",label:"Value Type",required:!0,options:x,cols:6},{name:"value",type:"text",label:"Value",required:!0,placeholder:"Enter comparison value",cols:12}]}};RuleSet.EDIT_FORM=C.edit,RuleSet.ADD_FORM=C.create,RuleSet.CREATE_FORM=C.create,RuleSet.BundleByOptions=w,RuleSet.MatchByOptions=f,Rule.EDIT_FORM=E.edit,Rule.ADD_FORM=E.create,Rule.CREATE_FORM=E.create,Rule.ComparatorOptions=S,Rule.ValueTypeOptions=x;class Job extends e{constructor(e={}){super(e,{endpoint:"/api/jobs/job"})}async cancel(){const e=await this.save({cancel_request:!0});return e.success&&e.data.status&&this.set("cancel_requested",!0),e}async retry(e=null){const t=e?{retry_request:{retry:!0,delay:e}}:{retry_request:!0},a=await this.save(t);return a.success&&a.data.status&&a.data.new_job_id?{...a,newJobId:a.data.new_job_id,originalJobId:a.data.original_job_id}:a}async getDetailedStatus(){const e=await this.save({get_status:!0});return e.success&&e.data.status&&this.set(e.data.data),e}async cloneJob(e={}){const t={publish_job:{payload:e,...e}},a=await this.save(t);return a.success&&a.data.status&&a.data.job_id?{...a,newJobId:a.data.job_id,templateJobId:a.data.template_job_id}:a}isActive(){const e=this.get("status");return["pending","running"].includes(e)}isTerminal(){const e=this.get("status");return["completed","failed","canceled","expired"].includes(e)}canRetry(){const e=this.get("status");return["failed","canceled","expired"].includes(e)&&!1!==this.get("is_retriable")}canCancel(){const e=this.get("status");return["pending","running"].includes(e)&&!this.get("cancel_requested")}getStatusBadgeClass(){return{pending:"bg-primary",running:"bg-success",completed:"bg-info",failed:"bg-danger",canceled:"bg-secondary",expired:"bg-warning"}[this.get("status")]||"bg-secondary"}getStatusIcon(){return{pending:"bi-hourglass",running:"bi-arrow-repeat",completed:"bi-check-circle",failed:"bi-x-octagon",canceled:"bi-x-circle",expired:"bi-clock"}[this.get("status")]||"bi-question-circle"}getEvents(){return this.get("recent_events")||[]}getFormattedDuration(){const e=this.get("duration_ms");return e&&0!==e?e<1e3?`${e}ms`:e<6e4?`${(e/1e3).toFixed(1)}s`:e<36e5?`${(e/6e4).toFixed(1)}m`:`${(e/36e5).toFixed(1)}h`:"N/A"}getQueuePosition(){return this.get("queue_position")}hasExpired(){const e=this.get("expires_at");return!!e&&new Date(e)</* @__PURE__ */new Date}getRunnerId(){return this.get("runner_id")}getPayload(){return this.get("payload")||{}}getMetadata(){return this.get("metadata")||{}}}class JobList extends t{constructor(e={}){super({ModelClass:Job,endpoint:"/api/jobs/job",...e})}async fetchByStatus(e,t={}){return this.fetch({status:e,...t})}async fetchByChannel(e,t={}){return this.fetch({channel:e,...t})}async fetchPending(e={}){return this.fetchByStatus("pending",e)}async fetchRunning(e={}){return this.fetchByStatus("running",e)}async fetchCompleted(e={}){return this.fetchByStatus("completed",e)}async fetchFailed(e={}){return this.fetchByStatus("failed",e)}async fetchScheduled(e={}){return this.fetch({scheduled:!0,...e})}}const M={publish:{title:"Publish New Job",fields:[{name:"func",type:"text",label:"Function",required:!0,placeholder:"myapp.jobs.send_email",help:"Module path to job function"},{name:"channel",type:"text",label:"Channel",value:"default",help:'Queue channel (default: "default")'},{name:"payload",type:"textarea",label:"Payload (JSON)",required:!0,rows:8,placeholder:'{\n "key": "value"\n}',help:"JSON data passed to the job function"},{name:"delay",type:"number",label:"Delay (seconds)",min:0,help:"Delay execution by specified seconds"},{name:"run_at",type:"datetime-local",label:"Run At",help:"Schedule for specific date/time"},{name:"max_retries",type:"number",label:"Max Retries",value:3,min:0,max:10},{name:"expires_in",type:"number",label:"Expires In (seconds)",value:900,min:60,help:"Job will expire if not completed in this time"},{name:"broadcast",type:"switch",label:"Broadcast to All Workers",help:"Execute on all available workers"}]},retry:{title:"Retry Job",fields:[{name:"delay",type:"number",label:"Delay (seconds)",value:0,min:0,help:"Delay before retry (0 = immediate)"}]},clone:{title:"Clone Job",fields:[{name:"channel",type:"text",label:"Channel",help:"Override channel for cloned job"},{name:"payload",type:"textarea",label:"Modified Payload (JSON)",rows:8,help:"Modified payload for cloned job"},{name:"delay",type:"number",label:"Delay (seconds)",min:0}]}};Job.publish=async function(e){return await a.POST("/api/jobs/publish",e)},Job.getStats=async function(){const e=await a.GET("/api/jobs/stats");return e.success?e.data:null},Job.getHealth=async function(e=null){const t=e?`/api/jobs/health/${e}`:"/api/jobs/health",s=a.GET(t);return s.success?s.data:null},Job.test=async function(){return await a.POST("/api/jobs/test",{})},Job.tests=async function(){return await a.POST("/api/jobs/tests",{})},Job.clearStuck=async function(e=null){const t=e?{channel:e}:{};return await a.POST("/api/jobs/control/clear-stuck",t)},Job.clearChannel=async function(e){return await a.POST("/api/jobs/control/clear-queue",{channel:e,confirm:"yes"})},Job.cleanConsumers=async function(){return await a.POST("/api/jobs/control/cleanup-consumers")},Job.purgeJobs=async function(e){return await a.POST("/api/jobs/control/purge",{days_old:e})};class JobLog extends e{constructor(e={}){super(e,{endpoint:"/api/jobs/logs"})}}class JobLogList extends t{constructor(e={}){super({endpoint:"/api/jobs/logs",model:JobLog,...e})}}class JobEvent extends e{constructor(e={}){super(e,{endpoint:"/api/jobs/event"})}}class JobEventList extends t{constructor(e={}){super({endpoint:"/api/jobs/event",model:JobEvent,...e})}}class JobsEngineStats extends e{constructor(e={}){super(e,{endpoint:"/api/jobs/stats",requiresId:!1})}}class JobRunner extends e{constructor(e={}){e.runner_id&&!e.id&&(e.id=e.runner_id),super(e,{endpoint:"/api/jobs/runners",idAttribute:"runner_id"})}async ping(e=2){const t=this.getApp();if(!t||!t.rest)throw new Error("App or REST client not available");const a=await t.rest.POST("/api/jobs/runners/ping",{runner_id:this.get("runner_id"),timeout:e});return a.success&&a.data.status&&(this.set("last_heartbeat",/* @__PURE__ */(new Date).toISOString()),this.set("ping_status",a.data.ping_status||"success")),a}async shutdown(e=!0){const t=this.getApp();if(!t||!t.rest)throw new Error("App or REST client not available");const a=await t.rest.POST("/api/jobs/runners/shutdown",{runner_id:this.get("runner_id"),graceful:e});return a.success&&a.data.status&&this.set("alive",!1),a}getChannels(){return this.get("channels")||[]}getStatusBadgeClass(){return this.get("alive")?"bg-success":"bg-danger"}getStatusIcon(){return this.get("alive")?"bi-check-circle-fill":"bi-x-octagon-fill"}isActive(){return!0===this.get("alive")}isHealthy(){if(!this.isActive())return!1;const e=this.get("last_heartbeat");return!!e&&(Date.now()-new Date(e).getTime())/1e3<120}getFormattedHeartbeatAge(){const e=this.get("last_heartbeat");if(!e)return"Never";const t=(Date.now()-new Date(e).getTime())/1e3;return t<60?`${Math.round(t)}s ago`:t<3600?`${Math.round(t/60)}m ago`:`${Math.round(t/3600)}h ago`}getUtilization(){const e=(this.get("jobs_processed")||0)+(this.get("jobs_failed")||0);return e>10?100:Math.min(10*e,100)}getFormattedUptime(){const e=this.get("started");if(!e)return"Unknown";const t=new Date(e),a=/* @__PURE__ */new Date-t,s=Math.floor(a/1e3);return s<60?`${s}s`:s<3600?`${Math.floor(s/60)}m`:s<86400?`${Math.floor(s/3600)}h`:`${Math.floor(s/86400)}d`}getWorkerInfo(){const e=this.get("jobs_processed")||0,t=this.get("jobs_failed")||0;return{processed:e,failed:t,total:e+t,alive:this.get("alive"),utilization:this.getUtilization()}}getDisplayName(){const e=this.get("runner_id");if(!e)return"Unknown Runner";const t=e.split("-");return t.length>1?t[0]:e}canControl(){return!0===this.get("alive")}}class JobRunnerList extends t{constructor(e={}){super({ModelClass:JobRunner,endpoint:"/api/jobs/runners",...e})}getActive(){return this.where(e=>e.isActive())}getByChannel(e){return this.where(t=>t.getChannels().includes(e))}getHealthy(){return this.where(e=>e.isHealthy())}getTotalProcessed(){return this.models.reduce((e,t)=>e+(t.get("jobs_processed")||0),0)}getTotalFailed(){return this.models.reduce((e,t)=>e+(t.get("jobs_failed")||0),0)}getSystemHealth(){if(0===this.models.length)return 0;const e=this.models.filter(e=>e.get("alive")).length;return Math.round(e/this.models.length*100)}getAllChannels(){const e=/* @__PURE__ */new Set;return this.models.forEach(t=>{t.getChannels().forEach(t=>e.add(t))}),Array.from(e).sort()}}JobRunner.ping=async function(e,t=2){const a="undefined"!=typeof window&&window.app;if(!a||!a.rest)throw new Error("App or REST client not available");return await a.rest.POST("/api/jobs/runners/ping",{runner_id:e,timeout:t})},JobRunner.shutdown=async function(e,t=!0){const a="undefined"!=typeof window&&window.app;if(!a||!a.rest)throw new Error("App or REST client not available");return await a.rest.POST("/api/jobs/runners/shutdown",{runner_id:e,graceful:t})},JobRunner.broadcast=async function(e,t={},a=2){const s="undefined"!=typeof window&&window.app;if(!s||!s.rest)throw new Error("App or REST client not available");return await s.rest.POST("/api/jobs/runners/broadcast",{command:e,data:t,timeout:a})},JobRunner.broadcastStatus=async function(e=2){return JobRunner.broadcast("status",{},e)},JobRunner.broadcastShutdown=async function(e=2){return JobRunner.broadcast("shutdown",{},e)},JobRunner.broadcastPause=async function(e=2){return JobRunner.broadcast("pause",{},e)},JobRunner.broadcastResume=async function(e=2){return JobRunner.broadcast("resume",{},e)},JobRunner.broadcastReload=async function(e=2){return JobRunner.broadcast("reload",{},e)};const I={broadcast:{title:"Broadcast Command",fields:[{name:"command",type:"select",label:"Command",required:!0,options:[{value:"status",label:"Status Check"},{value:"pause",label:"Pause Processing"},{value:"resume",label:"Resume Processing"},{value:"reload",label:"Reload Configuration"},{value:"shutdown",label:"Shutdown All Runners"}],help:"Command to send to all runners"},{name:"timeout",type:"number",label:"Timeout (seconds)",value:2,min:.5,max:10,step:.5,help:"How long to wait for responses"}]}};class MetricsPermission extends e{constructor(e={}){super(e,{endpoint:"/api/metrics/permissions",id_key:"account"})}}class MetricsPermissionList extends t{constructor(e={}){super({ModelClass:MetricsPermission,endpoint:"/api/metrics/permissions",...e})}}const L={edit:{title:"Edit Metrics Permissions",fields:[{name:"account",type:"text",label:"Account",columns:12},{name:"view_permissions",type:"tags",label:"View Permissions",help:'Enter permissions or "public"',columns:12},{name:"write_permissions",type:"tags",label:"Write Permissions",help:"Enter permissions",columns:12}]}};class PushDevice extends e{constructor(e={}){super(e,{endpoint:"/api/account/devices/push"})}}class PushDeviceList extends t{constructor(e={}){super({ModelClass:PushDevice,endpoint:"/api/account/devices/push",...e})}}class PushTemplate extends e{constructor(e={}){super(e,{endpoint:"/api/account/devices/push/templates"})}}class PushTemplateList extends t{constructor(e={}){super({ModelClass:PushTemplate,endpoint:"/api/account/devices/push/templates",...e})}}class PushConfig extends e{constructor(e={}){super(e,{endpoint:"/api/account/devices/push/config"})}}class PushConfigList extends t{constructor(e={}){super({ModelClass:PushConfig,endpoint:"/api/account/devices/push/config",...e})}}class PushDelivery extends e{constructor(e={}){super(e,{endpoint:"/api/account/devices/push/deliveries"})}}class PushDeliveryList extends t{constructor(e={}){super({ModelClass:PushDelivery,endpoint:"/api/account/devices/push/deliveries",...e})}}const P={create:{title:"Create Push Configuration",fields:[{name:"name",label:"Name",required:!0},{type:"collection",name:"group",label:"Group (optional)",Collection:n,labelField:"name",valueField:"id"},{name:"fcm_service_account",label:"Service Account",type:"textarea",rows:10}]},edit:{title:"Edit Push Configuration",fields:[{name:"name",label:"Name",required:!0},{type:"collection",name:"group",label:"Group (optional)",Collection:n,labelField:"name",valueField:"id"},{name:"fcm_service_account",label:"Service Account",type:"textarea",rows:10},{name:"is_active",label:"Is Active",type:"switch",value:!0}]}},R={edit:{title:"Edit Push Template",fields:[{name:"name",label:"Name",required:!0},{name:"category",label:"Category",required:!0},{type:"collection",name:"group",label:"Group (optional)",Collection:n,labelField:"name",valueField:"id",defaultParams:{is_active:!0}},{name:"title_template",label:"Title Template",required:!0},{name:"body_template",label:"Body Template",type:"textarea",required:!0},{name:"action_url",label:"Action URL"},{name:"priority",label:"Priority",type:"select",options:["high","normal"]},{name:"variables",label:"Variables",type:"json",help:"JSON format"},{name:"is_active",label:"Is Active",type:"switch"}]}};P.create=P.edit,R.create=R.edit;const D={title:"Edit Location",size:"lg",fields:[{name:"ip_address",label:"IP Address",type:"text",required:!0,readonly:!0,cols:6},{name:"subnet",label:"Subnet",type:"text",cols:6},{name:"country_name",label:"Country",type:"text",cols:6},{name:"country_code",label:"Country Code",type:"text",cols:6},{name:"region",label:"Region",type:"text",cols:6},{name:"city",label:"City",type:"text",cols:6},{name:"postal_code",label:"Postal Code",type:"text",cols:6},{name:"timezone",label:"Timezone",type:"text",cols:6},{name:"latitude",label:"Latitude",type:"number",step:"any",cols:6},{name:"longitude",label:"Longitude",type:"number",step:"any",cols:6}]};class GeoLocatedIP extends e{constructor(e={}){super(e,{endpoint:"/api/system/geoip"})}static async lookup(e){const t=new GeoLocatedIP,a=await t.rest.GET("/api/system/geoip/lookup",{ip:e});return a.success&&a.data&&a.data.data?new GeoLocatedIP(a.data.data):null}}GeoLocatedIP.EDIT_FORM=D,GeoLocatedIP.EDIT_LOCATION_FORM=D,GeoLocatedIP.EDIT_SECURITY_FORM={title:"Edit Security",size:"md",fields:[{name:"threat_level",label:"Threat Level",type:"select",cols:12,options:[{value:"",label:"None"},{value:"low",label:"Low"},{value:"medium",label:"Medium"},{value:"high",label:"High"},{value:"critical",label:"Critical"}]},{name:"is_threat",label:"Threat",type:"switch",cols:6},{name:"is_suspicious",label:"Suspicious",type:"switch",cols:6},{name:"is_known_attacker",label:"Known Attacker",type:"switch",cols:6},{name:"is_known_abuser",label:"Known Abuser",type:"switch",cols:6},{name:"risk_score",label:"Risk Score",type:"number",cols:6},{name:"is_tor",label:"TOR Exit Node",type:"switch",cols:6},{name:"is_vpn",label:"VPN",type:"switch",cols:6},{name:"is_proxy",label:"Proxy",type:"switch",cols:6},{name:"is_cloud",label:"Cloud Provider",type:"switch",cols:6},{name:"is_datacenter",label:"Datacenter",type:"switch",cols:6}]},GeoLocatedIP.EDIT_NETWORK_FORM={title:"Edit Network",size:"md",fields:[{name:"asn",label:"ASN",type:"text",cols:6},{name:"asn_org",label:"ASN Organization",type:"text",cols:6},{name:"isp",label:"ISP",type:"text",cols:12},{name:"connection_type",label:"Connection Type",type:"text",cols:6},{name:"provider",label:"Provider",type:"text",cols:6},{name:"is_mobile",label:"Mobile Connection",type:"switch",cols:6},{name:"mobile_carrier",label:"Mobile Carrier",type:"text",cols:6},{name:"last_seen",label:"Last Seen",type:"datetime",cols:12}]};class GeoLocatedIPList extends t{constructor(e={}){super({ModelClass:GeoLocatedIP,endpoint:"/api/system/geoip",...e})}}class Ticket extends e{constructor(e={}){super(e,{endpoint:"/api/incident/ticket"})}}class TicketList extends t{constructor(e={}){super({ModelClass:Ticket,endpoint:"/api/incident/ticket",...e})}}const A={ticket:"Ticket",bug:"Bug",feature:"Feature Request",incident:"Incident",security:"Security Incident",fulfillment:"Fulfillment",new_user:"New User",new_group:"New Group",qa:"Quality Assurance"},q=Object.entries(A).map(([e,t])=>({value:e,label:t})),N={create:{title:"Create Ticket",fields:[{name:"title",type:"text",label:"Title",required:!0,cols:12},{name:"description",type:"textarea",label:"Description",required:!1,cols:12},{name:"category",type:"select",label:"Category",options:q,cols:12,value:"ticket"},{name:"priority",type:"number",label:"Priority",value:5,cols:6},{name:"status",type:"select",label:"Status",options:["new","open","paused","resolved","qa","ignored"],cols:6,value:"new"},{type:"collection",name:"assignee",label:"Assignee",Collection:i,labelField:"display_name",valueField:"id",cols:12},{type:"collection",name:"incident",label:"Incident",Collection:IncidentList,labelField:"title",valueField:"id",cols:12}]},edit:{title:"Edit Ticket",fields:[{name:"title",type:"text",label:"Title",required:!0,cols:12},{name:"description",type:"textarea",label:"Description",required:!1,cols:12},{name:"category",type:"select",label:"Category",options:q,cols:12},{name:"priority",type:"number",label:"Priority",cols:6},{name:"status",type:"select",label:"Status",options:["new","open","paused","resolved","qa","ignored"],cols:6},{type:"collection",name:"assignee",label:"Assignee",Collection:i,labelField:"display_name",valueField:"id",cols:12},{type:"collection",name:"incident",label:"Incident",Collection:IncidentList,labelField:"title",valueField:"id",cols:12}]}};class TicketNote extends e{constructor(e={}){super(e,{endpoint:"/api/incident/ticket/note"})}}class TicketNoteList extends t{constructor(e={}){super({ModelClass:TicketNote,endpoint:"/api/incident/ticket/note",...e})}}class TablePage extends l{constructor(e={}){super({...e,pageName:e.pageName||e.name||"table"}),this.title=e.title||this.pageName,this.description=e.description||"",this.Collection=e.Collection||null,this.collection=e.collection||null,this.defaultQuery=e.defaultQuery||{},this.groupField=e.groupField||"group",this.tableViewConfig={columns:e.columns||[],actions:e.actions||null,contextMenu:e.contextMenu||null,batchActions:e.batchActions||null,batchBarLocation:e.batchBarLocation||"top",clickAction:e.clickAction||"view",addForm:e.addForm||e.formFields||e.formCreate,editForm:e.editForm||e.formEdit||e.formFields,itemView:e.itemView,deleteTemplate:e.deleteTemplate,formDialogConfig:e.formDialogConfig,viewDialogOptions:e.viewDialogOptions,searchable:!1!==e.searchable,sortable:!1!==e.sortable,filterable:!1!==e.filterable,paginated:!1!==e.paginated,selectionMode:e.selectionMode||(e.selectable?"multiple":"none"),filters:e.filters||e.additionalFilters||[],hideActivePills:e.hideActivePills||!1,hideActivePillNames:e.hideActivePillNames||[],searchPlacement:e.searchPlacement||"toolbar",tableOptions:{striped:!0,bordered:!1,hover:!0,responsive:!1,...e.tableOptions},emptyMessage:e.emptyMessage||"No data available",searchPlaceholder:e.searchPlaceholder||"Search...",showAdd:!1!==e.showAdd,showExport:!1!==e.showExport,onItemView:e.onItemView,onItemEdit:e.onItemEdit,onItemDelete:e.onItemDelete,onAdd:e.onAdd,onExport:e.onExport,...e.tableViewOptions},this.urlSyncEnabled=!1!==e.urlSyncEnabled,this.lastUpdated=null,this.isLoading=!1,this.template=e.template||this.buildTemplate()}buildTemplate(){return'\n <div class="table-page-container">\n\n <div class="table-container" data-container="table"></div>\n\n {{#showStatus}}\n <div class="table-status-bar table-status-top">\n <div class="status-info">\n <div class="d-flex justify-content-between w-100">\n <span class="text-muted">\n <i class="bi bi-clock me-1"></i>\n Last updated: <span data-status="last-updated">{{lastUpdated}}</span>\n </span>\n <span class="text-muted">\n <i class="bi bi-list-ol me-1"></i>\n Total records: <span data-status="record-count">0</span>\n </span>\n </div>\n </div>\n </div>\n {{/showStatus}}\n\n </div>\n '}async onInit(){await super.onInit(),this.collection||(this.Collection?this.collection=new this.Collection:this.collection=new t),this.applyQueryToCollection(),this.tableView=new r({collection:this.collection,containerId:"table",fetchOnMount:!0,...this.tableViewConfig}),this.addChild(this.tableView),this.setupEventListeners()}setupEventListeners(){this.urlSyncEnabled&&this.collection&&(this.collection.on("fetch:start",()=>{this.isLoading=!0}),this.collection.on("fetch:end",()=>{this.isLoading=!1,this.lastUpdated=/* @__PURE__ */(new Date).toLocaleTimeString(),this.updateStatusDisplay()})),this.tableView.on("params-changed",()=>{this.urlSyncEnabled&&this.syncUrl()}),this.tableView.on("filter:edit",async({key:e})=>{await this.handleFilterEdit(e)}),this.tableView.on("row:view",async({model:e})=>{this.onItemView&&await this.onItemView(e)}),this.tableView.on("row:edit",async({model:e})=>{this.onItemEdit&&await this.onItemEdit(e)}),this.tableView.on("row:delete",async({model:e})=>{this.onItemDelete&&await this.onItemDelete(e)}),this.tableView.on("table:add",async({event:e})=>{}),this.tableView.on("table:export",async({data:e})=>{this.tableViewConfig.onExport&&await this.tableViewConfig.onExport(e)})}applyQueryToCollection(){const e={},t={...this.defaultQuery,...this.query};if(!t||0===Object.keys(t).length)return;void 0!==t.start&&(e.start=parseInt(t.start)||0),void 0!==t.size&&(e.size=parseInt(t.size)||10),void 0!==t.sort&&(e.sort=t.sort),void 0!==t.search&&(e.search=t.search);const a=["start","size","sort","search","page"];Object.entries(t).forEach(([t,s])=>{if(!a.includes(t)&&void 0!==s&&""!==s)if("string"==typeof s&&(s.startsWith("{")||s.startsWith("[")))try{e[t]=JSON.parse(s)}catch(n){e[t]=s}else e[t]=s}),Object.keys(e).length>0&&(Object.keys(e).forEach(t=>{const{field:a,lookup:s}=c(t);"in"!==s&&"not_in"!==s||!e.hasOwnProperty(a)||delete e[a]}),this.collection.setParams({...this.collection.params,...e}))}syncUrl(e=!0){if(!this.urlSyncEnabled||!this.collection||!this.getApp()?.router)return;const t=new URL(window.location),a={};for(const[l,o]of t.searchParams)"page"!==l&&(a[l]=o);const s={},n=this.collection.params||{};n.start&&(s.start=n.start),n.size&&(s.size=n.size),n.sort&&(s.sort=n.sort),n.search&&(s.search=n.search),Object.entries(n).forEach(([e,t])=>{["start","size","sort","search"].includes(e)||void 0===t||""===t||(s[e]="object"==typeof t?JSON.stringify(t):t)});const i=Object.keys(s).some(e=>String(a[e]||"")!==String(s[e]||""))||Object.keys(a).some(e=>!(e in s));this.query=s,(i||e)&&this.updateBrowserUrl(s,!0,!1)}updateStatusDisplay(){if(!this.element)return;const e=this.element.querySelector('[data-status="last-updated"]');e&&(e.textContent=this.lastUpdated||"Never");const t=this.element.querySelector('[data-status="record-count"]');if(t&&this.collection){const e=this.collection.meta?.count||this.collection.length();t.textContent=e}}async onEnter(){await super.onEnter(),this.options.requiresGroup&&!this.query[this.groupField]&&this.getApp().activeGroup&&(this.query[this.groupField]=this.getApp().activeGroup.id),this.applyQueryToCollection(),this.tableView&&this.tableView.element&&setTimeout(()=>{this.tableView.updateFilterPills(),this.tableView.updateSortIcons()},100)}async refresh(){await this.tableView.refresh()}getSelectedItems(){return this.tableView.getSelectedItems()}clearSelection(){this.tableView.clearSelection()}async handleFilterEdit(e){const t=this.tableView.getAllAvailableFilters().find(t=>t.key===e),a=this.collection.params[e];if(!t)return;const s={name:"filter_value",label:t.label||e,value:a,...t.config},n=await o.showForm({title:`Edit ${s.label} Filter`,size:"md",fields:[s]});n&&void 0!==n.filter_value&&(this.tableView.setFilter(e,n.filter_value),this.collection.restEnabled&&this.collection.fetch(),await this.tableView.render(),this.syncUrl())}clearAllFilters(){if(!this.collection)return;const{start:e,size:t,sort:a}=this.collection.params;this.collection.params={start:e,size:t},a&&(this.collection.params.sort=a),this.syncUrl(),this.collection.restEnabled?this.collection.fetch():this.tableView.render()}async onGroupChange(e){e&&this.collection&&this.options.requiresGroup&&(this.query[this.groupField]=e.id,this.applyQueryToCollection(),this.collection&&this.collection.restEnabled&&this.collection.fetch())}async onBeforeDestroy(){this.collection&&(this.collection.off("fetch:start"),this.collection.off("fetch:end")),this.tableView&&(this.tableView.off("params-changed"),this.tableView.off("table:search"),this.tableView.off("table:sort"),this.tableView.off("table:page"),this.tableView.off("filter:edit"),this.tableView.off("row:view"),this.tableView.off("row:edit"),this.tableView.off("row:delete"),this.tableView.off("table:add"),this.tableView.off("table:export")),await super.onBeforeDestroy()}get showStatus(){return!0===this.options.showStatus}static create(e={}){return new this(e)}}class TabView extends s{constructor(e={}){const{tabs:t,activeTab:a,tabsClass:s,contentClass:n,minWidth:i,enableResponsive:l,tabPadding:o,dropdownStyle:r,enableTransitions:c,transitionDuration:d,...u}=e;super({tagName:"div",className:"tab-view",...u}),this.tabs={},this.tabLabels=Object.keys(this.tabs),this.activeTab=a||this.tabLabels[0]||null,this.tabsClass=s||"nav nav-tabs mb-3",this.contentClass=n||"tab-content",this.enableTransitions=!1!==c,this.transitionDuration=d||150,this.dropdownStyle=r||"select",this.minWidth=i||300,this.enableResponsive=!1!==l,this.tabPadding=o||80,this.currentMode="tabs",this.tabWidthCache=/* @__PURE__ */new Map,this.lastContainerWidth=0,this.resizeObserver=null,this._measurementSpan=null,this._tabComputedStyle=null,this.isMobileMode=!1,this.hasOverflow=!1;for(const[p,h]of Object.entries(t))this.addTab(p,h);this.handleResize=this.handleResize.bind(this)}async renderTemplate(){return`\n <div class="tab-view-container">\n ${this.buildTabNavigation()}\n ${this.buildTabContent()}\n </div>\n `}buildTabNavigation(){return 0===this.tabLabels.length?"":"dropdown"===this.currentMode?this.buildDropdownNavigation():this.buildTabsNavigation()}buildTabsNavigation(){const e=this.tabLabels.map(e=>{const t=e===this.activeTab,a=this.getTabId(e);return`\n <li class="nav-item" role="presentation">\n <button class="nav-link ${t?"active":""}"\n id="${a}-tab"\n data-action="show-tab"\n data-tab-label="${this.escapeHtml(e)}"\n type="button"\n role="tab"\n aria-controls="${a}"\n aria-selected="${t}">\n ${this.escapeHtml(e)}\n </button>\n </li>\n `}).join("");return`\n <ul class="${this.tabsClass}" role="tablist" data-tab-mode="tabs">\n ${e}\n </ul>\n `}buildDropdownNavigation(){const e=this.activeTab||this.tabLabels[0],t=this.tabLabels.map(e=>{const t=e===this.activeTab;return`\n <li>\n <button class="dropdown-item ${t?"active":""}"\n data-action="show-tab"\n data-tab-label="${this.escapeHtml(e)}"\n type="button">\n ${this.escapeHtml(e)}\n ${t?'<i class="bi bi-check-lg ms-2"></i>':""}\n </button>\n </li>\n `}).join("");let a;return a="select"===this.dropdownStyle?`\n <button class="btn tab-view-select-style dropdown-toggle"\n type="button"\n data-bs-toggle="dropdown"\n aria-expanded="false"\n id="tab-dropdown-${this.id}">\n <span class="tab-view-select-label">${this.escapeHtml(e)}</span>\n </button>\n `:`\n <button class="btn btn-outline-secondary dropdown-toggle w-100 w-sm-auto"\n type="button"\n data-bs-toggle="dropdown"\n aria-expanded="false"\n id="tab-dropdown-${this.id}">\n <i class="bi bi-list me-2"></i>\n ${this.escapeHtml(e)}\n </button>\n `,`\n <div class="dropdown mb-3" data-tab-mode="dropdown">\n ${a}\n <ul class="dropdown-menu" aria-labelledby="tab-dropdown-${this.id}">\n ${t}\n </ul>\n </div>\n `}buildMobileDropdownNavigation(){const e=this.activeTab||this.tabLabels[0],t=this.tabLabels.map(e=>{const t=e===this.activeTab;return`\n <li>\n <button class="dropdown-item ${t?"active":""}"\n data-action="show-tab"\n data-tab-label="${this.escapeHtml(e)}"\n type="button">\n ${this.escapeHtml(e)}\n ${t?'<i class="bi bi-check ms-2"></i>':""}\n </button>\n </li>\n `}).join("");return`\n <div class="dropdown mb-3" data-tab-navigation="mobile">\n <button class="btn btn-outline-secondary dropdown-toggle w-100 text-start"\n type="button"\n data-bs-toggle="dropdown"\n aria-expanded="false">\n <i class="bi bi-list me-2"></i>\n ${this.escapeHtml(e)}\n </button>\n <ul class="dropdown-menu w-100">\n ${t}\n </ul>\n </div>\n `}shouldUseMobileDropdown(){if(!this.enableMobileDropdown)return!1;const e=window.innerWidth;return e<this.mobileBreakpoint||this.hasOverflow&&e<992}buildTabContent(){if(0===this.tabLabels.length)return'<div class="alert alert-info">No tabs to display</div>';const e=this.tabLabels.map(e=>{const t=e===this.activeTab,a=this.getTabId(e);return`\n <div class="tab-pane fade ${t?"show active":""}"\n id="${a}"\n role="tabpanel"\n aria-labelledby="${a}-tab"\n data-tab-label="${this.escapeHtml(e)}">\n <div data-container="${a}-content"></div>\n </div>\n `}).join("");return`\n <div class="${this.contentClass}">\n ${e}\n </div>\n `}getTabId(e){return`tab-${e.toLowerCase().replace(/[^a-z0-9]/g,"-")}-${this.id}`}async showTab(e,t={}){const{force:a=!1}=t;if(!this.tabs[e])return console.warn(`TabView: Tab "${e}" does not exist`),!1;if(this.activeTab===e&&!a){const t=this.tabs[e];if(t&&t.isMounted()&&this.element.contains(t.element))return!0}const s=this.activeTab;this.activeTab=e;try{return await this.updateTabNavigation(e,s),await this.updateTabContent(e,s),this.emit("tab:changed",{activeTab:e,previousTab:s}),!0}catch(n){return console.error("TabView: Error showing tab:",n),this.activeTab=s,!1}}async updateTabNavigation(e,t){if(!this.element)return;if("dropdown"===this.currentMode)return void(await this.reRenderNavigation());if(t){const e=this.element.querySelector(`[data-tab-label="${t}"]`);e&&(e.classList.remove("active"),e.setAttribute("aria-selected","false"))}const a=this.element.querySelector(`[data-tab-label="${e}"]`);a&&(a.classList.add("active"),a.setAttribute("aria-selected","true"))}async updateTabContent(e,t){if(!this.element)return;const a=this.getTabId(e),s=t?this.getTabId(t):null,n=this.element.querySelector(`#${a}`),i=s?this.element.querySelector(`#${s}`):null,l=this.tabs[e];if(this.enableTransitions){if(i&&i.classList.contains("show")&&(i.classList.remove("show"),await new Promise(e=>{const t=this._getTransitionDuration(i)||this.transitionDuration;setTimeout(e,t)}),i.classList.remove("active")),l){const e=this.element.querySelector(`[data-container="${a}-content"]`);e&&!l.isMounted()&&await l.render(!0,e)}n&&(n.classList.add("active"),n.offsetHeight,n.classList.add("show"))}else{if(i&&i.classList.remove("show","active"),l){const e=this.element.querySelector(`[data-container="${a}-content"]`);e&&!l.isMounted()&&await l.render(!0,e)}n&&n.classList.add("show","active")}l&&l.onTabActivated&&await l.onTabActivated()}_getTransitionDuration(e){if(!e||"undefined"==typeof window||!window.getComputedStyle)return 0;const t=(window.getComputedStyle(e).transitionDuration||"0s").match(/^([0-9.]+)(m?s)$/);if(!t)return 0;const a=parseFloat(t[1]);return"s"===t[2]?1e3*a:a}async onActionShowTab(e,t){const a=t.getAttribute("data-tab-label");a&&await this.showTab(a)}_initializeMeasurementStyles(){if(!this.element||this._tabComputedStyle)return;const e=this.element.querySelector(".nav-link");if(e&&"function"==typeof window.getComputedStyle){const t=window.getComputedStyle(e);this._tabComputedStyle={font:t.font,letterSpacing:t.letterSpacing};const a=parseFloat(t.paddingLeft)||0,s=parseFloat(t.paddingRight)||0;this.tabPadding=a+s+12}}async onAfterRender(){await super.onAfterRender(),this._initializeMeasurementStyles(),this.enableResponsive&&this.setupResponsiveHandling(),this.activeTab&&this.tabs[this.activeTab]&&await this.showTab(this.activeTab,{force:!0})}async onAfterMount(){await super.onAfterMount()}async onBeforeDestroy(){await super.onBeforeDestroy(),this.resizeObserver&&(this.resizeObserver.disconnect(),this.resizeObserver=null),"undefined"!=typeof window&&window.removeEventListener("resize",this.handleResize),this._measurementSpan&&this._measurementSpan.parentElement&&this._measurementSpan.parentElement.removeChild(this._measurementSpan),this._measurementSpan=null;for(const[e,t]of Object.entries(this.tabs))t&&"function"==typeof t.destroy&&await t.destroy()}getActiveTab(){return this.activeTab}getTabLabels(){return[...this.tabLabels]}getTab(e){return this.tabs[e]||null}async addTab(e,t,a=!1){return this.tabs[e]?(console.warn(`TabView: Tab "${e}" already exists`),!1):!(t.options.permissions&&!this.getApp().activeUser.hasPerm(t.options.permissions)||(this.tabs[e]=t,t.containerId=this.getTabId(e),t.parent=this,this.tabLabels=Object.keys(this.tabs),this.activeTab&&!a||(this.activeTab=e),this.isMounted()&&(await this.render(),(a||this.activeTab===e)&&await this.showTab(e)),this.emit("tab:added",{label:e,view:t}),0))}async removeTab(e){if(!this.tabs[e])return console.warn(`TabView: Tab "${e}" does not exist`),!1;const t=this.tabs[e];return t&&"function"==typeof t.destroy&&await t.destroy(),delete this.tabs[e],this.tabLabels=Object.keys(this.tabs),this.activeTab===e&&(this.activeTab=this.tabLabels[0]||null),this.isMounted()&&(await this.render(),this.activeTab&&await this.showTab(this.activeTab)),this.emit("tab:removed",{label:e,view:t}),!0}calculateTabWidth(e){if(this.tabWidthCache.has(e))return this.tabWidthCache.get(e);if("undefined"==typeof document){const t=8*e.length+this.tabPadding;return this.tabWidthCache.set(e,t),t}this._measurementSpan||(this._measurementSpan=document.createElement("span"),this._measurementSpan.style.visibility="hidden",this._measurementSpan.style.position="absolute",this._measurementSpan.style.whiteSpace="nowrap");const t=this._measurementSpan;this._tabComputedStyle?(t.style.font=this._tabComputedStyle.font,t.style.letterSpacing=this._tabComputedStyle.letterSpacing):(t.style.fontSize="14px",t.style.fontFamily="system-ui, -apple-system, sans-serif"),t.textContent=e,document.body.appendChild(t);const a=t.offsetWidth+this.tabPadding;return document.body.removeChild(t),this.tabWidthCache.set(e,a),a}getTotalTabWidth(){return this.tabLabels.reduce((e,t)=>e+this.calculateTabWidth(t),0)}getContainerWidth(){return this.element&&(this.element.parentElement||this.element).offsetWidth||this.minWidth}shouldUseDropdown(){if(!this.enableResponsive)return!1;const e=this.getContainerWidth(),t=this.getTotalTabWidth();return e<Math.max(t,this.minWidth)}setupResponsiveHandling(){if(this.element&&this.enableResponsive)if(this.updateNavigationMode(),"undefined"!=typeof ResizeObserver){this.resizeObserver=new ResizeObserver(()=>{this.handleResize()});const e=this.element.parentElement||this.element;this.resizeObserver.observe(e)}else window.addEventListener("resize",this.handleResize)}async handleResize(){const e=this.getContainerWidth();Math.abs(e-this.lastContainerWidth)>50&&(this.lastContainerWidth=e,await this.updateNavigationMode())}async updateNavigationMode(){const e=this.shouldUseDropdown()?"dropdown":"tabs";e!==this.currentMode&&(this.currentMode=e,this.isMounted()&&await this.reRenderNavigation(),this.emit("navigation:modeChanged",{mode:this.currentMode,containerWidth:this.getContainerWidth(),totalTabWidth:this.getTotalTabWidth()}))}async reRenderNavigation(){if(!this.element)return;const e=this.element.querySelector("[data-tab-mode]");if(e){const t=this.buildTabNavigation();e.outerHTML=t}}getNavigationMode(){return this.currentMode}async setNavigationMode(e){"tabs"===e||"dropdown"===e?(this.currentMode=e,this.isMounted()&&await this.reRenderNavigation()):console.warn('TabView: Invalid navigation mode. Use "tabs" or "dropdown"')}clearWidthCache(){this.tabWidthCache.clear()}static create(e={}){return new TabView(e)}}class FilePreviewView extends s{constructor(e={}){super({className:"file-preview",...e}),this.file=e.file||{},this.isImage=this.file.content_type?.startsWith("image/"),this.isPdf="application/pdf"===this.file.content_type}getTemplate(){return`\n <div class="file-preview-item card card-body p-2 mt-2">\n <div class="d-flex align-items-center">\n <div class="flex-shrink-0">\n ${this.isImage?`<img src="${this.file.thumbnailUrl||this.file.url}" class="rounded" style="width: 40px; height: 40px; object-fit: cover;">`:'<i class="bi bi-file-earmark-text fs-2 text-secondary"></i>'}\n </div>\n <div class="flex-grow-1 ms-3">\n <div class="fw-bold text-truncate">{{file.filename}}</div>\n <div class="small text-muted">{{file.file_size|filesize}}</div>\n </div>\n <div class="flex-shrink-0">\n <button class="btn btn-sm btn-outline-primary" data-action="view-file">View</button>\n </div>\n </div>\n </div>\n `}async onActionViewFile(){if(this.isImage){const e=window.MOJO?.plugins?.LightboxGallery;e?e.show({src:this.file.url,alt:this.file.filename}):window.open(this.file.url,"_blank")}else if(this.isPdf){const e=window.MOJO?.plugins?.PDFViewer;e?e.showDialog(this.file.url,{title:this.file.filename}):window.open(this.file.url,"_blank")}else window.open(this.file.url,"_blank")}}class ChatMessageView extends s{constructor(e={}){super({className:"chat-message",...e}),this.message=e.message||{},this.theme=e.theme||"compact",this.isCurrentUser=e.isCurrentUser||!1,"bubbles"===this.theme&&(this.className+=this.isCurrentUser?" message-right":" message-left")}getTemplate(){return"system_event"===this.message.type?'\n <div class="chat-message-system text-center text-muted small py-2">\n <i class="bi bi-info-circle me-1"></i>\n {{message.content}} on {{message.timestamp|datetime}}\n </div>\n ':"bubbles"===this.theme?this.getBubblesTemplate():this.getCompactTemplate()}getCompactTemplate(){return`\n <div class="message-item">\n <div class="message-avatar ${this.isCurrentUser?"bg-primary":"bg-secondary"}">\n {{#message.author.avatarUrl}}\n <img src="{{message.author.avatarUrl}}" alt="{{message.author.name}}" class="w-100 h-100 rounded-circle">\n {{/message.author.avatarUrl}}\n {{^message.author.avatarUrl}}\n {{message.author.name|initials}}\n {{/message.author.avatarUrl}}\n </div>\n <div class="message-content">\n <div class="message-header">\n <div class="message-author">\n {{message.author.name}}\n {{#isCurrentUser}}\n <span class="badge bg-primary badge-sm ms-1">You</span>\n {{/isCurrentUser}}\n </div>\n <div class="message-time text-muted">{{message.timestamp|relative}}</div>\n </div>\n <div class="message-text">{{{message.content}}}</div>\n <div data-container="attachments"></div>\n </div>\n </div>\n `}getBubblesTemplate(){return'\n <div class="message-bubble-wrapper">\n <div class="message-meta">\n <strong>{{message.author.name}}</strong>\n <span class="text-muted">· {{message.timestamp|relative}}</span>\n </div>\n <div class="message-bubble">\n <div class="message-text">{{{message.content}}}</div>\n <div data-container="attachments"></div>\n </div>\n </div>\n '}async onAfterRender(){if(this.message.attachments&&this.message.attachments.length>0){const e=this.element.querySelector('[data-container="attachments"]');e&&this.message.attachments.forEach(t=>{const a=new FilePreviewView({file:t});this.addChild(a),a.render(!0,e)})}}}class ChatInputView extends s{constructor(e={}){super({className:"chat-input-view",...e}),this.placeholder=e.placeholder||"Type a message...",this.buttonText=e.buttonText||"Send",this.attachments=[],this.pendingUploads=/* @__PURE__ */new Map}getTemplate(){return`\n <div class="chat-input-container">\n <div class="chat-input-attachments" data-container="attachments"></div>\n <div class="chat-input-wrapper">\n <textarea\n class="chat-input form-control"\n placeholder="${this.placeholder}"\n rows="2"></textarea>\n <button class="chat-send-btn btn btn-primary" data-action="send-message" type="button">\n <i class="bi bi-send-fill"></i>\n <span class="spinner-border spinner-border-sm d-none" role="status" aria-hidden="true"></span>\n </button>\n </div>\n <div class="chat-input-footer">\n <small class="text-muted">\n <i class="bi bi-paperclip"></i>\n Drag & drop files to attach\n </small>\n </div>\n </div>\n `}async onAfterRender(){this.enableFileDrop({dropZoneSelector:".chat-input-container",multiple:!0,acceptedTypes:["*/*"],visualFeedback:!0,dragOverClass:"drag-over",dragActiveClass:"drag-active"});const e=this.element.querySelector(".chat-input");e&&(e.addEventListener("input",()=>this.autoResizeTextarea(e)),e.addEventListener("keydown",e=>this.handleKeydown(e)))}handleKeydown(e){"Enter"!==e.key||e.shiftKey||(e.preventDefault(),this.onActionSendMessage(e,e.target))}async onFileDrop(e){for(const t of e)await this.uploadFile(t)}async uploadFile(e){const t=new u,a=Date.now()+Math.random();this.addFilePreview(a,e,0),this.pendingUploads.set(a,{file:e,fileModel:t});try{await t.upload({file:e,onProgress:e=>{this.updateFileProgress(a,e)},onComplete:e=>{this.handleUploadComplete(a,t)}})}catch(s){console.error("File upload failed:",s),this.handleUploadError(a,s)}}addFilePreview(e,t,a){const s=this.element.querySelector('[data-container="attachments"]');if(!s)return;const n=document.createElement("div");n.className="attachment-preview",n.dataset.uploadId=e,n.innerHTML=`\n <div class="attachment-info">\n <i class="bi bi-file-earmark"></i>\n <span class="attachment-name">${this.escapeHtml(t.name)}</span>\n <span class="attachment-size">(${this.formatFileSize(t.size)})</span>\n </div>\n <div class="attachment-progress">\n <div class="progress" style="height: 4px;">\n <div class="progress-bar" role="progressbar" style="width: ${a}%"></div>\n </div>\n </div>\n <button class="attachment-remove btn btn-sm btn-link text-danger" data-action="remove-attachment" data-upload-id="${e}" type="button">\n <i class="bi bi-x"></i>\n </button>\n `,s.appendChild(n)}updateFileProgress(e,t){const a=this.element.querySelector(`[data-upload-id="${e}"]`);if(a){const e=a.querySelector(".progress-bar");e&&(e.style.width=`${t}%`)}}handleUploadComplete(e,t){this.attachments.push({id:t.id,name:t.get("name"),uploadId:e}),this.pendingUploads.delete(e);const a=this.element.querySelector(`[data-upload-id="${e}"]`);if(a){a.classList.add("upload-complete");const e=a.querySelector(".attachment-progress");e&&e.remove()}}handleUploadError(e,t){this.pendingUploads.delete(e);const a=this.element.querySelector(`[data-upload-id="${e}"]`);a&&(a.classList.add("upload-error"),a.querySelector(".attachment-info").innerHTML+='<span class="text-danger ms-2">Upload failed</span>')}async onActionRemoveAttachment(e,t){const a=t.dataset.uploadId;this.pendingUploads.delete(a);const s=this.element.querySelector(`[data-upload-id="${a}"]`);s&&s.remove()}async onActionSendMessage(e,t){const a=this.element.querySelector(".chat-input").value.trim();(a||0!==this.attachments.length)&&(this.pendingUploads.size>0||(this.setBusy(!0),this.emit("message:send",{text:a,files:this.attachments})))}setBusy(e){const t=this.element.querySelector(".chat-send-btn"),a=t.querySelector(".bi-send-fill"),s=t.querySelector(".spinner-border");e?(t.disabled=!0,a.classList.add("d-none"),s.classList.remove("d-none")):(t.disabled=!1,a.classList.remove("d-none"),s.classList.add("d-none"))}clearInput(){const e=this.element.querySelector(".chat-input");e&&(e.value="",e.style.height="auto");const t=this.element.querySelector('[data-container="attachments"]');t&&(t.innerHTML=""),this.attachments=[],this.pendingUploads.clear(),this.setBusy(!1)}autoResizeTextarea(e){e.style.height="auto",e.style.height=Math.min(e.scrollHeight,150)+"px"}formatFileSize(e){if(0===e)return"0 B";const t=Math.floor(Math.log(e)/Math.log(1024));return parseFloat((e/Math.pow(1024,t)).toFixed(1))+" "+["B","KB","MB","GB"][t]}escapeHtml(e){const t=document.createElement("div");return t.textContent=e,t.innerHTML}}d(ChatInputView);class ChatView extends s{constructor(e={}){super({className:"chat-view",...e}),this.adapter=e.adapter,this.theme=e.theme||"compact",this.currentUserId=e.currentUserId,this.inputPlaceholder=e.inputPlaceholder||"Type a message...",this.inputButtonText=e.inputButtonText||"Send",this.messages=[],this.messageViews=/* @__PURE__ */new Map}getTemplate(){return`\n <div class="chat-container chat-theme-${this.theme}">\n <div class="chat-messages" data-container="messages"></div>\n <div class="chat-input-wrapper" data-container="input"></div>\n </div>\n `}async onInit(){this.messages=await this.adapter.fetch(),this.inputView=new ChatInputView({containerId:"input",placeholder:this.inputPlaceholder,buttonText:this.inputButtonText}),this.addChild(this.inputView),this.inputView.on("message:send",async e=>{await this.handleSendMessage(e)})}async onAfterRender(){this._buildMessageViews(),await this._renderChildren(),this.scrollToBottom()}async _renderChildren(){await super._renderChildren();const e=this.element.querySelector('[data-container="messages"]');e?this.messageViews.forEach(t=>{e.appendChild(t.element),t.render(!1)}):console.error("ChatView: messages container not found")}_buildMessageViews(){this.messages&&0!==this.messages.length&&this.messages.forEach(e=>{this.messageViews.has(e.id)||this._createMessageView(e)})}_createMessageView(e){if(this.messageViews.has(e.id))return;const t=e.author&&e.author.id===this.currentUserId,a=new ChatMessageView({message:e,theme:this.theme,isCurrentUser:t});return this.addChild(a),this.messageViews.set(e.id,a),a}addMessage(e,t=!0){if(this.messageViews.has(e.id))return;const a=this._createMessageView(e);if(this.isMounted()){const e=this.element.querySelector('[data-container="messages"]');e&&(e.appendChild(a.element),a.render(!1))}t&&this.scrollToBottom()}async handleSendMessage(e){try{if(e.text&&e.text.trim()&&!(await this.adapter.addNote({text:e.text,files:e.files&&e.files.length>0?[e.files[0]]:[]})).success)throw new Error("Failed to send message");for(let t=e.text&&e.text.trim()&&e.files.length>0?1:0;t<(e.files?.length||0);t++){const a=e.files[t];(await this.adapter.addNote({text:"",files:[a]})).success||console.error("Failed to upload file:",a)}this.messages=await this.adapter.fetch(),this.messages.forEach(e=>{this.messageViews.has(e.id)||this.addMessage(e,!0)}),this.inputView.clearInput()}catch(t){console.error("Failed to send message:",t),this.inputView.setBusy(!1)}}scrollToBottom(){const e=this.element.querySelector(".chat-messages");e&&requestAnimationFrame(()=>{e.scrollTop=e.scrollHeight})}clearMessages(){this.messageViews.forEach(e=>e.destroy()),this.messageViews.clear(),this.messages=[];const e=this.element.querySelector('[data-container="messages"]');e&&(e.innerHTML="")}async refresh(){this.clearMessages(),this.messages=await this.adapter.fetch(),this._buildMessageViews(),this.isMounted()&&(await this._renderChildren(),this.scrollToBottom())}}export{PushDeviceList as $,JobList as A,w as B,ChatInputView as C,JobLog as D,EmailDomain as E,FilePreviewView as F,GeoLocatedIP as G,JobLogList as H,Incident as I,Job as J,JobRunner as K,I as L,JobRunnerList as M,JobsEngineStats as N,Mailbox as O,m as P,MailboxList as Q,f as R,L as S,MetricsPermission as T,MetricsPermissionList as U,PushConfig as V,P as W,PushConfigList as X,PushDelivery as Y,PushDeliveryList as Z,PushDevice as _,ChatMessageView as a,PushTemplate as a0,R as a1,PushTemplateList as a2,Rule as a3,E as a4,RuleList as a5,RuleSet as a6,C as a7,RuleSetList as a8,S3Bucket as a9,p as aa,S3BucketList as ab,SentMessage as ac,b as ad,SentMessageList as ae,TabView as af,TablePage as ag,Ticket as ah,A as ai,N as aj,TicketList as ak,TicketNote as al,TicketNoteList as am,x as an,ChatView as b,T as c,_ as d,S as e,h as f,EmailDomainList as g,EmailTemplate as h,y as i,EmailTemplateList as j,GeoLocatedIPList as k,IncidentEvent as l,g as m,IncidentEventList as n,v as o,IncidentHistory as p,IncidentHistoryList as q,IncidentList as r,IncidentRule as s,IncidentRuleList as t,IncidentRuleSet as u,IncidentRuleSetList as v,IncidentStats as w,JobEvent as x,JobEventList as y,M as z};
2
+ //# sourceMappingURL=ChatView-Dw-iVmht.js.map