hotsheet 0.2.14 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +824 -152
- package/dist/client/app.global.js +99 -3
- package/dist/client/styles.css +1 -1
- package/package.json +2 -2
|
@@ -1,4 +1,100 @@
|
|
|
1
|
-
"use strict";(()=>{var Ge=Object.defineProperty;var Ye=(e,t,s)=>t in e?Ge(e,t,{enumerable:!0,configurable:!0,writable:!0,value:s}):e[t]=s;var O=(e,t,s)=>Ye(e,typeof t!="symbol"?t+"":t,s);function ve(e){return e.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""")}function he(e){return e.replace(/&/g,"&").replace(/"/g,""").replace(/'/g,"'").replace(/</g,"<").replace(/>/g,">")}var S=class{constructor(t){O(this,"__html");this.__html=t}toString(){return this.__html}};function _(e){return new S(e)}var Xe=new Set(["area","base","br","col","embed","hr","img","input","link","meta","source","track","wbr"]);function Z(e){return e==null||typeof e=="boolean"?"":e instanceof S?e.__html:typeof e=="string"?ve(e):typeof e=="number"?String(e):Array.isArray(e)?e.map(Z).join(""):""}function Qe(e,t){if(t==null||t===!1)return"";if(t===!0)return` ${e}`;let s=e==="className"?"class":e==="htmlFor"?"for":e,i;return t instanceof S?i=t.__html:typeof t=="number"?i=String(t):typeof t=="string"?i=he(t):i="",` ${s}="${i}"`}function c(e,t){if(typeof e=="function")return e(t);let{children:s,...i}=t,a=Object.entries(i).map(([o,r])=>Qe(o,r)).join("");if(Xe.has(e))return new S(`<${e}${a}>`);let l=s!=null?Z(s):"";return new S(`<${e}${a}>${l}</${e}>`)}function D({children:e}){return new S(e!=null?Z(e):"")}function y(e){let t=document.createElement("template");return t.innerHTML=e.toString(),t.content.firstElementChild}function be(e){document.getElementById("network-error-popup")?.remove();let t=y(c("div",{id:"network-error-popup",className:"error-popup",children:c("div",{className:"error-popup-content",children:[c("strong",{children:"Connection Error"}),c("p",{children:e}),c("button",{children:_("Dismiss")})]})}));t.querySelector("button").addEventListener("click",()=>t.remove()),document.body.appendChild(t)}async function p(e,t={}){try{return(await fetch("/api"+e,{headers:t.body!==void 0?{"Content-Type":"application/json"}:{},method:t.method,body:t.body!==void 0?JSON.stringify(t.body):void 0})).json()}catch(s){throw be("Unable to reach the server. It may have been stopped."),s}}async function ke(e,t){try{let s=new FormData;return s.append("file",t),(await fetch("/api"+e,{method:"POST",body:s})).json()}catch(s){throw be("Unable to reach the server. It may have been stopped."),s}}var Ze={detail_position:"side",detail_width:360,detail_height:300,trash_cleanup_days:3,verified_cleanup_days:30},n={tickets:[],selectedIds:new Set,lastClickedId:null,activeTicketId:null,view:"all",layout:"list",sortBy:"created",sortDir:"desc",search:"",settings:{...Ze},backupPreview:null},et={issue:"#6b7280",bug:"#ef4444",feature:"#22c55e",requirement_change:"#f97316",task:"#3b82f6",investigation:"#8b5cf6"},tt={issue:"ISS",bug:"BUG",feature:"FEA",requirement_change:"REQ",task:"TSK",investigation:"INV"},nt={highest:"\u2B06\u2B06",high:"\u2B06",default:"\u2014",low:"\u2B07",lowest:"\u2B07\u2B07"},st={highest:"#ef4444",high:"#f97316",default:"#6b7280",low:"#3b82f6",lowest:"#94a3b8"},at={not_started:"\u25CB",started:"\u25D4",completed:"\u2713",verified:"svg",backlog:"\u25A1",archive:"\u25A0"},ee='<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><path d="M18 6 7 17l-5-5"/><path d="m22 10-9.5 9.5-2-2"/></svg>';function w(e){return et[e]||"#6b7280"}function H(e){return tt[e]||"ISS"}function F(e){return nt[e]||"\u2014"}function P(e){return st[e]||"#6b7280"}function te(e){return at[e]||"\u25CB"}function W(e){n.activeTicketId=e,se(e)}function Ee(){n.selectedIds.clear(),n.activeTicketId=null,A();let e=new CustomEvent("hotsheet:render");document.dispatchEvent(e)}function A(){let e=n.view==="trash",t=!!n.backupPreview?.active,s=document.getElementById("detail-panel"),i=document.getElementById("detail-resize-handle"),a=document.getElementById("detail-header"),l=document.getElementById("detail-body"),o=document.getElementById("detail-placeholder"),r=document.getElementById("detail-placeholder-text");if(e){s.style.display="none",i&&(i.style.display="none"),n.activeTicketId=null;return}if(s.style.display="flex",i&&(i.style.display=""),n.selectedIds.size===1){let u=Array.from(n.selectedIds)[0];s.classList.remove("detail-disabled"),a.style.display="",l.style.display="",o.style.display="none",n.activeTicketId!==u&&(n.activeTicketId=u,t?it(u):se(u))}else n.activeTicketId=null,s.classList.add("detail-disabled"),a.style.display="none",l.style.display="none",o.style.display="",n.selectedIds.size===0?r.textContent="Nothing selected":r.textContent=`${n.selectedIds.size} items selected`}function Te(e){let t=document.getElementById("detail-title"),s=document.getElementById("detail-details"),i=document.getElementById("detail-category"),a=document.getElementById("detail-priority"),l=document.getElementById("detail-status"),o=document.getElementById("detail-upnext"),r=document.querySelector(".upload-btn");t.readOnly=e,s.readOnly=e,i.disabled=e,a.disabled=e,l.disabled=e,o.disabled=e,r&&(r.style.display=e?"none":"")}function it(e){let t=n.backupPreview?.tickets.find(o=>o.id===e);if(!t||n.activeTicketId!==e)return;document.getElementById("detail-ticket-number").textContent=t.ticket_number,document.getElementById("detail-title").value=t.title,document.getElementById("detail-category").value=t.category,document.getElementById("detail-priority").value=t.priority,document.getElementById("detail-status").value=t.status,document.getElementById("detail-upnext").checked=t.up_next,document.getElementById("detail-details").value=t.details,Te(!0),document.getElementById("detail-attachments").innerHTML="";let s=document.getElementById("detail-notes-section"),i=document.getElementById("detail-notes"),a=Ie(t.notes);a.length>0?(s.style.display="",i.innerHTML=c(D,{children:a.map(o=>c("div",{className:"note-entry",children:[o.created_at?c("div",{className:"note-timestamp",children:new Date(o.created_at).toLocaleString()}):null,c("div",{className:"note-text",children:o.text})]}))}).toString()):(s.style.display="none",i.innerHTML="");let l=document.getElementById("detail-meta");l.innerHTML=c(D,{children:[c("div",{children:["Created: ",new Date(t.created_at).toLocaleString()]}),c("div",{children:["Updated: ",new Date(t.updated_at).toLocaleString()]}),t.completed_at?c("div",{children:["Completed: ",new Date(t.completed_at).toLocaleString()]}):null,t.verified_at?c("div",{children:["Verified: ",new Date(t.verified_at).toLocaleString()]}):null]}).toString()}function ne(){n.activeTicketId!=null&&se(n.activeTicketId)}async function se(e){let t=await p(`/tickets/${e}`);if(n.activeTicketId!==e)return;Te(!1),document.getElementById("detail-ticket-number").textContent=t.ticket_number,document.getElementById("detail-title").value=t.title,document.getElementById("detail-category").value=t.category,document.getElementById("detail-priority").value=t.priority,document.getElementById("detail-status").value=t.status,document.getElementById("detail-upnext").checked=t.up_next,document.getElementById("detail-details").value=t.details;let s=document.getElementById("detail-attachments");t.attachments.length>0?s.innerHTML=c(D,{children:t.attachments.map(r=>c("div",{className:"attachment-item",children:[c("span",{className:"attachment-name",children:r.original_filename}),c("button",{className:"attachment-reveal","data-att-id":String(r.id),title:"Show in file manager",children:_('<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M22 19a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h5l2 3h9a2 2 0 0 1 2 2z"/></svg>')}),c("button",{className:"attachment-delete","data-att-id":String(r.id),title:"Remove",children:_("×")})]}))}).toString():s.innerHTML="";let i=document.getElementById("detail-notes-section"),a=document.getElementById("detail-notes"),l=Ie(t.notes);l.length>0?(i.style.display="",a.innerHTML=c(D,{children:l.map(r=>c("div",{className:"note-entry",children:[r.created_at?c("div",{className:"note-timestamp",children:new Date(r.created_at).toLocaleString()}):null,c("div",{className:"note-text",children:r.text})]}))}).toString()):(i.style.display="none",a.innerHTML="");let o=document.getElementById("detail-meta");o.innerHTML=c(D,{children:[c("div",{children:["Created: ",new Date(t.created_at).toLocaleString()]}),c("div",{children:["Updated: ",new Date(t.updated_at).toLocaleString()]}),t.completed_at?c("div",{children:["Completed: ",new Date(t.completed_at).toLocaleString()]}):null,t.verified_at?c("div",{children:["Verified: ",new Date(t.verified_at).toLocaleString()]}):null]}).toString()}function Ie(e){if(!e||e==="")return[];try{let t=JSON.parse(e);if(Array.isArray(t))return t}catch{}return e.trim()?[{text:e,created_at:""}]:[]}async function J(){try{let e=await p("/stats"),t=document.getElementById("status-bar");t&&(t.textContent=`${e.total} tickets \xB7 ${e.open} open \xB7 ${e.up_next} up next`)}catch{}}function ae(e){let t=document.getElementById("content-area");t.classList.remove("detail-side","detail-bottom"),t.classList.add(e==="bottom"?"detail-bottom":"detail-side")}function ie(){let e=document.getElementById("detail-panel");n.settings.detail_position==="bottom"?(e.style.width="",e.style.height=`${n.settings.detail_height}px`):(e.style.height="",e.style.width=`${n.settings.detail_width}px`)}function we(){let e=document.getElementById("detail-resize-handle"),t=document.getElementById("detail-panel"),s=document.getElementById("content-area"),i=!1;e.addEventListener("mousedown",a=>{a.preventDefault(),i=!0,document.body.style.cursor=n.settings.detail_position==="bottom"?"row-resize":"col-resize",document.body.style.userSelect="none"}),document.addEventListener("mousemove",a=>{if(!i)return;let l=s.getBoundingClientRect();if(n.settings.detail_position==="bottom"){let o=Math.max(150,Math.min(500,l.bottom-a.clientY));n.settings.detail_height=o,t.style.height=`${o}px`}else{let o=Math.max(250,Math.min(600,l.right-a.clientX));n.settings.detail_width=o,t.style.width=`${o}px`}}),document.addEventListener("mouseup",()=>{i&&(i=!1,document.body.style.cursor="",document.body.style.userSelect="",n.settings.detail_position==="bottom"?p("/settings",{method:"PATCH",body:{detail_height:String(n.settings.detail_height)}}):p("/settings",{method:"PATCH",body:{detail_width:String(n.settings.detail_width)}}))})}function $(e,t){let s=t.getBoundingClientRect(),i=e.getBoundingClientRect(),a=window.innerWidth,l=window.innerHeight,o=s.left;o+i.width>a-8&&(o=s.right-i.width),o<8&&(o=8);let r=s.bottom+4;r+i.height>l-8&&(r=s.top-i.height-4),r<8&&(r=8),e.style.left=`${o}px`,e.style.top=`${r}px`}function R(e,t){let s=y(c("div",{className:"dropdown-menu",style:"visibility:hidden;top:0;left:0",children:t.map(r=>c("button",{className:`dropdown-item${r.active?" active":""}`,"data-key":r.key,children:[r.color?c("span",{className:"dropdown-dot",style:`background-color:${r.color}`}):null,c("span",{className:"dropdown-label",children:r.label}),r.shortcut?c("kbd",{className:"dropdown-kbd",children:r.shortcut}):null]}))}));s.querySelectorAll(".dropdown-item").forEach((r,u)=>{r.addEventListener("click",()=>{t[u].action(),s.remove()})});function a(r){let u=t.find(d=>r.key.toLowerCase()===d.key.toLowerCase());u?(r.preventDefault(),r.stopPropagation(),u.action(),l()):r.key==="Escape"&&(r.preventDefault(),l())}function l(){s.remove(),document.removeEventListener("keydown",a,!0),document.removeEventListener("click",o)}function o(){l()}return document.addEventListener("keydown",a,!0),setTimeout(()=>{document.addEventListener("click",o)},0),s}function U(){document.querySelectorAll(".dropdown-menu").forEach(e=>{e.remove()})}var oe=class{constructor(){O(this,"undoStack",[]);O(this,"redoStack",[])}push(t){console.log("[undo] push:",t.label,"stack depth:",this.undoStack.length+1,"before:",JSON.stringify(t.before),"after:",JSON.stringify(t.after)),this.undoStack.push(t),this.undoStack.length>1e3&&this.undoStack.shift(),this.redoStack=[]}coalesce(t){if(t.coalescingKey==null||t.coalescingKey==="")return!1;let s=this.peekUndo();return!s||s.coalescingKey!==t.coalescingKey||t.timestamp-s.timestamp>=5e3?!1:(s.after=t.after,!0)}popUndo(){let t=this.undoStack.pop();return t&&this.redoStack.push(t),t}popRedo(){let t=this.redoStack.pop();return t&&this.undoStack.push(t),t}peekUndo(){return this.undoStack[this.undoStack.length-1]}canUndo(){return this.undoStack.length>0}canRedo(){return this.redoStack.length>0}},h=new oe;function B(e){return{id:e.id,title:e.title,details:e.details,category:e.category,priority:e.priority,status:e.status,up_next:e.up_next}}async function T(e,t,s){let i=B(e),a=await p(`/tickets/${e.id}`,{method:"PATCH",body:t}),l=B(a);return h.push({label:s,timestamp:Date.now(),before:[i],after:[l]}),a}function G(e,t,s){let i=`${e.id}:${t}`,a=Date.now(),l={...B(e),[t]:s},o={label:`Edit ${t}`,timestamp:a,before:[B(e)],after:[l],coalescingKey:i};h.coalesce(o)||h.push(o)}async function b(e,t,s){let i=e.map(B);await p("/tickets/batch",{method:"POST",body:t});let a=i.map(l=>{let o={...l};return t.action==="category"?o.category=t.value:t.action==="priority"?o.priority=t.value:t.action==="status"?o.status=t.value:t.action==="up_next"?o.up_next=t.value:t.action==="delete"&&(o.status="deleted"),o});h.push({label:s,timestamp:Date.now(),before:i,after:a})}async function le(e,t,s){let i=e.map(B);for(let l of t)await p("/tickets/batch",{method:"POST",body:l});let a=i.map(l=>{let o={...l};for(let r of t)r.ids.includes(l.id)&&(r.action==="status"?o.status=r.value:r.action==="up_next"?o.up_next=r.value:r.action==="category"?o.category=r.value:r.action==="priority"?o.priority=r.value:r.action==="delete"&&(o.status="deleted"));return o});h.push({label:s,timestamp:Date.now(),before:i,after:a})}async function Le(e){let t=B(e);await p(`/tickets/${e.id}`,{method:"DELETE"});let s={...t,status:"deleted"};h.push({label:"Delete ticket",timestamp:Date.now(),before:[t],after:[s]})}async function xe(e){let t=B(e);await p(`/tickets/${e.id}/restore`,{method:"POST"});let s={...t,status:"not_started"};h.push({label:"Restore ticket",timestamp:Date.now(),before:[t],after:[s]})}async function Se(e){for(let t of e)t.status==="deleted"?await p(`/tickets/${t.id}`,{method:"DELETE"}):await p(`/tickets/${t.id}`,{method:"PATCH",body:{title:t.title,details:t.details,category:t.category,priority:t.priority,status:t.status,up_next:t.up_next}})}var C=!1;async function _e(){if(console.log("[undo] performUndo, inFlight:",C,"canUndo:",h.canUndo()),C){console.log("[undo] skipped \u2014 already in flight");return}let e=h.popUndo();if(!e){console.log("[undo] skipped \u2014 stack empty");return}console.log("[undo] applying before-state:",e.label,JSON.stringify(e.before)),C=!0;try{await Se(e.before),console.log("[undo] applySnapshots done, reloading tickets"),await m(),ne()}finally{C=!1}}async function Ce(){if(console.log("[undo] performRedo, inFlight:",C,"canRedo:",h.canRedo()),C){console.log("[undo] skipped \u2014 already in flight");return}let e=h.popRedo();if(!e){console.log("[undo] skipped \u2014 stack empty");return}console.log("[undo] applying after-state:",e.label,JSON.stringify(e.after)),C=!0;try{await Se(e.after),console.log("[undo] applySnapshots done, reloading tickets"),await m(),ne()}finally{C=!1}}function Be(){return h.canUndo()}function Me(){return h.canRedo()}var q=null;function de(){q&&(clearTimeout(q),q=null)}var z=!1,V=null,re="",E=[],Y=[{key:"i",value:"issue",label:"Issue"},{key:"b",value:"bug",label:"Bug"},{key:"f",value:"feature",label:"Feature"},{key:"r",value:"requirement_change",label:"Req Change"},{key:"k",value:"task",label:"Task"},{key:"g",value:"investigation",label:"Investigation"}],ce=[{key:"1",value:"highest",label:"Highest"},{key:"2",value:"high",label:"High"},{key:"3",value:"default",label:"Default"},{key:"4",value:"low",label:"Low"},{key:"5",value:"lowest",label:"Lowest"}];function ot(){let e=document.activeElement;if(!e||!(e instanceof HTMLElement))return null;let t=e.closest(".ticket-row");if(!t)return null;if(t.classList.contains("draft-row"))return"draft";let s=t.dataset.id;return s!==void 0&&s!==""?parseInt(s,10):null}function lt(e){e!=null&&(z=!0,e==="draft"?I():document.querySelector(`.ticket-row[data-id="${e}"] .ticket-title-input`)?.focus(),z=!1)}function X(){let e=n.view;return e!=="completed"&&e!=="verified"&&e!=="trash"&&e!=="backlog"&&e!=="archive"}function De(){return n.view==="up-next"||n.view==="open"?[{status:"not_started",label:"Not Started"},{status:"started",label:"Started"}]:n.view==="non-verified"?[{status:"not_started",label:"Not Started"},{status:"started",label:"Started"},{status:"completed",label:"Completed"}]:[{status:"not_started",label:"Not Started"},{status:"started",label:"Started"},{status:"completed",label:"Completed"},{status:"verified",label:"Verified"}]}function v(){let e=!!n.backupPreview?.active;if(n.layout==="columns"&&X()){if(e){ct();return}ut();return}let t=n.view==="trash",s=e?null:ot(),i=null;if(s!=null&&s!=="draft"){let o=document.querySelector(`.ticket-row[data-id="${s}"] .ticket-title-input`);o&&(i=o.value)}let a=document.getElementById("ticket-list"),l=a.scrollTop;if(a.innerHTML="",a.classList.remove("ticket-list-columns"),!t&&!e&&a.appendChild(Re()),n.tickets.length===0){let o=t?"Trash is empty":e?"No tickets match this view":"";o&&a.appendChild(y(c("div",{className:"ticket-list-empty",children:o})))}for(let o of n.tickets)e?a.appendChild(rt(o)):t?a.appendChild(yt(o)):a.appendChild(gt(o));if(a.scrollTop=l,e){let o=document.getElementById("batch-toolbar");o&&(o.style.display="none"),j(),A()}else{let o=document.getElementById("batch-toolbar");if(o&&(o.style.display=""),s!=null&&s!=="draft"&&i!=null){let r=document.querySelector(`.ticket-row[data-id="${s}"] .ticket-title-input`);r&&r.value!==i&&(r.value=i)}lt(s),K()}J()}function rt(e){let t=n.selectedIds.has(e.id),s=e.status==="completed"||e.status==="verified",i=e.status==="verified",a=y(c("div",{className:`ticket-row${t?" selected":""}${s?" completed":""}${e.up_next?" up-next":""}`,"data-id":String(e.id),children:[c("span",{className:"ticket-checkbox-spacer"}),c("span",{className:`ticket-status-btn${i?" verified":""}`,style:"cursor:default",children:i?_(ee):te(e.status)}),c("span",{className:"ticket-category-badge",style:`background-color:${w(e.category)};cursor:default`,title:e.category,children:H(e.category)}),c("span",{className:"ticket-number",children:e.ticket_number}),c("span",{className:"ticket-title-input",style:"cursor:default",children:e.title}),c("span",{className:"ticket-priority-indicator",style:`color:${P(e.priority)};cursor:default`,title:e.priority,children:F(e.priority)}),c("span",{className:`ticket-star${e.up_next?" active":""}`,style:"cursor:default",children:e.up_next?"\u2605":"\u2606"})]}));return a.addEventListener("click",()=>{n.selectedIds.clear(),n.selectedIds.add(e.id),n.lastClickedId=e.id,j(),A()}),a}function Pe(e){let t={scrollLeft:0,columns:{}},s=e.querySelector(".columns-container");return s&&(t.scrollLeft=s.scrollLeft,s.querySelectorAll(".column[data-status]").forEach(i=>{let a=i.dataset.status,l=i.querySelector(".column-body");l&&(t.columns[a]=l.scrollTop)})),t}function Ae(e,t){let s=e.querySelector(".columns-container");s&&(s.scrollLeft=t.scrollLeft,s.querySelectorAll(".column[data-status]").forEach(i=>{let a=i.dataset.status,l=i.querySelector(".column-body");l&&t.columns[a]!=null&&(l.scrollTop=t.columns[a])}))}function ct(){let e=document.getElementById("ticket-list"),t=Pe(e);e.innerHTML="",e.classList.add("ticket-list-columns");let s=De(),i=y(c("div",{className:"columns-container"}));for(let l of s){let o=n.tickets.filter(d=>d.status===l.status),r=y(c("div",{className:"column","data-status":l.status,children:[c("div",{className:"column-header",children:[c("span",{className:"column-title",children:l.label}),c("span",{className:"column-count",children:String(o.length)})]}),c("div",{className:"column-body"})]})),u=r.querySelector(".column-body");for(let d of o)u.appendChild(dt(d));i.appendChild(r)}e.appendChild(i),Ae(e,t);let a=document.getElementById("batch-toolbar");a&&(a.style.display="none"),J()}function dt(e){let t=n.selectedIds.has(e.id),s=y(c("div",{className:`column-card${t?" selected":""}${e.up_next?" up-next":""}`,"data-id":String(e.id),children:[c("div",{className:"column-card-header",children:[c("span",{className:"ticket-category-badge",style:`background-color:${w(e.category)}`,children:H(e.category)}),c("span",{className:"ticket-number",children:e.ticket_number}),c("span",{className:"ticket-priority-indicator",style:`color:${P(e.priority)};cursor:default`,children:F(e.priority)}),c("span",{className:`ticket-star${e.up_next?" active":""}`,style:"cursor:default",children:e.up_next?"\u2605":"\u2606"})]}),c("div",{className:"column-card-title",children:e.title})]}));return s.addEventListener("click",()=>{n.selectedIds.clear(),n.selectedIds.add(e.id),n.lastClickedId=e.id,$e(),A()}),s}function ut(){let e=document.getElementById("ticket-list"),t=Pe(e);e.innerHTML="",e.classList.add("ticket-list-columns"),e.appendChild(Re());let s=De(),i=y(c("div",{className:"columns-container"}));for(let a of s){let l=n.tickets.filter(u=>u.status===a.status),o=y(c("div",{className:"column","data-status":a.status,children:[c("div",{className:"column-header",children:[c("span",{className:"column-title",children:a.label}),c("span",{className:"column-count",children:String(l.length)})]}),c("div",{className:"column-body"})]})),r=o.querySelector(".column-body");for(let u of l)r.appendChild(pt(u));r.addEventListener("dragover",u=>{u.preventDefault(),u.dataTransfer.dropEffect="move",o.classList.add("column-drop-target")}),r.addEventListener("dragleave",u=>{let d=u.relatedTarget;(!d||!r.contains(d))&&o.classList.remove("column-drop-target")}),r.addEventListener("drop",u=>{u.preventDefault(),o.classList.remove("column-drop-target");let d=E;if(E=[],d.length===0)return;let f=n.tickets.filter(k=>d.includes(k.id));b(f,{ids:d,action:"status",value:a.status},"Change status").then(()=>{m()})}),i.appendChild(o)}e.appendChild(i),Ae(e,t),K(),J()}function pt(e){let t=n.selectedIds.has(e.id),s=y(c("div",{className:`column-card${t?" selected":""}${e.up_next?" up-next":""}`,"data-id":String(e.id),children:[c("div",{className:"column-card-header",children:[c("span",{className:"ticket-category-badge",style:`background-color:${w(e.category)}`,children:H(e.category)}),c("span",{className:"ticket-number",children:e.ticket_number}),c("span",{className:"ticket-priority-indicator",style:`color:${P(e.priority)}`,children:F(e.priority)}),c("button",{className:`ticket-star${e.up_next?" active":""}`,title:e.up_next?"Remove from Up Next":"Add to Up Next",children:e.up_next?"\u2605":"\u2606"})]}),c("div",{className:"column-card-title",children:e.title})]})),i=s.querySelector(".ticket-priority-indicator");return i.addEventListener("click",a=>{a.stopPropagation(),Oe(i,e)}),s.querySelector(".ticket-star").addEventListener("click",a=>{a.stopPropagation(),Ke(e)}),s.draggable=!0,s.addEventListener("dragstart",a=>{n.selectedIds.has(e.id)&&n.selectedIds.size>1?E=Array.from(n.selectedIds):E=[e.id],a.dataTransfer.setData("text/plain",JSON.stringify(E)),a.dataTransfer.effectAllowed="move"}),s.addEventListener("dragend",()=>{E=[]}),s.addEventListener("click",a=>{if(a.metaKey||a.ctrlKey)n.selectedIds.has(e.id)?n.selectedIds.delete(e.id):n.selectedIds.add(e.id),n.lastClickedId=e.id;else if(a.shiftKey&&n.lastClickedId!=null){let l=n.tickets.find(o=>o.id===n.lastClickedId);if(l&&l.status===e.status){let r=n.tickets.filter(f=>f.status===e.status).map(f=>f.id),u=r.indexOf(n.lastClickedId),d=r.indexOf(e.id);if(u!==-1&&d!==-1){let f=Math.min(u,d),k=Math.max(u,d);n.selectedIds.clear();for(let x=f;x<=k;x++)n.selectedIds.add(r[x])}}else n.selectedIds.clear(),n.selectedIds.add(e.id),n.lastClickedId=e.id}else n.selectedIds.clear(),n.selectedIds.add(e.id),n.lastClickedId=e.id;$e(),K()}),s}function $e(){document.querySelectorAll(".column-card[data-id]").forEach(e=>{let t=parseInt(e.dataset.id,10);n.selectedIds.has(t)?e.classList.add("selected"):e.classList.remove("selected")})}function Re(){let e=Ue(),t=n.view.startsWith("category:"),s=y(c("div",{className:"ticket-row draft-row",children:[c("span",{className:"ticket-checkbox-spacer"}),c("span",{className:"ticket-status-btn draft-placeholder",children:"\u25CB"}),c("span",{className:"ticket-category-badge draft-badge",style:`background-color:${w(e)}${t?"":";cursor:pointer;opacity:1"}`,children:H(e)}),c("span",{className:"ticket-number draft-number"}),c("input",{type:"text",className:"ticket-title-input draft-input",placeholder:"New ticket...",value:re}),c("span",{className:"ticket-priority-indicator draft-placeholder"}),c("span",{className:"ticket-star draft-placeholder"})]}));if(!t){let a=s.querySelector(".ticket-category-badge");a.addEventListener("click",l=>{l.stopPropagation(),ft(a)})}let i=s.querySelector(".draft-input");return i.addEventListener("input",()=>{re=i.value}),i.addEventListener("keydown",async a=>{if(a.key==="Enter"&&i.value.trim()){a.preventDefault();let l=i.value.trim();re="",i.value="";let o=mt();V&&!n.view.startsWith("category:")&&(o.category=V);let r=await p("/tickets",{method:"POST",body:{title:l,defaults:o}});r&&(n.selectedIds.clear(),n.selectedIds.add(r.id)),await m(),I()}else a.key==="ArrowDown"&&(a.preventDefault(),n.tickets.length>0&&document.querySelector(`.ticket-row[data-id="${n.tickets[0].id}"] .ticket-title-input`)?.focus())}),s}function I(){document.querySelector(".draft-row .draft-input")?.focus()}function mt(){let e=n.view;return e==="up-next"?{up_next:!0}:e==="open"?{}:e==="completed"?{status:"completed"}:e==="backlog"?{status:"backlog"}:e==="archive"?{status:"archive"}:e.startsWith("category:")?{category:e.split(":")[1]}:e.startsWith("priority:")?{priority:e.split(":")[1]}:{}}function Ue(){if(V)return V;let e=n.view;return e.startsWith("category:")?e.split(":")[1]:"issue"}function ft(e){U();let s=navigator.platform.includes("Mac")?"\u2318":"Ctrl+",i=Ue(),a=R(e,Y.map(l=>({label:l.label,key:l.key,shortcut:`${s}${l.key.toUpperCase()}`,color:w(l.value),active:i===l.value,action:()=>{V=l.value,v(),I()}})));document.body.appendChild(a),$(a,e),a.style.visibility=""}function gt(e){let t=n.selectedIds.has(e.id),s=e.status==="completed"||e.status==="verified",i=e.status==="verified",a=y(c("div",{className:`ticket-row${t?" selected":""}${s?" completed":""}${e.up_next?" up-next":""}`,"data-id":String(e.id),children:[c("input",{type:"checkbox",className:"ticket-checkbox",checked:t}),c("button",{className:`ticket-status-btn${i?" verified":""}`,title:e.status.replace("_"," "),children:i?_(ee):te(e.status)}),c("span",{className:"ticket-category-badge",style:`background-color:${w(e.category)}`,title:e.category,children:H(e.category)}),c("span",{className:"ticket-number",children:e.ticket_number}),c("input",{type:"text",className:"ticket-title-input",value:e.title}),c("span",{className:"ticket-priority-indicator",style:`color:${P(e.priority)}`,title:e.priority,children:F(e.priority)}),c("button",{className:`ticket-star${e.up_next?" active":""}`,title:e.up_next?"Remove from Up Next":"Add to Up Next",children:e.up_next?"\u2605":"\u2606"})]}));a.addEventListener("mousedown",d=>{let f=d.target;f.tagName!=="INPUT"&&f.tagName!=="BUTTON"&&(a.draggable=!0)}),a.addEventListener("mouseup",()=>{a.draggable=!1}),a.addEventListener("dragend",()=>{a.draggable=!1,E=[]}),a.addEventListener("dragstart",d=>{n.selectedIds.has(e.id)&&n.selectedIds.size>1?E=Array.from(n.selectedIds):E=[e.id],d.dataTransfer.setData("text/plain",JSON.stringify(E)),d.dataTransfer.effectAllowed="move"}),a.addEventListener("mousedown",d=>{(d.metaKey||d.ctrlKey||d.shiftKey)&&(d.preventDefault(),qe(d,e)&&d.stopPropagation())});let l=a.querySelector(".ticket-checkbox");l.addEventListener("click",d=>d.stopPropagation()),l.addEventListener("change",()=>{l.checked?n.selectedIds.add(e.id):n.selectedIds.delete(e.id),n.lastClickedId=e.id,v()}),a.querySelector(".ticket-status-btn").addEventListener("click",d=>{d.stopPropagation(),kt(e)});let o=a.querySelector(".ticket-category-badge");o.addEventListener("click",d=>{d.stopPropagation(),It(o,e)});let r=a.querySelector(".ticket-title-input");r.addEventListener("focus",()=>{z||n.selectedIds.size===1&&n.selectedIds.has(e.id)||(n.selectedIds.clear(),n.selectedIds.add(e.id),n.lastClickedId=e.id,j(),K())}),r.addEventListener("input",()=>{G(e,"title",r.value),Tt(e.id,{title:r.value})}),r.addEventListener("keydown",d=>{vt(d,e,r)});let u=a.querySelector(".ticket-priority-indicator");return u.addEventListener("click",d=>{d.stopPropagation(),Oe(u,e)}),a.querySelector(".ticket-star").addEventListener("click",d=>{d.stopPropagation(),Ke(e)}),a}function yt(e){let t=n.selectedIds.has(e.id),s=e.deleted_at?new Date(e.deleted_at):null,i=y(c("div",{className:`ticket-row trash-row${t?" selected":""}`,"data-id":String(e.id),children:[c("input",{type:"checkbox",className:"ticket-checkbox",checked:t}),c("span",{className:"ticket-category-badge",style:`background-color:${w(e.category)}`,children:H(e.category)}),c("span",{className:"ticket-number",children:e.ticket_number}),c("span",{className:"ticket-title-input trash-title",style:"cursor:default",children:e.title}),c("span",{className:"ticket-number",title:s?`Deleted: ${s.toLocaleString()}`:"",children:s?s.toLocaleDateString():""}),c("button",{className:"btn btn-sm",title:"Restore from trash",children:"Restore"})]}));i.addEventListener("mousedown",l=>{(l.metaKey||l.ctrlKey||l.shiftKey)&&(l.preventDefault(),qe(l,e)&&l.stopPropagation())});let a=i.querySelector(".ticket-checkbox");return a.addEventListener("click",l=>l.stopPropagation()),a.addEventListener("change",()=>{a.checked?n.selectedIds.add(e.id):n.selectedIds.delete(e.id),n.lastClickedId=e.id,v()}),i.querySelector(".trash-title").addEventListener("click",()=>{n.selectedIds.size===1&&n.selectedIds.has(e.id)||(n.selectedIds.clear(),n.selectedIds.add(e.id),n.lastClickedId=e.id,j(),K())}),i.querySelector(".btn").addEventListener("click",async l=>{l.stopPropagation(),await xe(e),m()}),i}function qe(e,t){let s=e.metaKey||e.ctrlKey,i=e.shiftKey;if(s)n.selectedIds.has(t.id)?n.selectedIds.delete(t.id):n.selectedIds.add(t.id),n.lastClickedId=t.id,v();else if(i&&n.lastClickedId!=null){let a=n.tickets.map(r=>r.id),l=a.indexOf(n.lastClickedId),o=a.indexOf(t.id);if(l!==-1&&o!==-1){let r=Math.min(l,o),u=Math.max(l,o);n.selectedIds.clear();for(let d=r;d<=u;d++)n.selectedIds.add(a[d])}v()}else return!1;return!0}function vt(e,t,s){if(e.key==="Enter")e.preventDefault(),I();else if(e.key==="Backspace"&&s.value==="")e.preventDefault(),Et(t.id);else if(e.key==="ArrowDown"&&e.shiftKey)e.preventDefault(),He(t.id,1);else if(e.key==="ArrowUp"&&e.shiftKey)e.preventDefault(),He(t.id,-1);else if(e.key==="ArrowDown")e.preventDefault(),ht(t.id);else if(e.key==="ArrowUp")e.preventDefault(),bt(t.id);else if((e.metaKey||e.ctrlKey)&&!e.altKey&&Y.some(i=>i.key===e.key)){e.preventDefault();let i=Y.find(a=>a.key===e.key);Ne(t,"category",i.value)}else if(e.altKey&&!e.metaKey&&!e.ctrlKey&&ce.some(i=>i.key===e.key)){e.preventDefault();let i=ce.find(a=>a.key===e.key);Ne(t,"priority",i.value)}}function ht(e){let t=n.tickets.findIndex(s=>s.id===e);t<n.tickets.length-1&&document.querySelector(`.ticket-row[data-id="${n.tickets[t+1].id}"] .ticket-title-input`)?.focus()}function bt(e){let t=n.tickets.findIndex(s=>s.id===e);t>0?document.querySelector(`.ticket-row[data-id="${n.tickets[t-1].id}"] .ticket-title-input`)?.focus():I()}function He(e,t){let i=n.tickets.findIndex(o=>o.id===e)+t;if(i<0||i>=n.tickets.length)return;let a=n.tickets[i].id;n.selectedIds.add(e),n.selectedIds.has(a)?n.selectedIds.delete(e):n.selectedIds.add(a),z=!0,document.querySelector(`.ticket-row[data-id="${a}"] .ticket-title-input`)?.focus(),z=!1,j(),K()}async function kt(e){let s={not_started:"started",started:"completed",completed:"verified",verified:"not_started",backlog:"not_started",archive:"not_started"}[e.status]||"not_started",i=await T(e,{status:s},"Change status");Object.assign(e,i),v()}async function Ke(e){!e.up_next&&(e.status==="completed"||e.status==="verified")?await T(e,{status:"not_started",up_next:!0},"Toggle up next"):await T(e,{up_next:!e.up_next},"Toggle up next"),m()}async function Ne(e,t,s){let i=await T(e,{[t]:s},`Change ${t}`);Object.assign(e,i),v()}async function Et(e){let t=n.tickets.findIndex(i=>i.id===e),s=n.tickets.find(i=>i.id===e);if(s?await Le(s):await p(`/tickets/${e}`,{method:"DELETE"}),n.tickets=n.tickets.filter(i=>i.id!==e),n.selectedIds.delete(e),v(),t>0&&n.tickets.length>0){let i=Math.min(t-1,n.tickets.length-1);document.querySelector(`.ticket-row[data-id="${n.tickets[i].id}"] .ticket-title-input`)?.focus()}else I()}function Tt(e,t){q&&clearTimeout(q),q=setTimeout(()=>{p(`/tickets/${e}`,{method:"PATCH",body:t})},300)}function It(e,t){U();let i=navigator.platform.includes("Mac")?"\u2318":"Ctrl+",a=R(e,Y.map(l=>({label:l.label,key:l.key,shortcut:`${i}${l.key.toUpperCase()}`,color:w(l.value),active:t.category===l.value,action:async()=>{let o=await T(t,{category:l.value},"Change category");Object.assign(t,o),v()}})));document.body.appendChild(a),$(a,e),a.style.visibility=""}function Oe(e,t){U();let s=R(e,ce.map(i=>({label:i.label,key:i.key,shortcut:`Alt+${i.key}`,color:P(i.value),active:t.priority===i.value,action:async()=>{let a=await T(t,{priority:i.value},"Change priority");Object.assign(t,a),v()}})));document.body.appendChild(s),$(s,e),s.style.visibility=""}function j(){document.querySelectorAll(".ticket-row[data-id]").forEach(e=>{let t=parseInt(e.dataset.id,10),s=e.querySelector(".ticket-checkbox");n.selectedIds.has(t)?(e.classList.add("selected"),s&&(s.checked=!0)):(e.classList.remove("selected"),s&&(s.checked=!1))})}function K(){let e=n.selectedIds.size,t=n.tickets.length,s=e>0,i=n.view==="trash",a=document.getElementById("batch-select-all");a.checked=t>0&&e===t,a.indeterminate=e>0&&e<t,document.getElementById("batch-count").textContent=s?`${e} selected`:"";let l=["batch-category","batch-priority","batch-status","batch-upnext","batch-delete","batch-more"];for(let f of l){let k=document.getElementById(f);k.style.display=i?"none":"",i||(k.disabled=!s)}let o=document.getElementById("batch-restore"),r=document.getElementById("batch-empty-trash");if(i){let f=document.getElementById("batch-toolbar");o||(o=y(c("button",{id:"batch-restore",className:"btn btn-sm",children:"Restore"})),o.addEventListener("click",async()=>{await p("/tickets/batch",{method:"POST",body:{ids:Array.from(n.selectedIds),action:"restore"}}),n.selectedIds.clear(),m()}),f.insertBefore(o,document.getElementById("batch-count"))),o.disabled=!s,o.style.display="",r||(r=y(c("button",{id:"batch-empty-trash",className:"btn btn-sm btn-danger",children:"Empty Trash"})),r.addEventListener("click",async()=>{await p("/trash/empty",{method:"POST"}),n.selectedIds.clear(),m()}),f.insertBefore(r,document.getElementById("batch-count"))),r.disabled=t===0,r.style.display=""}else o&&(o.style.display="none"),r&&(r.style.display="none");let u=document.querySelector(".batch-star-icon"),d=document.getElementById("batch-upnext");if(!i&&u&&s){let f=n.tickets.filter(M=>n.selectedIds.has(M.id)),k=f.every(M=>M.up_next),x=f.every(M=>!M.up_next);k?(u.textContent="\u2605",d.classList.add("active"),d.classList.remove("mixed")):x?(u.textContent="\u2606",d.classList.remove("active","mixed")):(u.innerHTML=c("span",{className:"star-mixed-wrap",children:[c("span",{className:"star-mixed-fill",children:"\u2605"}),"\u2606"]}).toString(),d.classList.remove("active"),d.classList.add("mixed"))}else u&&(u.textContent="\u2606",d.classList.remove("active","mixed"));A()}async function m(){if(n.backupPreview?.active){wt();return}let e=new URLSearchParams;n.view==="trash"?e.set("status","deleted"):n.view==="up-next"?e.set("up_next","true"):n.view==="open"?e.set("status","open"):n.view==="completed"?e.set("status","completed"):n.view==="non-verified"?e.set("status","non_verified"):n.view==="verified"?e.set("status","verified"):n.view==="backlog"?e.set("status","backlog"):n.view==="archive"?e.set("status","archive"):n.view.startsWith("category:")?e.set("category",n.view.split(":")[1]):n.view.startsWith("priority:")?e.set("priority",n.view.split(":")[1]):e.set("status","active"),n.search&&e.set("search",n.search),e.set("sort_by",n.sortBy),e.set("sort_dir",n.sortDir);let t=e.toString();n.tickets=await p(`/tickets${t?"?"+t:""}`),v()}function wt(){let e=[...n.backupPreview?.tickets||[]];if(n.view==="trash")e=e.filter(t=>t.status==="deleted");else if(n.view==="up-next")e=e.filter(t=>t.up_next&&t.status!=="deleted");else if(n.view==="open")e=e.filter(t=>t.status==="not_started"||t.status==="started");else if(n.view==="completed")e=e.filter(t=>t.status==="completed");else if(n.view==="non-verified")e=e.filter(t=>t.status!=="verified"&&t.status!=="deleted"&&t.status!=="backlog"&&t.status!=="archive");else if(n.view==="verified")e=e.filter(t=>t.status==="verified");else if(n.view==="backlog")e=e.filter(t=>t.status==="backlog");else if(n.view==="archive")e=e.filter(t=>t.status==="archive");else if(n.view.startsWith("category:")){let t=n.view.split(":")[1];e=e.filter(s=>s.category===t&&s.status!=="deleted"&&s.status!=="backlog"&&s.status!=="archive")}else if(n.view.startsWith("priority:")){let t=n.view.split(":")[1];e=e.filter(s=>s.priority===t&&s.status!=="deleted"&&s.status!=="backlog"&&s.status!=="archive")}else e=e.filter(t=>t.status!=="deleted"&&t.status!=="backlog"&&t.status!=="archive");if(n.search){let t=n.search.toLowerCase();e=e.filter(s=>s.title.toLowerCase().includes(t)||s.ticket_number.toLowerCase().includes(t)||s.details&&s.details.toLowerCase().includes(t))}n.tickets=e,v()}function Lt(e){let t=Date.now()-new Date(e).getTime(),s=Math.floor(t/6e4);if(s<1)return"just now";if(s<60)return`${s}m ago`;let i=Math.floor(s/60);return i<24?`${i}h ago`:`${Math.floor(i/24)}d ago`}function xt(e){return e<1024?`${e} B`:e<1024*1024?`${(e/1024).toFixed(0)} KB`:`${(e/(1024*1024)).toFixed(1)} MB`}function St(e){return e==="5min"?"Recent (every 5 min)":e==="hourly"?"Hourly":e==="daily"?"Daily":e}async function ue(){var t;let e=document.getElementById("backup-list");if(e)try{let s=await p("/backups");if(s.backups.length===0){e.textContent="No backups yet. First backup will be created shortly.";return}let i={};for(let a of s.backups)(i[t=a.tier]||(i[t]=[])).push(a);e.innerHTML="";for(let a of["5min","hourly","daily"]){let l=i[a];if(!(!l||l.length===0)){e.appendChild(y(c("div",{className:"backup-tier-label",children:St(a)})));for(let o of l){let r=y(c("div",{className:"backup-row","data-tier":o.tier,"data-filename":o.filename,children:[c("span",{className:"backup-row-time",children:Lt(o.createdAt)}),c("span",{className:"backup-row-meta",children:[new Date(o.createdAt).toLocaleString()," \xB7 ",xt(o.sizeBytes)]})]}));r.addEventListener("click",()=>{_t(o.tier,o.filename,o.createdAt)}),e.appendChild(r)}}}}catch{e.textContent="Failed to load backups."}}async function _t(e,t,s){let i=document.getElementById("settings-overlay");i.style.display="none";let a=document.getElementById("backup-preview-banner"),l=document.getElementById("backup-preview-label");l.textContent="Loading backup preview...",a.style.display="flex";try{let o=await p(`/backups/preview/${e}/${t}`);n.backupPreview={active:!0,tickets:o.tickets,timestamp:s,tier:e,filename:t},n.selectedIds.clear(),n.activeTicketId=null,l.textContent=`Previewing backup from ${new Date(s).toLocaleString()} (${o.stats.total} tickets, ${o.stats.open} open) \u2014 read-only`,m()}catch{l.textContent="Failed to load backup preview.",setTimeout(()=>{a.style.display="none"},3e3)}}async function Ct(){let e=document.getElementById("backup-preview-banner");e.style.display="none",n.backupPreview=null,n.selectedIds.clear(),n.activeTicketId=null,await p("/backups/preview/cleanup",{method:"POST"}),m()}async function Bt(){if(!n.backupPreview)return;let e=document.getElementById("backup-restore-btn");e.textContent="Restoring...",e.disabled=!0;try{await p("/backups/restore",{method:"POST",body:{tier:n.backupPreview.tier,filename:n.backupPreview.filename}}),window.location.reload()}catch{e.textContent="Restore failed",e.disabled=!1,setTimeout(()=>{e.textContent="Restore This Backup"},3e3)}}function Fe(){document.getElementById("backup-cancel-btn")?.addEventListener("click",()=>{Ct()}),document.getElementById("backup-restore-btn")?.addEventListener("click",()=>{Bt()});let e=document.getElementById("backup-now-btn");e?.addEventListener("click",async()=>{e.textContent="Backing up...",e.disabled=!0;try{(await p("/backups/now",{method:"POST"})).error?e.textContent="In progress...":(e.textContent="Done!",ue())}catch{e.textContent="Failed"}setTimeout(()=>{e.textContent="Backup Now",e.disabled=!1},1500)})}async function Mt(){await Ht(),Nt(),await m(),Ot(),Ut(),qt(),Ft(),zt(),Vt(),jt(),Gt(),Dt(),Fe(),$t(),Rt(),we(),Yt(),Pt(),document.addEventListener("hotsheet:render",()=>v()),I()}async function Ht(){try{let e=await p("/settings");(e.detail_position==="side"||e.detail_position==="bottom")&&(n.settings.detail_position=e.detail_position),e.detail_width&&(n.settings.detail_width=parseInt(e.detail_width,10)||360),e.detail_height&&(n.settings.detail_height=parseInt(e.detail_height,10)||300),e.trash_cleanup_days&&(n.settings.trash_cleanup_days=parseInt(e.trash_cleanup_days,10)||3),e.verified_cleanup_days&&(n.settings.verified_cleanup_days=parseInt(e.verified_cleanup_days,10)||30),(e.layout==="list"||e.layout==="columns")&&(n.layout=e.layout)}catch{}ae(n.settings.detail_position),ie()}async function Nt(){try{let e=await p("/file-settings");if(e.appName){document.title=e.appName;let t=document.querySelector(".app-title h1");t&&(t.textContent=e.appName)}}catch{}}function Dt(){let e=document.getElementById("settings-overlay"),t=document.getElementById("settings-close");document.getElementById("settings-btn").addEventListener("click",()=>{document.getElementById("settings-trash-days").value=String(n.settings.trash_cleanup_days),document.getElementById("settings-verified-days").value=String(n.settings.verified_cleanup_days),e.style.display="flex",ue(),p("/file-settings").then(g=>{document.getElementById("settings-app-name").value=g.appName||"",document.getElementById("settings-backup-dir").value=g.backupDir||""})}),t.addEventListener("click",()=>{e.style.display="none"}),e.addEventListener("click",g=>{g.target===e&&(e.style.display="none")});let i=document.getElementById("settings-trash-days"),a=null;i.addEventListener("input",()=>{a&&clearTimeout(a),a=setTimeout(()=>{let g=Math.max(1,parseInt(i.value,10)||3);i.value=String(g),n.settings.trash_cleanup_days=g,p("/settings",{method:"PATCH",body:{trash_cleanup_days:String(g)}})},500)});let l=document.getElementById("settings-verified-days"),o=null;l.addEventListener("input",()=>{o&&clearTimeout(o),o=setTimeout(()=>{let g=Math.max(1,parseInt(l.value,10)||30);l.value=String(g),n.settings.verified_cleanup_days=g,p("/settings",{method:"PATCH",body:{verified_cleanup_days:String(g)}})},500)});let r=document.getElementById("settings-app-name"),u=document.getElementById("settings-app-name-hint"),d=null;r.addEventListener("input",()=>{d&&clearTimeout(d),d=setTimeout(()=>{let g=r.value.trim();p("/file-settings",{method:"PATCH",body:{appName:g}}).then(()=>{let N=g||"Hot Sheet";document.title=N;let ye=document.querySelector(".app-title h1");ye&&(ye.textContent=N),u.textContent=g?"Saved. Restart the desktop app to update the title bar.":"Using default name."})},800)});let f=document.getElementById("check-updates-btn"),k=document.getElementById("check-updates-status");f.addEventListener("click",async()=>{let g=ge();if(g){f.disabled=!0,f.textContent="Checking...",k.textContent="";try{let N=await g("check_for_update");N?(k.textContent=`Update available: v${N}`,document.getElementById("settings-overlay").style.display="none",We(N)):k.textContent="Your software is up to date."}catch{k.textContent="Could not check for updates."}f.textContent="Check for Updates",f.disabled=!1}});let x=document.getElementById("settings-backup-dir"),M=document.getElementById("settings-backup-dir-hint"),Q=null;x.addEventListener("input",()=>{Q&&clearTimeout(Q),Q=setTimeout(()=>{let g=x.value.trim();p("/file-settings",{method:"PATCH",body:{backupDir:g}}).then(()=>{M.textContent=g?"Saved. New backups will use this location.":"Using default location inside the data directory."})},800)})}async function Pt(){let e=ge();if(!e)return;let t=document.getElementById("settings-updates-section");t&&(t.style.display="");let s=[0,3e3,1e4];for(let i of s){i>0&&await new Promise(a=>setTimeout(a,i));try{let a=await e("get_pending_update");if(a){We(a);return}}catch{return}}}function ge(){return window.__TAURI__?.core?.invoke??null}function We(e){let t=document.getElementById("update-banner");if(!t)return;let s=document.getElementById("update-banner-label");s&&(s.textContent=`Update available: v${e}`),t.style.display="flex";let i=document.getElementById("update-install-btn");i?.addEventListener("click",async()=>{if(i){i.textContent="Installing...",i.disabled=!0;try{await ge()?.("install_update"),s&&(s.textContent="Update installed! Restart the app to apply."),i.style.display="none"}catch{i.textContent="Install Failed",i.disabled=!1}}}),document.getElementById("update-banner-dismiss")?.addEventListener("click",()=>{t.style.display="none"})}function At(){let e=document.getElementById("skills-banner");if(!e)return;e.style.display="flex",document.getElementById("skills-banner-dismiss")?.addEventListener("click",()=>{e.style.display="none"})}function $t(){let e=document.getElementById("copy-prompt-section"),t=document.getElementById("copy-prompt-btn"),s=document.getElementById("copy-prompt-label"),i=document.getElementById("copy-prompt-icon"),a="";p("/worklist-info").then(l=>{a=l.prompt,e.style.display="",l.skillCreated&&At()}),t.addEventListener("click",()=>{a!==""&&navigator.clipboard.writeText(a).then(()=>{s.textContent="Copied!",i.innerHTML='<svg xmlns="http://www.w3.org/2000/svg" width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M20 6L9 17l-5-5"/></svg>',setTimeout(()=>{s.textContent="Copy AI prompt",i.innerHTML='<svg xmlns="http://www.w3.org/2000/svg" width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg>'},1500)})})}function Rt(){let e=document.getElementById("glassbox-btn"),t=document.getElementById("glassbox-icon");p("/glassbox/status").then(({available:s})=>{s&&(t.src="/static/assets/glassbox-icon.png",e.style.display="")}).catch(()=>{}),e.addEventListener("click",()=>{p("/glassbox/launch",{method:"POST"})})}function fe(){let e=document.getElementById("layout-toggle"),t=X(),s=e.querySelector('[data-layout="columns"]');s.disabled=!t,s.style.opacity=t?"":"0.3";let i=n.layout==="columns"&&!t?"list":n.layout;e.querySelectorAll(".layout-btn").forEach(a=>{a.classList.toggle("active",a.dataset.layout===i)})}function Ut(){document.getElementById("layout-toggle").querySelectorAll(".layout-btn").forEach(t=>{t.addEventListener("click",()=>{let s=t.dataset.layout;s==="columns"&&!X()||(n.layout=s,fe(),v(),p("/settings",{method:"PATCH",body:{layout:s}}))})}),fe()}function ze(){document.getElementById("detail-position-toggle").querySelectorAll(".layout-btn").forEach(t=>{t.classList.toggle("active",t.dataset.position===n.settings.detail_position)})}function qt(){document.getElementById("detail-position-toggle").querySelectorAll(".layout-btn").forEach(t=>{t.addEventListener("click",()=>{let s=t.dataset.position;n.settings.detail_position=s,ae(s),ie(),ze(),p("/settings",{method:"PATCH",body:{detail_position:s}})})}),ze()}function Je(e){return e==="up-next"?{action:"up_next",value:!0}:e==="open"?{action:"status",value:"not_started"}:e==="completed"?{action:"status",value:"completed"}:e==="verified"?{action:"status",value:"verified"}:e==="backlog"?{action:"status",value:"backlog"}:e==="archive"?{action:"status",value:"archive"}:e==="trash"?{action:"delete",value:null}:e.startsWith("category:")?{action:"category",value:e.split(":")[1]}:e.startsWith("priority:")?{action:"priority",value:e.split(":")[1]}:null}async function Kt(e,t){let s=Je(e);if(!s)return;let i=n.tickets.filter(a=>t.includes(a.id));s.action==="delete"?await b(i,{ids:t,action:"delete"},"Delete tickets"):await b(i,{ids:t,action:s.action,value:s.value},`Change ${s.action}`),m()}function Ot(){let e=document.querySelectorAll(".sidebar-item[data-view]");e.forEach(t=>{t.addEventListener("click",()=>{e.forEach(i=>{i.classList.remove("active")}),t.classList.add("active"),n.view=t.dataset.view,n.selectedIds.clear(),fe(),m()});let s=t.dataset.view;Je(s)&&(t.addEventListener("dragover",i=>{i.preventDefault(),i.dataTransfer.dropEffect="move",t.classList.add("drop-target")}),t.addEventListener("dragleave",()=>{t.classList.remove("drop-target")}),t.addEventListener("drop",i=>{i.preventDefault(),t.classList.remove("drop-target");let a=[...E];a.length!==0&&Kt(s,a)}))})}function Ft(){let e=document.getElementById("sort-select");e.addEventListener("change",()=>{let[t,s]=e.value.split(":");n.sortBy=t,n.sortDir=s,m()})}var pe=null;function zt(){let e=document.getElementById("search-input");e.addEventListener("input",()=>{pe&&clearTimeout(pe),pe=setTimeout(()=>{n.search=e.value,m()},200)}),e.addEventListener("keydown",t=>{t.key==="Escape"&&(e.value="",n.search="",m())})}function Vt(){let e=document.getElementById("batch-category");e.addEventListener("change",async()=>{if(!e.value)return;let a=Array.from(n.selectedIds),l=n.tickets.filter(o=>n.selectedIds.has(o.id));await b(l,{ids:a,action:"category",value:e.value},"Batch change category"),e.value="",m()});let t=document.getElementById("batch-priority");t.addEventListener("change",async()=>{if(!t.value)return;let a=Array.from(n.selectedIds),l=n.tickets.filter(o=>n.selectedIds.has(o.id));await b(l,{ids:a,action:"priority",value:t.value},"Batch change priority"),t.value="",m()});let s=document.getElementById("batch-status");s.addEventListener("change",async()=>{if(!s.value)return;let a=Array.from(n.selectedIds),l=n.tickets.filter(o=>n.selectedIds.has(o.id));await b(l,{ids:a,action:"status",value:s.value},"Batch change status"),s.value="",m()}),document.getElementById("batch-upnext").addEventListener("click",async()=>{let a=n.tickets.filter(u=>n.selectedIds.has(u.id)),o=!a.every(u=>u.up_next),r=Array.from(n.selectedIds);if(o){let u=a.filter(d=>d.status==="completed"||d.status==="verified");if(u.length>0){let d=[{ids:u.map(f=>f.id),action:"status",value:"not_started"},{ids:r,action:"up_next",value:!0}];await le(a,d,"Batch toggle up next")}else await b(a,{ids:r,action:"up_next",value:!0},"Batch toggle up next")}else await b(a,{ids:r,action:"up_next",value:!1},"Batch toggle up next");m()}),document.getElementById("batch-delete").addEventListener("click",async()=>{let a=Array.from(n.selectedIds),l=n.tickets.filter(o=>n.selectedIds.has(o.id));await b(l,{ids:a,action:"delete"},"Batch delete"),n.selectedIds.clear(),m()});let i=document.getElementById("batch-more");i.addEventListener("click",a=>{a.stopPropagation(),U();let l=R(i,[{label:"Duplicate",key:"d",action:async()=>{let o=Array.from(n.selectedIds),r=await p("/tickets/duplicate",{method:"POST",body:{ids:o}});n.selectedIds.clear();for(let u of r)n.selectedIds.add(u.id);m()}},{label:"Move to Backlog",key:"b",action:async()=>{let o=Array.from(n.selectedIds),r=n.tickets.filter(u=>n.selectedIds.has(u.id));await b(r,{ids:o,action:"status",value:"backlog"},"Move to backlog"),n.selectedIds.clear(),m()}},{label:"Archive",key:"a",action:async()=>{let o=Array.from(n.selectedIds),r=n.tickets.filter(u=>n.selectedIds.has(u.id));await b(r,{ids:o,action:"status",value:"archive"},"Archive"),n.selectedIds.clear(),m()}}]);document.body.appendChild(l),$(l,i),l.style.visibility=""}),document.getElementById("batch-select-all").addEventListener("change",a=>{if(a.target.checked)for(let o of n.tickets)n.selectedIds.add(o.id);else n.selectedIds.clear();v()})}var L=null;function jt(){document.getElementById("detail-close").addEventListener("click",Ee);let e=["detail-title","detail-details"];for(let s of e){let i=document.getElementById(s);i.addEventListener("input",()=>{let a=n.tickets.find(l=>l.id===n.activeTicketId);if(a){let l=s.replace("detail-","");G(a,l,i.value)}L&&clearTimeout(L),L=setTimeout(()=>{if(n.activeTicketId==null)return;let l=s.replace("detail-","");p(`/tickets/${n.activeTicketId}`,{method:"PATCH",body:{[l]:i.value}}).then(()=>{m()})},300)})}let t=["detail-category","detail-priority","detail-status"];for(let s of t){let i=document.getElementById(s);i.addEventListener("change",async()=>{if(n.activeTicketId==null)return;let a=n.tickets.find(o=>o.id===n.activeTicketId),l=s.replace("detail-","");a?await T(a,{[l]:i.value},`Change ${l}`):await p(`/tickets/${n.activeTicketId}`,{method:"PATCH",body:{[l]:i.value}}),m()})}document.getElementById("detail-upnext").addEventListener("change",async()=>{if(n.activeTicketId==null)return;let s=n.tickets.find(a=>a.id===n.activeTicketId),i=document.getElementById("detail-upnext");s?i.checked&&(s.status==="completed"||s.status==="verified")?await T(s,{status:"not_started",up_next:!0},"Toggle up next"):await T(s,{up_next:!s.up_next},"Toggle up next"):await p(`/tickets/${n.activeTicketId}/up-next`,{method:"POST"}),m(),W(n.activeTicketId)}),document.getElementById("detail-file-input").addEventListener("change",async s=>{let i=s.target,a=i.files?.[0];!a||n.activeTicketId==null||(await ke(`/tickets/${n.activeTicketId}/attachments`,a),i.value="",W(n.activeTicketId),m())}),document.getElementById("detail-attachments").addEventListener("click",async s=>{let i=s.target,a=i.closest(".attachment-reveal");if(a){let r=a.dataset.attId;r&&p(`/attachments/${r}/reveal`,{method:"POST"});return}let l=i.closest(".attachment-delete");if(l===null)return;let o=l.dataset.attId;o===void 0||o===""||(await p(`/attachments/${o}`,{method:"DELETE"}),n.activeTicketId!=null&&W(n.activeTicketId))})}function Wt(e){if(!e||e==="")return[];try{let t=JSON.parse(e);if(Array.isArray(t))return t}catch{}return e.trim()?[{text:e,created_at:""}]:[]}function Jt(e){let t=[];t.push(`${e.ticket_number}: ${e.title}`),e.details.trim()&&(t.push(""),t.push(e.details.trim()));let s=Wt(e.notes);if(s.length>0){t.push("");for(let i of s)t.push(`- ${i.text}`)}return t.join(`
|
|
2
|
-
|
|
1
|
+
"use strict";(()=>{var an=Object.defineProperty;var sn=(e,t,n)=>t in e?an(e,t,{enumerable:!0,configurable:!0,writable:!0,value:n}):e[t]=n;var ce=(e,t,n)=>sn(e,typeof t!="symbol"?t+"":t,n);var Me=!1;function H(){Me=!0}function lt(){let e=new Map;return document.querySelectorAll(".ticket-row[data-id], .column-card[data-id]").forEach(t=>{let n=t.dataset.id;e.set(n,t.getBoundingClientRect())}),e}function he(e){if(Me){Me=!1;return}e.size!==0&&document.querySelectorAll(".ticket-row[data-id], .column-card[data-id]").forEach(t=>{let n=t,s=n.dataset.id,o=e.get(s);if(!o)return;let i=n.getBoundingClientRect(),l=o.left-i.left,c=o.top-i.top;if(Math.abs(l)<1&&Math.abs(c)<1)return;n.style.transform=`translate(${l}px, ${c}px)`,n.offsetHeight,n.style.transition="transform 200ms ease-out",n.style.transform="";let u=()=>{n.style.transition=""};n.addEventListener("transitionend",u,{once:!0}),setTimeout(u,250)})}function v(e){let t=document.createElement("template");return t.innerHTML=e.toString(),t.content.firstElementChild}function ct(e){return e.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""")}function dt(e){return e.replace(/&/g,"&").replace(/"/g,""").replace(/'/g,"'").replace(/</g,"<").replace(/>/g,">")}var j=class{constructor(t){ce(this,"__html");this.__html=t}toString(){return this.__html}};function D(e){return new j(e)}var on=new Set(["area","base","br","col","embed","hr","img","input","link","meta","source","track","wbr"]);function Ne(e){return e==null||typeof e=="boolean"?"":e instanceof j?e.__html:typeof e=="string"?ct(e):typeof e=="number"?String(e):Array.isArray(e)?e.map(Ne).join(""):""}var rn={className:"class",htmlFor:"for",httpEquiv:"http-equiv",acceptCharset:"accept-charset",accessKey:"accesskey",autoCapitalize:"autocapitalize",autoComplete:"autocomplete",autoFocus:"autofocus",autoPlay:"autoplay",colSpan:"colspan",contentEditable:"contenteditable",crossOrigin:"crossorigin",dateTime:"datetime",defaultChecked:"checked",defaultValue:"value",encType:"enctype",formAction:"formaction",formEncType:"formenctype",formMethod:"formmethod",formNoValidate:"formnovalidate",formTarget:"formtarget",hrefLang:"hreflang",inputMode:"inputmode",maxLength:"maxlength",minLength:"minlength",noModule:"nomodule",noValidate:"novalidate",readOnly:"readonly",referrerPolicy:"referrerpolicy",rowSpan:"rowspan",spellCheck:"spellcheck",srcDoc:"srcdoc",srcLang:"srclang",srcSet:"srcset",tabIndex:"tabindex",useMap:"usemap",strokeWidth:"stroke-width",strokeLinecap:"stroke-linecap",strokeLinejoin:"stroke-linejoin",strokeDasharray:"stroke-dasharray",strokeDashoffset:"stroke-dashoffset",strokeMiterlimit:"stroke-miterlimit",strokeOpacity:"stroke-opacity",fillOpacity:"fill-opacity",fillRule:"fill-rule",clipPath:"clip-path",clipRule:"clip-rule",colorInterpolation:"color-interpolation",colorInterpolationFilters:"color-interpolation-filters",floodColor:"flood-color",floodOpacity:"flood-opacity",lightingColor:"lighting-color",stopColor:"stop-color",stopOpacity:"stop-opacity",shapeRendering:"shape-rendering",imageRendering:"image-rendering",textRendering:"text-rendering",pointerEvents:"pointer-events",vectorEffect:"vector-effect",paintOrder:"paint-order",fontFamily:"font-family",fontSize:"font-size",fontStyle:"font-style",fontVariant:"font-variant",fontWeight:"font-weight",fontStretch:"font-stretch",textAnchor:"text-anchor",textDecoration:"text-decoration",dominantBaseline:"dominant-baseline",alignmentBaseline:"alignment-baseline",baselineShift:"baseline-shift",letterSpacing:"letter-spacing",wordSpacing:"word-spacing",writingMode:"writing-mode",glyphOrientationHorizontal:"glyph-orientation-horizontal",glyphOrientationVertical:"glyph-orientation-vertical",markerStart:"marker-start",markerMid:"marker-mid",markerEnd:"marker-end",gradientUnits:"gradientUnits",gradientTransform:"gradientTransform",spreadMethod:"spreadMethod",patternUnits:"patternUnits",patternContentUnits:"patternContentUnits",patternTransform:"patternTransform",maskUnits:"maskUnits",maskContentUnits:"maskContentUnits",filterUnits:"filterUnits",primitiveUnits:"primitiveUnits",clipPathUnits:"clipPathUnits",xlinkHref:"xlink:href",xlinkShow:"xlink:show",xlinkActuate:"xlink:actuate",xlinkType:"xlink:type",xlinkRole:"xlink:role",xlinkTitle:"xlink:title",xlinkArcrole:"xlink:arcrole",xmlBase:"xml:base",xmlLang:"xml:lang",xmlSpace:"xml:space",xmlns:"xmlns",xmlnsXlink:"xmlns:xlink",stdDeviation:"stdDeviation",baseFrequency:"baseFrequency",numOctaves:"numOctaves",kernelMatrix:"kernelMatrix",surfaceScale:"surfaceScale",specularConstant:"specularConstant",specularExponent:"specularExponent",diffuseConstant:"diffuseConstant",pointsAtX:"pointsAtX",pointsAtY:"pointsAtY",pointsAtZ:"pointsAtZ",limitingConeAngle:"limitingConeAngle",tableValues:"tableValues"};function ln(e,t){let n=rn[e]??e;if(t==null||t===!1)return"";if(t===!0)return` ${n}`;let s;return t instanceof j?s=t.__html:typeof t=="number"?s=String(t):typeof t=="string"?s=dt(t):s="",` ${n}="${s}"`}function r(e,t){if(typeof e=="function")return e(t);let{children:n,...s}=t,o=Object.entries(s).map(([l,c])=>ln(l,c)).join("");if(on.has(e))return new j(`<${e}${o}>`);let i=n!=null?Ne(n):"";return new j(`<${e}${o}>${i}</${e}>`)}function de({children:e}){return new j(e!=null?Ne(e):"")}function ut(e){document.getElementById("network-error-popup")?.remove();let t=v(r("div",{id:"network-error-popup",className:"error-popup",children:r("div",{className:"error-popup-content",children:[r("strong",{children:"Connection Error"}),r("p",{children:e}),r("button",{children:"Dismiss"})]})}));t.querySelector("button").addEventListener("click",()=>t.remove()),document.body.appendChild(t)}async function y(e,t={}){try{return(await fetch("/api"+e,{headers:t.body!==void 0?{"Content-Type":"application/json"}:{},method:t.method,body:t.body!==void 0?JSON.stringify(t.body):void 0})).json()}catch(n){throw ut("Unable to reach the server. It may have been stopped."),n}}async function pt(e,t){try{let n=new FormData;return n.append("file",t),(await fetch("/api"+e,{method:"POST",body:n})).json()}catch(n){throw ut("Unable to reach the server. It may have been stopped."),n}}var cn={detail_position:"side",detail_width:360,detail_height:300,trash_cleanup_days:3,verified_cleanup_days:30},a={tickets:[],customViews:[],categories:[{id:"issue",label:"Issue",shortLabel:"ISS",color:"#6b7280",shortcutKey:"i",description:""},{id:"bug",label:"Bug",shortLabel:"BUG",color:"#ef4444",shortcutKey:"b",description:""},{id:"feature",label:"Feature",shortLabel:"FEA",color:"#22c55e",shortcutKey:"f",description:""},{id:"requirement_change",label:"Req Change",shortLabel:"REQ",color:"#f97316",shortcutKey:"r",description:""},{id:"task",label:"Task",shortLabel:"TSK",color:"#3b82f6",shortcutKey:"k",description:""},{id:"investigation",label:"Investigation",shortLabel:"INV",color:"#8b5cf6",shortcutKey:"g",description:""}],selectedIds:new Set,lastClickedId:null,activeTicketId:null,view:"all",layout:"list",sortBy:"created",sortDir:"desc",search:"",settings:{...cn},backupPreview:null},dn='<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="#9ca3af" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 2v20"/><path d="m8 18 4 4 4-4"/><path d="m8 6 4-4 4 4"/></svg>',un={highest:"\u2B06\u2B06",high:"\u2B06",default:dn,low:"\u2B07",lowest:"\u2B07\u2B07"},pn={highest:"#ef4444",high:"#f97316",default:"#6b7280",low:"#3b82f6",lowest:"#94a3b8"},mt='<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 6 7 17l-5-5"/><path d="m22 10-7.5 7.5L13 16"/></svg>',mn={not_started:"\u25CB",started:"\u25D4",completed:"\u2713",verified:mt,backlog:"\u25A1",archive:"\u25A0"},_e=mt;function I(e){return a.categories.find(n=>n.id===e)?.color||"#6b7280"}function K(e){return a.categories.find(n=>n.id===e)?.shortLabel||e.slice(0,3).toUpperCase()}function A(e){return un[e]||"\u2014"}function P(e){return pn[e]||"#6b7280"}function z(e){return mn[e]||"\u25CB"}function O(e){if(!e||e==="[]")return[];try{let t=JSON.parse(e);if(Array.isArray(t))return t.filter(n=>typeof n=="string"&&n.trim())}catch{}return[]}function ue(e,t){let n=document.getElementById("detail-tags");n.innerHTML="";for(let s of e){let o=v(r("span",{className:"tag-chip",children:[s,t?null:r("button",{className:"tag-chip-remove","data-tag":s,title:"Remove tag",children:"\xD7"})]}));t||o.querySelector(".tag-chip-remove").addEventListener("click",async()=>{if(a.activeTicketId==null)return;let i=a.tickets.find(u=>u.id===a.activeTicketId);if(!i)return;let c=O(i.tags).filter(u=>u!==s);await y(`/tickets/${a.activeTicketId}`,{method:"PATCH",body:{tags:JSON.stringify(c)}}),i.tags=JSON.stringify(c),ue(c,!1)}),n.appendChild(o)}}var gn={not_started:"Not Started",started:"Started",completed:"Completed",verified:"Verified",backlog:"Backlog",archive:"Archive"},fn={highest:"Highest",high:"High",default:"Default",low:"Low",lowest:"Lowest"};function pe(e){let t=document.getElementById("detail-category");t.dataset.value=e;let n=a.categories.find(o=>o.id===e),s=I(e);t.innerHTML=`<span class="cat-dot" style="background:${s}"></span> ${n?.label||e}`}function be(e){let t=document.getElementById("detail-priority");t.dataset.value=e,t.innerHTML=`<span class="dropdown-icon" style="color:${P(e)}">${A(e)}</span> ${fn[e]||e}`}function ke(e){let t=document.getElementById("detail-status");t.dataset.value=e,t.innerHTML=`<span class="dropdown-icon">${z(e)}</span> ${gn[e]||e}`}function ee(e){a.activeTicketId=e,He(e)}function ft(){a.selectedIds.clear(),a.activeTicketId=null,te();let e=new CustomEvent("hotsheet:render");document.dispatchEvent(e)}function te(){let e=a.view==="trash",t=!!a.backupPreview?.active,n=document.getElementById("detail-panel"),s=document.getElementById("detail-resize-handle"),o=document.getElementById("detail-header"),i=document.getElementById("detail-body"),l=document.getElementById("detail-placeholder"),c=document.getElementById("detail-placeholder-text");if(e){n.style.display="none",s&&(s.style.display="none"),a.activeTicketId=null;return}if(n.style.display="flex",s&&(s.style.display=""),a.selectedIds.size===1){let u=Array.from(a.selectedIds)[0];n.classList.remove("detail-disabled"),o.style.display="",i.style.display="",l.style.display="none",a.activeTicketId!==u&&(a.activeTicketId=u,t?yn(u):He(u))}else a.activeTicketId=null,n.classList.add("detail-disabled"),o.style.display="none",i.style.display="none",l.style.display="",a.selectedIds.size===0?c.textContent="Nothing selected":c.textContent=`${a.selectedIds.size} items selected`}function yt(e){let t=document.getElementById("detail-title"),n=document.getElementById("detail-details"),s=document.getElementById("detail-category"),o=document.getElementById("detail-priority"),i=document.getElementById("detail-status"),l=document.getElementById("detail-upnext"),c=document.querySelector(".upload-btn");t.readOnly=e,n.readOnly=e,s.disabled=e,o.disabled=e,i.disabled=e,l.disabled=e,c&&(c.style.display=e?"none":"")}function yn(e){let t=a.backupPreview?.tickets.find(l=>l.id===e);if(!t||a.activeTicketId!==e)return;document.getElementById("detail-ticket-number").textContent=t.ticket_number,document.getElementById("detail-title").value=t.title,pe(t.category),be(t.priority),ke(t.status);let n=document.getElementById("detail-upnext");n.textContent=t.up_next?"\u2605":"\u2606",n.classList.toggle("active",t.up_next),document.getElementById("detail-details").value=t.details,yt(!0),document.getElementById("detail-attachments").innerHTML="",ue(O(t.tags),!0);let s=document.getElementById("detail-notes"),o=vt(t.notes);o.length>0?s.innerHTML=r(de,{children:o.map(l=>r("div",{className:"note-entry",children:[l.created_at?r("div",{className:"note-timestamp",children:new Date(l.created_at).toLocaleString()}):null,r("div",{className:"note-text",children:l.text})]}))}).toString():s.innerHTML="";let i=document.getElementById("detail-meta");i.innerHTML=r(de,{children:[r("div",{children:["Created: ",new Date(t.created_at).toLocaleString()]}),r("div",{children:["Updated: ",new Date(t.updated_at).toLocaleString()]}),t.completed_at?r("div",{children:["Completed: ",new Date(t.completed_at).toLocaleString()]}):null,t.verified_at?r("div",{children:["Verified: ",new Date(t.verified_at).toLocaleString()]}):null]}).toString()}function me(){a.activeTicketId!=null&&He(a.activeTicketId)}async function He(e){let t=await y(`/tickets/${e}`);if(a.activeTicketId!==e)return;yt(!1),document.getElementById("detail-ticket-number").textContent=t.ticket_number,document.getElementById("detail-title").value=t.title,pe(t.category),be(t.priority),ke(t.status);let n=document.getElementById("detail-upnext");n.textContent=t.up_next?"\u2605":"\u2606",n.classList.toggle("active",t.up_next),document.getElementById("detail-details").value=t.details;let s=document.getElementById("detail-attachments");t.attachments.length>0?s.innerHTML=r(de,{children:t.attachments.map(i=>r("div",{className:"attachment-item",children:[r("span",{className:"attachment-name",children:i.original_filename}),r("button",{className:"attachment-reveal","data-att-id":String(i.id),title:"Show in file manager",children:r("svg",{xmlns:"http://www.w3.org/2000/svg",width:"12",height:"12",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",children:r("path",{d:"M22 19a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h5l2 3h9a2 2 0 0 1 2 2z"})})}),r("button",{className:"attachment-delete","data-att-id":String(i.id),title:"Remove",children:"\xD7"})]}))}).toString():s.innerHTML="",ue(O(t.tags),!1),Be(t.id,vt(t.notes));let o=document.getElementById("detail-meta");o.innerHTML=r(de,{children:[r("div",{children:["Created: ",new Date(t.created_at).toLocaleString()]}),r("div",{children:["Updated: ",new Date(t.updated_at).toLocaleString()]}),t.completed_at?r("div",{children:["Completed: ",new Date(t.completed_at).toLocaleString()]}):null,t.verified_at?r("div",{children:["Verified: ",new Date(t.verified_at).toLocaleString()]}):null]}).toString()}function Be(e,t){let n=document.getElementById("detail-notes");if(n.innerHTML="",t.length===0){n.innerHTML='<div class="notes-empty">No notes added</div>';return}for(let s of t){let o=v(r("div",{className:"note-entry",children:[s.created_at?r("div",{className:"note-timestamp",children:new Date(s.created_at).toLocaleString()}):null,r("div",{className:"note-text",children:s.text})]}));o.addEventListener("click",()=>{let i=o.querySelector(".note-text");if(o.querySelector(".note-edit-area"))return;let l=document.createElement("textarea");l.className="note-edit-area",l.value=s.text,l.rows=3,i.style.display="none",o.appendChild(l),l.focus();let c=async()=>{let u=l.value.trim();u&&u!==s.text&&(await y(`/tickets/${e}/notes/${s.id}`,{method:"PATCH",body:{text:u}}),s.text=u),Be(e,t)};l.addEventListener("blur",()=>{c()}),l.addEventListener("keydown",u=>{u.key==="Enter"&&(u.metaKey||u.ctrlKey)&&(u.preventDefault(),c()),u.key==="Escape"&&(u.stopPropagation(),l.blur())})}),o.addEventListener("contextmenu",i=>{i.preventDefault(),document.querySelectorAll(".note-context-menu").forEach(c=>c.remove());let l=v(r("div",{className:"note-context-menu context-menu",style:`top:${i.clientY}px;left:${i.clientX}px`,children:r("div",{className:"context-menu-item danger",children:r("span",{className:"context-menu-label",children:"Delete Note"})})}));l.querySelector(".context-menu-item").addEventListener("click",async c=>{c.stopPropagation(),l.remove(),await y(`/tickets/${e}/notes/${s.id}`,{method:"DELETE"});let u=t.indexOf(s);u>=0&&t.splice(u,1),Be(e,t)}),document.body.appendChild(l),setTimeout(()=>{let c=()=>{l.remove(),document.removeEventListener("click",c)};document.addEventListener("click",c)},0)}),n.appendChild(o)}}var vn=0;function gt(){return`cn_${Date.now().toString(36)}_${(vn++).toString(36)}`}function vt(e){if(!e||e==="")return[];try{let t=JSON.parse(e);if(Array.isArray(t))return t.map(n=>({id:n.id||gt(),text:n.text,created_at:n.created_at}))}catch{}return e.trim()?[{id:gt(),text:e,created_at:""}]:[]}async function we(){try{let e=await y("/stats"),t=document.getElementById("status-bar");t&&(t.textContent=`${e.total} tickets \xB7 ${e.open} open \xB7 ${e.up_next} up next`)}catch{}}function De(e){let t=document.getElementById("content-area");t.classList.remove("detail-side","detail-bottom"),t.classList.add(e==="bottom"?"detail-bottom":"detail-side")}function Ae(){let e=document.getElementById("detail-panel");a.settings.detail_position==="bottom"?(e.style.width="",e.style.height=`${a.settings.detail_height}px`):(e.style.height="",e.style.width=`${a.settings.detail_width}px`)}function ht(){let e=document.getElementById("detail-resize-handle"),t=document.getElementById("detail-panel"),n=document.getElementById("content-area"),s=!1;e.addEventListener("mousedown",o=>{o.preventDefault(),s=!0,document.body.style.cursor=a.settings.detail_position==="bottom"?"row-resize":"col-resize",document.body.style.userSelect="none"}),document.addEventListener("mousemove",o=>{if(!s)return;let i=n.getBoundingClientRect();if(a.settings.detail_position==="bottom"){let l=Math.max(150,Math.min(500,i.bottom-o.clientY));a.settings.detail_height=l,t.style.height=`${l}px`}else{let l=Math.max(250,Math.min(600,i.right-o.clientX));a.settings.detail_width=l,t.style.width=`${l}px`}}),document.addEventListener("mouseup",()=>{s&&(s=!1,document.body.style.cursor="",document.body.style.userSelect="",a.settings.detail_position==="bottom"?y("/settings",{method:"PATCH",body:{detail_height:String(a.settings.detail_height)}}):y("/settings",{method:"PATCH",body:{detail_width:String(a.settings.detail_width)}}))})}var Pe=class{constructor(){ce(this,"undoStack",[]);ce(this,"redoStack",[])}push(t){console.log("[undo] push:",t.label,"stack depth:",this.undoStack.length+1,"before:",JSON.stringify(t.before),"after:",JSON.stringify(t.after)),this.undoStack.push(t),this.undoStack.length>1e3&&this.undoStack.shift(),this.redoStack=[]}coalesce(t){if(t.coalescingKey==null||t.coalescingKey==="")return!1;let n=this.peekUndo();return!n||n.coalescingKey!==t.coalescingKey||t.timestamp-n.timestamp>=5e3?!1:(n.after=t.after,!0)}popUndo(){let t=this.undoStack.pop();return t&&this.redoStack.push(t),t}popRedo(){let t=this.redoStack.pop();return t&&this.undoStack.push(t),t}peekUndo(){return this.undoStack[this.undoStack.length-1]}canUndo(){return this.undoStack.length>0}canRedo(){return this.redoStack.length>0}},$=new Pe;function Y(e){return{id:e.id,title:e.title,details:e.details,category:e.category,priority:e.priority,status:e.status,up_next:e.up_next}}async function R(e,t,n){let s=Y(e),o=await y(`/tickets/${e.id}`,{method:"PATCH",body:t}),i=Y(o);return $.push({label:n,timestamp:Date.now(),before:[s],after:[i]}),o}function Ee(e,t,n){let s=`${e.id}:${t}`,o=Date.now(),i={...Y(e),[t]:n},l={label:`Edit ${t}`,timestamp:o,before:[Y(e)],after:[i],coalescingKey:s};$.coalesce(l)||$.push(l)}async function C(e,t,n){let s=e.map(Y);await y("/tickets/batch",{method:"POST",body:t});let o=s.map(i=>{let l={...i};return t.action==="category"?l.category=t.value:t.action==="priority"?l.priority=t.value:t.action==="status"?l.status=t.value:t.action==="up_next"?l.up_next=t.value:t.action==="delete"&&(l.status="deleted"),l});$.push({label:n,timestamp:Date.now(),before:s,after:o})}async function Re(e,t,n){let s=e.map(Y);for(let i of t)await y("/tickets/batch",{method:"POST",body:i});let o=s.map(i=>{let l={...i};for(let c of t)c.ids.includes(i.id)&&(c.action==="status"?l.status=c.value:c.action==="up_next"?l.up_next=c.value:c.action==="category"?l.category=c.value:c.action==="priority"?l.priority=c.value:c.action==="delete"&&(l.status="deleted"));return l});$.push({label:n,timestamp:Date.now(),before:s,after:o})}async function xe(e){let t=Y(e);await y(`/tickets/${e.id}`,{method:"DELETE"});let n={...t,status:"deleted"};$.push({label:"Delete ticket",timestamp:Date.now(),before:[t],after:[n]})}async function bt(e){let t=Y(e);await y(`/tickets/${e.id}/restore`,{method:"POST"});let n={...t,status:"not_started"};$.push({label:"Restore ticket",timestamp:Date.now(),before:[t],after:[n]})}async function kt(e){for(let t of e)t.status==="deleted"?await y(`/tickets/${t.id}`,{method:"DELETE"}):await y(`/tickets/${t.id}`,{method:"PATCH",body:{title:t.title,details:t.details,category:t.category,priority:t.priority,status:t.status,up_next:t.up_next}})}var J=!1;async function wt(){if(console.log("[undo] performUndo, inFlight:",J,"canUndo:",$.canUndo()),J){console.log("[undo] skipped \u2014 already in flight");return}let e=$.popUndo();if(!e){console.log("[undo] skipped \u2014 stack empty");return}console.log("[undo] applying before-state:",e.label,JSON.stringify(e.before)),J=!0;try{await kt(e.before),console.log("[undo] applySnapshots done, reloading tickets"),await w(),me()}finally{J=!1}}async function Et(){if(console.log("[undo] performRedo, inFlight:",J,"canRedo:",$.canRedo()),J){console.log("[undo] skipped \u2014 already in flight");return}let e=$.popRedo();if(!e){console.log("[undo] skipped \u2014 stack empty");return}console.log("[undo] applying after-state:",e.label,JSON.stringify(e.after)),J=!0;try{await kt(e.after),console.log("[undo] applySnapshots done, reloading tickets"),await w(),me()}finally{J=!1}}function xt(){return $.canUndo()}function Tt(){return $.canRedo()}function Ve(e,t){e.preventDefault(),X(),a.selectedIds.has(t.id)||(a.selectedIds.clear(),a.selectedIds.add(t.id),a.lastClickedId=t.id,L());let n=v(r("div",{className:"context-menu",style:`top:${e.clientY}px;left:${e.clientX}px`}));qe(n,"Category",a.categories.map(i=>({label:i.label,icon:`<span class="dropdown-dot" style="background-color:${i.color}"></span>`,active:t.category===i.id,action:()=>ne("category",i.id)}))),qe(n,"Priority",[{value:"highest",label:"Highest"},{value:"high",label:"High"},{value:"default",label:"Default"},{value:"low",label:"Low"},{value:"lowest",label:"Lowest"}].map(i=>({label:i.label,icon:A(i.value),iconColor:P(i.value),active:t.priority===i.value,action:()=>ne("priority",i.value)}))),qe(n,"Status",[{value:"not_started",label:"Not Started"},{value:"started",label:"Started"},{value:"completed",label:"Completed"},{value:"verified",label:"Verified"}].map(i=>({label:i.label,icon:z(i.value),active:t.status===i.value,action:()=>ne("status",i.value)}))),ae(n,t.up_next?"\u2605 Up Next":"\u2606 Up Next",()=>{ne("up_next",!t.up_next)}),Ue(n),ae(n,"Tags...",()=>{document.dispatchEvent(new CustomEvent("hotsheet:show-tags-dialog"))}),ae(n,"Duplicate",async()=>{let i=Array.from(a.selectedIds),l=await y("/tickets/duplicate",{method:"POST",body:{ids:i}});a.selectedIds.clear();for(let c of l)a.selectedIds.add(c.id);w()}),Ue(n),ae(n,"Move to Backlog",()=>ne("status","backlog")),ae(n,"Archive",()=>ne("status","archive")),Ue(n),ae(n,"Delete",async()=>{if(a.selectedIds.size===1)await xe(t);else{let i=Array.from(a.selectedIds),l=a.tickets.filter(c=>a.selectedIds.has(c.id));await C(l,{ids:i,action:"delete"},"Delete")}a.selectedIds.clear(),w()},!0),document.body.appendChild(n),hn(n),setTimeout(()=>{document.addEventListener("click",X),document.addEventListener("contextmenu",X)},0)}function X(){document.querySelectorAll(".context-menu").forEach(e=>e.remove()),document.removeEventListener("click",X),document.removeEventListener("contextmenu",X)}function hn(e){let t=e.getBoundingClientRect();t.right>window.innerWidth-8&&(e.style.left=`${window.innerWidth-t.width-8}px`),t.bottom>window.innerHeight-8&&(e.style.top=`${window.innerHeight-t.height-8}px`)}async function ne(e,t){let n=Array.from(a.selectedIds),s=a.tickets.filter(o=>a.selectedIds.has(o.id));if(n.length===1){let o=s[0];await R(o,{[e]:t},`Change ${e}`)}else await C(s,{ids:n,action:e,value:t},`Change ${e}`);w()}function qe(e,t,n){let s=v(r("div",{className:"context-menu-item has-submenu",children:[r("span",{className:"context-menu-label",children:t}),r("span",{className:"context-menu-arrow",children:"\u25B8"})]})),o=v(r("div",{className:"context-submenu"}));for(let i of n){let l=v(r("div",{className:`context-menu-item${i.active?" active":""}`,children:[i.icon?r("span",{className:"dropdown-icon",style:i.iconColor?`color:${i.iconColor}`:"",children:D(i.icon)}):null,r("span",{className:"context-menu-label",children:i.label})]}));l.addEventListener("click",c=>{c.stopPropagation(),i.action(),X()}),o.appendChild(l)}s.appendChild(o),e.appendChild(s)}function ae(e,t,n,s=!1){let o=v(r("div",{className:`context-menu-item${s?" danger":""}`,children:r("span",{className:"context-menu-label",children:t})}));o.addEventListener("click",i=>{i.stopPropagation(),X(),n()}),e.appendChild(o)}function Ue(e){e.appendChild(v(r("div",{className:"context-menu-separator"})))}function M(e,t){let n=t.getBoundingClientRect(),s=e.getBoundingClientRect(),o=window.innerWidth,i=window.innerHeight,l=n.left;l+s.width>o-8&&(l=n.right-s.width),l<8&&(l=8);let c=n.bottom+4;c+s.height>i-8&&(c=n.top-s.height-4),c<8&&(c=8),e.style.left=`${l}px`,e.style.top=`${c}px`}function N(e,t){let n=v(r("div",{className:"dropdown-menu",style:"visibility:hidden;top:0;left:0",children:t.map(u=>u.separator?r("div",{className:"dropdown-separator"}):r("button",{className:`dropdown-item${u.active?" active":""}`,"data-key":u.key,children:[u.color?r("span",{className:"dropdown-dot",style:`background-color:${u.color}`}):null,u.icon?r("span",{className:"dropdown-icon",style:u.iconColor?`color:${u.iconColor}`:"",children:D(u.icon)}):null,r("span",{className:"dropdown-label",children:u.label}),u.shortcut?r("kbd",{className:"dropdown-kbd",children:u.shortcut}):null]}))})),s=t.filter(u=>!u.separator);n.querySelectorAll(".dropdown-item").forEach((u,d)=>{u.addEventListener("click",()=>{s[d].action(),n.remove()})});function i(u){let d=t.find(p=>u.key.toLowerCase()===p.key.toLowerCase());d?(u.preventDefault(),u.stopPropagation(),d.action(),l()):u.key==="Escape"&&(u.preventDefault(),l())}function l(){n.remove(),document.removeEventListener("keydown",i,!0),document.removeEventListener("click",c)}function c(){l()}return document.addEventListener("keydown",i,!0),setTimeout(()=>{document.addEventListener("click",c)},0),n}function _(){document.querySelectorAll(".dropdown-menu").forEach(e=>{e.remove()})}var se=null;function ze(){se&&(clearTimeout(se),se=null)}var ge=!1,fe=null,Oe="",U=[];function Te(){return a.categories.map(e=>({key:e.shortcutKey,value:e.id,label:e.label}))}var Ke=[{key:"1",value:"highest",label:"Highest"},{key:"2",value:"high",label:"High"},{key:"3",value:"default",label:"Default"},{key:"4",value:"low",label:"Low"},{key:"5",value:"lowest",label:"Lowest"}];function bn(){let e=document.activeElement;if(!e||!(e instanceof HTMLElement))return null;let t=e.closest(".ticket-row");if(!t)return null;if(t.classList.contains("draft-row"))return"draft";let n=t.dataset.id;return n!==void 0&&n!==""?parseInt(n,10):null}function kn(e){e!=null&&(ge=!0,e==="draft"?F():document.querySelector(`.ticket-row[data-id="${e}"] .ticket-title-input`)?.focus(),ge=!1)}function Le(){let e=a.view;return e.startsWith("custom:")?!0:e!=="completed"&&e!=="verified"&&e!=="trash"&&e!=="backlog"&&e!=="archive"}function Ct(){return a.view==="up-next"||a.view==="open"?[{status:"not_started",label:"Not Started"},{status:"started",label:"Started"}]:a.view==="non-verified"?[{status:"not_started",label:"Not Started"},{status:"started",label:"Started"},{status:"completed",label:"Completed"}]:[{status:"not_started",label:"Not Started"},{status:"started",label:"Started"},{status:"completed",label:"Completed"},{status:"verified",label:"Verified"}]}function L(){let e=lt(),t=!!a.backupPreview?.active;if(a.layout==="columns"&&Le()){if(t){En(),he(e);return}Tn(),he(e);return}let n=a.view==="trash",s=t?null:bn(),o=null;if(s!=null&&s!=="draft"){let c=document.querySelector(`.ticket-row[data-id="${s}"] .ticket-title-input`);c&&(o=c.value)}let i=document.getElementById("ticket-list"),l=i.scrollTop;if(i.innerHTML="",i.classList.remove("ticket-list-columns"),!n&&!t&&i.appendChild(Nt()),a.tickets.length===0){let c=n?"Trash is empty":t?"No tickets match this view":"";c&&i.appendChild(v(r("div",{className:"ticket-list-empty",children:c})))}for(let c of a.tickets)t?i.appendChild(wn(c)):n?i.appendChild($n(c)):i.appendChild(Sn(c));if(i.scrollTop=l,t){let c=document.getElementById("batch-toolbar");c&&(c.style.display="none"),ye(),te()}else{let c=document.getElementById("batch-toolbar");if(c&&(c.style.display=""),s!=null&&s!=="draft"&&o!=null){let u=document.querySelector(`.ticket-row[data-id="${s}"] .ticket-title-input`);u&&u.value!==o&&(u.value=o)}kn(s),oe()}we(),he(e)}function wn(e){let t=a.selectedIds.has(e.id),n=e.status==="completed"||e.status==="verified",s=e.status==="verified",o=v(r("div",{className:`ticket-row${t?" selected":""}${n?" completed":""}${e.up_next?" up-next":""}`,"data-id":String(e.id),children:[r("span",{className:"ticket-checkbox-spacer"}),r("span",{className:"ticket-category-badge",style:`background-color:${I(e.category)};cursor:default`,title:e.category,children:K(e.category)}),r("span",{className:"ticket-number",children:e.ticket_number}),r("span",{className:`ticket-status-btn${s?" verified":""}`,style:"cursor:default",children:D(s?_e:z(e.status))}),r("span",{className:"ticket-title-input",style:"cursor:default",children:e.title}),r("span",{className:"ticket-priority-indicator",style:`color:${P(e.priority)};cursor:default`,title:e.priority,children:D(A(e.priority))}),r("span",{className:`ticket-star${e.up_next?" active":""}`,style:"cursor:default",children:e.up_next?"\u2605":"\u2606"})]}));return o.addEventListener("click",()=>{a.selectedIds.clear(),a.selectedIds.add(e.id),a.lastClickedId=e.id,ye(),te()}),o}function St(e){let t={scrollLeft:0,columns:{}},n=e.querySelector(".columns-container");return n&&(t.scrollLeft=n.scrollLeft,n.querySelectorAll(".column[data-status]").forEach(s=>{let o=s.dataset.status,i=s.querySelector(".column-body");i&&(t.columns[o]=i.scrollTop)})),t}function $t(e,t){let n=e.querySelector(".columns-container");n&&(n.scrollLeft=t.scrollLeft,n.querySelectorAll(".column[data-status]").forEach(s=>{let o=s.dataset.status,i=s.querySelector(".column-body");i&&t.columns[o]!=null&&(i.scrollTop=t.columns[o])}))}function En(){let e=document.getElementById("ticket-list"),t=St(e);e.innerHTML="",e.classList.add("ticket-list-columns");let n=Ct(),s=v(r("div",{className:"columns-container"}));for(let i of n){let l=a.tickets.filter(d=>d.status===i.status),c=v(r("div",{className:"column","data-status":i.status,children:[r("div",{className:"column-header",children:[r("span",{className:"column-title",children:i.label}),r("span",{className:"column-count",children:String(l.length)})]}),r("div",{className:"column-body"})]})),u=c.querySelector(".column-body");for(let d of l)u.appendChild(xn(d));s.appendChild(c)}e.appendChild(s),$t(e,t);let o=document.getElementById("batch-toolbar");o&&(o.style.display="none"),we()}function xn(e){let t=a.selectedIds.has(e.id),n=v(r("div",{className:`column-card${t?" selected":""}${e.up_next?" up-next":""}`,"data-id":String(e.id),children:[r("div",{className:"column-card-header",children:[r("span",{className:"ticket-category-badge",style:`background-color:${I(e.category)}`,children:K(e.category)}),r("span",{className:"ticket-number",children:e.ticket_number}),r("span",{className:"ticket-priority-indicator",style:`color:${P(e.priority)};cursor:default`,children:D(A(e.priority))}),r("span",{className:`ticket-star${e.up_next?" active":""}`,style:"cursor:default",children:e.up_next?"\u2605":"\u2606"})]}),r("div",{className:"column-card-title",children:e.title})]}));return n.addEventListener("click",()=>{a.selectedIds.clear(),a.selectedIds.add(e.id),a.lastClickedId=e.id,Mt(),te()}),n}function Tn(){let e=document.getElementById("ticket-list"),t=St(e);e.innerHTML="",e.classList.add("ticket-list-columns"),e.appendChild(Nt());let n=Ct(),s=v(r("div",{className:"columns-container"}));for(let o of n){let i=a.tickets.filter(u=>u.status===o.status),l=v(r("div",{className:"column","data-status":o.status,children:[r("div",{className:"column-header",children:[r("span",{className:"column-title",children:o.label}),r("span",{className:"column-count",children:String(i.length)})]}),r("div",{className:"column-body"})]})),c=l.querySelector(".column-body");for(let u of i)c.appendChild(Ln(u));c.addEventListener("dragover",u=>{u.preventDefault(),u.dataTransfer.dropEffect="move",l.classList.add("column-drop-target")}),c.addEventListener("dragleave",u=>{let d=u.relatedTarget;(!d||!c.contains(d))&&l.classList.remove("column-drop-target")}),c.addEventListener("drop",u=>{u.preventDefault(),l.classList.remove("column-drop-target");let d=U;if(U=[],d.length===0)return;let p=a.tickets.filter(m=>d.includes(m.id));H(),C(p,{ids:d,action:"status",value:o.status},"Change status").then(()=>{w()})}),s.appendChild(l)}e.appendChild(s),$t(e,t),oe(),we()}function Ln(e){let t=a.selectedIds.has(e.id),n=v(r("div",{className:`column-card${t?" selected":""}${e.up_next?" up-next":""}`,"data-id":String(e.id),children:[r("div",{className:"column-card-header",children:[r("span",{className:"ticket-category-badge",style:`background-color:${I(e.category)}`,children:K(e.category)}),r("span",{className:"ticket-number",children:e.ticket_number}),r("span",{className:"ticket-priority-indicator",style:`color:${P(e.priority)}`,children:D(A(e.priority))}),r("button",{className:`ticket-star${e.up_next?" active":""}`,title:e.up_next?"Remove from Up Next":"Add to Up Next",children:e.up_next?"\u2605":"\u2606"})]}),r("div",{className:"column-card-title",children:e.title})]})),s=n.querySelector(".ticket-category-badge");s.addEventListener("click",i=>{i.stopPropagation(),Dt(s,e)});let o=n.querySelector(".ticket-priority-indicator");return o.addEventListener("click",i=>{i.stopPropagation(),At(o,e)}),n.querySelector(".ticket-star").addEventListener("click",i=>{i.stopPropagation(),Ht(e)}),n.addEventListener("contextmenu",i=>{Ve(i,e)}),n.draggable=!0,n.addEventListener("dragstart",i=>{a.selectedIds.has(e.id)&&a.selectedIds.size>1?U=Array.from(a.selectedIds):U=[e.id],i.dataTransfer.setData("text/plain",JSON.stringify(U)),i.dataTransfer.effectAllowed="move"}),n.addEventListener("dragend",()=>{U=[]}),n.addEventListener("click",i=>{if(i.metaKey||i.ctrlKey)a.selectedIds.has(e.id)?a.selectedIds.delete(e.id):a.selectedIds.add(e.id),a.lastClickedId=e.id;else if(i.shiftKey&&a.lastClickedId!=null){let l=a.tickets.find(c=>c.id===a.lastClickedId);if(l&&l.status===e.status){let u=a.tickets.filter(m=>m.status===e.status).map(m=>m.id),d=u.indexOf(a.lastClickedId),p=u.indexOf(e.id);if(d!==-1&&p!==-1){let m=Math.min(d,p),g=Math.max(d,p);a.selectedIds.clear();for(let f=m;f<=g;f++)a.selectedIds.add(u[f])}}else a.selectedIds.clear(),a.selectedIds.add(e.id),a.lastClickedId=e.id}else a.selectedIds.clear(),a.selectedIds.add(e.id),a.lastClickedId=e.id;Mt(),oe()}),n}function Mt(){document.querySelectorAll(".column-card[data-id]").forEach(e=>{let t=parseInt(e.dataset.id,10);a.selectedIds.has(t)?e.classList.add("selected"):e.classList.remove("selected")})}function Nt(){let e=_t(),t=a.view.startsWith("category:"),n=v(r("div",{className:"ticket-row draft-row",children:[r("span",{className:"ticket-checkbox-spacer"}),r("span",{className:"ticket-status-btn draft-placeholder",children:"\u25CB"}),r("span",{className:"ticket-category-badge draft-badge",style:`background-color:${I(e)}${t?"":";cursor:pointer;opacity:1"}`,children:K(e)}),r("span",{className:"ticket-number draft-number"}),r("input",{type:"text",className:"ticket-title-input draft-input",placeholder:"New ticket...",value:Oe}),r("span",{className:"ticket-priority-indicator draft-placeholder"}),r("span",{className:"ticket-star draft-placeholder"})]}));if(!t){let o=n.querySelector(".ticket-category-badge");o.addEventListener("click",i=>{i.stopPropagation(),Cn(o)})}let s=n.querySelector(".draft-input");return s.addEventListener("input",()=>{Oe=s.value}),s.addEventListener("keydown",async o=>{if(o.key==="Enter"&&s.value.trim()){o.preventDefault();let i=s.value.trim();Oe="",s.value="";let l=In();fe&&!a.view.startsWith("category:")&&(l.category=fe);let c=await y("/tickets",{method:"POST",body:{title:i,defaults:l}});c&&(a.selectedIds.clear(),a.selectedIds.add(c.id)),await w(),F()}else o.key==="ArrowDown"&&(o.preventDefault(),a.tickets.length>0&&document.querySelector(`.ticket-row[data-id="${a.tickets[0].id}"] .ticket-title-input`)?.focus())}),n}function F(){document.querySelector(".draft-row .draft-input")?.focus()}function In(){let e=a.view;return e==="up-next"?{up_next:!0}:e==="open"?{}:e==="completed"?{status:"completed"}:e==="backlog"?{status:"backlog"}:e==="archive"?{status:"archive"}:e.startsWith("category:")?{category:e.split(":")[1]}:e.startsWith("priority:")?{priority:e.split(":")[1]}:{}}function _t(){if(fe)return fe;let e=a.view;return e.startsWith("category:")?e.split(":")[1]:"issue"}function Cn(e){_();let n=navigator.platform.includes("Mac")?"\u2318":"Ctrl+",s=_t(),o=N(e,Te().map(i=>({label:i.label,key:i.key,shortcut:`${n}${i.key.toUpperCase()}`,color:I(i.value),active:s===i.value,action:()=>{fe=i.value,L(),F()}})));document.body.appendChild(o),M(o,e),o.style.visibility=""}function Sn(e){let t=a.selectedIds.has(e.id),n=e.status==="completed"||e.status==="verified",s=e.status==="verified",o=v(r("div",{className:`ticket-row${t?" selected":""}${n?" completed":""}${e.up_next?" up-next":""}`,"data-id":String(e.id),children:[r("input",{type:"checkbox",className:"ticket-checkbox",checked:t}),r("span",{className:"ticket-category-badge",style:`background-color:${I(e.category)}`,title:e.category,children:K(e.category)}),r("span",{className:"ticket-number",children:e.ticket_number}),r("button",{className:`ticket-status-btn${s?" verified":""}`,title:e.status.replace("_"," "),children:D(s?_e:z(e.status))}),r("input",{type:"text",className:"ticket-title-input",value:e.title}),r("span",{className:"ticket-priority-indicator",style:`color:${P(e.priority)}`,title:e.priority,children:D(A(e.priority))}),r("button",{className:`ticket-star${e.up_next?" active":""}`,title:e.up_next?"Remove from Up Next":"Add to Up Next",children:e.up_next?"\u2605":"\u2606"})]}));o.addEventListener("mousedown",d=>{let p=d.target;p.tagName!=="INPUT"&&p.tagName!=="BUTTON"&&(o.draggable=!0)}),o.addEventListener("mouseup",()=>{o.draggable=!1}),o.addEventListener("dragend",()=>{o.draggable=!1,U=[]}),o.addEventListener("contextmenu",d=>{Ve(d,e)}),o.addEventListener("dragstart",d=>{a.selectedIds.has(e.id)&&a.selectedIds.size>1?U=Array.from(a.selectedIds):U=[e.id],d.dataTransfer.setData("text/plain",JSON.stringify(U)),d.dataTransfer.effectAllowed="move"}),o.addEventListener("mousedown",d=>{(d.metaKey||d.ctrlKey||d.shiftKey)&&(d.preventDefault(),Bt(d,e)&&d.stopPropagation())});let i=o.querySelector(".ticket-checkbox");i.addEventListener("click",d=>d.stopPropagation()),i.addEventListener("change",()=>{i.checked?a.selectedIds.add(e.id):a.selectedIds.delete(e.id),a.lastClickedId=e.id,L()}),o.querySelector(".ticket-status-btn").addEventListener("click",d=>{d.stopPropagation(),Bn(e)});let l=o.querySelector(".ticket-category-badge");l.addEventListener("click",d=>{d.stopPropagation(),Dt(l,e)});let c=o.querySelector(".ticket-title-input");c.addEventListener("focus",()=>{ge||a.selectedIds.size===1&&a.selectedIds.has(e.id)||(a.selectedIds.clear(),a.selectedIds.add(e.id),a.lastClickedId=e.id,ye(),oe())}),c.addEventListener("input",()=>{Ee(e,"title",c.value),Dn(e.id,{title:c.value})}),c.addEventListener("keydown",d=>{Mn(d,e,c)});let u=o.querySelector(".ticket-priority-indicator");return u.addEventListener("click",d=>{d.stopPropagation(),At(u,e)}),o.querySelector(".ticket-star").addEventListener("click",d=>{d.stopPropagation(),Ht(e)}),o}function $n(e){let t=a.selectedIds.has(e.id),n=e.deleted_at?new Date(e.deleted_at):null,s=v(r("div",{className:`ticket-row trash-row${t?" selected":""}`,"data-id":String(e.id),children:[r("input",{type:"checkbox",className:"ticket-checkbox",checked:t}),r("span",{className:"ticket-category-badge",style:`background-color:${I(e.category)}`,children:K(e.category)}),r("span",{className:"ticket-number",children:e.ticket_number}),r("span",{className:"ticket-title-input trash-title",style:"cursor:default",children:e.title}),r("span",{className:"ticket-number",title:n?`Deleted: ${n.toLocaleString()}`:"",children:n?n.toLocaleDateString():""}),r("button",{className:"btn btn-sm",title:"Restore from trash",children:"Restore"})]}));s.addEventListener("mousedown",i=>{(i.metaKey||i.ctrlKey||i.shiftKey)&&(i.preventDefault(),Bt(i,e)&&i.stopPropagation())});let o=s.querySelector(".ticket-checkbox");return o.addEventListener("click",i=>i.stopPropagation()),o.addEventListener("change",()=>{o.checked?a.selectedIds.add(e.id):a.selectedIds.delete(e.id),a.lastClickedId=e.id,L()}),s.querySelector(".trash-title").addEventListener("click",()=>{a.selectedIds.size===1&&a.selectedIds.has(e.id)||(a.selectedIds.clear(),a.selectedIds.add(e.id),a.lastClickedId=e.id,ye(),oe())}),s.querySelector(".btn").addEventListener("click",async i=>{i.stopPropagation(),await bt(e),w()}),s}function Bt(e,t){let n=e.metaKey||e.ctrlKey,s=e.shiftKey;if(n)a.selectedIds.has(t.id)?a.selectedIds.delete(t.id):a.selectedIds.add(t.id),a.lastClickedId=t.id,L();else if(s&&a.lastClickedId!=null){let o=a.tickets.map(c=>c.id),i=o.indexOf(a.lastClickedId),l=o.indexOf(t.id);if(i!==-1&&l!==-1){let c=Math.min(i,l),u=Math.max(i,l);a.selectedIds.clear();for(let d=c;d<=u;d++)a.selectedIds.add(o[d])}L()}else return!1;return!0}function Mn(e,t,n){if(e.key==="Enter")e.preventDefault(),F();else if(e.key==="Backspace"&&n.value==="")e.preventDefault(),Hn(t.id);else if(e.key==="ArrowDown"&&e.shiftKey)e.preventDefault(),Lt(t.id,1);else if(e.key==="ArrowUp"&&e.shiftKey)e.preventDefault(),Lt(t.id,-1);else if(e.key==="ArrowDown")e.preventDefault(),Nn(t.id);else if(e.key==="ArrowUp")e.preventDefault(),_n(t.id);else if((e.metaKey||e.ctrlKey)&&!e.altKey&&Te().some(s=>s.key===e.key)){e.preventDefault();let s=Te().find(o=>o.key===e.key);It(t,"category",s.value)}else if(e.altKey&&!e.metaKey&&!e.ctrlKey&&Ke.some(s=>s.key===e.key)){e.preventDefault();let s=Ke.find(o=>o.key===e.key);It(t,"priority",s.value)}}function Nn(e){let t=a.tickets.findIndex(n=>n.id===e);t<a.tickets.length-1&&document.querySelector(`.ticket-row[data-id="${a.tickets[t+1].id}"] .ticket-title-input`)?.focus()}function _n(e){let t=a.tickets.findIndex(n=>n.id===e);t>0?document.querySelector(`.ticket-row[data-id="${a.tickets[t-1].id}"] .ticket-title-input`)?.focus():F()}function Lt(e,t){let s=a.tickets.findIndex(l=>l.id===e)+t;if(s<0||s>=a.tickets.length)return;let o=a.tickets[s].id;a.selectedIds.add(e),a.selectedIds.has(o)?a.selectedIds.delete(e):a.selectedIds.add(o),ge=!0,document.querySelector(`.ticket-row[data-id="${o}"] .ticket-title-input`)?.focus(),ge=!1,ye(),oe()}async function Bn(e){let n={not_started:"started",started:"completed",completed:"verified",verified:"not_started",backlog:"not_started",archive:"not_started"}[e.status]||"not_started",s=await R(e,{status:n},"Change status");Object.assign(e,s),L()}async function Ht(e){!e.up_next&&(e.status==="completed"||e.status==="verified")?await R(e,{status:"not_started",up_next:!0},"Toggle up next"):await R(e,{up_next:!e.up_next},"Toggle up next"),w()}async function It(e,t,n){let s=await R(e,{[t]:n},`Change ${t}`);Object.assign(e,s),L()}async function Hn(e){let t=a.tickets.findIndex(s=>s.id===e),n=a.tickets.find(s=>s.id===e);if(n?await xe(n):await y(`/tickets/${e}`,{method:"DELETE"}),a.tickets=a.tickets.filter(s=>s.id!==e),a.selectedIds.delete(e),L(),t>0&&a.tickets.length>0){let s=Math.min(t-1,a.tickets.length-1);document.querySelector(`.ticket-row[data-id="${a.tickets[s].id}"] .ticket-title-input`)?.focus()}else F()}function Dn(e,t){se&&clearTimeout(se),se=setTimeout(()=>{y(`/tickets/${e}`,{method:"PATCH",body:t})},300)}function Dt(e,t){_();let s=navigator.platform.includes("Mac")?"\u2318":"Ctrl+",o=N(e,Te().map(i=>({label:i.label,key:i.key,shortcut:`${s}${i.key.toUpperCase()}`,color:I(i.value),active:t.category===i.value,action:async()=>{let l=await R(t,{category:i.value},"Change category");Object.assign(t,l),L()}})));document.body.appendChild(o),M(o,e),o.style.visibility=""}function At(e,t){_();let n=N(e,Ke.map(s=>({label:s.label,key:s.key,shortcut:`Alt+${s.key}`,icon:A(s.value),iconColor:P(s.value),active:t.priority===s.value,action:async()=>{let o=await R(t,{priority:s.value},"Change priority");Object.assign(t,o),L()}})));document.body.appendChild(n),M(n,e),n.style.visibility=""}function ye(){document.querySelectorAll(".ticket-row[data-id]").forEach(e=>{let t=parseInt(e.dataset.id,10),n=e.querySelector(".ticket-checkbox");a.selectedIds.has(t)?(e.classList.add("selected"),n&&(n.checked=!0)):(e.classList.remove("selected"),n&&(n.checked=!1))})}function oe(){let e=a.selectedIds.size,t=a.tickets.length,n=e>0,s=a.view==="trash",o=document.getElementById("batch-select-all");o.checked=t>0&&e===t,o.indeterminate=e>0&&e<t,document.getElementById("batch-count").textContent=n?`${e} selected`:"";let i=["batch-category","batch-priority","batch-status","batch-upnext","batch-delete","batch-more"];for(let p of i){let m=document.getElementById(p);m.style.display=s?"none":"",s||(m.disabled=!n)}let l=document.getElementById("batch-restore"),c=document.getElementById("batch-empty-trash");if(s){let p=document.getElementById("batch-toolbar");l||(l=v(r("button",{id:"batch-restore",className:"btn btn-sm",children:"Restore"})),l.addEventListener("click",async()=>{await y("/tickets/batch",{method:"POST",body:{ids:Array.from(a.selectedIds),action:"restore"}}),a.selectedIds.clear(),w()}),p.insertBefore(l,document.getElementById("batch-count"))),l.disabled=!n,l.style.display="",c||(c=v(r("button",{id:"batch-empty-trash",className:"btn btn-sm btn-danger",children:"Empty Trash"})),c.addEventListener("click",async()=>{await y("/trash/empty",{method:"POST"}),a.selectedIds.clear(),w()}),p.insertBefore(c,document.getElementById("batch-count"))),c.disabled=t===0,c.style.display=""}else l&&(l.style.display="none"),c&&(c.style.display="none");let u=document.querySelector(".batch-star-icon"),d=document.getElementById("batch-upnext");if(!s&&u&&n){let p=a.tickets.filter(f=>a.selectedIds.has(f.id)),m=p.every(f=>f.up_next),g=p.every(f=>!f.up_next);m?(u.textContent="\u2605",d.classList.add("active"),d.classList.remove("mixed")):g?(u.textContent="\u2606",d.classList.remove("active","mixed")):(u.innerHTML=r("span",{className:"star-mixed-wrap",children:[r("span",{className:"star-mixed-fill",children:"\u2605"}),"\u2606"]}).toString(),d.classList.remove("active"),d.classList.add("mixed"))}else u&&(u.textContent="\u2606",d.classList.remove("active","mixed"));te()}async function w(){if(a.backupPreview?.active){An();return}if(a.view.startsWith("custom:")){let n=a.view.slice(7),s=a.customViews.find(o=>o.id===n);s?a.tickets=await y("/tickets/query",{method:"POST",body:{logic:s.logic,conditions:s.conditions,sort_by:a.sortBy,sort_dir:a.sortDir}}):a.tickets=[],L();return}let e=new URLSearchParams;a.view==="trash"?e.set("status","deleted"):a.view==="up-next"?e.set("up_next","true"):a.view==="open"?e.set("status","open"):a.view==="completed"?e.set("status","completed"):a.view==="non-verified"?e.set("status","non_verified"):a.view==="verified"?e.set("status","verified"):a.view==="backlog"?e.set("status","backlog"):a.view==="archive"?e.set("status","archive"):a.view.startsWith("category:")?e.set("category",a.view.split(":")[1]):a.view.startsWith("priority:")?e.set("priority",a.view.split(":")[1]):e.set("status","active"),a.search&&e.set("search",a.search),e.set("sort_by",a.sortBy),e.set("sort_dir",a.sortDir);let t=e.toString();a.tickets=await y(`/tickets${t?"?"+t:""}`),L()}function An(){let e=[...a.backupPreview?.tickets||[]];if(a.view==="trash")e=e.filter(t=>t.status==="deleted");else if(a.view==="up-next")e=e.filter(t=>t.up_next&&t.status!=="deleted");else if(a.view==="open")e=e.filter(t=>t.status==="not_started"||t.status==="started");else if(a.view==="completed")e=e.filter(t=>t.status==="completed");else if(a.view==="non-verified")e=e.filter(t=>t.status!=="verified"&&t.status!=="deleted"&&t.status!=="backlog"&&t.status!=="archive");else if(a.view==="verified")e=e.filter(t=>t.status==="verified");else if(a.view==="backlog")e=e.filter(t=>t.status==="backlog");else if(a.view==="archive")e=e.filter(t=>t.status==="archive");else if(a.view.startsWith("category:")){let t=a.view.split(":")[1];e=e.filter(n=>n.category===t&&n.status!=="deleted"&&n.status!=="backlog"&&n.status!=="archive")}else if(a.view.startsWith("priority:")){let t=a.view.split(":")[1];e=e.filter(n=>n.priority===t&&n.status!=="deleted"&&n.status!=="backlog"&&n.status!=="archive")}else e=e.filter(t=>t.status!=="deleted"&&t.status!=="backlog"&&t.status!=="archive");if(a.search){let t=a.search.toLowerCase();e=e.filter(n=>n.title.toLowerCase().includes(t)||n.ticket_number.toLowerCase().includes(t)||n.details&&n.details.toLowerCase().includes(t))}a.tickets=e,L()}function Pn(e){let t=Date.now()-new Date(e).getTime(),n=Math.floor(t/6e4);if(n<1)return"just now";if(n<60)return`${n}m ago`;let s=Math.floor(n/60);return s<24?`${s}h ago`:`${Math.floor(s/24)}d ago`}function Rn(e){return e<1024?`${e} B`:e<1024*1024?`${(e/1024).toFixed(0)} KB`:`${(e/(1024*1024)).toFixed(1)} MB`}function qn(e){return e==="5min"?"Recent (every 5 min)":e==="hourly"?"Hourly":e==="daily"?"Daily":e}async function Fe(){var t;let e=document.getElementById("backup-list");if(e)try{let n=await y("/backups");if(n.backups.length===0){e.textContent="No backups yet. First backup will be created shortly.";return}let s={};for(let o of n.backups)(s[t=o.tier]||(s[t]=[])).push(o);e.innerHTML="";for(let o of["5min","hourly","daily"]){let i=s[o];if(!(!i||i.length===0)){e.appendChild(v(r("div",{className:"backup-tier-label",children:qn(o)})));for(let l of i){let c=v(r("div",{className:"backup-row","data-tier":l.tier,"data-filename":l.filename,children:[r("span",{className:"backup-row-time",children:Pn(l.createdAt)}),r("span",{className:"backup-row-meta",children:[new Date(l.createdAt).toLocaleString()," \xB7 ",Rn(l.sizeBytes)]})]}));c.addEventListener("click",()=>{Un(l.tier,l.filename,l.createdAt)}),e.appendChild(c)}}}}catch{e.textContent="Failed to load backups."}}async function Un(e,t,n){let s=document.getElementById("settings-overlay");s.style.display="none";let o=document.getElementById("backup-preview-banner"),i=document.getElementById("backup-preview-label");i.textContent="Loading backup preview...",o.style.display="flex";try{let l=await y(`/backups/preview/${e}/${t}`);a.backupPreview={active:!0,tickets:l.tickets,timestamp:n,tier:e,filename:t},a.selectedIds.clear(),a.activeTicketId=null,i.textContent=`Previewing backup from ${new Date(n).toLocaleString()} (${l.stats.total} tickets, ${l.stats.open} open) \u2014 read-only`,w()}catch{i.textContent="Failed to load backup preview.",setTimeout(()=>{o.style.display="none"},3e3)}}async function Vn(){let e=document.getElementById("backup-preview-banner");e.style.display="none",a.backupPreview=null,a.selectedIds.clear(),a.activeTicketId=null,await y("/backups/preview/cleanup",{method:"POST"}),w()}async function On(){if(!a.backupPreview)return;let e=document.getElementById("backup-restore-btn");e.textContent="Restoring...",e.disabled=!0;try{await y("/backups/restore",{method:"POST",body:{tier:a.backupPreview.tier,filename:a.backupPreview.filename}}),window.location.reload()}catch{e.textContent="Restore failed",e.disabled=!1,setTimeout(()=>{e.textContent="Restore This Backup"},3e3)}}function Pt(){document.getElementById("backup-cancel-btn")?.addEventListener("click",()=>{Vn()}),document.getElementById("backup-restore-btn")?.addEventListener("click",()=>{On()});let e=document.getElementById("backup-now-btn");e?.addEventListener("click",async()=>{e.textContent="Backing up...",e.disabled=!0;try{(await y("/backups/now",{method:"POST"})).error?e.textContent="In progress...":(e.textContent="Done!",Fe())}catch{e.textContent="Failed"}setTimeout(()=>{e.textContent="Backup Now",e.disabled=!1},1500)})}var Ce,G=null;function Ut(e){Ce=e,document.getElementById("add-custom-view-btn").addEventListener("click",t=>{t.stopPropagation(),Je()})}async function Vt(){try{let e=await y("/settings");if(e.custom_views){let t=JSON.parse(e.custom_views);Array.isArray(t)&&(a.customViews=t)}}catch{}We()}function We(){let e=document.getElementById("custom-views-container");if(e.innerHTML="",a.customViews.length!==0){e.appendChild(v(r("div",{className:"sidebar-divider"})));for(let t=0;t<a.customViews.length;t++){let n=a.customViews[t],s=v(r("button",{className:`sidebar-item sidebar-custom-view${a.view===`custom:${n.id}`?" active":""}`,"data-view":`custom:${n.id}`,"data-cv-index":String(t),draggable:"true",children:n.name}));s.addEventListener("click",()=>{document.querySelectorAll(".sidebar-item").forEach(o=>o.classList.remove("active")),s.classList.add("active"),a.view=`custom:${n.id}`,a.selectedIds.clear(),H(),Ce()}),s.addEventListener("dblclick",o=>{o.preventDefault(),Je(n)}),s.addEventListener("contextmenu",o=>{o.preventDefault(),Fn(s,n)}),s.addEventListener("dragstart",o=>{G=t,o.dataTransfer.setData("text/plain",String(t)),o.dataTransfer.effectAllowed="move",setTimeout(()=>s.classList.add("dragging"),0)}),s.addEventListener("dragend",()=>{s.classList.remove("dragging"),G=null}),s.addEventListener("dragover",o=>{G!==null&&(o.preventDefault(),o.dataTransfer.dropEffect="move",s.classList.add("drop-target"))}),s.addEventListener("dragleave",()=>{s.classList.remove("drop-target")}),s.addEventListener("drop",o=>{if(o.preventDefault(),s.classList.remove("drop-target"),G===null||G===t)return;let[i]=a.customViews.splice(G,1);a.customViews.splice(t,0,i),G=null,je()}),e.appendChild(s)}}}var Kn='<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21.174 6.812a1 1 0 0 0-3.986-3.987L3.842 16.174a2 2 0 0 0-.5.83l-1.321 4.352a.5.5 0 0 0 .623.622l4.353-1.32a2 2 0 0 0 .83-.497z"/><path d="m15 5 4 4"/></svg>',zn='<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M3 6h18"/><path d="M19 6v14c0 1-1 2-2 2H7c-1 0-2-1-2-2V6"/><path d="M8 6V4c0-1 1-2 2-2h4c1 0 2 1 2 2v2"/></svg>';function Fn(e,t){_();let n=N(e,[{label:"Edit",key:"e",icon:Kn,action:()=>Je(t)},{label:"Delete",key:"d",icon:zn,action:()=>Wn(t.id)}]);document.body.appendChild(n),M(n,e),n.style.visibility=""}async function je(){await y("/settings",{method:"PATCH",body:{custom_views:JSON.stringify(a.customViews)}}),We()}async function Wn(e){a.customViews=a.customViews.filter(t=>t.id!==e),a.view===`custom:${e}`&&(a.view="all",document.querySelectorAll(".sidebar-item").forEach(t=>{t.classList.toggle("active",t.dataset.view==="all")}),Ce()),await je()}var Ie=[{value:"category",label:"Category",type:"select"},{value:"priority",label:"Priority",type:"ordinal"},{value:"status",label:"Status",type:"ordinal"},{value:"title",label:"Title",type:"text"},{value:"details",label:"Details",type:"text"},{value:"up_next",label:"Up Next",type:"boolean"},{value:"tags",label:"Tags",type:"text"}];function Rt(e){return e==="ordinal"?[{value:"equals",label:"="},{value:"not_equals",label:"\u2260"},{value:"lt",label:"<"},{value:"lte",label:"\u2264"},{value:"gt",label:">"},{value:"gte",label:"\u2265"}]:e==="select"?[{value:"equals",label:"is"},{value:"not_equals",label:"is not"}]:e==="boolean"?[{value:"equals",label:"is"}]:[{value:"contains",label:"contains"},{value:"not_contains",label:"does not contain"}]}var jn=["highest","high","default","low","lowest"],Jn=["not_started","started","completed","verified","backlog","archive"];function qt(e){return e==="category"?a.categories.map(t=>t.id):e==="priority"?jn:e==="status"?Jn:e==="up_next"?["true","false"]:null}function Yn(e,t){return e==="category"?a.categories.find(s=>s.id===t)?.label||t:e==="status"?t.replace(/_/g," "):e==="up_next"?t==="true"?"Yes":"No":t}function Je(e){let t=!!e,n=e?e.conditions.map(u=>({...u})):[],s=e?.logic||"all",o=e?.name||"",i=v(r("div",{className:"custom-view-editor-overlay",children:r("div",{className:"custom-view-editor",children:[r("div",{className:"custom-view-editor-header",children:[r("span",{children:t?"Edit Custom View":"New Custom View"}),r("button",{className:"detail-close",id:"cv-editor-close",children:"\xD7"})]}),r("div",{className:"custom-view-editor-body",children:[r("div",{className:"settings-field",children:[r("label",{children:"Name"}),r("input",{type:"text",id:"cv-name",value:o,placeholder:"View name..."})]}),r("div",{className:"cv-logic-row",children:[r("span",{children:"Match"}),r("label",{children:[r("input",{type:"radio",name:"cv-logic",value:"all",checked:s==="all"})," All of"]}),r("label",{children:[r("input",{type:"radio",name:"cv-logic",value:"any",checked:s==="any"})," Any of"]})]}),r("div",{id:"cv-conditions"}),r("button",{className:"btn btn-sm",id:"cv-add-condition",style:"margin-top:8px",children:"+ Add Condition"})]}),r("div",{className:"custom-view-editor-footer",children:[r("button",{className:"btn btn-sm",id:"cv-cancel",children:"Cancel"}),r("button",{className:"btn btn-sm btn-accent",id:"cv-save",children:"Save"})]})]})}));function l(){let u=i.querySelector("#cv-conditions");u.innerHTML="",n.forEach((d,p)=>{let m=Ie.find(x=>x.value===d.field)||Ie[0],g=Rt(m.type),f=qt(d.field),b=v(r("div",{className:"cv-condition-row",children:[r("select",{className:"cv-field-select",children:Ie.map(x=>r("option",{value:x.value,selected:x.value===d.field,children:x.label}))}),r("select",{className:"cv-op-select",children:g.map(x=>r("option",{value:x.value,selected:x.value===d.operator,children:x.label}))}),f?r("select",{className:"cv-value-select",children:f.map(x=>r("option",{value:x,selected:x===d.value,children:Yn(d.field,x)}))}):r("input",{type:"text",className:"cv-value-input",value:d.value,placeholder:"Value..."}),r("button",{className:"category-delete-btn",title:"Remove",children:"\xD7"})]})),E=b.querySelector(".cv-field-select"),T=b.querySelector(".cv-op-select"),k=b.querySelector(".cv-value-select")||b.querySelector(".cv-value-input");E.addEventListener("change",()=>{let x=E.value,B=Ie.find(Q=>Q.value===x),re=Rt(B.type);n[p].field=x,n[p].operator=re[0].value;let Z=qt(x);n[p].value=Z?Z[0]:"",l()}),T.addEventListener("change",()=>{n[p].operator=T.value}),k.addEventListener("change",()=>{n[p].value=k.value}),k.tagName==="INPUT"&&k.addEventListener("input",()=>{n[p].value=k.value}),b.querySelector(".category-delete-btn").addEventListener("click",()=>{n.splice(p,1),l()}),u.appendChild(b)})}l(),document.body.appendChild(i),i.querySelector("#cv-name").focus(),i.querySelectorAll('input[name="cv-logic"]').forEach(u=>{u.addEventListener("change",()=>{s=u.value})}),i.querySelector("#cv-add-condition").addEventListener("click",()=>{n.push({field:"category",operator:"equals",value:a.categories[0]?.id||"issue"}),l()});let c=()=>i.remove();i.querySelector("#cv-editor-close").addEventListener("click",c),i.querySelector("#cv-cancel").addEventListener("click",c),i.addEventListener("click",u=>{u.target===i&&c()}),i.querySelector("#cv-save").addEventListener("click",async()=>{if(o=i.querySelector("#cv-name").value.trim(),!o){i.querySelector("#cv-name").focus();return}let u={id:e?.id||o.toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-|-$/g,"")||`view-${Date.now()}`,name:o,logic:s,conditions:n.filter(d=>d.value!=="")};if(t){let d=a.customViews.findIndex(p=>p.id===e.id);d>=0?a.customViews[d]=u:a.customViews.push(u)}else a.customViews.push(u);await je(),document.querySelectorAll(".sidebar-item").forEach(d=>d.classList.remove("active")),a.view=`custom:${u.id}`,a.selectedIds.clear(),We(),Ce(),c()})}var ie=30;async function Xe(e){e.innerHTML='<div class="dashboard-loading">Loading dashboard...</div>';try{let t=await y(`/dashboard?days=${ie}`);e.innerHTML="",e.appendChild(Xn(t))}catch{e.innerHTML='<div class="dashboard-loading">Failed to load dashboard data.</div>'}}function Xn(e){let t=v(r("div",{className:"dashboard"})),n=v(r("div",{className:"dashboard-range-bar",children:[r("button",{className:`btn btn-sm${ie===7?" active":""}`,"data-days":"7",children:"7 days"}),r("button",{className:`btn btn-sm${ie===30?" active":""}`,"data-days":"30",children:"30 days"}),r("button",{className:`btn btn-sm${ie===90?" active":""}`,"data-days":"90",children:"90 days"})]}));n.querySelectorAll("button").forEach(m=>{m.addEventListener("click",()=>{ie=parseInt(m.dataset.days,10);let g=document.getElementById("dashboard-container");g&&Xe(g)})}),t.appendChild(n);let s=e.kpi,o=s.completedLastWeek>0?Math.round((s.completedThisWeek-s.completedLastWeek)/s.completedLastWeek*100):0,i=o>0?"\u2191":o<0?"\u2193":"",l=s.createdThisWeek>0?(s.completedThisWeek/s.createdThisWeek).toFixed(1):"\u2014";t.appendChild(v(r("div",{className:"dashboard-kpi-row",children:[r("div",{className:"dashboard-kpi-card",children:[r("div",{className:"kpi-value",children:String(s.completedThisWeek)}),r("div",{className:"kpi-label",children:"Completed this week"}),i?r("div",{className:`kpi-trend${o>0?" up":" down"}`,children:[i," ",Math.abs(o),"%"]}):null]}),r("div",{className:"dashboard-kpi-card",children:[r("div",{className:"kpi-value",children:s.medianCycleTimeDays!==null?`${s.medianCycleTimeDays}d`:"\u2014"}),r("div",{className:"kpi-label",children:"Median cycle time"})]}),r("div",{className:"dashboard-kpi-card",children:[r("div",{className:"kpi-value",children:String(s.wipCount)}),r("div",{className:"kpi-label",children:"In progress"})]}),r("div",{className:"dashboard-kpi-card",children:[r("div",{className:"kpi-value",children:String(l)}),r("div",{className:"kpi-label",children:"Completed / created"})]})]})));let c=v(r("div",{className:"dashboard-grid"})),u=ve("Throughput","Items completed per day. Shows your sustainable delivery pace.",Gn(e.throughput));Ye(u,e.throughput.map(m=>({date:m.date,lines:[{label:"Completed",color:"#3b82f6",value:m.completed}]}))),c.appendChild(u);let d=ve("Created vs Completed","Compares items created (orange) vs completed (green) over time. When created outpaces completed, the backlog grows.",Zn(e.throughput));Ye(d,e.throughput.map(m=>({date:m.date,lines:[{label:"Completed",color:"#22c55e",value:m.completed},{label:"Created",color:"#f97316",value:m.created}]}))),c.appendChild(d);let p=ve("Cumulative Flow","Stacked area showing ticket counts by status over time. Widening bands indicate bottlenecks. A healthy flow has consistent band widths.",Qn(e.snapshots));return Ye(p,e.snapshots.map(m=>({date:m.date,lines:[{label:"Not Started",color:"#6b7280",value:m.data.not_started},{label:"Started",color:"#3b82f6",value:m.data.started},{label:"Completed",color:"#22c55e",value:m.data.completed},{label:"Verified",color:"#8b5cf6",value:m.data.verified}]}))),c.appendChild(p),c.appendChild(ve("Category Breakdown","Distribution of tickets by category. Left: currently open. Right: all tickets active in the selected time period.",ea(e.categoryBreakdown,e.categoryPeriod))),c.appendChild(ve("Cycle Time","Each dot is a completed ticket plotted by completion date and days to complete. Dashed lines show 50th and 85th percentile delivery times.",ta(e.cycleTime))),t.appendChild(c),t}function ve(e,t,n){let s=v(r("div",{className:"dashboard-chart-card",children:[r("div",{className:"dashboard-chart-header",children:[r("span",{className:"dashboard-chart-title",children:e}),r("button",{className:"dashboard-info-btn",title:"About this chart",children:r("svg",{xmlns:"http://www.w3.org/2000/svg",width:"14",height:"14",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",children:[r("circle",{cx:"12",cy:"12",r:"10"}),r("path",{d:"M12 16v-4"}),r("path",{d:"M12 8h.01"})]})})]}),r("div",{className:"dashboard-chart-info",style:"display:none",children:t}),r("div",{className:"dashboard-chart-body",children:D(n)})]})),o=s.querySelector(".dashboard-info-btn"),i=s.querySelector(".dashboard-chart-info");return o.addEventListener("click",l=>{l.stopPropagation(),i.style.display=i.style.display==="none"?"":"none"}),s}function Ye(e,t){let n=e.querySelector(".dashboard-chart-body");if(!n||t.length===0)return;let s=document.createElement("div");s.className="chart-cursor",s.style.display="none",n.style.position="relative",n.appendChild(s);let o=document.createElement("div");o.className="chart-tooltip",o.style.display="none",n.appendChild(o);let i=n.querySelector("svg");i&&(i.addEventListener("mousemove",l=>{let c=i.getBoundingClientRect(),u=n.getBoundingClientRect(),d=c.left-u.left,p=c.top-u.top,m=q/c.width,g=V/c.height,f=(l.clientX-c.left)*m,b=q-h.left-h.right,E=Math.max(0,Math.min(1,(f-h.left)/b)),T=Math.round(E*(t.length-1));if(T<0||T>=t.length)return;let k=h.left+T/Math.max(t.length-1,1)*b,x=d+k/m,B=p+h.top/g,re=(V-h.top-h.bottom)/g;s.style.display="",s.style.left=`${x}px`,s.style.top=`${B}px`,s.style.height=`${re}px`;let Z=t[T];o.style.display="",o.innerHTML=`<div class="chart-tooltip-date">${Ge(Z.date)}</div>${Z.lines.map(le=>`<div class="chart-tooltip-row"><span class="chart-legend-dot" style="background:${le.color}"></span>${le.label}: <b>${le.value}</b></div>`).join("")}`;let Q=x+10;Q+120>u.width?o.style.left=`${x-120}px`:o.style.left=`${Q}px`,o.style.top=`${l.clientY-u.top-10}px`}),i.addEventListener("mouseleave",()=>{s.style.display="none",o.style.display="none"}))}var q=400,V=180,h={top:10,right:10,bottom:25,left:35};function Gn(e){if(e.length===0)return'<div class="chart-empty">No data</div>';let t=e.map(c=>c.completed),n=Math.max(...t,1),s=q-h.left-h.right,o=V-h.top-h.bottom,i=Math.max(2,s/e.length-2),l="";for(let c=0;c<e.length;c++){let u=h.left+c/e.length*s,d=t[c]/n*o,p=h.top+o-d,m=Ge(e[c].date);l+=`<rect x="${u}" y="${p}" width="${i}" height="${d}" fill="#3b82f6" rx="1" opacity="0.8" class="chart-hover"><title>${m}: ${t[c]} completed</title></rect>`}return`<svg viewBox="0 0 ${q} ${V}" class="dashboard-svg">
|
|
2
|
+
${Ze(n,o)}
|
|
3
|
+
${l}
|
|
4
|
+
${Se(e.map(c=>c.date))}
|
|
5
|
+
</svg>`}function Zn(e){if(e.length<2)return'<div class="chart-empty">Not enough data</div>';let t=Math.max(...e.map(l=>Math.max(l.completed,l.created)),1),n=q-h.left-h.right,s=V-h.top-h.bottom,o='<div class="chart-legend"><span class="chart-legend-item"><span class="chart-legend-dot" style="background:#22c55e"></span>Completed</span><span class="chart-legend-item"><span class="chart-legend-dot" style="background:#f97316"></span>Created</span></div>',i=`<svg viewBox="0 0 ${q} ${V}" class="dashboard-svg">
|
|
6
|
+
${Ze(t,s)}
|
|
7
|
+
<path d="${Kt(e.map(l=>l.created),t,n,s)}" fill="none" stroke="#f97316" stroke-width="2" opacity="0.7"/>
|
|
8
|
+
<path d="${Kt(e.map(l=>l.completed),t,n,s)}" fill="none" stroke="#22c55e" stroke-width="2"/>
|
|
9
|
+
${Se(e.map(l=>l.date))}
|
|
10
|
+
</svg>`;return o+i}function Qn(e){if(e.length<2)return'<div class="chart-empty">Not enough data</div>';let t=["verified","completed","started","not_started"],n={not_started:"#6b7280",started:"#3b82f6",completed:"#22c55e",verified:"#8b5cf6"},s={not_started:"Not Started",started:"Started",completed:"Completed",verified:"Verified"},o=`<div class="chart-legend">${t.map(g=>`<span class="chart-legend-item"><span class="chart-legend-dot" style="background:${n[g]}"></span>${s[g]}</span>`).join("")}</div>`,i=e.map(g=>{let f=0;return t.map(b=>(f+=g.data[b]||0,f))}),l=Math.max(...i.map(g=>g[g.length-1]),1),c=q-h.left-h.right,u=V-h.top-h.bottom,d=e.length,p="";for(let g=t.length-1;g>=0;g--){let f=i.map((E,T)=>{let k=h.left+T/(d-1)*c,x=h.top+u-E[g]/l*u;return`${k},${x}`}),b=g>0?i.map((E,T)=>{let k=h.left+T/(d-1)*c,x=h.top+u-E[g-1]/l*u;return`${k},${x}`}).reverse():[`${h.left+c},${h.top+u}`,`${h.left},${h.top+u}`];p+=`<polygon points="${f.join(" ")} ${b.join(" ")}" fill="${n[t[g]]}" opacity="0.6"/>`}let m=`<svg viewBox="0 0 ${q} ${V}" class="dashboard-svg">
|
|
11
|
+
${p}
|
|
12
|
+
${Se(e.map(g=>g.date))}
|
|
13
|
+
</svg>`;return o+m}function ea(e,t){let n=new Map;for(let c of[...e,...t])if(!n.has(c.category)){let u=a.categories.find(d=>d.id===c.category);n.set(c.category,{color:I(c.category),label:u?.label||c.category})}let s=`<div class="chart-legend">${Array.from(n.values()).map(c=>`<span class="chart-legend-item"><span class="chart-legend-dot" style="background:${c.color}"></span>${c.label}</span>`).join("")}</div>`,o=Ot(e,"Open",90),i=Ot(t,`${ie}d active`,290),l=`<svg viewBox="0 0 ${q} ${V}" class="dashboard-svg">${o}${i}</svg>`;return s+l}function Ot(e,t,n){if(e.length===0)return`<text x="${n}" y="95" text-anchor="middle" fill="#9ca3af" font-size="11">No data</text>`;let s=e.reduce((d,p)=>d+p.count,0),o=95,i=60,l=38,c=-Math.PI/2,u="";for(let d of e){let p=d.count/s*Math.PI*2,m=n+i*Math.cos(c),g=o+i*Math.sin(c),f=n+i*Math.cos(c+p),b=o+i*Math.sin(c+p),E=n+l*Math.cos(c+p),T=o+l*Math.sin(c+p),k=n+l*Math.cos(c),x=o+l*Math.sin(c),B=p>Math.PI?1:0,re=I(d.category),Q=a.categories.find(le=>le.id===d.category)?.label||d.category;u+=`<path d="M ${m} ${g} A ${i} ${i} 0 ${B} 1 ${f} ${b} L ${E} ${T} A ${l} ${l} 0 ${B} 0 ${k} ${x} Z" fill="${re}" opacity="0.8" class="chart-hover"><title>${Q}: ${d.count}</title></path>`,c+=p}return u+=`<text x="${n}" y="${o+4}" text-anchor="middle" fill="currentColor" font-size="16" font-weight="600">${s}</text>`,u+=`<text x="${n}" y="${o+17}" text-anchor="middle" fill="#6b7280" font-size="9">${t}</text>`,u}function ta(e){if(e.length===0)return'<div class="chart-empty">No completed tickets</div>';let t=Math.max(...e.map(E=>E.days),1),n=q-h.left-h.right,s=V-h.top-h.bottom,o=e.map(E=>new Date(E.completed_at).getTime()),i=Math.min(...o),c=Math.max(...o)-i||1,u="";for(let E of e){let T=h.left+(new Date(E.completed_at).getTime()-i)/c*n,k=h.top+s-E.days/t*s;u+=`<circle cx="${T}" cy="${k}" r="4" fill="#3b82f6" opacity="0.5" class="chart-hover"><title>${E.ticket_number}: ${E.title}
|
|
14
|
+
${E.days} days</title></circle>`}let d=e.map(E=>E.days).sort((E,T)=>E-T),p=d[Math.floor(d.length*.5)],m=d[Math.floor(d.length*.85)],g=h.top+s-p/t*s,f=h.top+s-m/t*s,b=`
|
|
15
|
+
<line x1="${h.left}" y1="${g}" x2="${h.left+n}" y2="${g}" stroke="#22c55e" stroke-dasharray="4,4" opacity="0.6"/>
|
|
16
|
+
<text x="${h.left+n+2}" y="${g+3}" fill="#22c55e" font-size="9">50% (${p}d)</text>
|
|
17
|
+
<line x1="${h.left}" y1="${f}" x2="${h.left+n}" y2="${f}" stroke="#f97316" stroke-dasharray="4,4" opacity="0.6"/>
|
|
18
|
+
<text x="${h.left+n+2}" y="${f+3}" fill="#f97316" font-size="9">85% (${m}d)</text>
|
|
19
|
+
`;return`<svg viewBox="0 0 ${q} ${V}" class="dashboard-svg">
|
|
20
|
+
${Ze(t,s,"d")}
|
|
21
|
+
${u}
|
|
22
|
+
${b}
|
|
23
|
+
${Se(e.map(E=>E.completed_at.slice(0,10)))}
|
|
24
|
+
</svg>`}function Ge(e){let t=new Date(e);return`${t.getMonth()+1}/${t.getDate()}`}function Kt(e,t,n,s){return e.map((o,i)=>{let l=h.left+i/(e.length-1)*n,c=h.top+s-o/t*s;return`${i===0?"M":"L"} ${l} ${c}`}).join(" ")}function Ze(e,t,n=""){let o="";for(let i=0;i<=4;i++){let l=Math.round(e/4*i),c=h.top+t-i/4*t;o+=`<line x1="${h.left}" y1="${c}" x2="${q-h.right}" y2="${c}" stroke="#e5e7eb" stroke-width="0.5"/>`,o+=`<text x="${h.left-4}" y="${c+3}" text-anchor="end" fill="#9ca3af" font-size="9">${l}${n}</text>`}return o}function Se(e){if(e.length===0)return"";let t=V,n=q-h.left-h.right,s="",o=e.length<=7?e.map((i,l)=>l):[0,Math.floor(e.length/2),e.length-1];for(let i of o){let l=h.left+i/Math.max(e.length-1,1)*n;s+=`<text x="${l}" y="${t-4}" text-anchor="middle" fill="#9ca3af" font-size="9">${Ge(e[i])}</text>`}return s}async function zt(){let e=v(r("div",{className:"sidebar-dashboard-widget",id:"sidebar-dashboard-widget"}));try{let t=await y("/dashboard?days=7"),n=t.kpi,s=n.completedLastWeek>0?Math.round((n.completedThisWeek-n.completedLastWeek)/n.completedLastWeek*100):0,o=s>0?"\u2191":s<0?"\u2193":"",i=t.throughput.slice(-7),l=Math.max(...i.map(u=>u.completed),1),c=i.map((u,d)=>{let p=u.completed/l*20;return`<rect x="${d*14}" y="${20-p}" width="10" height="${p}" fill="#3b82f6" rx="1" opacity="0.7"/>`}).join("");e.innerHTML=`
|
|
25
|
+
<div class="sidebar-widget-spark"><svg viewBox="0 0 98 20" width="98" height="20">${c}</svg></div>
|
|
26
|
+
<div class="sidebar-widget-stats">
|
|
27
|
+
<span class="sidebar-widget-value">${n.completedThisWeek} completed</span>
|
|
28
|
+
${o?`<span class="sidebar-widget-trend ${s>0?"up":"down"}">${o}${Math.abs(s)}%</span>`:""}
|
|
29
|
+
</div>
|
|
30
|
+
<div class="sidebar-widget-wip">${n.wipCount} in progress</div>
|
|
31
|
+
`}catch{e.innerHTML='<div class="sidebar-widget-stats">Dashboard</div>'}return e}function Qe(){let e=a.view==="dashboard",t=a.selectedIds.size>0,n=a.activeTicketId!=null,s=v(r("div",{className:"print-dialog-overlay",children:r("div",{className:"print-dialog",children:[r("div",{className:"print-dialog-header",children:[r("span",{children:"Print"}),r("button",{className:"detail-close",id:"print-close",children:"\xD7"})]}),r("div",{className:"print-dialog-body",children:[r("div",{className:"settings-field",children:[r("label",{children:"What to print"}),r("select",{id:"print-scope",children:[e?r("option",{value:"dashboard",children:"Dashboard"}):null,e?null:r("option",{value:"view",children:"All tickets in current view"}),!e&&t?r("option",{value:"selected",children:["Selected tickets (",String(a.selectedIds.size),")"]}):null,!e&&n?r("option",{value:"current",children:"Current ticket detail"}):null]})]}),r("div",{className:"settings-field",id:"print-format-field",children:[r("label",{children:"Format"}),r("select",{id:"print-format",children:[r("option",{value:"checklist",children:"Checklist (titles only)"}),r("option",{value:"summary",children:"Summary (title, category, priority, status)"}),r("option",{value:"full",children:"Full details"})]})]})]}),r("div",{className:"print-dialog-footer",children:[r("button",{className:"btn btn-sm",id:"print-cancel",children:"Cancel"}),r("button",{className:"btn btn-sm btn-accent",id:"print-go",children:"Print"})]})]})})),o=s.querySelector("#print-scope"),i=s.querySelector("#print-format-field"),l=()=>{i.style.display=o.value==="dashboard"?"none":""};o.addEventListener("change",l),l();let c=()=>s.remove();s.querySelector("#print-close").addEventListener("click",c),s.querySelector("#print-cancel").addEventListener("click",c),s.addEventListener("click",u=>{u.target===s&&c()}),s.querySelector("#print-go").addEventListener("click",()=>{let u=o.value,d=s.querySelector("#print-format").value;if(c(),u==="dashboard")aa();else{let p=na(u);sa(p,d)}}),document.body.appendChild(s)}function na(e){if(e==="selected")return a.tickets.filter(t=>a.selectedIds.has(t.id));if(e==="current"&&a.activeTicketId!=null){let t=a.tickets.find(n=>n.id===a.activeTicketId);return t?[t]:[]}return a.tickets}function Ft(e){let t=`<!DOCTYPE html><html><head>
|
|
32
|
+
<meta charset="utf-8">
|
|
33
|
+
<title>Hot Sheet</title>
|
|
34
|
+
<style>${et()}</style>
|
|
35
|
+
</head><body>${e}</body></html>`;y("/print",{method:"POST",body:{html:t}})}function aa(){let e=document.getElementById("dashboard-container");e&&Ft(`<style>${et()}
|
|
36
|
+
.dashboard-grid { grid-template-columns: 1fr 1fr; }
|
|
37
|
+
.dashboard-kpi-row { grid-template-columns: repeat(4, 1fr); }
|
|
38
|
+
.dashboard-chart-body svg { max-width: 100%; }
|
|
39
|
+
.chart-cursor, .chart-tooltip, .dashboard-info-btn, .dashboard-range-bar, .dashboard-chart-info { display: none !important; }
|
|
40
|
+
</style>${e.innerHTML}`)}function sa(e,t){let n="";t==="checklist"?n=`<h2>Checklist</h2><div class="print-checklist">${e.map(s=>`<div class="print-check-item"><span class="print-checkbox">\u25A1</span><span>${S(s.ticket_number)}: ${S(s.title)}</span></div>`).join("")}</div>`:t==="summary"?n=`<h2>Ticket Summary</h2><table class="print-table">
|
|
41
|
+
<thead><tr><th>Ticket</th><th>Title</th><th>Category</th><th>Priority</th><th>Status</th><th>Up Next</th></tr></thead>
|
|
42
|
+
<tbody>${e.map(s=>{let o=a.categories.find(i=>i.id===s.category);return`<tr>
|
|
43
|
+
<td>${S(s.ticket_number)}</td>
|
|
44
|
+
<td>${S(s.title)}</td>
|
|
45
|
+
<td><span class="print-cat" style="background:${I(s.category)}">${S(K(s.category))}</span> ${S(o?.label||s.category)}</td>
|
|
46
|
+
<td>${S(s.priority)}</td>
|
|
47
|
+
<td>${S(s.status.replace(/_/g," "))}</td>
|
|
48
|
+
<td>${s.up_next?"\u2605":""}</td>
|
|
49
|
+
</tr>`}).join("")}</tbody>
|
|
50
|
+
</table>`:n=e.map(s=>{let o=a.categories.find(c=>c.id===s.category),i=O(s.tags),l=[];try{l=JSON.parse(s.notes)}catch{}return Array.isArray(l)||(l=[]),`<div class="print-ticket">
|
|
51
|
+
<div class="print-ticket-header">
|
|
52
|
+
<span class="print-cat" style="background:${I(s.category)}">${S(K(s.category))}</span>
|
|
53
|
+
<strong>${S(s.ticket_number)}</strong>: ${S(s.title)}
|
|
54
|
+
${s.up_next?'<span class="print-star">\u2605</span>':""}
|
|
55
|
+
</div>
|
|
56
|
+
<div class="print-ticket-meta">
|
|
57
|
+
${S(o?.label||s.category)} \xB7 ${S(s.priority)} \xB7 ${S(s.status.replace(/_/g," "))}
|
|
58
|
+
${i.length>0?" \xB7 "+i.map(c=>`<span class="print-tag">${S(c)}</span>`).join(" "):""}
|
|
59
|
+
</div>
|
|
60
|
+
${s.details.trim()?`<div class="print-ticket-details">${S(s.details)}</div>`:""}
|
|
61
|
+
${l.length>0?`<div class="print-ticket-notes"><strong>Notes:</strong>${l.map(c=>`<div class="print-note">${c.created_at?`<span class="print-note-time">${new Date(c.created_at).toLocaleString()}</span>`:""}${S(c.text)}</div>`).join("")}</div>`:""}
|
|
62
|
+
</div>`}).join(""),Ft(`<style>${et()}</style>${n}`)}function S(e){return e.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">")}function et(){return`
|
|
63
|
+
* { box-sizing: border-box; margin: 0; padding: 0; }
|
|
64
|
+
body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; font-size: 12px; color: #111; padding: 20px; }
|
|
65
|
+
h2 { font-size: 16px; margin-bottom: 12px; }
|
|
66
|
+
.print-checklist { display: flex; flex-direction: column; gap: 6px; }
|
|
67
|
+
.print-check-item { display: flex; align-items: center; gap: 8px; font-size: 13px; }
|
|
68
|
+
.print-checkbox { font-size: 16px; color: #999; }
|
|
69
|
+
.print-table { width: 100%; border-collapse: collapse; font-size: 12px; }
|
|
70
|
+
.print-table th, .print-table td { padding: 6px 8px; border: 1px solid #ddd; text-align: left; }
|
|
71
|
+
.print-table th { background: #f5f5f5; font-weight: 600; }
|
|
72
|
+
.print-cat { display: inline-block; padding: 1px 5px; border-radius: 3px; font-size: 9px; font-weight: 600; color: white; text-transform: uppercase; vertical-align: middle; }
|
|
73
|
+
.print-star { color: #eab308; }
|
|
74
|
+
.print-tag { display: inline-block; padding: 1px 6px; background: #f0f0f0; border-radius: 10px; font-size: 10px; }
|
|
75
|
+
.print-ticket { margin-bottom: 16px; padding-bottom: 16px; border-bottom: 1px solid #eee; }
|
|
76
|
+
.print-ticket-header { font-size: 14px; margin-bottom: 4px; }
|
|
77
|
+
.print-ticket-meta { font-size: 11px; color: #666; margin-bottom: 6px; }
|
|
78
|
+
.print-ticket-details { white-space: pre-wrap; font-size: 12px; margin-bottom: 6px; background: #fafafa; padding: 8px; border-radius: 4px; }
|
|
79
|
+
.print-ticket-notes { font-size: 11px; }
|
|
80
|
+
.print-note { margin-top: 4px; padding: 4px 8px; background: #f5f5f5; border-left: 3px solid #3b82f6; border-radius: 3px; }
|
|
81
|
+
.print-note-time { color: #999; font-size: 10px; display: block; margin-bottom: 2px; }
|
|
82
|
+
.dashboard-kpi-row { display: grid; grid-template-columns: repeat(4, 1fr); gap: 12px; margin-bottom: 16px; }
|
|
83
|
+
.dashboard-kpi-card { padding: 12px; border: 1px solid #ddd; border-radius: 6px; text-align: center; }
|
|
84
|
+
.kpi-value { font-size: 24px; font-weight: 700; }
|
|
85
|
+
.kpi-label { font-size: 11px; color: #666; }
|
|
86
|
+
.kpi-trend { font-size: 11px; }
|
|
87
|
+
.kpi-trend.up { color: #22c55e; }
|
|
88
|
+
.kpi-trend.down { color: #ef4444; }
|
|
89
|
+
.dashboard-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }
|
|
90
|
+
.dashboard-chart-card { border: 1px solid #ddd; border-radius: 6px; overflow: hidden; }
|
|
91
|
+
.dashboard-chart-header { padding: 8px 12px; border-bottom: 1px solid #ddd; font-size: 12px; font-weight: 600; }
|
|
92
|
+
.dashboard-chart-body { padding: 8px; }
|
|
93
|
+
.chart-legend { display: flex; flex-wrap: wrap; gap: 6px 12px; padding-bottom: 6px; font-size: 10px; }
|
|
94
|
+
.chart-legend-item { display: inline-flex; align-items: center; gap: 4px; }
|
|
95
|
+
.chart-legend-dot { width: 8px; height: 8px; border-radius: 50%; }
|
|
96
|
+
@media print { body { padding: 0; } }
|
|
97
|
+
`}async function oa(){await ia(),await ra(),await Vt(),la(),H(),await w(),ha(),fa(),ya(),ba(),ka(),Ta(),La(),Sa(),ca(),Pt(),ma(),ga(),Ut(()=>{w()}),ht(),$a(),ua(),document.addEventListener("hotsheet:render",()=>L()),document.addEventListener("hotsheet:show-tags-dialog",()=>{nn()}),document.getElementById("print-btn").addEventListener("click",Qe),xa(),F()}async function ia(){try{let e=await y("/settings");(e.detail_position==="side"||e.detail_position==="bottom")&&(a.settings.detail_position=e.detail_position),e.detail_width&&(a.settings.detail_width=parseInt(e.detail_width,10)||360),e.detail_height&&(a.settings.detail_height=parseInt(e.detail_height,10)||300),e.trash_cleanup_days&&(a.settings.trash_cleanup_days=parseInt(e.trash_cleanup_days,10)||3),e.verified_cleanup_days&&(a.settings.verified_cleanup_days=parseInt(e.verified_cleanup_days,10)||30),(e.layout==="list"||e.layout==="columns")&&(a.layout=e.layout)}catch{}De(a.settings.detail_position),Ae()}async function ra(){try{let e=await y("/categories");e.length>0&&(a.categories=e)}catch{}ot()}function ot(){let e=document.querySelector(".sidebar-section:nth-child(3)");if(e){let t=e.querySelector(".sidebar-label");e.innerHTML="",t&&e.appendChild(t);for(let n of a.categories){let s=v(r("button",{className:`sidebar-item${a.view===`category:${n.id}`?" active":""}`,"data-view":`category:${n.id}`,children:[r("span",{className:"cat-dot",style:`background:${n.color}`})," ",n.label]}));s.addEventListener("click",()=>{document.querySelectorAll(".sidebar-item").forEach(o=>o.classList.remove("active")),s.classList.add("active"),a.view=`category:${n.id}`,a.selectedIds.clear(),rt(),H(),w()}),e.appendChild(s)}}if(a.activeTicketId!=null){let t=a.tickets.find(n=>n.id===a.activeTicketId);t&&pe(t.category)}}async function la(){try{let e=await y("/file-settings");if(e.appName){document.title=e.appName;let t=document.querySelector(".app-title h1");t&&(t.textContent=e.appName)}}catch{}}function ca(){let e=document.getElementById("settings-overlay"),t=document.getElementById("settings-close"),n=document.getElementById("settings-btn"),s=document.querySelectorAll(".settings-tab"),o=document.querySelectorAll(".settings-tab-panel");s.forEach(k=>{k.addEventListener("click",()=>{let x=k.dataset.tab;s.forEach(B=>B.classList.remove("active")),o.forEach(B=>B.classList.remove("active")),k.classList.add("active"),document.querySelector(`.settings-tab-panel[data-panel="${x}"]`)?.classList.add("active")})}),n.addEventListener("click",()=>{document.getElementById("settings-trash-days").value=String(a.settings.trash_cleanup_days),document.getElementById("settings-verified-days").value=String(a.settings.verified_cleanup_days),e.style.display="flex",Fe(),y("/file-settings").then(k=>{document.getElementById("settings-app-name").value=k.appName||"",document.getElementById("settings-backup-dir").value=k.backupDir||""})}),t.addEventListener("click",()=>{e.style.display="none"}),e.addEventListener("click",k=>{k.target===e&&(e.style.display="none")});let i=document.getElementById("settings-trash-days"),l=null;i.addEventListener("input",()=>{l&&clearTimeout(l),l=setTimeout(()=>{let k=Math.max(1,parseInt(i.value,10)||3);i.value=String(k),a.settings.trash_cleanup_days=k,y("/settings",{method:"PATCH",body:{trash_cleanup_days:String(k)}})},500)});let c=document.getElementById("settings-verified-days"),u=null;c.addEventListener("input",()=>{u&&clearTimeout(u),u=setTimeout(()=>{let k=Math.max(1,parseInt(c.value,10)||30);c.value=String(k),a.settings.verified_cleanup_days=k,y("/settings",{method:"PATCH",body:{verified_cleanup_days:String(k)}})},500)});let d=document.getElementById("settings-app-name"),p=document.getElementById("settings-app-name-hint"),m=null;d.addEventListener("input",()=>{m&&clearTimeout(m),m=setTimeout(()=>{let k=d.value.trim();y("/file-settings",{method:"PATCH",body:{appName:k}}).then(()=>{let x=k||"Hot Sheet";document.title=x;let B=document.querySelector(".app-title h1");B&&(B.textContent=x),p.textContent=k?"Saved. Restart the desktop app to update the title bar.":"Using default name."})},800)});let g=document.getElementById("check-updates-btn"),f=document.getElementById("check-updates-status");g.addEventListener("click",async()=>{let k=it();if(k){g.disabled=!0,g.textContent="Checking...",f.textContent="";try{let x=await k("check_for_update");x?(f.textContent=`Update available: v${x}`,document.getElementById("settings-overlay").style.display="none",Gt(x)):f.textContent="Your software is up to date."}catch{f.textContent="Could not check for updates."}g.textContent="Check for Updates",g.disabled=!1}});let b=document.getElementById("settings-backup-dir"),E=document.getElementById("settings-backup-dir-hint"),T=null;b.addEventListener("input",()=>{T&&clearTimeout(T),T=setTimeout(()=>{let k=b.value.trim();y("/file-settings",{method:"PATCH",body:{backupDir:k}}).then(()=>{E.textContent=k?"Saved. New backups will use this location.":"Using default location inside the data directory."})},800)}),da()}function $e(){let e=document.getElementById("category-list");e.innerHTML="";for(let t=0;t<a.categories.length;t++){let n=a.categories[t],s=v(r("div",{className:"category-row",children:[r("input",{type:"color",className:"category-color-input",value:n.color,title:"Color"}),r("input",{type:"text",className:"category-label-input",value:n.label,placeholder:"Label",title:"Display name"}),r("input",{type:"text",className:"category-short-input",value:n.shortLabel,placeholder:"ABR",title:"Short label (3 chars)",maxlength:"4"}),r("input",{type:"text",className:"category-key-input",value:n.shortcutKey,placeholder:"k",title:"Keyboard shortcut",maxlength:"1"}),r("input",{type:"text",className:"category-desc-input",value:n.description,placeholder:"Description...",title:"Description (for AI tools)"}),r("button",{className:"category-delete-btn",title:"Remove",children:"\xD7"})]})),o=s.querySelectorAll("input"),[i,l,c,u,d]=o,p=()=>{jt()};i.addEventListener("input",()=>{a.categories[t].color=i.value,p()}),l.addEventListener("input",()=>{a.categories[t].label=l.value,(!n.id||n.id==="")&&(a.categories[t].id=l.value.toLowerCase().replace(/[^a-z0-9]+/g,"_").replace(/^_|_$/g,"")),p()}),c.addEventListener("input",()=>{a.categories[t].shortLabel=c.value.toUpperCase(),p()}),u.addEventListener("input",()=>{let m=u.value.toLowerCase().slice(0,1);u.value=m,a.categories[t].shortcutKey=m,Wt(),p()}),d.addEventListener("input",()=>{a.categories[t].description=d.value,p()}),s.querySelector(".category-delete-btn").addEventListener("click",()=>{a.categories.splice(t,1),$e(),jt()}),e.appendChild(s)}Wt()}function Wt(){let e=document.querySelectorAll(".category-key-input"),t=new Map;a.categories.forEach((n,s)=>{if(n.shortcutKey){let o=n.shortcutKey.toLowerCase();t.has(o)||t.set(o,[]),t.get(o).push(s)}}),e.forEach((n,s)=>{let o=a.categories[s]?.shortcutKey?.toLowerCase();o&&t.get(o).length>1?n.classList.add("category-key-conflict"):n.classList.remove("category-key-conflict")})}var tt=null;function jt(){tt&&clearTimeout(tt),tt=setTimeout(async()=>{await y("/categories",{method:"PUT",body:a.categories}),ot()},500)}function da(){document.getElementById("category-add-btn").addEventListener("click",()=>{a.categories.push({id:"",label:"",shortLabel:"",color:"#6b7280",shortcutKey:"",description:""}),$e();let n=document.querySelectorAll(".category-row");n[n.length-1]?.querySelector(".category-label-input")?.focus()});let e=document.getElementById("category-preset-select");y("/category-presets").then(n=>{for(let s of n)e.appendChild(v(r("option",{value:s.id,children:s.name})))}),e.addEventListener("change",async()=>{if(!e.value)return;let s=(await y("/category-presets")).find(o=>o.id===e.value);s&&(a.categories=[...s.categories],await y("/categories",{method:"PUT",body:a.categories}),$e(),ot()),e.value=""}),document.getElementById("settings-btn").addEventListener("click",()=>{$e()})}async function ua(){let e=it();if(!e)return;let t=document.getElementById("settings-updates-section");t&&(t.style.display="");let n=document.getElementById("settings-tab-updates");n&&(n.style.display="");let s=[0,3e3,1e4];for(let o of s){o>0&&await new Promise(i=>setTimeout(i,o));try{let i=await e("get_pending_update");if(i){Gt(i);return}}catch{return}}}function it(){return window.__TAURI__?.core?.invoke??null}function Gt(e){let t=document.getElementById("update-banner");if(!t)return;let n=document.getElementById("update-banner-label");n&&(n.textContent=`Update available: v${e}`),t.style.display="flex";let s=document.getElementById("update-install-btn");s?.addEventListener("click",async()=>{if(s){s.textContent="Installing...",s.disabled=!0;try{await it()?.("install_update"),n&&(n.textContent="Update installed! Restart the app to apply."),s.style.display="none"}catch{s.textContent="Install Failed",s.disabled=!1}}}),document.getElementById("update-banner-dismiss")?.addEventListener("click",()=>{t.style.display="none"})}function pa(){let e=document.getElementById("skills-banner");if(!e)return;e.style.display="flex",document.getElementById("skills-banner-dismiss")?.addEventListener("click",()=>{e.style.display="none"})}function ma(){let e=document.getElementById("copy-prompt-section"),t=document.getElementById("copy-prompt-btn"),n=document.getElementById("copy-prompt-label"),s=document.getElementById("copy-prompt-icon"),o="";y("/worklist-info").then(i=>{o=i.prompt,e.style.display="",i.skillCreated&&pa()}),t.addEventListener("click",()=>{o!==""&&navigator.clipboard.writeText(o).then(()=>{n.textContent="Copied!",s.innerHTML='<svg xmlns="http://www.w3.org/2000/svg" width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M20 6L9 17l-5-5"/></svg>',setTimeout(()=>{n.textContent="Copy AI prompt",s.innerHTML='<svg xmlns="http://www.w3.org/2000/svg" width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg>'},1500)})})}function ga(){let e=document.getElementById("glassbox-btn"),t=document.getElementById("glassbox-icon");y("/glassbox/status").then(({available:n})=>{n&&(t.src="/static/assets/glassbox-icon.png",e.style.display="")}).catch(()=>{}),e.addEventListener("click",()=>{y("/glassbox/launch",{method:"POST"})})}function st(){let e=document.getElementById("layout-toggle"),t=Le(),n=e.querySelector('[data-layout="columns"]');n.disabled=!t,n.style.opacity=t?"":"0.3";let s=a.layout==="columns"&&!t?"list":a.layout;e.querySelectorAll(".layout-btn").forEach(o=>{o.classList.toggle("active",o.dataset.layout===s)})}function fa(){document.getElementById("layout-toggle").querySelectorAll(".layout-btn").forEach(t=>{t.addEventListener("click",()=>{let n=t.dataset.layout;n==="columns"&&!Le()||(a.layout=n,H(),st(),L(),y("/settings",{method:"PATCH",body:{layout:n}}))})}),st()}function Jt(){document.getElementById("detail-position-toggle").querySelectorAll(".layout-btn").forEach(t=>{t.classList.toggle("active",t.dataset.position===a.settings.detail_position)})}function ya(){document.getElementById("detail-position-toggle").querySelectorAll(".layout-btn").forEach(t=>{t.addEventListener("click",()=>{let n=t.dataset.position;a.settings.detail_position=n,De(n),Ae(),Jt(),y("/settings",{method:"PATCH",body:{detail_position:n}})})}),Jt()}function Zt(e){return e==="up-next"?{action:"up_next",value:!0}:e==="open"?{action:"status",value:"not_started"}:e==="completed"?{action:"status",value:"completed"}:e==="verified"?{action:"status",value:"verified"}:e==="backlog"?{action:"status",value:"backlog"}:e==="archive"?{action:"status",value:"archive"}:e==="trash"?{action:"delete",value:null}:e.startsWith("category:")?{action:"category",value:e.split(":")[1]}:e.startsWith("priority:")?{action:"priority",value:e.split(":")[1]}:null}async function va(e,t){let n=Zt(e);if(!n)return;let s=a.tickets.filter(o=>t.includes(o.id));n.action==="delete"?await C(s,{ids:t,action:"delete"},"Delete tickets"):await C(s,{ids:t,action:n.action,value:n.value},`Change ${n.action}`),H(),w()}function ha(){document.querySelectorAll(".sidebar-item[data-view]").forEach(t=>{t.addEventListener("click",()=>{document.querySelectorAll(".sidebar-item").forEach(s=>s.classList.remove("active")),t.classList.add("active"),a.view=t.dataset.view,a.selectedIds.clear(),rt(),H(),st(),w()});let n=t.dataset.view;Zt(n)&&(t.addEventListener("dragover",s=>{s.preventDefault(),s.dataTransfer.dropEffect="move",t.classList.add("drop-target")}),t.addEventListener("dragleave",()=>{t.classList.remove("drop-target")}),t.addEventListener("drop",s=>{s.preventDefault(),t.classList.remove("drop-target");let o=[...U];o.length!==0&&va(n,o)}))})}function ba(){let e=document.getElementById("sort-select");e.addEventListener("change",()=>{let[t,n]=e.value.split(":");a.sortBy=t,a.sortDir=n,H(),w()})}var nt=null;function ka(){let e=document.getElementById("search-input");e.addEventListener("input",()=>{nt&&clearTimeout(nt),nt=setTimeout(()=>{a.search=e.value,H(),w()},200)}),e.addEventListener("keydown",t=>{t.key==="Escape"&&(e.value="",a.search="",H(),w())})}function rt(){let e=document.getElementById("dashboard-container");e&&(e.id="ticket-list",e.innerHTML="",Ea())}var Qt=["search-input","layout-toggle","sort-select","detail-position-toggle","glassbox-btn"];function wa(){a.view="dashboard",document.querySelectorAll(".sidebar-item").forEach(o=>o.classList.remove("active"));for(let o of Qt){let i=document.getElementById(o);if(i){let l=i.closest(".search-box, .layout-toggle, .sort-controls")||i;l.style.display="none"}}let e=document.getElementById("batch-toolbar");e&&(e.style.display="none");let t=document.getElementById("detail-panel");t&&(t.style.display="none");let n=document.getElementById("detail-resize-handle");n&&(n.style.display="none");let s=document.getElementById("ticket-list");s.innerHTML="",s.id="dashboard-container",s.classList.remove("ticket-list-columns"),Xe(s)}function Ea(){for(let e of Qt){let t=document.getElementById(e);if(t){let n=t.closest(".search-box, .layout-toggle, .sort-controls")||t;n.style.display=""}}rt()}async function xa(){let e=await zt(),t=document.getElementById("stats-bar");t&&t.after(e),e.addEventListener("click",()=>wa())}var en=[{key:"1",value:"highest",label:"Highest"},{key:"2",value:"high",label:"High"},{key:"3",value:"default",label:"Default"},{key:"4",value:"low",label:"Low"},{key:"5",value:"lowest",label:"Lowest"}],tn=[{key:"n",value:"not_started",label:"Not Started"},{key:"s",value:"started",label:"Started"},{key:"c",value:"completed",label:"Completed"},{key:"v",value:"verified",label:"Verified"},{key:"b",value:"backlog",label:"Backlog"},{key:"a",value:"archive",label:"Archive"}];function Ta(){let e=document.getElementById("batch-category");e.addEventListener("click",o=>{o.stopPropagation(),_();let i=N(e,a.categories.map(l=>({label:l.label,key:l.shortcutKey,color:l.color,action:async()=>{let c=Array.from(a.selectedIds),u=a.tickets.filter(d=>a.selectedIds.has(d.id));await C(u,{ids:c,action:"category",value:l.id},"Batch change category"),w()}})));document.body.appendChild(i),M(i,e),i.style.visibility=""});let t=document.getElementById("batch-priority");t.addEventListener("click",o=>{o.stopPropagation(),_();let i=N(t,en.map(l=>({label:l.label,key:l.key,icon:A(l.value),iconColor:P(l.value),action:async()=>{let c=Array.from(a.selectedIds),u=a.tickets.filter(d=>a.selectedIds.has(d.id));await C(u,{ids:c,action:"priority",value:l.value},"Batch change priority"),w()}})));document.body.appendChild(i),M(i,t),i.style.visibility=""});let n=document.getElementById("batch-status");n.addEventListener("click",o=>{o.stopPropagation(),_();let i=N(n,tn.map(l=>({label:l.label,key:l.key,icon:z(l.value),action:async()=>{let c=Array.from(a.selectedIds),u=a.tickets.filter(d=>a.selectedIds.has(d.id));await C(u,{ids:c,action:"status",value:l.value},"Batch change status"),w()}})));document.body.appendChild(i),M(i,n),i.style.visibility=""}),document.getElementById("batch-upnext").addEventListener("click",async()=>{let o=a.tickets.filter(u=>a.selectedIds.has(u.id)),l=!o.every(u=>u.up_next),c=Array.from(a.selectedIds);if(l){let u=o.filter(d=>d.status==="completed"||d.status==="verified");if(u.length>0){let d=[{ids:u.map(p=>p.id),action:"status",value:"not_started"},{ids:c,action:"up_next",value:!0}];await Re(o,d,"Batch toggle up next")}else await C(o,{ids:c,action:"up_next",value:!0},"Batch toggle up next")}else await C(o,{ids:c,action:"up_next",value:!1},"Batch toggle up next");w()}),document.getElementById("batch-delete").addEventListener("click",async()=>{let o=Array.from(a.selectedIds),i=a.tickets.filter(l=>a.selectedIds.has(l.id));await C(i,{ids:o,action:"delete"},"Batch delete"),a.selectedIds.clear(),w()});let s=document.getElementById("batch-more");s.addEventListener("click",o=>{o.stopPropagation(),_();let i=N(s,[{label:"Tags...",key:"t",action:()=>{nn()}},{label:"Duplicate",key:"d",action:async()=>{let l=Array.from(a.selectedIds),c=await y("/tickets/duplicate",{method:"POST",body:{ids:l}});a.selectedIds.clear();for(let u of c)a.selectedIds.add(u.id);w()}},{label:"",key:"",separator:!0,action:()=>{}},{label:"Move to Backlog",key:"b",action:async()=>{let l=Array.from(a.selectedIds),c=a.tickets.filter(u=>a.selectedIds.has(u.id));await C(c,{ids:l,action:"status",value:"backlog"},"Move to backlog"),a.selectedIds.clear(),w()}},{label:"Archive",key:"a",action:async()=>{let l=Array.from(a.selectedIds),c=a.tickets.filter(u=>a.selectedIds.has(u.id));await C(c,{ids:l,action:"status",value:"archive"},"Archive"),a.selectedIds.clear(),w()}}]);document.body.appendChild(i),M(i,s),i.style.visibility=""}),document.getElementById("batch-select-all").addEventListener("change",o=>{if(o.target.checked)for(let l of a.tickets)a.selectedIds.add(l.id);else a.selectedIds.clear();L()})}var W=null;function La(){document.getElementById("detail-close").addEventListener("click",ft);let e=["detail-title","detail-details"];for(let d of e){let p=document.getElementById(d);p.addEventListener("input",()=>{let m=a.tickets.find(g=>g.id===a.activeTicketId);if(m){let g=d.replace("detail-","");Ee(m,g,p.value)}W&&clearTimeout(W),W=setTimeout(()=>{if(a.activeTicketId==null)return;let g=d.replace("detail-","");y(`/tickets/${a.activeTicketId}`,{method:"PATCH",body:{[g]:p.value}}).then(()=>{w()})},300)})}async function t(d,p){if(a.activeTicketId==null)return;let m=a.tickets.find(g=>g.id===a.activeTicketId);m?await R(m,{[d]:p},`Change ${d}`):await y(`/tickets/${a.activeTicketId}`,{method:"PATCH",body:{[d]:p}}),w(),ee(a.activeTicketId)}document.getElementById("detail-category").addEventListener("click",d=>{d.stopPropagation();let p=d.currentTarget;if(p.disabled)return;_();let m=p.dataset.value||"",g=N(p,a.categories.map(f=>({label:f.label,key:f.shortcutKey,color:f.color,active:f.id===m,action:()=>{pe(f.id),t("category",f.id)}})));document.body.appendChild(g),M(g,p),g.style.visibility=""}),document.getElementById("detail-priority").addEventListener("click",d=>{d.stopPropagation();let p=d.currentTarget;if(p.disabled)return;_();let m=p.dataset.value||"",g=N(p,en.map(f=>({label:f.label,key:f.key,icon:A(f.value),iconColor:P(f.value),active:f.value===m,action:()=>{be(f.value),t("priority",f.value)}})));document.body.appendChild(g),M(g,p),g.style.visibility=""}),document.getElementById("detail-status").addEventListener("click",d=>{d.stopPropagation();let p=d.currentTarget;if(p.disabled)return;_();let m=p.dataset.value||"",g=N(p,tn.map(f=>({label:f.label,key:f.key,icon:z(f.value),active:f.value===m,action:()=>{ke(f.value),t("status",f.value)}})));document.body.appendChild(g),M(g,p),g.style.visibility=""}),document.getElementById("detail-upnext").addEventListener("click",async()=>{if(a.activeTicketId==null)return;let d=a.tickets.find(p=>p.id===a.activeTicketId);d?!d.up_next&&(d.status==="completed"||d.status==="verified")?await R(d,{status:"not_started",up_next:!0},"Toggle up next"):await R(d,{up_next:!d.up_next},"Toggle up next"):await y(`/tickets/${a.activeTicketId}/up-next`,{method:"POST"}),w(),ee(a.activeTicketId)}),document.getElementById("detail-add-note-btn").addEventListener("click",async()=>{a.activeTicketId!=null&&(await y(`/tickets/${a.activeTicketId}`,{method:"PATCH",body:{notes:"(new note)"}}),ee(a.activeTicketId))}),document.getElementById("detail-file-input").addEventListener("change",async d=>{let p=d.target,m=p.files?.[0];!m||a.activeTicketId==null||(await pt(`/tickets/${a.activeTicketId}/attachments`,m),p.value="",ee(a.activeTicketId),w())}),document.getElementById("detail-attachments").addEventListener("click",async d=>{let p=d.target,m=p.closest(".attachment-reveal");if(m){let b=m.dataset.attId;b&&y(`/attachments/${b}/reveal`,{method:"POST"});return}let g=p.closest(".attachment-delete");if(g===null)return;let f=g.dataset.attId;f===void 0||f===""||(await y(`/attachments/${f}`,{method:"DELETE"}),a.activeTicketId!=null&&ee(a.activeTicketId))});let n=document.getElementById("detail-tag-input"),s=null,o=-1,i=[];y("/tags").then(d=>{i=d});function l(){s?.remove(),s=null,o=-1}function c(){l();let d=n.value.trim().toLowerCase();if(!d)return;let p=a.tickets.find(b=>b.id===a.activeTicketId),m=p?O(p.tags):[],g=i.filter(b=>b.toLowerCase().includes(d)&&!m.includes(b));if(g.length===0)return;s=v(r("div",{className:"tag-autocomplete"}));for(let b=0;b<g.length;b++){let E=v(r("div",{className:"tag-autocomplete-item",children:g[b]}));E.addEventListener("mousedown",T=>{T.preventDefault(),n.value=g[b],l(),u()}),s.appendChild(E)}let f=n.getBoundingClientRect();s.style.position="fixed",s.style.left=`${f.left}px`,s.style.top=`${f.bottom+2}px`,s.style.width=`${f.width}px`,document.body.appendChild(s)}async function u(){let d=n.value.trim();if(!d||a.activeTicketId==null)return;let p=a.tickets.find(f=>f.id===a.activeTicketId);if(!p)return;let m=O(p.tags);if(m.includes(d)){n.value="";return}let g=[...m,d];n.value="",l(),await y(`/tickets/${a.activeTicketId}`,{method:"PATCH",body:{tags:JSON.stringify(g)}}),p.tags=JSON.stringify(g),ue(g,!1),i.includes(d)||i.push(d)}n.addEventListener("input",()=>{c()}),n.addEventListener("blur",()=>{l()}),n.addEventListener("keydown",d=>{if(d.key==="Enter"){if(d.preventDefault(),s&&o>=0){let p=s.querySelectorAll(".tag-autocomplete-item");n.value=p[o]?.textContent||n.value}l(),u()}else if(d.key==="Escape")l();else if(d.key==="ArrowDown"&&s){d.preventDefault();let p=s.querySelectorAll(".tag-autocomplete-item");o=Math.min(o+1,p.length-1),p.forEach((m,g)=>m.classList.toggle("active",g===o))}else if(d.key==="ArrowUp"&&s){d.preventDefault();let p=s.querySelectorAll(".tag-autocomplete-item");o=Math.max(o-1,0),p.forEach((m,g)=>m.classList.toggle("active",g===o))}})}async function nn(){let e=a.tickets.filter(p=>a.selectedIds.has(p.id));if(e.length===0)return;let t=await y("/tags");for(let p of e)for(let m of O(p.tags))t.includes(m)||t.push(m);t.sort();let n=new Map;for(let p of t){let m=e.filter(g=>O(g.tags).includes(p)).length;m===e.length?n.set(p,"checked"):m===0?n.set(p,"unchecked"):n.set(p,"mixed")}let s=new Map(n),o=new Map(n),i=v(r("div",{className:"tags-dialog-overlay",children:r("div",{className:"tags-dialog",children:[r("div",{className:"tags-dialog-header",children:[r("span",{children:"Tags"}),r("button",{className:"detail-close",id:"tags-dialog-close",children:"\xD7"})]}),r("div",{className:"tags-dialog-body",id:"tags-dialog-body"}),r("div",{className:"tags-dialog-new",children:[r("input",{type:"text",id:"tags-dialog-new-input",placeholder:"New tag..."}),r("button",{className:"btn btn-sm",id:"tags-dialog-add-btn",children:"Add"})]}),r("div",{className:"tags-dialog-footer",children:[r("button",{className:"btn btn-sm",id:"tags-dialog-cancel",children:"Cancel"}),r("button",{className:"btn btn-sm btn-accent",id:"tags-dialog-done",children:"Done"})]})]})}));function l(){let p=i.querySelector("#tags-dialog-body");p.innerHTML="";for(let m of t){let g=o.get(m),f=v(r("label",{className:"tags-dialog-row",children:[r("input",{type:"checkbox",checked:g==="checked"}),r("span",{children:m})]})),b=f.querySelector("input");g==="mixed"&&(b.indeterminate=!0),b.addEventListener("change",()=>{o.set(m,b.checked?"checked":"unchecked")}),p.appendChild(f)}t.length===0&&(p.innerHTML='<div style="padding:12px 16px;color:var(--text-muted);font-size:13px">No tags yet. Create one below.</div>')}l(),document.body.appendChild(i);let c=i.querySelector("#tags-dialog-new-input"),u=()=>{let p=c.value.trim();if(!p||t.includes(p)){c.value="";return}t.push(p),t.sort(),o.set(p,"checked"),s.set(p,"unchecked"),c.value="",l()};i.querySelector("#tags-dialog-add-btn").addEventListener("click",u),c.addEventListener("keydown",p=>{p.key==="Enter"&&(p.preventDefault(),u())});let d=()=>i.remove();i.querySelector("#tags-dialog-close").addEventListener("click",d),i.querySelector("#tags-dialog-cancel").addEventListener("click",d),i.addEventListener("click",p=>{p.target===i&&d()}),i.querySelector("#tags-dialog-done").addEventListener("click",async()=>{let p=[],m=[];for(let g of t){let f=s.get(g),b=o.get(g);f!==b&&(b==="checked"?p.push(g):b==="unchecked"&&m.push(g))}if(p.length>0||m.length>0){for(let g of e){let f=O(g.tags),b=[...f];for(let E of p)b.includes(E)||b.push(E);for(let E of m)b=b.filter(T=>T!==E);JSON.stringify(b)!==JSON.stringify(f)&&await y(`/tickets/${g.id}`,{method:"PATCH",body:{tags:JSON.stringify(b)}})}w(),me()}d()})}function Ia(e){if(!e||e==="")return[];try{let t=JSON.parse(e);if(Array.isArray(t))return t}catch{}return e.trim()?[{text:e,created_at:""}]:[]}function Ca(e){let t=[];t.push(`${e.ticket_number}: ${e.title}`),e.details.trim()&&(t.push(""),t.push(e.details.trim()));let n=Ia(e.notes);if(n.length>0){t.push("");for(let s of n)t.push(`- ${s.text}`)}return t.join(`
|
|
98
|
+
`)}function Yt(){console.log("[undo] triggerUndo called, canUndo:",xt()),W&&(clearTimeout(W),W=null),ze(),wt().then(()=>console.log("[undo] performUndo completed")).catch(e=>console.error("[undo] performUndo error:",e))}function Xt(){console.log("[undo] triggerRedo called, canRedo:",Tt()),W&&(clearTimeout(W),W=null),ze(),Et().then(()=>console.log("[undo] performRedo completed")).catch(e=>console.error("[undo] performRedo error:",e))}function Sa(){window.addEventListener("app:undo",Yt),window.addEventListener("app:redo",Xt),document.addEventListener("keydown",e=>{(e.metaKey||e.ctrlKey)&&e.key.toLowerCase()==="z"&&(e.preventDefault(),e.stopPropagation(),e.shiftKey?Xt():Yt())},!0),document.addEventListener("keydown",e=>{let t=e.target.tagName,n=t==="INPUT"||t==="TEXTAREA"||t==="SELECT",s=document.getElementById("settings-overlay");if(e.key==="Escape"&&s.style.display!=="none"){s.style.display="none";return}if(e.key==="Escape"){let o=document.activeElement;if(o&&(o.tagName==="INPUT"||o.tagName==="TEXTAREA")&&o.closest(".detail-panel, .detail-body")){o.blur();return}a.selectedIds.size>0&&(a.selectedIds.clear(),L());return}if((e.metaKey||e.ctrlKey)&&e.key==="a"&&!n){e.preventDefault(),a.selectedIds.clear();for(let o of a.tickets)a.selectedIds.add(o.id);L();return}if((e.metaKey||e.ctrlKey)&&e.key==="d"){if(a.selectedIds.size>0){e.preventDefault();let o=a.tickets.filter(u=>a.selectedIds.has(u.id)),l=!o.every(u=>u.up_next),c=Array.from(a.selectedIds);if(l){let u=o.filter(d=>d.status==="completed"||d.status==="verified");if(u.length>0){Re(o,[{ids:u.map(d=>d.id),action:"status",value:"not_started"},{ids:c,action:"up_next",value:!0}],"Toggle up next").then(()=>{w()});return}}C(o,{ids:c,action:"up_next",value:l},"Toggle up next").then(()=>{w()})}return}if((e.metaKey||e.ctrlKey)&&e.key==="c"&&a.selectedIds.size>0&&!(n&&!e.altKey)){let o=!e.altKey&&window.getSelection();if(!(o&&!o.isCollapsed&&o.toString().trim()!=="")){e.preventDefault();let l=a.tickets.filter(c=>a.selectedIds.has(c.id)).map(Ca).join(`
|
|
3
99
|
|
|
4
|
-
`);navigator.clipboard.writeText(
|
|
100
|
+
`);navigator.clipboard.writeText(l);return}}if((e.metaKey||e.ctrlKey)&&e.key==="n"){e.preventDefault(),F();return}if((e.metaKey||e.ctrlKey)&&e.key==="p"){e.preventDefault(),Qe();return}if((e.metaKey||e.ctrlKey)&&e.key==="f"){e.preventDefault(),document.getElementById("search-input").focus();return}if(e.key==="n"&&!n){e.preventDefault(),F();return}})}var at=0;function $a(){async function e(){try{let t=await y(`/poll?version=${at}`);t.version>at&&(at=t.version,a.backupPreview?.active||w())}catch{await new Promise(t=>setTimeout(t,5e3))}setTimeout(e,100)}e()}oa();})();
|