@starlove/orbit 1.3.5 → 1.4.1
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/Dockerfile +2 -1
- package/README.md +10 -9
- package/SKILL-ORBIT.md +41 -17
- package/dist/full/fonts/Chakra_Petch/ChakraPetch-Bold.ttf +0 -0
- package/dist/full/fonts/Chakra_Petch/ChakraPetch-BoldItalic.ttf +0 -0
- package/dist/full/fonts/Chakra_Petch/ChakraPetch-Italic.ttf +0 -0
- package/dist/full/fonts/Chakra_Petch/ChakraPetch-Light.ttf +0 -0
- package/dist/full/fonts/Chakra_Petch/ChakraPetch-LightItalic.ttf +0 -0
- package/dist/full/fonts/Chakra_Petch/ChakraPetch-Medium.ttf +0 -0
- package/dist/full/fonts/Chakra_Petch/ChakraPetch-MediumItalic.ttf +0 -0
- package/dist/full/fonts/Chakra_Petch/ChakraPetch-Regular.ttf +0 -0
- package/dist/full/fonts/Chakra_Petch/ChakraPetch-SemiBold.ttf +0 -0
- package/dist/full/fonts/Chakra_Petch/ChakraPetch-SemiBoldItalic.ttf +0 -0
- package/dist/full/fonts/Chakra_Petch/OFL.txt +93 -0
- package/dist/full/fonts/Inter/Inter-Italic-VariableFont_opsz,wght.ttf +0 -0
- package/dist/full/fonts/Inter/Inter-VariableFont_opsz,wght.ttf +0 -0
- package/dist/full/fonts/Inter/OFL.txt +93 -0
- package/dist/full/fonts/Inter/README.txt +118 -0
- package/dist/full/fonts/JetBrains_Mono/JetBrainsMono-Italic-VariableFont_wght.ttf +0 -0
- package/dist/full/fonts/JetBrains_Mono/JetBrainsMono-VariableFont_wght.ttf +0 -0
- package/dist/full/fonts/JetBrains_Mono/OFL.txt +93 -0
- package/dist/full/fonts/JetBrains_Mono/README.txt +79 -0
- package/dist/full/fonts/OpenRing-Regular.ttf +0 -0
- package/dist/full/fonts/Open_Sans/OFL.txt +93 -0
- package/dist/full/fonts/Open_Sans/OpenSans-Italic-VariableFont_wdth,wght.ttf +0 -0
- package/dist/full/fonts/Open_Sans/OpenSans-VariableFont_wdth,wght.ttf +0 -0
- package/dist/full/fonts/Open_Sans/README.txt +100 -0
- package/dist/full/fonts/Orbitron/OFL.txt +93 -0
- package/dist/full/fonts/Orbitron/Orbitron-VariableFont_wght.ttf +0 -0
- package/dist/full/fonts/Orbitron/README.txt +68 -0
- package/dist/full/fonts/Rajdhani/OFL.txt +93 -0
- package/dist/full/fonts/Rajdhani/Rajdhani-Bold.ttf +0 -0
- package/dist/full/fonts/Rajdhani/Rajdhani-Light.ttf +0 -0
- package/dist/full/fonts/Rajdhani/Rajdhani-Medium.ttf +0 -0
- package/dist/full/fonts/Rajdhani/Rajdhani-Regular.ttf +0 -0
- package/dist/full/fonts/Rajdhani/Rajdhani-SemiBold.ttf +0 -0
- package/dist/full/fonts/runescape-uf.ttf +0 -0
- package/dist/full/index.html +135 -25
- package/dist/full/js/app.4e6fbe20.js +952 -0
- package/dist/full/js/app.4e6fbe20.js.map +7 -0
- package/dist/full/styles.4e60d824.css +1 -0
- package/dist/full/version.json +2 -2
- package/docs/AGENT_PROTOCOL.md +20 -13
- package/docs/ORBIT_DISPATCH.md +73 -38
- package/docs/UPDATING.md +114 -0
- package/package.json +5 -7
- package/public/fonts/Chakra_Petch/ChakraPetch-Bold.ttf +0 -0
- package/public/fonts/Chakra_Petch/ChakraPetch-BoldItalic.ttf +0 -0
- package/public/fonts/Chakra_Petch/ChakraPetch-Italic.ttf +0 -0
- package/public/fonts/Chakra_Petch/ChakraPetch-Light.ttf +0 -0
- package/public/fonts/Chakra_Petch/ChakraPetch-LightItalic.ttf +0 -0
- package/public/fonts/Chakra_Petch/ChakraPetch-Medium.ttf +0 -0
- package/public/fonts/Chakra_Petch/ChakraPetch-MediumItalic.ttf +0 -0
- package/public/fonts/Chakra_Petch/ChakraPetch-Regular.ttf +0 -0
- package/public/fonts/Chakra_Petch/ChakraPetch-SemiBold.ttf +0 -0
- package/public/fonts/Chakra_Petch/ChakraPetch-SemiBoldItalic.ttf +0 -0
- package/public/fonts/Chakra_Petch/OFL.txt +93 -0
- package/public/fonts/Inter/Inter-Italic-VariableFont_opsz,wght.ttf +0 -0
- package/public/fonts/Inter/Inter-VariableFont_opsz,wght.ttf +0 -0
- package/public/fonts/Inter/OFL.txt +93 -0
- package/public/fonts/Inter/README.txt +118 -0
- package/public/fonts/JetBrains_Mono/JetBrainsMono-Italic-VariableFont_wght.ttf +0 -0
- package/public/fonts/JetBrains_Mono/JetBrainsMono-VariableFont_wght.ttf +0 -0
- package/public/fonts/JetBrains_Mono/OFL.txt +93 -0
- package/public/fonts/JetBrains_Mono/README.txt +79 -0
- package/public/fonts/OpenRing-Regular.ttf +0 -0
- package/public/fonts/Open_Sans/OFL.txt +93 -0
- package/public/fonts/Open_Sans/OpenSans-Italic-VariableFont_wdth,wght.ttf +0 -0
- package/public/fonts/Open_Sans/OpenSans-VariableFont_wdth,wght.ttf +0 -0
- package/public/fonts/Open_Sans/README.txt +100 -0
- package/public/fonts/Orbitron/OFL.txt +93 -0
- package/public/fonts/Orbitron/Orbitron-VariableFont_wght.ttf +0 -0
- package/public/fonts/Orbitron/README.txt +68 -0
- package/public/fonts/Rajdhani/OFL.txt +93 -0
- package/public/fonts/Rajdhani/Rajdhani-Bold.ttf +0 -0
- package/public/fonts/Rajdhani/Rajdhani-Light.ttf +0 -0
- package/public/fonts/Rajdhani/Rajdhani-Medium.ttf +0 -0
- package/public/fonts/Rajdhani/Rajdhani-Regular.ttf +0 -0
- package/public/fonts/Rajdhani/Rajdhani-SemiBold.ttf +0 -0
- package/public/fonts/runescape-uf.ttf +0 -0
- package/public/index.html +133 -23
- package/public/js/artifact-drawer.js +79 -0
- package/public/js/board-export.js +161 -0
- package/public/js/board-menu.js +219 -17
- package/public/js/card-actions.js +1 -1
- package/public/js/create-card.js +60 -23
- package/public/js/drawer.js +164 -4
- package/public/js/font-preference.js +230 -0
- package/public/js/format.js +0 -10
- package/public/js/icons.js +16 -0
- package/public/js/local-backend.js +31 -4
- package/public/js/main.js +7 -1
- package/public/js/modal.js +3 -1
- package/public/js/panel.js +58 -0
- package/public/js/settings-tabs.js +1 -1
- package/public/js/settings.js +606 -275
- package/public/js/sse.js +3 -0
- package/public/js/state.js +1 -1
- package/public/js/text-editing.js +128 -0
- package/public/js/ticket-detail.js +377 -148
- package/public/js/ticket-typeahead.js +49 -0
- package/public/js/toast.js +19 -4
- package/public/js/topbar-notes.js +3 -3
- package/public/js/typeahead.js +206 -0
- package/public/js/update-check.js +58 -0
- package/public/styles.css +5447 -3572
- package/src/cli/orbit.js +9 -5
- package/src/core/agent.js +12 -4
- package/src/core/agents-md.js +3 -3
- package/src/core/artifacts.js +149 -0
- package/src/core/board.js +3 -2
- package/src/core/boards.js +0 -1
- package/src/core/css-bundle.js +1 -0
- package/src/core/db.js +6 -0
- package/src/core/dispatch.js +344 -34
- package/src/core/http.js +9 -2
- package/src/core/paths.js +26 -2
- package/src/core/router.js +33 -0
- package/src/core/search.js +3 -2
- package/src/core/snapshots.js +10 -5
- package/src/core/tickets.js +34 -3
- package/src/core/util.js +3 -2
- package/src/core/version-check.js +154 -0
- package/src/mcp/orbit-client.js +18 -2
- package/src/mcp-server.js +19 -14
- package/src/server.js +28 -3
- package/dist/full/js/app.4ae80764.js +0 -742
- package/dist/full/js/app.4ae80764.js.map +0 -7
- package/dist/full/styles.b9e0c130.css +0 -1
|
@@ -1,742 +0,0 @@
|
|
|
1
|
-
var Qn=Object.defineProperty;var P=(e,t)=>()=>(e&&(t=e(e=0)),t);var pt=(e,t)=>{for(var a in t)Qn(e,a,{get:t[a],enumerable:!0})};var v,ue,te,$,K,S,we,Me,Xt,ke,mt,pe,Ha,Yt,ie=P(()=>{v=e=>document.querySelector(e),ue=v("#boardMenuBtn"),te=v("#boardFlyout"),$=v("#kanban"),K=v("#drawer"),S=v("#drawerInner"),we=v("#drawerBackdrop"),Me=v("#createFlyout"),Xt=v("#createFlyoutInner"),ke=v("#createFlyoutBackdrop"),mt=v("#searchInput"),pe=v("#searchResults"),Ha=v("#themeToggle"),Yt=v("#themeIcon")});function Pe(e){try{return e??globalThis.localStorage??null}catch{return null}}function Wt(e){return typeof window<"u"&&typeof window.matchMedia=="function"?window.matchMedia(e):{matches:!1}}function ft(e=Pe()){let a=Pe(e)?.getItem?.(qa);return a==="true"?!0:a==="false"?!1:null}function Vt(e=Wt){try{return!!e("(prefers-reduced-motion: reduce)")?.matches}catch{return!1}}function Ae({storage:e=Pe(),mediaMatcher:t=Wt}={}){return ft(e)??Vt(t)}function Ua(e,t=Pe()){let a=Pe(t),n=e?"true":"false";return a?.setItem?.(qa,n),e}function Xe({doc:e=globalThis.document,storage:t=Pe(),mediaMatcher:a=Wt}={}){let n=e?.documentElement,r=ft(t);return n&&(r===!0?n.setAttribute("data-motion","reduce"):r===!1?n.setAttribute("data-motion","full"):n.removeAttribute("data-motion")),Ae({storage:t,mediaMatcher:a})}var qa,Qt=P(()=>{qa="mab_reduce_motion"});function Be(e){try{return e??globalThis.localStorage??null}catch{return null}}function Fe(e){try{return e??globalThis.document??null}catch{return null}}function Zt(e){try{return e??globalThis.window??null}catch{return null}}function Zn(e){return ea.has(e)?e:"light"}function bt(e=Be()){let a=Be(e)?.getItem?.(za);return ea.has(a)?a:null}function Ga(){try{return globalThis.matchMedia?.("(prefers-color-scheme: dark)").matches?"dark":"light"}catch{return"light"}}function $e({doc:e=Fe(),storage:t=Be()}={}){let a=Fe(e)?.documentElement?.getAttribute?.("data-theme");return ea.has(a)?a:bt(t)??Ga()}function Ka({doc:e=Fe(),storage:t=Be()}={}){let a=bt(t)??Ga();return Fe(e)?.documentElement?.setAttribute?.("data-theme",a),a}function Ye(e,{doc:t=Fe(),storage:a=Be(),eventTarget:n=Zt(),notify:r=!0}={}){let o=Zn(e);return Fe(t)?.documentElement?.setAttribute?.("data-theme",o),Be(a)?.setItem?.(za,o),r&&er(o,n),o}function Ja(e={}){let t=$e(e)==="dark"?"light":"dark";return Ye(t,e)}function er(e,t=Zt()){let a=Zt(t);if(typeof a?.dispatchEvent=="function"){if(typeof CustomEvent=="function"){a.dispatchEvent(new CustomEvent(ht,{detail:{theme:e}}));return}a.dispatchEvent({type:ht,detail:{theme:e}})}}var za,ht,ea,ta=P(()=>{za="mab_theme",ht="orbit:theme-change",ea=new Set(["light","dark"])});function We(e){return!e||!gt.has(e)?"lanes":e}var gt,yt=P(()=>{gt=new Set(["lanes","appearance","ai","notes","journal","repository","archive"])});var Wa={};pt(Wa,{boardLabelCatalog:()=>ra,currentBoard:()=>U,getSettingsTab:()=>na,isAiReadyState:()=>oa,selectableStatesForProject:()=>ia,state:()=>c,statesForProject:()=>Re,syncBoardSelection:()=>xe,ticketsForProject:()=>X,upsertTicket:()=>sa,visibleStatesForProject:()=>Le});function na(){return We(c.settingsTab||localStorage.getItem("mab_settings_tab"))}function xe(){if(!c.data)return;let e=c.data.boards||[],t=c.boardId?e.find(a=>a.id===c.boardId):null;if(!t&&c.boardSlug&&(t=e.find(a=>a.slug===c.boardSlug)||e.find(a=>a.id===c.boardSlug)),!t){let a=c.data.active_board_id;t=e.find(n=>n.id===a)||e[0]||null}c.boardId=t?.id||"",c.boardSlug=t?.slug||""}function U(){return(c.data?.boards||[]).find(e=>e.id===c.boardId)}function ra(){return c.boardId?(c.data?.labels||[]).filter(e=>e.board_id===c.boardId):[]}function Re(){return c.data.states.filter(e=>e.board_id===c.boardId)}function oa(e){return e?.role==="ai_ready"||e?.name==="AI Ready"}function Le(){let e=Re();return U()?.ai_enabled!==0?e:e.filter(t=>!oa(t))}function ia(e=""){let t=Re();return U()?.ai_enabled!==0?t:t.filter(a=>!oa(a)||a.id===e)}function X(){return c.data.tickets.filter(e=>e.board_id===c.boardId)}function ir(e){return e?{id:e.id,board_id:e.board_id,board_slug:e.board_slug,number:e.number,title:e.title,type:e.type,state_name:e.state_name,state_role:e.state_role,priority:e.priority}:null}function sr(e){if(!c.data?.tickets)return;let t=c.data.tickets.filter(r=>r.board_id===e&&!r.archived_at),a=new Map(t.map(r=>[r.id,r])),n=new Map;for(let r of t)r.parent_ticket_id&&n.set(r.parent_ticket_id,(n.get(r.parent_ticket_id)||0)+1);for(let r of t)r.parent_ticket=r.parent_ticket_id?ir(a.get(r.parent_ticket_id)):null,r.child_count=n.get(r.id)||0}function sa(e){if(!c.data?.tickets||!e?.id)return;let t=c.data.tickets.findIndex(r=>r.id===e.id),a=t>=0?c.data.tickets[t]:{},n={...a,...e,labels:e.labels||a.labels||[],comment_count:e.comment_count??a.comment_count??0,child_count:e.child_count??a.child_count??0,parent_ticket:e.parent_ticket||a.parent_ticket||null};t>=0?c.data.tickets.splice(t,1,n):c.data.tickets.push(n),c.data.tickets.sort((r,o)=>String(o.updated_at||"").localeCompare(String(r.updated_at||""))||String(r.id).localeCompare(String(o.id))),sr(n.board_id||c.boardId)}var c,z=P(()=>{yt();c={data:null,boardId:"",boardSlug:"",selectedTicketId:"",expandedCardIds:new Set,detailMode:"empty",settingsTab:We(localStorage.getItem("mab_settings_tab")),showPriority:localStorage.getItem("mab_show_priority")!=="false",eventSource:null}});function d(e){return String(e??"").replaceAll("&","&").replaceAll("<","<").replaceAll(">",">").replaceAll('"',""").replaceAll("'","'")}function dr(e){if(!e)return e;let t=e;for(let[a,n]of cr)t=t.split(a).join(n);return t}function V(e){return e?dr(String(e)).replace(/\r\n?/g,`
|
|
2
|
-
`):""}function ce(e){return d(V(e))}function ur(e){let t=String(e||"").trim();if(!t)return"";let a=t.replace(/[\u0000-\u001f\u007f\s]+/g,"").toLowerCase();if(/^(?:javascript|data|vbscript):/.test(a))return"";let n=a.match(/^([a-z][a-z0-9+.-]*):/);return n&&!lr.has(`${n[1]}:`)?"":t}function ca(e){let t=d(e);return t=t.replace(/(\*\*|__)(?=\S)([\s\S]*?\S)\1/g,"<strong>$2</strong>"),t=t.replace(/(\*|_)(?=\S)([^*_]*?\S)\1/g,"<em>$2</em>"),t}function da(e){let t=/\[([^\]\n]+)\]\(([^)\s]+)(?:\s+"[^"]*")?\)/g,a="",n=0,r;for(;r=t.exec(e);){a+=ca(e.slice(n,r.index));let o=ca(r[1]),s=ur(r[2]);a+=s?`<a href="${d(s)}" target="_blank" rel="noopener noreferrer">${o}</a>`:o,n=r.index+r[0].length}return a+=ca(e.slice(n)),a}function vt(e){let t=String(e??""),a="",n=0;for(;n<t.length;){let r=t.indexOf("`",n);if(r===-1){a+=da(t.slice(n));break}let o=t.indexOf("`",r+1);if(o===-1){a+=da(t.slice(n));break}a+=da(t.slice(n,r)),a+=`<code>${d(t.slice(r+1,o))}</code>`,n=o+1}return a}function pr(e){return`<p>${vt(e.join(`
|
|
3
|
-
`)).replaceAll(`
|
|
4
|
-
`,"<br>")}</p>`}function mr(e){let t=e.match(/^\[( |x|X)\]\s+(.*)$/);if(!t)return null;let a=t[1].toLowerCase()==="x",n=vt(t[2].trim()).replaceAll(`
|
|
5
|
-
`,"<br>");return{checked:a,html:`<input type="checkbox" disabled${a?" checked":""}> ${n}`}}function la(e){let t=V(e);if(!t.trim())return"";let a=[],n=t.split(`
|
|
6
|
-
`),r=[],o=null,s=null,i=()=>{r.length&&(a.push(pr(r)),r=[])},l=()=>{if(!o)return;let m=o.taskList?' class="task-list"':"";a.push(`<${o.type}${m}>${o.items.map(f=>`<li${f.taskClass?` class="${f.taskClass}"`:""}>${f.html}</li>`).join("")}</${o.type}>`),o=null},u=()=>{s&&(a.push(`<blockquote>${la(s.join(`
|
|
7
|
-
`))}</blockquote>`),s=null)},p=()=>{i(),l(),u()};for(let m=0;m<n.length;m+=1){let f=n[m];if(/^\s*```/.test(f)){p();let M=[];for(m+=1;m<n.length&&!/^\s*```\s*$/.test(n[m]);)M.push(n[m]),m+=1;a.push(`<pre><code>${d(M.join(`
|
|
8
|
-
`))}</code></pre>`);continue}if(/^\s*(?:-\s*){3,}\s*$/.test(f)||/^\s*(?:\*\s*){3,}\s*$/.test(f)||/^\s*(?:_\s*){3,}\s*$/.test(f)){p(),a.push("<hr>");continue}let b=f.match(/^\s{0,3}(#{1,6})\s+(.+?)\s*#*\s*$/);if(b){p();let M=b[1].length;a.push(`<h${M}>${vt(b[2])}</h${M}>`);continue}let k=f.match(/^\s{0,3}>\s?(.*)$/);if(k){i(),l(),s||(s=[]),s.push(k[1]);continue}if(s&&!f.trim()){u();continue}if(u(),!f.trim()){i(),l();continue}let x=f.match(/^\s*\d+[.)]\s+(.+)$/),A=f.match(/^\s*[-*+]\s+(.+)$/);if(x||A){i();let M=x?"ol":"ul",h=(x||A)[1].trim(),E=null;A&&(E=mr(h)),(!o||o.type!==M||!!o.taskList!=!!E)&&(l(),o={type:M,items:[],taskList:!!E}),E?o.items.push({html:E.html,taskClass:E.checked?"task-item task-item-done":"task-item"}):o.items.push({html:vt(h).replaceAll(`
|
|
9
|
-
`,"<br>")});continue}l(),r.push(f)}return p(),a.join("")}function Ve(e){return e?new Intl.DateTimeFormat(void 0,{month:"short",day:"numeric",hour:"numeric",minute:"2-digit"}).format(new Date(e)):""}function Va(e){return e?new Intl.DateTimeFormat(void 0,{year:"numeric",month:"short",day:"numeric",hour:"numeric",minute:"2-digit",second:"2-digit"}).format(new Date(e)):""}function ae(e){return`#${e.number}`}function Qe(e){let t=e?.state_role||e?.role||e?.state_name||e?.name||"state";return String(t).toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-|-$/g,"")||"state"}function O(e){return e==="epic"||e==="feature"||e==="bug"||e==="task"?e:"task"}function De(e){return{epic:"Epic",feature:"Feature",task:"Task",bug:"Bug"}[O(e)]||"Task"}function Qa(e){return{epic:"Epic",feature:"Feature",task:"Task",bug:"Bug"}[O(e)]||"Task"}function Ne(e){return{0:"MAYBE",1:"LOW",2:"MED",3:"HIGH",4:"URGENT"}[Number(e)]||"MED"}function Oe(e){let t=["maybe","low","med","high","urgent"],a=Number(e);return t[Number.isFinite(a)?Math.max(0,Math.min(4,a)):2]}function Za(e=[]){return e.length?`
|
|
10
|
-
<div class="labels">
|
|
11
|
-
${e.map(t=>`<span class="label" style="--label-color: ${d(t.color)}">${d(t.name)}</span>`).join("")}
|
|
12
|
-
</div>
|
|
13
|
-
`:""}function en(e){let t=String(e||"").trim();if(!t)return"Not set";let a=t.match(/github\.com\/([^/\s]+)\/([^/\s]+?)(?:\.git)?$/i);if(a)return`${a[1]}/${a[2]}`;let n=t.match(/github\.com[:/]([^/\s]+)\/([^/\s]+?)(?:\.git)?$/i);return n?`${n[1]}/${n[2]}`:t}var cr,lr,ne=P(()=>{cr=[["\u0393\xC7\xF4","\u2013"],["\u0393\xC7\xF6","\u2014"],["\u0393\xC7\xA3",'"'],["\u0393\xC7\xA5",'"'],["\u0393\xC7\xFF","'"],["\u0393\xC7\xD6","'"],["\u0393\xC7\xAA","\u2026"],["\u0393\xC7\xF3","\u2022"],["\u0393\xC7\u2591","\u2030"],["\u0393\xC7\u2563","\u2039"],["\u0393\xC7\u2551","\u203A"],["\u0393\xF6\xC7","\u2500"],["\u0393\xF6\xE9","\u2502"],["\u0393\xF6\xEE","\u250C"],["\u0393\xF6\xC9","\u2510"],["\u0393\xF6\xF6","\u2514"],["\u0393\xF6\xFF","\u2518"],["\u0393\xF6\xA3","\u251C"],["\u0393\xF6\xF1","\u2524"],["\u0393\xF6\xBC","\u252C"],["\u0393\xF6\u2524","\u2534"],["\u0393\xF6\u255D","\u253C"],["\u0393\xF2\xC9","\u2550"],["\u0393\xF2\xE6","\u2551"],["\u0393\xF2\xC6","\u2552"],["\u0393\xF2\xF6","\u2554"],["\u0393\xF2\xA1","\u256D"],["\u0393\xF2\xAB","\u256E"],["\u0393\xF2\xBB","\u256F"],["\u0393\xF2\u2591","\u2570"],["\u0393\xFB\xE6","\u2591"],["\u0393\xFB\xC6","\u2592"],["\u0393\xFB\xF4","\u2593"],["\u0393\xFB\xC9","\u2590"],["\u0393\xFB\xEE","\u258C"],["\u0393\xFB\xC4",">"],["\u0393\xFB\xE1","\u25A0"],["\u0393\xFB\u255D","\u25BC"],["\u0393\xF9\xC5","\u25CF"],["\u0393\xF9\xEF","\u25CB"],["\u0393\xDC\xF2","\u2695"],["\u0393\xDC\xE1","\u26A0"],["\u0393\xDC\xED","\u26A1"],["\u0393\xDC\xF4","\u2693"],["\u0393\xE5\xC9","\u2190"],["\u0393\xE5\xE6","\u2191"],["\u0393\xE5\xC6","\u2192"],["\u0393\xE5\xF4","\u2193"],["\u0393\xE5\xF6","\u2194"],["\u252C\xE1"," "],["\u252C\u2310","\xA9"],["\u252C\xAB","\xAE"],["\u252C\u2591","\xB0"],["\u252C\xBA","\xA7"],["\u252C\u2556","\xB7"],["\u201C",'"'],["\u201D",'"'],["\u2018","'"],["\u2019","'"]];lr=new Set(["http:","https:","mailto:","tel:"])});function hr(){return Ee&&Ee.isConnected||(Ee=document.createElement("div"),Ee.className="toast-container",document.body.append(Ee)),Ee}function g(e,t="info",a=4e3){let n=hr(),r=document.createElement("div");r.className=`toast toast-${t}`,r.setAttribute("role","status");let o=fr[t];r.innerHTML=`<span class="toast-icon">${o}</span><span class="toast-msg">${d(e)}</span><button class="toast-close" aria-label="Dismiss">×</button>`,r.querySelector(".toast-close").addEventListener("click",()=>ua(r)),n.prepend(r),requestAnimationFrame(()=>requestAnimationFrame(()=>r.classList.add("toast-enter")));let s=setTimeout(()=>ua(r),a);r.addEventListener("mouseenter",()=>clearTimeout(s)),r.addEventListener("mouseleave",()=>{let i=setTimeout(()=>ua(r),1500);r.addEventListener("mouseenter",()=>clearTimeout(i),{once:!0})})}function ua(e){e.classList.contains("toast-exit")||(e.classList.add("toast-exit"),e.addEventListener("animationend",()=>e.remove(),{once:!0}))}function tn(e,t){let a=new Blob([JSON.stringify(t,null,2)],{type:"application/json"}),n=URL.createObjectURL(a),r=document.createElement("a");r.href=n,r.download=e,document.body.append(r),r.click(),r.remove(),URL.revokeObjectURL(n)}function wt(e,t){let a=0;return(...n)=>{clearTimeout(a),a=setTimeout(()=>e(...n),t)}}var fr,Ee,me=P(()=>{ne();fr={info:'<svg viewBox="0 0 20 20" fill="currentColor"><path fill-rule="evenodd" d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7-4a1 1 0 11-2 0 1 1 0 012 0zM9 9a.75.75 0 000 1.5h.253a.25.25 0 01.244.304l-.459 2.066A1.75 1.75 0 0010.747 15H11a.75.75 0 000-1.5h-.253a.25.25 0 01-.244-.304l.459-2.066A1.75 1.75 0 009.253 9H9z" clip-rule="evenodd"/></svg>',success:'<svg viewBox="0 0 20 20" fill="currentColor"><path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.857-9.809a.75.75 0 00-1.214-.882l-3.483 4.79-1.88-1.88a.75.75 0 10-1.06 1.061l2.5 2.5a.75.75 0 001.137-.089l4-5.5z" clip-rule="evenodd"/></svg>',warning:'<svg viewBox="0 0 24 24" fill="currentColor"><path fill-rule="evenodd" d="M9.401 3.003c1.155-2 4.043-2 5.197 0l7.355 12.748c1.154 2-.29 4.5-2.599 4.5H4.645c-2.309 0-3.752-2.5-2.598-4.5L9.4 3.003zM12 8.25a.75.75 0 01.75.75v3.75a.75.75 0 01-1.5 0V9a.75.75 0 01.75-.75zm0 8.25a.75.75 0 100-1.5.75.75 0 000 1.5z" clip-rule="evenodd"/></svg>',error:'<svg viewBox="0 0 20 20" fill="currentColor"><path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zM8.28 7.22a.75.75 0 00-1.06 1.06L8.94 10l-1.72 1.72a.75.75 0 101.06 1.06L10 11.06l1.72 1.72a.75.75 0 101.06-1.06L11.06 10l1.72-1.72a.75.75 0 00-1.06-1.06L10 8.94 8.28 7.22z" clip-rule="evenodd"/></svg>'},Ee=null;g.info=(e,t)=>g(e,"info",t);g.success=(e,t)=>g(e,"success",t);g.warning=(e,t)=>g(e,"warning",t);g.error=(e,t)=>g(e,"error",t)});async function an({method:e="GET",path:t,body:a,headers:n}){let r={"Content-Type":"application/json",...n||{}},o=await fetch(t,{method:e,headers:r,body:a!==void 0?JSON.stringify(a):void 0}),s=await o.text(),i=s?JSON.parse(s):{};if(!o.ok){let l=new Error(i.error||o.statusText);throw l.payload=i,l.status=o.status,l}return i}var nn=P(()=>{});var rn={};pt(rn,{api:()=>w,bootstrapPath:()=>Ze,withBoardQuery:()=>T});function Ze(){return`/api/bootstrap${c.boardId?`?board_id=${encodeURIComponent(c.boardId)}`:c.boardSlug?`?board=${encodeURIComponent(c.boardSlug)}`:""}`}function T(e){if(!c.boardId||e.includes("board_id="))return e;let t=e.includes("?")?"&":"?";return`${e}${t}board_id=${encodeURIComponent(c.boardId)}`}async function w(e,t={}){try{return await an({method:t.method||"GET",path:e,body:t.body,headers:t.headers})}catch(a){throw g.error(a.payload?.error||a.message||"Request failed"),a}}var Q=P(()=>{z();me();nn()});function ma(){pa+=1,K.hidden=!1,we.hidden=!1,requestAnimationFrame(()=>{K.classList.add("is-open"),we.classList.add("is-visible")})}function kt(){let e=++pa,t=K.classList.contains("is-open");K.classList.remove("is-open"),we.classList.remove("is-visible");let a=()=>{if(pa!==e)return;K.hidden=!0,we.hidden=!0,S.innerHTML="";let o=document.getElementById("drawerTitleBlock"),s=document.getElementById("drawerTabs");o&&(o.innerHTML=""),s&&(s.innerHTML="",s.hidden=!0),K.classList.remove("is-wide")};if(!t){a();return}let n=!1,r=()=>{n||(n=!0,a())};K.addEventListener("transitionend",r,{once:!0}),setTimeout(r,360)}function $t({eyebrow:e,title:t,titleAttrs:a,subtitleHtml:n,tabs:r,activeTab:o,onTabSelect:s,body:i,mode:l}){K.classList.toggle("is-settings",l==="settings"),K.classList.toggle("is-wide",l==="ticket"||l==="settings");let u=document.getElementById("drawerTitleBlock"),p=document.getElementById("drawerTabs"),f=` class="drawer-title drawer-title-text${a?.class?` ${a.class}`:""}"`;for(let[x,A]of Object.entries(a||{}))x!=="class"&&(f+=` ${x}="${d(String(A))}"`);let b=[];e&&b.push(`<span class="drawer-eyebrow">${d(e)}</span>`),b.push(`<h2${f}>${d(t??"")}</h2>`),n&&b.push(`<div class="drawer-subtitle">${n}</div>`),u.innerHTML=b.join(""),r&&r.length?(p.hidden=!1,p.innerHTML=r.map(x=>`<button type="button" role="tab" class="drawer-tab ${x.id===o?"is-active":""}" data-drawer-tab="${d(x.id)}" aria-selected="${x.id===o}">${d(x.label)}</button>`).join(""),typeof s=="function"&&p.querySelectorAll(".drawer-tab").forEach(x=>{x.addEventListener("click",()=>s(x.dataset.drawerTab))})):(p.hidden=!0,p.innerHTML="");let k=document.getElementById("drawerArchiveBtn");k&&(k.hidden=c.detailMode!=="ticket"),S.innerHTML=i??""}var pa,xt=P(()=>{ie();z();ne();pa=0});function wr(e,t=Le()){return e?[{id:"move",label:"Move to",children:t.map(a=>({id:`move:${a.id}`,label:a.name,action:"move",value:a.id,checked:a.id===e.state_id,disabled:a.id===e.state_id}))},{id:"priority",label:"Priority",children:gr.map(a=>({id:`priority:${a}`,label:Ne(a),action:"priority",value:a,checked:Number(e.priority)===a,disabled:Number(e.priority)===a}))},{id:"type",label:"Type",children:br.map(a=>({id:`type:${a}`,label:De(a),action:"type",value:a,checked:O(e.type)===a,disabled:O(e.type)===a}))},{id:"open",label:"Open",action:"open"},{id:"archive",label:"Archive",action:"archive",danger:!0}]:[]}function kr({x:e,y:t,menuWidth:a,menuHeight:n,viewportWidth:r,viewportHeight:o,margin:s=ha}){let i=Math.max(s,r-a-s),l=Math.max(s,o-n-s),u=e+a+s>r?e-a:e,p=t+n+s>o?t-n:t;return{left:Math.min(Math.max(s,u),i),top:Math.min(Math.max(s,p),l)}}function $r({triggerRect:e,submenuWidth:t,submenuHeight:a,viewportWidth:n,viewportHeight:r,margin:o=ha,gap:s=yr}){let i=Math.max(o,n-t-o),l=e.right+s,u=e.left-t-s,p=l+t+o<=n,m=u>=o,f=p||!m?l:u,b=Math.max(0,r-o*2),k=Math.min(a,b),x=Math.max(o,r-k-o),A=e.top-s;return{left:Math.min(Math.max(o,f),i),top:Math.min(Math.max(o,A),x),maxHeight:b}}function Tt({apiClient:e=w,navigator:t=null,confirmer:a=globalThis.confirm}={}){async function n(r,o){await e(T(`/api/tickets/${encodeURIComponent(r.id)}`),{method:"PATCH",body:o})}return{async open(r){return t?t({boardId:c.boardId,view:"ticket",ticketId:r.id}):null},async move(r,o){await n(r,{state_id:o})},async priority(r,o){await n(r,{priority:o})},async type(r,o){await n(r,{type:o})},async archive(r){return typeof a=="function"&&!a(`Archive "${r.title||"card"}"? You can restore it from Settings \u2192 Card Archive.`)?!1:(await e(T(`/api/tickets/${encodeURIComponent(r.id)}/archive`),{method:"POST"}),g.error(`Archived: ${r.title||"card"}`),!0)}}}function ga(e){ba=!!e}function re({restoreFocus:e=!1}={}){de(),et&&(et.abort(),et=null);for(let t of at)t.isConnected&&t.remove();at.clear(),J&&(J.querySelectorAll(".card-action-menu-item.has-submenu").forEach(t=>{let a=Se.get(t);a?.isConnected&&a.remove(),Se.delete(t)}),J.remove(),J=null),e&&Lt?.isConnected&&Lt.focus({preventScroll:!0}),Lt=null}function xr({ticket:e,anchor:t,x:a,y:n,handlers:r=Tt(),onBeforeOpen:o=null}){if(re(),!e||ba)return null;typeof o=="function"&&o(),Lt=t||document.activeElement;let s=document.createElement("div");s.className="card-action-menu",s.setAttribute("role","menu"),s.setAttribute("aria-label",`Actions for #${e.number||""} ${e.title||"card"}`.trim()),s.dataset.ticketId=e.id,s.innerHTML=cn(wr(e)),document.body.append(s),J=s,s.querySelectorAll(".card-action-menu-item.has-submenu").forEach(m=>{let f=m.querySelector(":scope > .card-action-submenu");f&&(f.remove(),document.body.append(f),Se.set(m,f),fa.set(f,m),Sr(f,e,r))});let i=s.getBoundingClientRect(),l=kr({x:a,y:n,menuWidth:i.width,menuHeight:i.height,viewportWidth:window.innerWidth,viewportHeight:window.innerHeight});s.style.left=`${l.left}px`,s.style.top=`${l.top}px`,Er(s,e,r),va(s)?.focus({preventScroll:!0}),et=new AbortController;let p=et.signal;return requestAnimationFrame(()=>{document.addEventListener("pointerdown",Tr,{signal:p,capture:!0})}),document.addEventListener("keydown",Ir,{signal:p,capture:!0}),document.addEventListener("scroll",_r,{signal:p,capture:!0,passive:!0}),window.addEventListener("resize",()=>re(),{signal:p,passive:!0}),window.addEventListener("blur",()=>re(),{signal:p}),s}function sn(e,t,{handlers:a=Tt(),onBeforeOpen:n=null}={}){e.addEventListener("contextmenu",r=>{let o=r.target instanceof Element?r.target.closest(".card"):null;if(!o)return;let s=t(o.dataset.ticketId);if(s){if(r.preventDefault(),r.stopPropagation(),ba){re();return}xr({ticket:s,anchor:o,x:r.clientX,y:r.clientY,handlers:a,onBeforeOpen:n})}})}function cn(e){return`<ul class="card-action-menu-list" role="none">${e.map(Lr).join("")}</ul>`}function Lr(e){let t=!!e.children?.length,a=["card-action-menu-item"];t&&a.push("has-submenu"),e.danger&&a.push("is-danger");let n=e.checked?'<span class="card-action-check" aria-hidden="true">\u2713</span>':'<span class="card-action-check" aria-hidden="true"></span>',r=t?'<span class="card-action-arrow" aria-hidden="true">\u203A</span>':"";return`
|
|
14
|
-
<li class="${a.join(" ")}" role="none">
|
|
15
|
-
<button type="button"
|
|
16
|
-
class="card-action-button"
|
|
17
|
-
role="menuitem${e.checked?"checkbox":""}"
|
|
18
|
-
data-action="${d(e.action||"")}" data-value="${d(e.value??"")}" data-menu-id="${d(e.id)}"
|
|
19
|
-
${e.disabled?"disabled":""}
|
|
20
|
-
${e.checked?'aria-checked="true"':""}
|
|
21
|
-
${t?'aria-haspopup="menu" aria-expanded="false"':""}>
|
|
22
|
-
${t?"":n}
|
|
23
|
-
<span class="card-action-label">${d(e.label)}</span>
|
|
24
|
-
${r}
|
|
25
|
-
</button>
|
|
26
|
-
${t?`<div class="card-action-submenu" role="menu">${cn(e.children)}</div>`:""}
|
|
27
|
-
</li>
|
|
28
|
-
`}function Er(e,t,a){e.addEventListener("pointerover",n=>{let r=n.target instanceof Element?n.target.closest(".card-action-menu-item"):null;!r||!e.contains(r)||(r.classList.contains("has-submenu")?(de(),Et(r)):Cr(e))},!0),e.addEventListener("focusin",n=>{let r=n.target instanceof Element?n.target.closest(".card-action-menu-item"):null;!r||!e.contains(r)||(r.classList.contains("has-submenu")?(de(),Et(r)):(de(),pn(e)))}),e.addEventListener("click",n=>dn(n,e,t,a)),e.addEventListener("keydown",n=>ln(n,e))}function Sr(e,t,a){e.addEventListener("pointerenter",de),e.addEventListener("pointerover",n=>{n.target instanceof Element&&e.contains(n.target)&&de()},!0),e.addEventListener("click",n=>{J&&dn(n,J,t,a,e)}),e.addEventListener("keydown",n=>{J&&ln(n,J)})}function dn(e,t,a,n,r=t){let o=e.target instanceof Element?e.target.closest("button.card-action-button"):null;if(!o||!r.contains(o)||o.disabled)return;e.preventDefault(),e.stopPropagation();let s=o.closest(".card-action-menu-item");if(s?.classList.contains("has-submenu")){de(),Et(s),va(Se.get(s))?.focus({preventScroll:!0});return}let i=o.dataset.action,l=o.dataset.value;if(re(),i==="open")return n.open(a);if(i==="move")return n.move(a,l);if(i==="priority")return n.priority(a,Number(l));if(i==="type")return n.type(a,l);if(i==="archive")return n.archive(a)}function ln(e,t){let a=e.target instanceof Element?e.target.closest("button.card-action-button"):null;if(!a)return;let n=a.closest(".card-action-submenu");if(!t.contains(a)&&!n)return;let o=a.closest(".card-action-menu-list"),s=a.closest(".card-action-menu-item");if(e.key==="Escape"){if(e.preventDefault(),n){let i=fa.get(n),l=i?.querySelector(":scope > .card-action-button");St(i),l?.focus({preventScroll:!0})}else re({restoreFocus:!0});return}if(e.key==="ArrowDown"||e.key==="ArrowUp"){e.preventDefault(),Mr(o,a,e.key==="ArrowDown"?1:-1);return}if(e.key==="Home"||e.key==="End"){e.preventDefault();let i=ya(o);i[e.key==="Home"?0:i.length-1]?.focus({preventScroll:!0});return}if(e.key==="ArrowRight"&&s?.classList.contains("has-submenu")){e.preventDefault(),de(),Et(s),va(Se.get(s))?.focus({preventScroll:!0});return}if(e.key==="ArrowLeft"&&n){let i=fa.get(n),l=i?.querySelector(":scope > .card-action-button");l&&(e.preventDefault(),St(i),l.focus({preventScroll:!0}))}}function Tr(e){J&&(un(e)||re())}function Ir(e){e.key==="Escape"&&J&&(e.preventDefault(),re({restoreFocus:!0}))}function _r(e){J&&(un(e)||re())}function un(e){let t=e.target;if(!(t instanceof Node))return!1;if(J?.contains(t))return!0;for(let a of at)if(a.contains(t))return!0;return!1}function Et(e){let t=e.parentElement?.children||[];for(let n of t)n!==e&&n.classList?.contains("has-submenu")&&n.classList.contains("is-open")&&St(n);let a=Se.get(e);if(a){if(e.classList.contains("is-open")){on(e,a);return}e.classList.add("is-open"),e.querySelector(":scope > .card-action-button")?.setAttribute("aria-expanded","true"),a.classList.add("is-open"),at.add(a),on(e,a)}}function St(e){if(!e)return;e.classList.remove("is-open"),e.querySelector(":scope > .card-action-button")?.setAttribute("aria-expanded","false");let t=Se.get(e);t&&(t.classList.remove("is-open"),t.style.removeProperty("left"),t.style.removeProperty("top"),t.style.removeProperty("max-height"),at.delete(t))}function pn(e){e.querySelectorAll(".card-action-menu-item.has-submenu.is-open").forEach(St)}function Cr(e){de(),tt=setTimeout(()=>{tt=null,J===e&&pn(e)},vr)}function de(){tt!=null&&(clearTimeout(tt),tt=null)}function on(e,t){let a=e.querySelector(":scope > .card-action-button");if(!t||!a)return;let n=Math.max(0,window.innerHeight-ha*2);t.style.maxHeight=`${n}px`,t.style.left="0px",t.style.top="0px";let r=t.getBoundingClientRect(),o=$r({triggerRect:a.getBoundingClientRect(),submenuWidth:r.width,submenuHeight:r.height,viewportWidth:window.innerWidth,viewportHeight:window.innerHeight});t.style.left=`${o.left}px`,t.style.top=`${o.top}px`,t.style.maxHeight=`${o.maxHeight}px`}function ya(e){if(!e)return[];let t=e.classList?.contains("card-action-menu-list")?e:e.querySelector(":scope > .card-action-menu-list");return t?[...t.querySelectorAll(":scope > .card-action-menu-item > .card-action-button")].filter(a=>!a.disabled):[]}function va(e){return ya(e)[0]||null}function Mr(e,t,a){let n=ya(e);if(!n.length)return;let r=n.indexOf(t),o=r===-1?0:(r+a+n.length)%n.length;n[o].focus({preventScroll:!0})}var br,gr,ha,yr,vr,J,ba,et,Lt,Se,fa,at,tt,mn=P(()=>{Q();z();ne();me();br=["epic","feature","task","bug"],gr=[0,1,2,3,4],ha=8,yr=6,vr=180,J=null,ba=!1,et=null,Lt=null,Se=new WeakMap,fa=new WeakMap,at=new Set,tt=null});function Pr(e){return e?typeof e=="string"?{readAt:e,count:0}:{readAt:e.readAt||null,count:Number(e.count)||0}:{readAt:null,count:0}}function nt(e){if(!e)return new Map;let t=ka.get(e);if(t)return t;t=new Map;try{let a=localStorage.getItem(fn(e));if(a){let n=JSON.parse(a);for(let[r,o]of Object.entries(n))t.set(r,Pr(o))}}catch{}return ka.set(e,t),t}function It(e){let t=ka.get(e);if(t)try{let a={};for(let[n,r]of t)a[n]=r;localStorage.setItem(fn(e),JSON.stringify(a))}catch{}}function hn(e,t){let a=e.get(t);return a||(a={readAt:null,count:0},e.set(t,a)),a}function _t(e){let t=e?.board_id||c.boardId;if(!t||!e?.id)return 0;let n=nt(t).get(e.id);return n?n.count:localStorage.getItem(wa(t))==="1"?1:0}function Ct(e,t){let a=c.boardId;if(!a||!e)return;let n=nt(a),r=hn(n,e);r.count===0&&r.readAt&&t&&r.readAt>=t||(r.count=0,t&&(r.readAt=t),It(a))}function bn(e){let t=c.boardId;if(!t||!e)return;let a=nt(t),n=hn(a,e);n.count=(n.count||0)+1,It(t)}function gn(e){let t=c.boardId;if(!t||!e)return;let a=nt(t);a.has(e)&&(a.delete(e),It(t))}function yn(e,t){if(!e||localStorage.getItem(wa(e))==="1")return;let a=nt(e);for(let n of t||[])!a.has(n.id)&&n.updated_at&&a.set(n.id,{readAt:n.updated_at,count:0});It(e);try{localStorage.setItem(wa(e),"1")}catch{}}var fn,wa,ka,rt=P(()=>{z();fn=e=>`mab_card_read:${e}`,wa=e=>`mab_card_read_seeded:${e}`,ka=new Map});function je(){let e=Le(),t=X();xa=new Map(t.map(a=>[a.id,a])),$.innerHTML=e.map(a=>Fr(a,t)).join("")}function Ar(e){if(!e)return;let t=e.dataset.ticketId,a=!c.expandedCardIds.has(t);if(a){if(c.expandedCardIds.add(t),!e.querySelector(".card-expandable")){let r=xa.get(t),o=e.querySelector(".card-meta");r&&o&&o.insertAdjacentHTML("afterend",kn(r))}}else c.expandedCardIds.delete(t);e.classList.toggle("is-expanded",a);let n=e.querySelector("button.card-expand-trigger");n&&n.setAttribute("aria-expanded",a?"true":"false")}function vn(){$a=$a||Tt({navigator:F});let e=null,t=a=>{e!==a&&(e&&e.classList.remove("drag-over"),e=a,e&&e.classList.add("drag-over"))};$.addEventListener("dragstart",a=>{let n=a.target instanceof Element?a.target.closest(".card"):null;n&&(re(),ga(!0),a.dataTransfer.setData("text/plain",n.dataset.ticketId),a.dataTransfer.effectAllowed="move")}),$.addEventListener("dragover",a=>{let n=a.target instanceof Element?a.target.closest(".column"):null;n&&(a.preventDefault(),t(n))}),$.addEventListener("dragend",()=>{ga(!1),t(null),Mt=!0,setTimeout(()=>{Mt=!1},0)}),$.addEventListener("drop",async a=>{let n=a.target instanceof Element?a.target.closest(".column"):null;if(!n)return;a.preventDefault(),t(null);let r=a.dataTransfer.getData("text/plain");r&&(N(),await w(T(`/api/tickets/${r}`),{method:"PATCH",body:{state_id:n.dataset.stateId}}),await C())}),$.addEventListener("click",a=>{let n=a.target instanceof Element?a.target:a.target?.parentElement;if(!n)return;let r=n.closest("[data-add-to-state]");if(r){a.stopPropagation(),At(r.dataset.addToState||"");return}let o=n.closest("button.card-expand-trigger");if(o){a.stopPropagation(),a.preventDefault(),Ar(o.closest(".card"));return}if(n.closest("a")){a.stopPropagation();return}let s=n.closest(".epic-mini-header[data-ticket-id]");if(s){N(),F({boardId:c.boardId,view:"ticket",ticketId:s.dataset.ticketId});return}let i=n.closest(".card");if(i){if(Mt){Mt=!1,a.preventDefault(),a.stopPropagation();return}N(),F({boardId:c.boardId,view:"ticket",ticketId:i.dataset.ticketId})}}),sn($,a=>xa.get(a),{handlers:$a,onBeforeOpen:N})}function wn(){$.querySelectorAll(".card.selected").forEach(e=>e.classList.remove("selected")),c.selectedTicketId&&$.querySelectorAll(`.card[data-ticket-id="${CSS.escape(c.selectedTicketId)}"]`).forEach(e=>e.classList.add("selected"))}function Br(e){let t=e.toLowerCase(),a={icon:'<svg class="empty-state-icon" viewBox="0 0 24 24"><path d="M18 6L6 18M6 6l12 12" opacity="0.5" /></svg>',title:"Nothing here",subtitle:"Tasks will appear when ready"};return t==="ai ready"?a={icon:`<svg class="empty-state-icon ai-sparkle" viewBox="0 0 24 24">
|
|
29
|
-
<path d="M12 3L14.5 9L21 11.5L14.5 14L12 20L9.5 14L3 11.5L9.5 9L12 3Z" fill="currentColor" opacity="0.65" />
|
|
30
|
-
<circle cx="12" cy="11.5" r="1.8" fill="#fff" />
|
|
31
|
-
</svg>`,title:"Ready for agents",subtitle:"Drop unblocked cards here \u2014 the claim-next tool picks them up"}:t.includes("progress")?a={icon:`<svg class="empty-state-icon orbit" viewBox="0 0 100 100">
|
|
32
|
-
<circle cx="50" cy="50" r="10" fill="currentColor" opacity="0.9" />
|
|
33
|
-
<circle class="ring" cx="50" cy="50" r="30" stroke="currentColor" stroke-dasharray="4 6" />
|
|
34
|
-
<circle class="satellite" cx="80" cy="50" r="4" fill="currentColor" />
|
|
35
|
-
</svg>`,title:"Work in progress",subtitle:"Active work will appear here"}:t.includes("review")?a={icon:`<svg class="empty-state-icon star" viewBox="0 0 24 24">
|
|
36
|
-
<path d="M12 2L14.5 9.5L22 12L14.5 14.5L12 22L9.5 14.5L2 12L9.5 9.5L12 2Z" fill="currentColor" />
|
|
37
|
-
</svg>`,title:"Under review",subtitle:"Quality gate before merge"}:t.includes("todo")||t.includes("backlog")?a={icon:`<svg class="empty-state-icon ai-sparkle" viewBox="0 0 24 24">
|
|
38
|
-
<path d="M12 3L14.5 9L21 11.5L14.5 14L12 20L9.5 14L3 11.5L9.5 9L12 3Z" fill="currentColor" opacity="0.5" />
|
|
39
|
-
<path d="M19 8L20 10L21 8L20 6L19 8ZM19 16L20 18L21 16L20 14L19 16ZM5 8L6 10L7 8L6 6L5 8Z" fill="currentColor" />
|
|
40
|
-
</svg>`,title:"Ready for launch",subtitle:"Create a card manually or task an AI to generate tasks"}:t.includes("done")||t.includes("finished")?a={icon:`<svg class="empty-state-icon" viewBox="0 0 24 24">
|
|
41
|
-
<circle cx="12" cy="12" r="10" />
|
|
42
|
-
<path d="M8 12L11 15L16 9" />
|
|
43
|
-
</svg>`,title:"Done",subtitle:"Move completed tickets here"}:t.includes("cancel")&&(a={icon:`<svg class="empty-state-icon" viewBox="0 0 24 24">
|
|
44
|
-
<circle cx="12" cy="12" r="10" opacity="0.2" />
|
|
45
|
-
<path d="M15 9L9 15M9 9l6 6" />
|
|
46
|
-
</svg>`,title:"Not moving forward",subtitle:"Parked or replaced"}),`
|
|
47
|
-
<div class="column-empty-state">
|
|
48
|
-
<div class="empty-state-visual">
|
|
49
|
-
<div class="empty-state-glow"></div>
|
|
50
|
-
${a.icon}
|
|
51
|
-
</div>
|
|
52
|
-
<div class="empty-state-title">${d(a.title)}</div>
|
|
53
|
-
<div class="empty-state-subtitle">${d(a.subtitle)}</div>
|
|
54
|
-
</div>
|
|
55
|
-
`}function Fr(e,t){let a=t.filter(i=>i.state_id===e.id),n=a.length===0,r=e.name==="AI Ready",o=["column","lane"];r&&o.push("column--ai-ready");let s=r?' data-accent="ai-ready"':"";return`
|
|
56
|
-
<section class="${o.join(" ")}" data-flat${s} data-state-id="${e.id}" data-state-name="${d(e.name)}">
|
|
57
|
-
<div class="column-head lane-head">
|
|
58
|
-
<h2 class="lane-title"${r?' title="Agent staging \u2014 cards here are picked up by the claim-next tool when unblocked"':""}>
|
|
59
|
-
${r?'<span class="agent-dot" aria-hidden="true"></span>':""}${d(e.name)}
|
|
60
|
-
</h2>
|
|
61
|
-
<div class="column-head-actions lane-actions">
|
|
62
|
-
<button type="button" class="column-add-btn" data-variant="plus" data-add-to-state="${d(e.id)}" title="New card">+</button>
|
|
63
|
-
<span class="count">${a.length}</span>
|
|
64
|
-
</div>
|
|
65
|
-
</div>
|
|
66
|
-
${n?Br(e.name):Rr(a,t)}
|
|
67
|
-
<button type="button" class="add-card-phantom" data-add-to-state="${d(e.id)}">+ Add a card</button>
|
|
68
|
-
</section>
|
|
69
|
-
`}function Rr(e,t){let a=new Map(t.filter(i=>O(i.type)==="epic").map(i=>[i.id,i])),n=new Set(e.filter(i=>O(i.type)==="epic").map(i=>i.id)),r=new Map;for(let i of e)if(i.parent_ticket_id&&a.has(i.parent_ticket_id)){let l=r.get(i.parent_ticket_id)||[];l.push(i),r.set(i.parent_ticket_id,l)}let o=new Set,s=[];for(let i of e)if(!o.has(i.id)){if(O(i.type)==="epic"){let l=r.get(i.id)||[];if(l.length){let u=l.map(p=>ot(p,{asEpicChild:!0})).join("");s.push(`${ot(i)}<div class="epic-children">${u}</div>`),l.forEach(p=>o.add(p.id))}else s.push(ot(i));o.add(i.id);continue}if(!(i.parent_ticket_id&&n.has(i.parent_ticket_id))){if(i.parent_ticket_id&&a.has(i.parent_ticket_id)&&!n.has(i.parent_ticket_id)){let l=a.get(i.parent_ticket_id),u=r.get(i.parent_ticket_id)||[],p=u.map(m=>ot(m,{asEpicChild:!0})).join("");s.push(`${Dr(l)}<div class="epic-children">${p}</div>`),u.forEach(m=>o.add(m.id));continue}s.push(ot(i)),o.add(i.id)}}return s.join("")}function Dr(e){return`
|
|
70
|
-
<div class="epic-mini-header" data-ticket-id="${d(e.id)}" title="Open epic">
|
|
71
|
-
<div class="card-type-id type-pill-epic">
|
|
72
|
-
${Pt("epic")}
|
|
73
|
-
<span class="card-type-label">EPIC</span>
|
|
74
|
-
</div>
|
|
75
|
-
<span class="ticket-number">${d(ae(e))}</span>
|
|
76
|
-
<span class="epic-mini-title">${d(e.title)}</span>
|
|
77
|
-
</div>
|
|
78
|
-
`}function La(e){let t=Oe(e),a=Ne(e);return`<div class="card-priority-id priority-pill" data-variant="${d(t)}"><span class="card-priority-label">${d(a)}</span></div>`}function Pt(e){let t=O(e),a="",n="currentColor";switch(t){case"epic":n="#c084fc",a='<path d="M12 2L14.5 9.5L22 12L14.5 14.5L12 22L9.5 14.5L2 12L9.5 9.5L12 2Z" fill="currentColor" />';break;case"feature":n="#4ade80",a='<path d="M19 21l-7-5-7 5V5a2 2 0 012-2h10a2 2 0 012 2v16z" fill="currentColor" />';break;case"bug":n="#f87171",a='<circle cx="12" cy="12" r="10" /><path d="M12 8v4M12 16h.01" />';break;default:n="#60a5fa",a='<rect x="3" y="3" width="18" height="18" rx="2" /><path d="M9 12l2 2 4-4" />'}return`
|
|
79
|
-
<svg class="card-type-icon" viewBox="0 0 24 24" style="color: ${n}">
|
|
80
|
-
${a}
|
|
81
|
-
</svg>
|
|
82
|
-
`}function ot(e,{asEpicChild:t=!1}={}){let a=O(e.type),n=Oe(e.priority),r=De(e.type).toUpperCase(),o=c.expandedCardIds.has(e.id),i=!!String(e.description||"").trim()||e.labels&&e.labels.length||e.parent_ticket||e.child_count,l=`
|
|
83
|
-
<span class="ticket-number">${d(ae(e))}</span>
|
|
84
|
-
<div class="card-type-id type-pill-${d(a)}">
|
|
85
|
-
${Pt(e.type)}
|
|
86
|
-
<span class="card-type-label">${d(r)}</span>
|
|
87
|
-
</div>
|
|
88
|
-
${c.showPriority?La(e.priority):""}
|
|
89
|
-
${i?'<svg class="card-expand-chevron" viewBox="0 0 24 24" aria-hidden="true"><path d="M6 9l6 6 6-6" /></svg>':""}
|
|
90
|
-
`,u=_t(e),p=u===0?"":u===1?'<span class="card-unread-dot" role="status" aria-label="1 unread update"></span>':`<span class="card-unread-dot has-count" role="status" aria-label="${u} unread updates">${u>99?"99+":u}</span>`;return`
|
|
91
|
-
<article class="card type-${d(a)} priority-${d(n)}${o?" is-expanded":""}${t?" is-epic-child":""} ${e.id===c.selectedTicketId?"selected":""}" data-variant="${d(a)}" draggable="true" data-ticket-id="${e.id}">
|
|
92
|
-
${p}
|
|
93
|
-
<h3>${d(e.title)}</h3>
|
|
94
|
-
|
|
95
|
-
<div class="card-meta">
|
|
96
|
-
${i?`<button type="button" class="card-expand-trigger" data-variant="card-accordion" data-card-toggle aria-expanded="${o?"true":"false"}">${l}</button>`:`<div class="card-expand-trigger card-expand-trigger--static">${l}</div>`}
|
|
97
|
-
</div>
|
|
98
|
-
|
|
99
|
-
${i&&o?kn(e):""}
|
|
100
|
-
</article>
|
|
101
|
-
`}function kn(e){return`
|
|
102
|
-
<div class="card-expandable">
|
|
103
|
-
${!!String(e.description||"").trim()?`<div class="card-description markdown-body">${la(e.description)}</div>`:""}
|
|
104
|
-
${Za(e.labels)}
|
|
105
|
-
${e.parent_ticket?`<div class="parent-line">-> ${d(ae(e.parent_ticket))}</div>`:""}
|
|
106
|
-
${e.child_count?`<div class="child-count">${e.child_count} feature${e.child_count===1?"":"s"} inside</div>`:""}
|
|
107
|
-
</div>
|
|
108
|
-
`}function $n(){let a=()=>Math.max($.clientWidth,1),n=!1,r=!1,o=0,s=0,i=0,l=h=>h instanceof Element?!!(h.closest(".card")||h.closest("a, button, input, select, textarea, [draggable='true']")):!1,u=(h,E)=>E===WheelEvent.DOM_DELTA_LINE?h*16:E===WheelEvent.DOM_DELTA_PAGE?h*a():h;$.addEventListener("wheel",h=>{if(h.defaultPrevented||h.ctrlKey)return;let E=h.deltaX||(h.shiftKey?h.deltaY:0);!E||!(Math.abs(E)>=Math.abs(h.deltaY)||h.shiftKey)||$.scrollWidth<=$.clientWidth||(h.preventDefault(),$.scrollLeft+=u(E,h.deltaMode))},{passive:!1}),$.addEventListener("pointerdown",h=>{h.button===0&&(r=!1,!l(h.target)&&(n=!0,i=h.pointerId,o=h.clientX,s=$.scrollLeft,$.classList.add("is-grabbing")))}),$.addEventListener("pointermove",h=>{if(!n||h.pointerId!==i)return;let E=h.clientX-o;if(!r&&Math.abs(E)>4){r=!0;try{$.setPointerCapture(i)}catch{}}r&&(h.preventDefault(),$.scrollLeft=s-E)});let p=h=>{if(!(!n||h&&h.pointerId!==i)){n=!1,$.classList.remove("is-grabbing");try{$.releasePointerCapture(i)}catch{}}};$.addEventListener("pointerup",p),$.addEventListener("pointercancel",p),$.addEventListener("pointerleave",p),$.addEventListener("click",h=>{r&&(h.stopPropagation(),h.preventDefault(),r=!1)},!0);let m=!1,f=0,b=!1;$.addEventListener("pointerdown",h=>{h.pointerType!=="mouse"||(h.buttons&3)!==3||(m=!0,f=h.clientX,b=!0,n=!1,$.classList.add("is-grabbing"))}),$.addEventListener("pointermove",h=>{if(h.pointerType!=="mouse")return;if((h.buttons&3)===3){if(h.preventDefault(),!m){m=!0,f=h.clientX,b=!0,n=!1,$.classList.add("is-grabbing");return}let L=h.clientX-f;L&&($.scrollLeft-=L,f=h.clientX,r=!0)}else m&&(m=!1,$.classList.remove("is-grabbing"))}),$.addEventListener("pointerup",h=>{h.pointerType==="mouse"&&m&&(h.buttons&3)!==3&&(m=!1,$.classList.remove("is-grabbing"))}),$.addEventListener("contextmenu",h=>{if(b){h.preventDefault(),h.stopPropagation(),b=!1;return}h.target instanceof Element&&h.target.closest(".card")||(h.preventDefault(),h.stopPropagation())});let k=!1,x=0,A=h=>(h[0].clientX+h[1].clientX)/2;$.addEventListener("touchstart",h=>{r=!1,h.touches.length===2?(k=!0,x=A(h.touches),n=!1,$.classList.add("is-grabbing")):k=!1},{passive:!0}),$.addEventListener("touchmove",h=>{if(!k||h.touches.length!==2)return;let E=A(h.touches),L=E-x;L&&(h.preventDefault(),$.scrollLeft-=L,x=E,r=!0)},{passive:!1});let M=h=>{h.touches.length<2&&k&&(k=!1,$.classList.remove("is-grabbing"))};$.addEventListener("touchend",M,{passive:!0}),$.addEventListener("touchcancel",M,{passive:!0})}var xa,$a,Mt,it=P(()=>{ie();z();ne();Q();he();He();fe();mn();rt();xa=new Map,$a=null,Mt=!1});var xn,Te,j,qe=P(()=>{xn="full";xn="full";Te=xn,j={sse:Te==="full",ai:Te==="full",multiBoard:Te==="full",tokenAuth:Te==="full",attachments:Te==="full"}});async function be(){let e=await w(`/api/boards/${c.boardId}/context?include_struck=true`),t=e.board,a=na(),n=[{id:"lanes",label:"Lanes"},{id:"appearance",label:"Appearance"},{id:"archive",label:"Card Archive"},{id:"notes",label:"Notes"},{id:"journal",label:"Journal"},...j.ai?[{id:"ai",label:"AI"}]:[],{id:"repository",label:"Repository"}],r=a==="ai"&&!j.ai?"lanes":a;$t({eyebrow:"SETTINGS",mode:"settings",title:t.name,tabs:n,activeTab:r,onTabSelect:async o=>{F({boardId:c.boardId,view:"settings",tab:o})},body:Nr(e,r)}),ro(e,r)}function Nr(e,t){switch(t){case"notes":return eo(e);case"lanes":return En();case"appearance":return to();case"ai":return j.ai?Or(e):En();case"journal":return ao(e);case"archive":return Yr();case"repository":default:return Wr(e)}}function Or(e){let t=e.board,a=t.ai_enabled!==0,n=a?'<div class="separator" aria-hidden="true"></div>':"",r=a?jr(t):"",o=a&&j.multiBoard?Vr(t):"",s=a?Hr(e):"";return`
|
|
109
|
-
<div class="section">
|
|
110
|
-
<label class="orbit-check" for="aiEnabledToggle">
|
|
111
|
-
<input
|
|
112
|
-
type="checkbox"
|
|
113
|
-
id="aiEnabledToggle"
|
|
114
|
-
${a?"checked":""}
|
|
115
|
-
/>
|
|
116
|
-
<span class="orbit-check-box" aria-hidden="true">
|
|
117
|
-
<svg viewBox="0 0 16 16" class="orbit-check-tick"><path d="M3.5 8.5l3 3 6-7" /></svg>
|
|
118
|
-
</span>
|
|
119
|
-
<span class="orbit-check-label">Enable AI</span>
|
|
120
|
-
</label>
|
|
121
|
-
<p class="description">Provisions the <strong>AI Ready</strong>, <strong>In Progress</strong>, and <strong>Review</strong> lanes if missing, surfaces agent context fields, and exposes the MCP setup snippet. Disabling AI hides the AI Ready column but keeps its cards in place.</p>
|
|
122
|
-
</div>
|
|
123
|
-
${n}
|
|
124
|
-
${r}
|
|
125
|
-
${o?`${n}${o}`:""}
|
|
126
|
-
${n}
|
|
127
|
-
${s}
|
|
128
|
-
`}function jr(e){let t=`This project is about\u2026
|
|
129
|
-
|
|
130
|
-
How any AI agent should use this board and work in this repo.`,a=e.agent_instructions||"",n=!!a.trim(),r=n?"":"is-placeholder",o=n?ce(a):d(t);return`
|
|
131
|
-
<div class="section ai-subsection ai-context-setup">
|
|
132
|
-
<div class="ai-context-title-row">
|
|
133
|
-
<span class="section-mark" aria-hidden="true">Context</span>
|
|
134
|
-
<h3>Agent Instructions</h3>
|
|
135
|
-
</div>
|
|
136
|
-
<p class="description">This project-level context is provided to agents when they work on tickets.</p>
|
|
137
|
-
<div class="inline-md-field">
|
|
138
|
-
<div
|
|
139
|
-
class="inline-md-field-body preserved-text-body editable-field settings-agent-instructions-body ${r}"
|
|
140
|
-
data-edit-field="agent_instructions"
|
|
141
|
-
tabindex="0"
|
|
142
|
-
title="Click to edit"
|
|
143
|
-
role="button"
|
|
144
|
-
aria-label="Edit Agent Instructions"
|
|
145
|
-
>${o}</div>
|
|
146
|
-
</div>
|
|
147
|
-
</div>
|
|
148
|
-
`}function Hr(e){let t=Bt(),a="claude-code",n=Ur(e,t),r=Ea(a,n),o=Sa(t,n),s=Rt[a];return`
|
|
149
|
-
<details class="section ai-subsection mcp-setup" data-mcp-setup>
|
|
150
|
-
<summary>
|
|
151
|
-
<div class="mcp-title-row">
|
|
152
|
-
<span class="section-mark" aria-hidden="true">MCP</span>
|
|
153
|
-
<h3>Connect Your Agent to MCP</h3>
|
|
154
|
-
</div>
|
|
155
|
-
</summary>
|
|
156
|
-
<div>
|
|
157
|
-
<p class="description">A tiny service running on your computer alongside your AI agent, providing it with tools and context to collaborate with you more effectively. Tell your AI to use the snippet below, it knows what MCP is.</p>
|
|
158
|
-
<div class="mcp-flow">
|
|
159
|
-
<label>
|
|
160
|
-
<span>Operating system</span>
|
|
161
|
-
<select id="mcpOsSelect" class="select-chevron-field">
|
|
162
|
-
${Object.entries(Ft).map(([i,l])=>`<option value="${i}" ${i===t?"selected":""}>${d(l.label)}</option>`).join("")}
|
|
163
|
-
</select>
|
|
164
|
-
</label>
|
|
165
|
-
<label>
|
|
166
|
-
<span>Agent app</span>
|
|
167
|
-
<select id="mcpClientSelect" class="select-chevron-field">
|
|
168
|
-
${Object.entries(Rt).map(([i,l])=>`<option value="${i}" ${i===a?"selected":""}>${d(l.label)}</option>`).join("")}
|
|
169
|
-
</select>
|
|
170
|
-
</label>
|
|
171
|
-
</div>
|
|
172
|
-
<div class="mcp-path-grid">
|
|
173
|
-
<label>
|
|
174
|
-
<span>Orbit MCP server file</span>
|
|
175
|
-
<input id="mcpServerPathInput" value="${d(n.serverPath)}" />
|
|
176
|
-
</label>
|
|
177
|
-
</div>
|
|
178
|
-
</div>
|
|
179
|
-
|
|
180
|
-
<div class="mcp-options-stack">
|
|
181
|
-
<div class="mcp-option-card">
|
|
182
|
-
<div class="mcp-option-card-head">
|
|
183
|
-
<div>
|
|
184
|
-
<strong data-mcp-output-title>${d(s.label)} setup</strong>
|
|
185
|
-
<p class="description" data-mcp-helper>${d(s.helper)}</p>
|
|
186
|
-
</div>
|
|
187
|
-
<button type="button" data-variant="secondary" data-copy-mcp="config">Copy setup</button>
|
|
188
|
-
</div>
|
|
189
|
-
<div class="mcp-terminal">
|
|
190
|
-
<div class="mcp-terminal-chrome" aria-hidden="true"><span></span><span></span><span></span></div>
|
|
191
|
-
<pre class="mcp-snippet"><code data-mcp-config>${d(r)}</code></pre>
|
|
192
|
-
</div>
|
|
193
|
-
</div>
|
|
194
|
-
|
|
195
|
-
<div class="mcp-or-divider" aria-hidden="true"><span>OR</span></div>
|
|
196
|
-
|
|
197
|
-
<div class="mcp-option-card">
|
|
198
|
-
<div class="mcp-option-card-head">
|
|
199
|
-
<div>
|
|
200
|
-
<strong>Manual run command</strong>
|
|
201
|
-
<p class="description">Use this only when an app asks you to start the MCP server yourself.</p>
|
|
202
|
-
</div>
|
|
203
|
-
<button type="button" data-variant="secondary" data-copy-mcp="command">Copy command</button>
|
|
204
|
-
</div>
|
|
205
|
-
<div class="mcp-terminal">
|
|
206
|
-
<div class="mcp-terminal-chrome" aria-hidden="true"><span></span><span></span><span></span></div>
|
|
207
|
-
<pre class="mcp-snippet mcp-snippet--compact"><code data-mcp-command>${d(o)}</code></pre>
|
|
208
|
-
</div>
|
|
209
|
-
</div>
|
|
210
|
-
</div>
|
|
211
|
-
</details>
|
|
212
|
-
`}function Bt(){let e=String(navigator.userAgentData?.platform||navigator.platform||navigator.userAgent||"").toLowerCase();return e.includes("win")?"windows":e.includes("mac")?"macos":"linux"}function qr(e){return{serverPath:(Ft[e]||Ft.linux).serverPath}}function Ur(e,t){let a=qr(t);return{serverPath:(e.deployment||{}).mcp_server_path||a.serverPath}}function Ln(){return{serverPath:v("#mcpServerPathInput")?.value||""}}function Ea(e,t){if(e==="claude-code")return Jr(t);if(e==="codex")return Kr(t);if(e==="opencode")return zr(t);if(e==="vscode")return Gr(t);let a={mcpServers:{"starscape-orbit":{command:"node",args:[t.serverPath]}}};return JSON.stringify(a,null,2)}function zr(e){return JSON.stringify({$schema:"https://opencode.ai/config.json",mcp:{"starscape-orbit":{type:"local",command:["node",e.serverPath],enabled:!0}}},null,2)}function Gr(e){return JSON.stringify({servers:{starscapeOrbit:{type:"stdio",command:"node",args:[e.serverPath]}}},null,2)}function Kr(e){return`[mcp_servers.starscape-orbit]
|
|
213
|
-
command = "node"
|
|
214
|
-
args = ["${Xr(e.serverPath)}"]
|
|
215
|
-
enabled = true`}function Jr(e){return["claude mcp add starscape-orbit","--","node",Tn(e.serverPath)].join(" ")}function Sa(e,t){return`node ${Tn(t.serverPath)}`}function Tn(e){return`"${String(e||"").replace(/"/g,'\\"')}"`}function Xr(e){return String(e||"").replace(/\\/g,"\\\\").replace(/"/g,'\\"')}function Yr(){return`
|
|
216
|
-
<p class="description">Archived cards are hidden from the kanban, search, and agent claim-next. Restore to put a card back on the board, or delete to permanently remove it.</p>
|
|
217
|
-
<div class="section">
|
|
218
|
-
<div id="archiveList" class="archive-list">Loading\u2026</div>
|
|
219
|
-
</div>
|
|
220
|
-
`}function Wr(e){let t=e.board;return H.boardId!==t.id&&(H.boardId=t.id,H.step="idle",H.exported=!1),`
|
|
221
|
-
${j.multiBoard?`
|
|
222
|
-
<div class="detail-head project-manual-head">
|
|
223
|
-
<div class="meta-grid">
|
|
224
|
-
<div class="meta meta--repo-path">
|
|
225
|
-
<span>Repo</span>
|
|
226
|
-
<strong>${d(en(t.repo_url))}</strong>
|
|
227
|
-
<span>Path</span>
|
|
228
|
-
<strong>${d(t.system_path||e.deployment?.system_path||"Not available")}</strong>
|
|
229
|
-
</div>
|
|
230
|
-
</div>
|
|
231
|
-
</div>`:`
|
|
232
|
-
<p class="description">This board lives in your browser only. Export a snapshot if you want to move it to a real Orbit install, or import one to seed this preview.</p>`}
|
|
233
|
-
|
|
234
|
-
${j.multiBoard?Qr(t):""}
|
|
235
|
-
|
|
236
|
-
<div class="section">
|
|
237
|
-
<h3>Board Snapshot</h3>
|
|
238
|
-
<p class="description">Import accepts Orbit snapshots or Trello board JSON exports. The default import creates a separate board and leaves this board untouched.</p>
|
|
239
|
-
${j.attachments?`
|
|
240
|
-
<label class="orbit-check">
|
|
241
|
-
<input type="checkbox" id="exportProjectImages" />
|
|
242
|
-
<span class="orbit-check-box" aria-hidden="true">
|
|
243
|
-
<svg viewBox="0 0 16 16" class="orbit-check-tick"><path d="M3.5 8.5l3 3 6-7" /></svg>
|
|
244
|
-
</span>
|
|
245
|
-
<span>Include attached images</span>
|
|
246
|
-
</label>
|
|
247
|
-
<p class="description">Image exports are embedded in the .orbit.json snapshot and may be much larger.</p>
|
|
248
|
-
`:""}
|
|
249
|
-
<div class="deployment-actions">
|
|
250
|
-
<button type="button" data-variant="secondary" id="exportProject">Export</button>
|
|
251
|
-
<input type="file" id="importSnapshotAsNewFile" class="import-file-input" accept=".orbit.json,.json,application/json" />
|
|
252
|
-
<button type="button" data-variant="secondary" id="importSnapshotAsNewButton">Import as New Board</button>
|
|
253
|
-
</div>
|
|
254
|
-
</div>
|
|
255
|
-
|
|
256
|
-
<div class="section repository-danger-zone">
|
|
257
|
-
<h3>Replace Current Board</h3>
|
|
258
|
-
<p class="description">Advanced: replace this board from an Orbit snapshot or Trello export after making the normal pre-import backup. Type <strong>${d(t.slug||"")}</strong> to enable replacement.</p>
|
|
259
|
-
<label class="repository-confirm-field">
|
|
260
|
-
<span>Board slug</span>
|
|
261
|
-
<input id="replaceImportConfirmInput" autocomplete="off" spellcheck="false" placeholder="${d(t.slug||"")}" />
|
|
262
|
-
</label>
|
|
263
|
-
<div class="deployment-actions">
|
|
264
|
-
<input type="file" id="replaceCurrentBoardImportFile" class="import-file-input" accept=".orbit.json,.json,application/json" disabled />
|
|
265
|
-
<button type="button" data-variant="secondary" id="replaceCurrentBoardImportButton" disabled>Replace Current Board</button>
|
|
266
|
-
</div>
|
|
267
|
-
</div>
|
|
268
|
-
|
|
269
|
-
${j.multiBoard?Zr(t):""}
|
|
270
|
-
`}function Vr(e){let t=!!e.system_path,a=!!e.manage_helper_files;return`
|
|
271
|
-
<div class="section ai-subsection helper-files-section">
|
|
272
|
-
<div class="ai-context-title-row">
|
|
273
|
-
<span class="section-mark" aria-hidden="true">Files</span>
|
|
274
|
-
<h3>AI Helper Files</h3>
|
|
275
|
-
</div>
|
|
276
|
-
<p class="description">Orbit can keep <code>SKILL-ORBIT.md</code> and <code>AGENTS.md</code> in this board's coding project folder so your AI agent knows how to use Orbit.${t?"":" Link a folder to enable this."}</p>
|
|
277
|
-
<div class="folder-picker-field helper-files-folder">
|
|
278
|
-
<input id="helperFolderInput" type="text" readonly placeholder="No folder linked" value="${d(e.system_path||"")}" />
|
|
279
|
-
<button type="button" id="helperPickFolderBtn">${t?"Change":"Browse"}</button>
|
|
280
|
-
</div>
|
|
281
|
-
<label class="orbit-check">
|
|
282
|
-
<input type="checkbox" id="manageHelperFilesToggle" ${a?"checked":""} ${t?"":"disabled"} />
|
|
283
|
-
<span class="orbit-check-box" aria-hidden="true">
|
|
284
|
-
<svg viewBox="0 0 16 16" class="orbit-check-tick"><path d="M3.5 8.5l3 3 6-7" /></svg>
|
|
285
|
-
</span>
|
|
286
|
-
<span>Generate & maintain helper files in this folder</span>
|
|
287
|
-
</label>
|
|
288
|
-
</div>
|
|
289
|
-
`}function Qr(e){return`
|
|
290
|
-
<div class="section board-rename-section">
|
|
291
|
-
<h3>Board Name</h3>
|
|
292
|
-
<p class="description">Rename the board display name only. The canonical URL slug stays <strong>${d(e.slug||"")}</strong>, so existing board links keep working.</p>
|
|
293
|
-
<form id="boardRenameForm" class="field-form">
|
|
294
|
-
<label>
|
|
295
|
-
<span>Display name</span>
|
|
296
|
-
<input name="name" value="${d(e.name||"")}" maxlength="120" required />
|
|
297
|
-
</label>
|
|
298
|
-
<button type="submit" data-variant="secondary">Rename Board</button>
|
|
299
|
-
</form>
|
|
300
|
-
</div>
|
|
301
|
-
`}function Zr(e){let t=d(e.slug||"");if(H.step==="choice")return`
|
|
302
|
-
<div class="section repository-danger-zone">
|
|
303
|
-
<h3>Delete Board</h3>
|
|
304
|
-
<p class="description">Delete this board from Orbit and remove its repo-local Orbit files. Export a snapshot first if you may need this board again.</p>
|
|
305
|
-
<div class="repository-delete-actions">
|
|
306
|
-
<button type="button" data-variant="secondary" id="deleteBoardExportFirst">Export first</button>
|
|
307
|
-
<button type="button" data-variant="ghost" class="danger-button" id="deleteBoardSkipExport">Delete without exporting</button>
|
|
308
|
-
<button type="button" data-variant="ghost" id="deleteBoardCancel">Cancel</button>
|
|
309
|
-
</div>
|
|
310
|
-
</div>
|
|
311
|
-
`;if(H.step==="confirm"){let a=H.exported?"Snapshot exported. Type the board slug to confirm permanent deletion.":"Type the board slug to confirm permanent deletion.";return`
|
|
312
|
-
<div class="section repository-danger-zone is-confirming">
|
|
313
|
-
<h3>Delete Board</h3>
|
|
314
|
-
<p class="description">${d(a)}</p>
|
|
315
|
-
<label class="repository-confirm-field">
|
|
316
|
-
<span>Board slug</span>
|
|
317
|
-
<strong>${t}</strong>
|
|
318
|
-
<input id="deleteBoardConfirmInput" autocomplete="off" spellcheck="false" placeholder="${t}" autofocus />
|
|
319
|
-
</label>
|
|
320
|
-
<div class="repository-delete-actions">
|
|
321
|
-
<button type="button" data-variant="primary" class="danger-button" id="deleteBoardConfirm" disabled>Delete board permanently</button>
|
|
322
|
-
<button type="button" data-variant="ghost" id="deleteBoardCancel">Cancel</button>
|
|
323
|
-
</div>
|
|
324
|
-
</div>
|
|
325
|
-
`}return`
|
|
326
|
-
<div class="section repository-danger-zone">
|
|
327
|
-
<h3>Delete Board</h3>
|
|
328
|
-
<p class="description">Remove this board from Orbit and delete its repo-local Orbit files. This cannot be undone without an exported snapshot.</p>
|
|
329
|
-
<button type="button" data-variant="ghost" class="danger-button" id="deleteBoardStart">Delete Board</button>
|
|
330
|
-
</div>
|
|
331
|
-
`}function eo(e){let t=e.board,a="Remember to mention SKILL-ORBIT.md to my AI agents if they get confused",n=t.project_notes||"",r=!!n.trim(),o=r?"":"is-placeholder",s=r?ce(n):d(a);return`
|
|
332
|
-
<div class="section ai-fields">
|
|
333
|
-
<div class="inline-md-field">
|
|
334
|
-
<span class="inline-md-field-label">Notes For You</span>
|
|
335
|
-
<div
|
|
336
|
-
class="inline-md-field-body preserved-text-body editable-field settings-notes-body ${o}"
|
|
337
|
-
data-edit-field="project_notes"
|
|
338
|
-
tabindex="0"
|
|
339
|
-
title="Click to edit"
|
|
340
|
-
role="button"
|
|
341
|
-
aria-label="Edit Notes For You"
|
|
342
|
-
>${s}</div>
|
|
343
|
-
</div>
|
|
344
|
-
</div>
|
|
345
|
-
`}function En(){return`
|
|
346
|
-
<div class="section">
|
|
347
|
-
<label class="orbit-check" for="showPriorityToggle">
|
|
348
|
-
<input
|
|
349
|
-
type="checkbox"
|
|
350
|
-
id="showPriorityToggle"
|
|
351
|
-
${c.showPriority?"checked":""}
|
|
352
|
-
/>
|
|
353
|
-
<span class="orbit-check-box" aria-hidden="true">
|
|
354
|
-
<svg viewBox="0 0 16 16" class="orbit-check-tick"><path d="M3.5 8.5l3 3 6-7" /></svg>
|
|
355
|
-
</span>
|
|
356
|
-
<span class="orbit-check-label">Show priority label on cards</span>
|
|
357
|
-
</label>
|
|
358
|
-
<p class="description lanes-description">Rename, reorder, add, or remove lanes.</p>
|
|
359
|
-
${lo()}
|
|
360
|
-
<form id="laneCreateForm" class="lane-create-form">
|
|
361
|
-
<input name="name" placeholder="New lane name..." required />
|
|
362
|
-
<button type="submit" data-variant="primary">Add Lane</button>
|
|
363
|
-
</form>
|
|
364
|
-
</div>
|
|
365
|
-
`}function to(){let e=$e(),t=Ae(),a=ft(),n=Vt(),r=a===null?`Using browser default (${n?"reduced motion":"motion allowed"}).`:"Using your saved preference.";return`
|
|
366
|
-
<div class="section appearance-theme-section">
|
|
367
|
-
<fieldset class="appearance-theme-field">
|
|
368
|
-
<legend>Theme</legend>
|
|
369
|
-
<div class="appearance-theme-options">
|
|
370
|
-
${Sn("light","Light",e)}
|
|
371
|
-
${Sn("dark","Dark",e)}
|
|
372
|
-
</div>
|
|
373
|
-
<p class="description">Applies the light/dark theme used by the top rail toggle.</p>
|
|
374
|
-
</fieldset>
|
|
375
|
-
</div>
|
|
376
|
-
<div class="section">
|
|
377
|
-
<label class="orbit-check" for="reduceMotionToggle">
|
|
378
|
-
<input
|
|
379
|
-
type="checkbox"
|
|
380
|
-
id="reduceMotionToggle"
|
|
381
|
-
${t?"checked":""}
|
|
382
|
-
/>
|
|
383
|
-
<span class="orbit-check-box" aria-hidden="true">
|
|
384
|
-
<svg viewBox="0 0 16 16" class="orbit-check-tick"><path d="M3.5 8.5l3 3 6-7" /></svg>
|
|
385
|
-
</span>
|
|
386
|
-
<span class="orbit-check-label">Reduce theme motion</span>
|
|
387
|
-
</label>
|
|
388
|
-
<p class="description">Turns off the animated starfield, meteors, and theme animations. ${d(r)}</p>
|
|
389
|
-
</div>
|
|
390
|
-
`}function Sn(e,t,a){return`
|
|
391
|
-
<label class="appearance-theme-option">
|
|
392
|
-
<input type="radio" name="themePreference" value="${e}" ${a===e?"checked":""} />
|
|
393
|
-
<span class="appearance-theme-option-mark" aria-hidden="true">
|
|
394
|
-
<svg
|
|
395
|
-
class="appearance-theme-option-icon"
|
|
396
|
-
width="16"
|
|
397
|
-
height="16"
|
|
398
|
-
viewBox="0 0 24 24"
|
|
399
|
-
fill="none"
|
|
400
|
-
stroke="currentColor"
|
|
401
|
-
stroke-width="2"
|
|
402
|
-
stroke-linecap="round"
|
|
403
|
-
stroke-linejoin="round"
|
|
404
|
-
>${e==="dark"?'<path d="M21 12.79A9 9 0 1111.21 3 7 7 0 0021 12.79z" />':'<circle cx="12" cy="12" r="5" /><path d="M12 1v2m0 18v2M4.2 4.2l1.4 1.4m12.8 12.8l1.4 1.4M1 12h2m18 0h2M4.2 19.8l1.4-1.4M18.4 5.6l1.4-1.4" />'}</svg>
|
|
405
|
-
</span>
|
|
406
|
-
<span class="appearance-theme-option-label">${t}</span>
|
|
407
|
-
</label>
|
|
408
|
-
`}function ao(e){return`
|
|
409
|
-
${e.board?.ai_enabled!==0?'<p class="description">Agent-facing project memory: decisions to follow and lessons to apply. Struck entries stay visible here but are excluded from agent context.</p>':""}
|
|
410
|
-
<div class="section">
|
|
411
|
-
${io(e.entries)}
|
|
412
|
-
<form id="projectEntryForm" class="comment-form project-entry-form">
|
|
413
|
-
<select name="type" class="select-chevron-field" aria-label="Entry type">
|
|
414
|
-
<option value="decision">Decision</option>
|
|
415
|
-
<option value="lesson">Lesson</option>
|
|
416
|
-
</select>
|
|
417
|
-
<input name="title" placeholder="Entry title..." required />
|
|
418
|
-
<textarea name="body" placeholder="Decision rationale or lesson: do X instead of Y when working with Z." required></textarea>
|
|
419
|
-
<button type="submit" data-variant="primary">Add Entry</button>
|
|
420
|
-
</form>
|
|
421
|
-
</div>
|
|
422
|
-
`}function no(e){if(String(e||"").trimStart().startsWith("<"))throw new Error("That file looks like an HTML page instead of JSON. In Trello, use Export JSON/download the board JSON, not Save Page As.");try{return JSON.parse(e)}catch(a){throw new Error(a?.message||"invalid JSON")}}function ro(e,t){let a=e.board;if(t==="repository"){let n=async(m=!!v("#exportProjectImages")?.checked)=>{let f=m?"?include_attachments=true":"",b=await w(`/api/boards/${encodeURIComponent(a.id)}/export${f}`),k=m?`${a.slug}.with-images.orbit.json`:`${a.slug}.orbit.json`;tn(k,b)};v("#exportProject")?.addEventListener("click",async()=>{await n()}),v("#boardRenameForm")?.addEventListener("submit",async m=>{m.preventDefault();let f=new FormData(m.currentTarget),b=String(f.get("name")||"").trim();!b||b===a.name||(await w(`/api/boards/${encodeURIComponent(a.id)}`,{method:"PATCH",body:{name:b}}),await C(),c.detailMode="settings",g.success(`Renamed board to ${b}. Canonical slug unchanged: ${a.slug}`))});let r=async(m,f)=>{let b=await m.text(),k=no(b);return w("/api/admin/import",{method:"POST",body:f(k)})},o=v("#importSnapshotAsNewFile");v("#importSnapshotAsNewButton")?.addEventListener("click",()=>{o?.click()}),o?.addEventListener("change",async m=>{let f=m.currentTarget,b=f.files?.[0];if(b)try{let k=await r(b,M=>({snapshot:M,create_new:!0,board_id:a.id}));c.boardId=k.imported_board_id,c.boardSlug=k.imported_board_slug,c.detailMode="empty",await C(),await F({boardId:k.imported_board_id,view:"board"});let x=k.imported_counts||{},A=Number.isFinite(Number(x.tickets))?` (${x.tickets} cards)`:"";g.success(k.source_format==="trello-board-export"?`Trello board imported as new board${A}`:"Board imported as new board")}catch(k){g.error(`Import failed: ${k?.message||"invalid JSON"}`)}finally{f.value=""}});let s=v("#replaceImportConfirmInput"),i=v("#replaceCurrentBoardImportFile"),l=v("#replaceCurrentBoardImportButton");s?.addEventListener("input",()=>{let m=s.value.trim()!==a.slug;i&&(i.disabled=m),l&&(l.disabled=m)}),l?.addEventListener("click",()=>{l.disabled||i?.disabled||i?.click()}),i?.addEventListener("change",async m=>{let f=m.currentTarget,b=f.files?.[0];if(b){if(s.value.trim()!==a.slug){g.error("Type the board slug before replacing this board."),f.value="";return}try{let k=await r(b,M=>({snapshot:M,replace_existing:!0,board_id:a.id}));await C(),c.detailMode="settings";let x=k.imported_counts||{},A=Number.isFinite(Number(x.tickets))?` (${x.tickets} cards)`:"";g.success(k.source_format==="trello-board-export"?`Trello board replaced from Trello import${A}`:"Board replaced from snapshot")}catch(k){g.error(`Import failed: ${k?.message||"invalid JSON"}`)}finally{f.value=""}}}),v("#deleteBoardStart")?.addEventListener("click",async()=>{H.step="choice",H.exported=!1,await be()}),v("#deleteBoardExportFirst")?.addEventListener("click",async()=>{await n(),H.step="confirm",H.exported=!0,await be()}),v("#deleteBoardSkipExport")?.addEventListener("click",async()=>{H.step="confirm",H.exported=!1,await be()}),v("#deleteBoardCancel")?.addEventListener("click",async()=>{H.step="idle",H.exported=!1,await be()});let u=v("#deleteBoardConfirmInput"),p=v("#deleteBoardConfirm");u?.addEventListener("input",()=>{p&&(p.disabled=u.value.trim()!==a.slug)}),p?.addEventListener("click",async()=>{await w(`/api/boards/${encodeURIComponent(a.id)}`,{method:"DELETE",body:{confirm_slug:a.slug,delete_files:!0}}),H.step="idle",H.exported=!1,await C(),g.success(`Deleted board: ${a.name}`),F({boardId:c.boardId,view:"board"},{replace:!0})})}if(t==="notes"){let n=S.querySelector('[data-edit-field="project_notes"]');if(n){let r=()=>Ie(n,{fieldName:"project_notes",multiline:!0,initialValue:a.project_notes||"",ariaLabel:"Edit Notes For You",rerender:async()=>{c.detailMode="settings",await be()},commit:async o=>{await w(`/api/boards/${a.id}`,{method:"PATCH",body:{project_notes:V(o)}}),await C(),c.detailMode="settings",g.success("Saved")}});n.addEventListener("click",o=>{o.preventDefault(),r()}),n.addEventListener("keydown",o=>{(o.key==="Enter"||o.key===" ")&&(o.preventDefault(),r())})}}if(t==="lanes"&&(S.querySelectorAll("[data-lane-action]").forEach(n=>{n.addEventListener("click",async()=>{await uo(n)})}),S.querySelectorAll(".lane-row input, .lane-row select").forEach(n=>{n.addEventListener("change",async()=>{await _n(n.closest(".lane-row"))})}),v("#laneCreateForm")?.addEventListener("submit",async n=>{n.preventDefault();let r=new FormData(n.currentTarget);await w(`/api/boards/${a.id}/states`,{method:"POST",body:Object.fromEntries(r.entries())}),await C(),c.detailMode="settings",g.success("Lane added")}),v("#showPriorityToggle")?.addEventListener("change",n=>{c.showPriority=!!n.currentTarget.checked,localStorage.setItem("mab_show_priority",c.showPriority?"true":"false"),je()})),t==="appearance"&&(S.querySelectorAll("input[name='themePreference']").forEach(n=>{n.addEventListener("change",r=>{if(!r.currentTarget.checked)return;let o=Ye(r.currentTarget.value);g.success(o==="dark"?"Dark theme enabled":"Light theme enabled")})}),v("#reduceMotionToggle")?.addEventListener("change",n=>{let r=!!n.currentTarget.checked;Ua(r),Xe(),window.dispatchEvent(new CustomEvent("orbit:motion-preference-change",{detail:{reduce:r}})),g.success(r?"Theme motion reduced":"Theme motion enabled")})),t==="ai"){let n=()=>{let i=v("#mcpOsSelect")?.value||Bt(),l=v("#mcpClientSelect")?.value||"claude-code",u=Rt[l]||Rt.generic,p=Ln(),m=Ea(l,p),f=Sa(i,p),b=S.querySelector("[data-mcp-os-note]");b&&(b.textContent=`Detected: ${Ft[Bt()]?.label||"Linux"}`);let k=S.querySelector("[data-mcp-client-format]");k&&(k.textContent=u.format);let x=S.querySelector("[data-mcp-output-title]");x&&(x.textContent=`${u.label} setup`);let A=S.querySelector("[data-mcp-helper]");A&&(A.textContent=u.helper);let M=S.querySelector("[data-mcp-config]");M&&(M.textContent=m);let h=S.querySelector("[data-mcp-command]");h&&(h.textContent=f)};v("#mcpOsSelect")?.addEventListener("change",()=>n()),v("#mcpClientSelect")?.addEventListener("change",()=>n()),["#mcpServerPathInput"].forEach(i=>{v(i)?.addEventListener("input",()=>n())}),S.querySelectorAll("[data-copy-mcp]").forEach(i=>{i.addEventListener("click",async()=>{let l=v("#mcpOsSelect")?.value||Bt(),u=v("#mcpClientSelect")?.value||"claude-code",p=Ln(),m=i.dataset.copyMcp==="command"?Sa(l,p):Ea(u,p);await oo(m),g.success(i.dataset.copyMcp==="command"?"MCP command copied":"MCP config copied")})});let r=S.querySelector('[data-edit-field="agent_instructions"]');if(r){let i=()=>Ie(r,{fieldName:"agent_instructions",multiline:!0,initialValue:a.agent_instructions||"",ariaLabel:"Edit Agent Instructions",rerender:async()=>{c.detailMode="settings",await be()},commit:async l=>{await w(`/api/boards/${a.id}`,{method:"PATCH",body:{agent_instructions:V(l)}}),await C(),c.detailMode="settings",g.success("Saved")}});r.addEventListener("click",l=>{l.preventDefault(),i()}),r.addEventListener("keydown",l=>{(l.key==="Enter"||l.key===" ")&&(l.preventDefault(),i())})}v("#aiEnabledToggle")?.addEventListener("change",async i=>{let l=!!i.currentTarget.checked;await w(`/api/boards/${a.id}`,{method:"PATCH",body:{ai_enabled:l}}),await C(),c.detailMode="settings",g.success(l?"AI features enabled \u2014 agent lanes provisioned":"AI features disabled \u2014 AI Ready hidden")});let o=v("#helperPickFolderBtn");o?.addEventListener("click",async()=>{o.disabled=!0;try{let i=await w("/api/system/pick-folder",{method:"POST"});if(!i.path)return;await w(`/api/boards/${encodeURIComponent(a.id)}`,{method:"PATCH",body:{system_path:i.path}}),await C(),c.detailMode="settings",g.success("Linked coding project folder updated")}catch(i){g.error(i?.message||"Folder picker unavailable")}finally{o.disabled=!1}});let s=v("#manageHelperFilesToggle");s?.addEventListener("change",async()=>{let i=s.checked;s.disabled=!0;try{await w(`/api/boards/${encodeURIComponent(a.id)}`,{method:"PATCH",body:{manage_helper_files:i}}),await C(),c.detailMode="settings",g.success(i?"Generated SKILL-ORBIT.md and AGENTS.md \u2014 Orbit will keep them in sync":"Stopped maintaining helper files (existing files left in place)")}catch(l){s.checked=!i,s.disabled=!1,g.error(l?.message||"Could not update helper files setting")}})}if(t==="archive"){let n=v("#archiveList");if(n){let r=async()=>{try{let s=(await w(`/api/boards/${encodeURIComponent(a.id)}/archive`)).tickets||[];if(s.length===0){n.innerHTML='<p class="description">No archived cards yet. Click the trash icon in the card detail header to archive a card.</p>';return}n.innerHTML=`<div class="detail-card-grid">${s.map(i=>Ue(i,{archive:{id:i.id},disableOpen:!0})).join("")}</div>`}catch(o){n.innerHTML=`<p class="description">Could not load archive: ${d(o?.message||"unknown error")}</p>`}};r(),n.addEventListener("click",async o=>{let s=o.target.closest("[data-archive-restore]"),i=o.target.closest("[data-archive-delete]");if(!s&&!i)return;o.stopPropagation();let u=(s||i).closest("article")?.querySelector("h3")?.textContent||"card";if(s){let p=s.dataset.archiveRestore;await w(T(`/api/tickets/${encodeURIComponent(p)}/restore`),{method:"POST"}),g.success(`Restored: ${u}`),await C(),await r();return}if(i){let p=i.dataset.archiveDelete;if(!confirm(`Permanently delete "${u}"? This cannot be undone.`))return;await w(T(`/api/tickets/${encodeURIComponent(p)}`),{method:"DELETE"}),g.success(`Deleted: ${u}`),await r()}})}}t==="journal"&&(S.querySelectorAll("[data-entry-action='toggle-struck']").forEach(n=>{n.addEventListener("click",async()=>{await w(T(`/api/board-entries/${n.dataset.entryId}`),{method:"PATCH",body:{struck:n.dataset.struck!=="true"}}),await C(),c.detailMode="settings",g.info(n.dataset.struck==="true"?"Project entry restored":"Project entry struck")})}),v("#projectEntryForm")?.addEventListener("submit",async n=>{n.preventDefault();let r=new FormData(n.currentTarget);await w(`/api/boards/${a.id}/entries`,{method:"POST",body:Object.fromEntries(r.entries())}),await C(),c.detailMode="settings",g.success("Project entry added")}))}async function oo(e){if(navigator.clipboard?.writeText){await navigator.clipboard.writeText(e);return}let t=document.createElement("textarea");t.value=e,t.setAttribute("readonly",""),t.style.position="fixed",t.style.left="-9999px",document.body.append(t),t.select(),document.execCommand("copy"),t.remove()}function io(e=[]){return e.length?e.map(t=>{let a=!!t.struck_at;return`
|
|
423
|
-
<div class="comment project-entry ${d(t.type)} ${a?"is-struck":""}">
|
|
424
|
-
<div class="comment-meta">
|
|
425
|
-
<div>
|
|
426
|
-
<strong>${d(t.type.toUpperCase())}: ${d(t.title)}</strong>
|
|
427
|
-
${a?'<span class="project-entry-status">Excluded from agent context</span>':""}
|
|
428
|
-
</div>
|
|
429
|
-
<div class="project-entry-actions">
|
|
430
|
-
<span>${d(t.created_by)} - ${Ve(t.created_at)}</span>
|
|
431
|
-
<button
|
|
432
|
-
type="button"
|
|
433
|
-
data-variant="ghost"
|
|
434
|
-
class="project-entry-strike"
|
|
435
|
-
data-entry-action="toggle-struck"
|
|
436
|
-
data-entry-id="${d(t.id)}"
|
|
437
|
-
data-struck="${a?"true":"false"}"
|
|
438
|
-
aria-pressed="${a?"true":"false"}"
|
|
439
|
-
>${a?"Restore":"Strike"}</button>
|
|
440
|
-
</div>
|
|
441
|
-
</div>
|
|
442
|
-
<div class="comment-body">${d(t.body)}</div>
|
|
443
|
-
</div>
|
|
444
|
-
`}).join(""):'<p class="description">No project entries yet.</p>'}function so(e,t,a){return!!(t.get(e.id)||e.is_default||In.has(e.role)||a&&e.role==="ai_ready")}function co(e,t,a){let n=t.get(e.id)||0;return n>0?`Cannot delete \u2014 ${n} card${n===1?"":"s"} in this lane`:e.is_default?"Cannot delete \u2014 default lane for new cards (move it first)":In.has(e.role)?"Cannot delete \u2014 core kanban lane":a&&e.role==="ai_ready"?"Cannot delete \u2014 required by agent flow while AI is enabled":"Delete lane"}function lo(){let e=Re(),t=U()?.ai_enabled!==0,a=new Map;for(let n of X())a.set(n.state_id,(a.get(n.state_id)||0)+1);return`
|
|
445
|
-
<div class="lane-list">
|
|
446
|
-
${e.map((n,r)=>{let o=n.role==="ai_ready",s=o?"AI Ready lane name is locked \u2014 disable AI to hide this column":"";return`
|
|
447
|
-
<div class="lane-row${o?" lane-row--locked":""}" data-lane-id="${n.id}">
|
|
448
|
-
<button type="button" data-variant="ghost" class="settings-lane-icon-btn" data-lane-action="up" ${r===0?"disabled":""} title="Move lane left" aria-label="Move lane left">\u2191</button>
|
|
449
|
-
<button type="button" data-variant="ghost" class="settings-lane-icon-btn" data-lane-action="down" ${r===e.length-1?"disabled":""} title="Move lane right" aria-label="Move lane right">\u2193</button>
|
|
450
|
-
<input name="name" value="${d(n.name)}" aria-label="Lane name" ${o?`readonly title="${d(s)}"`:""} />
|
|
451
|
-
<button type="button" data-variant="${n.is_default?"secondary":"ghost"}" class="settings-lane-new-toggle ${n.is_default?"is-on":""}" data-lane-action="toggle-default" aria-pressed="${n.is_default?"true":"false"}" title="${n.is_default?"Default lane for new cards \u2014 click another lane to move it":"Make this the default lane for new cards"}" aria-label="Default lane for new cards">
|
|
452
|
-
<span class="lane-new-sun" aria-hidden="true"></span>
|
|
453
|
-
<span class="lane-new-label">New</span>
|
|
454
|
-
</button>
|
|
455
|
-
<button type="button" data-variant="ghost" class="settings-lane-delete-btn danger-button" data-lane-action="delete" ${so(n,a,t)?"disabled":""} title="${co(n,a,t)}" aria-label="Delete lane">\xD7</button>
|
|
456
|
-
</div>
|
|
457
|
-
`}).join("")}
|
|
458
|
-
</div>
|
|
459
|
-
`}async function uo(e){let t=e.closest(".lane-row"),a=t.dataset.laneId,n=e.dataset.laneAction;if(n==="delete"){await w(T(`/api/states/${a}`),{method:"DELETE"}),await C(),c.detailMode="settings",g.success("Lane deleted");return}if(n==="toggle-default"){if(e.getAttribute("aria-pressed")==="true")return;S.querySelectorAll('[data-lane-action="toggle-default"]').forEach(l=>{l.setAttribute("aria-pressed","false"),l.setAttribute("data-variant","ghost"),l.classList.remove("is-on")}),e.setAttribute("aria-pressed","true"),e.setAttribute("data-variant","secondary"),e.classList.add("is-on"),await _n(t,{silent:!0}),g.success("Default lane updated");return}let r=Re().map(i=>i.id),o=r.indexOf(a),s=n==="up"?o-1:o+1;s<0||s>=r.length||([r[o],r[s]]=[r[s],r[o]],await w(`/api/boards/${c.boardId}/states`,{method:"PATCH",body:{state_ids:r}}),await C(),c.detailMode="settings",g.success("Lanes reordered"))}async function _n(e,{silent:t=!1}={}){let a=e.querySelector('input[name="name"]').value,r=e.querySelector('[data-lane-action="toggle-default"]')?.getAttribute("aria-pressed")==="true";await w(T(`/api/states/${e.dataset.laneId}`),{method:"PATCH",body:{name:a,is_default:r}}),await C(),c.detailMode="settings",t||g.success("Lane updated")}var H,Ft,Rt,In,Cn=P(()=>{z();ie();ne();Q();me();xt();he();it();Dt();fe();qe();Qt();ta();H={boardId:"",step:"idle",exported:!1};Ft={windows:{label:"Windows",shell:"PowerShell",serverPath:"C:\\Path\\To\\StarscapeOrbit\\src\\mcp-server.js"},macos:{label:"macOS",shell:"Terminal",serverPath:"/Users/you/apps/starscape-orbit/src/mcp-server.js"},linux:{label:"Linux",shell:"Terminal",serverPath:"/home/you/apps/starscape-orbit/src/mcp-server.js"}},Rt={"claude-code":{label:"Claude Code",format:"CLI command",helper:"Run this command once. Claude Code records the local Orbit tool server for the project."},codex:{label:"Codex",format:"config.toml",helper:"Paste this TOML into Codex config. Project-local config may require the project to be trusted."},cursor:{label:"Cursor",format:"MCP JSON",helper:"Paste this JSON into Cursor MCP settings. Cursor starts Orbit when an agent needs the tools."},vscode:{label:"VS Code",format:"mcp.json",helper:"Paste this JSON into VS Code's user or workspace MCP configuration."},opencode:{label:"OpenCode",format:"opencode.json",helper:"Paste this into OpenCode config under the local MCP server list."},openclaw:{label:"OpenClaw",format:"MCP JSON",helper:"Paste this JSON into OpenClaw's MCP server list. OpenClaw will spawn Orbit on demand."},generic:{label:"Other MCP app",format:"MCP JSON",helper:"Most MCP clients accept this JSON shape for local stdio servers."}};In=new Set(["in_progress","review"])});function _e(e){return String(e||"").trim()}function Ia(e){let t=_e(e);return t?t.replace(/^@+/,"").replace(/[-_]+/g," ").replace(/\s+/g," ").trim().replace(/\b\w/g,a=>a.toUpperCase()):""}function Pn({actor:e,actorId:t}={}){let a=_e(e),n=_e(t),r=a.toLowerCase(),o=n.toLowerCase();return a&&!Ta.has(r)&&!Mn.has(r)?Ia(a):n&&!Ta.has(o)&&!Mn.has(o)?Ia(n):""}function _a({actor:e,actorType:t,actorId:a}={}){let n=_e(t).toLowerCase(),r=_e(e),o=r.toLowerCase();if(n==="agent"){let s=Pn({actor:r,actorId:a});return s?`Agent \xB7 ${s}`:"Agent"}return!r||Ta.has(o)?"You":Ia(r)}function An(e={}){let t=_e(e.kind).toLowerCase(),a=_e(e.author);if(po.has(t)||t&&t!=="human_comment"){let r=Pn({actor:a});return r?`Agent \xB7 ${r}`:"Agent"}return _a({actor:a,actorType:"human"})}var Ta,Mn,po,Bn=P(()=>{Ta=new Set(["local","local-owner","owner"]),Mn=new Set(["agent","local-agent","orbit-agent"]),po=new Set(["agent_note","checkpoint","completion"])});var Dn={};pt(Dn,{renderDetail:()=>ye,renderDetailCard:()=>Ue,renderInlinePreservedTextField:()=>Nt,startInlineEdit:()=>Ie});async function le(e,{renderBoardAfter:t=!1}={}){let[a,n,r]=await Promise.all([w(T(`/api/tickets/${e}/context?depth=1`)),w(T(`/api/tickets/${e}/history`)),w(T(`/api/tickets/${e}/comments`))]);a.ticket?.id===e&&(sa(a.ticket),t&&je(),!(c.detailMode!=="ticket"||c.selectedTicketId!==e)&&await ye({context:a,statusHistory:n,comments:r.comments||[]}))}async function ge(e,t){await w(T(`/api/tickets/${e}`),{method:"PATCH",body:t}),await le(e,{renderBoardAfter:!0})}function mo(e,t,a){if(!e||!t||typeof t.clientX!="number"||typeof t.clientY!="number")return null;let n=null;if(document.caretPositionFromPoint){let r=document.caretPositionFromPoint(t.clientX,t.clientY);r?.offsetNode&&(r.offsetNode===e||e.contains(r.offsetNode))&&(n=document.createRange(),n.setStart(e,0),n.setEnd(r.offsetNode,r.offset))}else if(document.caretRangeFromPoint){let r=document.caretRangeFromPoint(t.clientX,t.clientY);r?.startContainer&&(r.startContainer===e||e.contains(r.startContainer))&&(n=document.createRange(),n.setStart(e,0),n.setEnd(r.startContainer,r.startOffset))}return n?Math.max(0,Math.min(a,n.toString().length)):null}function fo(e){let t=e?.closest?.(".drawer-inner");return t?{scrollContainer:t,nodeRect:e.getBoundingClientRect(),scrollTop:t.scrollTop}:null}function ho(e,t){if(!e?.scrollContainer||!t?.isConnected)return;let a=t.getBoundingClientRect(),n=Math.max(0,e.scrollContainer.scrollTop+(a.top-e.nodeRect.top));Number.isFinite(n)?e.scrollContainer.scrollTop=n:e.scrollContainer.scrollTop=e.scrollTop}function bo(e){try{e.focus({preventScroll:!0})}catch{e.focus()}}function Ie(e,t){if(!e||e.dataset.editing==="true")return;let{fieldName:a,multiline:n=!0,initialValue:r="",ariaLabel:o,emptyMessage:s,sourceEvent:i,rerender:l,commit:u}=t,p=n?fo(e):null,m=String(r),f=n?mo(e,i,m.length):null;e.dataset.editing="true";let b=document.createElement(n?"textarea":"input");if(b.className=n?"inline-desc-editor":"inline-title-editor",b.value=m,a&&b.setAttribute("data-editing-field",a),o&&b.setAttribute("aria-label",o),!n)b.type="text",b.maxLength=500,b.autocomplete="off",b.spellcheck=!0;else{b.rows=Math.max(3,m.split(`
|
|
460
|
-
`).length+1);let I=e.getBoundingClientRect().height;Number.isFinite(I)&&I>0&&(b.style.minHeight=`${Math.ceil(I)}px`)}if(e.replaceWith(b),bo(b),!n)b.select();else{let I=f??0;b.setSelectionRange(I,I),ho(p,b)}let k=!1,x=()=>{document.removeEventListener("pointerdown",h,!0)},A=()=>{b.isConnected&&b.replaceWith(e),delete e.dataset.editing},M=()=>{k=!0,x(),A()};function h(I){k||I.target===b||b.contains(I.target)||b.blur()}document.addEventListener("pointerdown",h,!0);let E=async()=>{if(k)return;let I=n?b.value:b.value.trim();if(M(),String(I)===String(r)){l&&await l();return}if(s&&!I.trim()){g.warning(s),l&&await l();return}u&&await u(I)},L=async()=>{k||(M(),l&&await l())};b.addEventListener("blur",E),b.addEventListener("keydown",I=>{if(I.key==="Escape"){I.preventDefault(),L();return}I.key==="Enter"&&(n?(I.metaKey||I.ctrlKey)&&(I.preventDefault(),E()):(I.preventDefault(),E()))})}function go(e){let t=e.id,a=()=>Ie(n,{fieldName:"title",multiline:!1,initialValue:e.title||"",ariaLabel:"Edit ticket title",emptyMessage:"Title cannot be empty",rerender:()=>ye(),commit:u=>ge(t,{title:u})}),n=K.querySelector('[data-edit-field="title"]');n&&(n.addEventListener("click",a),n.addEventListener("keydown",u=>{(u.key==="Enter"||u.key===" ")&&(u.preventDefault(),a())}));let r=S.querySelector('[data-edit-field="description"]'),o=u=>Ie(r,{fieldName:"description",multiline:!0,initialValue:e.description||"",ariaLabel:"Edit ticket description",sourceEvent:u,rerender:()=>ye(),commit:p=>ge(t,{description:V(p)})});r&&(r.addEventListener("click",u=>{u.preventDefault(),o(u)}),r.addEventListener("keydown",u=>{(u.key==="Enter"||u.key===" ")&&(u.preventDefault(),o())}));let s=[{key:"ai_plan",label:"AI plan"},{key:"implementation_summary",label:"Implementation summary"},{key:"implementation_updates",label:"Implementation updates / lessons"}];for(let{key:u,label:p}of s){let m=S.querySelector(`[data-edit-field="${u}"]`);if(!m)continue;let f=b=>Ie(m,{fieldName:u,multiline:!0,initialValue:e[u]||"",ariaLabel:`Edit ${p}`,sourceEvent:b,rerender:()=>ye(),commit:k=>ge(t,{[u]:V(k)})});m.addEventListener("click",b=>{b.preventDefault(),f(b)}),m.addEventListener("keydown",b=>{(b.key==="Enter"||b.key===" ")&&(b.preventDefault(),f())})}K.querySelectorAll(".meta-select[data-meta-field]").forEach(u=>{u.addEventListener("change",async()=>{let p=u.dataset.metaField;if(p==="type"){await ge(t,{type:u.value});return}if(p==="state_id"){await ge(t,{state_id:u.value});return}if(p==="parent_ticket_id"){await ge(t,{parent_ticket_id:u.value||null});return}p==="priority"&&await ge(t,{priority:Number(u.value)})})});let i=async u=>{await ge(t,{labels:u})};S.querySelectorAll("[data-remove-label]").forEach(u=>{u.addEventListener("click",async()=>{let p=u.getAttribute("data-remove-label"),m=(e.labels||[]).map(f=>f.name).filter(f=>f!==p);await i(m)})});let l=async()=>{let u=S.querySelector("[data-label-input]");if(!u)return;let p=u.value.trim();if(!p)return;let m=(e.labels||[]).map(f=>f.name);if(m.includes(p)){u.value="";return}m.push(p),u.value="",await i(m)};S.querySelector("[data-label-add]")?.addEventListener("click",()=>{l()}),S.querySelector("[data-label-input]")?.addEventListener("keydown",u=>{u.key==="Enter"&&(u.preventDefault(),l())})}async function ye(e={}){if(c.detailMode==="settings"){await be(),ma();return}if(!c.selectedTicketId){kt();return}let t=c.selectedTicketId,a=y=>Object.prototype.hasOwnProperty.call(e,y),[n,r,o,s]=await Promise.all([a("context")?Promise.resolve(e.context):w(T(`/api/tickets/${t}/context?depth=1`)),a("statusHistory")?Promise.resolve(e.statusHistory):w(T(`/api/tickets/${t}/history`)),a("comments")?Promise.resolve(e.comments):w(T(`/api/tickets/${t}/comments`)).then(y=>y.comments||[]),a("attachmentList")?Promise.resolve(e.attachmentList):j.attachments?w(T(`/api/tickets/${t}/attachments`)).catch(()=>({attachments:[]})):Promise.resolve({attachments:[]})]);if(c.detailMode!=="ticket"||c.selectedTicketId!==t||n.ticket?.id!==t)return;let i=n.ticket;Ct(i.id,i.updated_at),document.querySelector(`.card[data-ticket-id="${CSS.escape(i.id)}"] .card-unread-dot`)?.remove();let l=ia(i.state_id),u=["epic","feature","task","bug"].map(y=>`<option value="${d(y)}" ${O(i.type)===y?"selected":""}>${d(Qa(y))}</option>`).join(""),p=l.map(y=>`<option value="${d(y.id)}" ${y.id===i.state_id?"selected":""}>${d(y.name)}</option>`).join(""),m=[0,1,2,3,4].map(y=>`<option value="${y}" ${Number(i.priority)===y?"selected":""}>${d(Ne(y))}</option>`).join(""),f=(i.labels||[]).map(y=>`
|
|
461
|
-
<span class="label-pill-removable" style="--label-color: ${d(y.color)}">
|
|
462
|
-
${d(y.name)}
|
|
463
|
-
<button type="button" class="label-pill-remove" data-remove-label="${d(y.name)}" title="Remove label">\xD7</button>
|
|
464
|
-
</span>`).join(""),k=ra().map(y=>y.name).filter(y=>!i.labels?.some(B=>B.name===y)).map(y=>`<option value="${d(y)}"></option>`).join(""),x=O(i.type),A=Oe(i.priority),M=l.find(y=>y.id===i.state_id),h=Qe(M),E=i.description?ce(i.description):d("No description yet."),L=i.description?"description preserved-text-body editable-field":"description editable-field is-placeholder",I=`
|
|
465
|
-
<span class="ticket-number">${d(ae(i))}</span>
|
|
466
|
-
<div class="detail-meta-badge-row" aria-label="Ticket metadata controls">
|
|
467
|
-
<select class="detail-meta-badge detail-state-badge meta-select" data-variant="${d(h)}" data-meta-field="state_id" aria-label="Ticket state">${p}</select>
|
|
468
|
-
<select class="detail-meta-badge detail-type-badge type-pill-${d(x)} meta-select" data-meta-field="type" aria-label="Ticket type">${u}</select>
|
|
469
|
-
<select class="detail-meta-badge detail-priority-badge priority-pill meta-select" data-variant="${d(A)}" data-meta-field="priority" aria-label="Ticket priority">${m}</select>
|
|
470
|
-
</div>
|
|
471
|
-
`;$t({mode:"ticket",title:i.title,titleAttrs:{class:"editable-field","data-edit-field":"title",role:"button",tabindex:"0",title:"Click or press Enter to edit ticket title","aria-label":"Edit ticket title"},subtitleHtml:I,body:`
|
|
472
|
-
<div class="detail-head">
|
|
473
|
-
<p class="detail-updated" title="Last saved change">Updated ${d(Va(i.updated_at))}</p>
|
|
474
|
-
<div class="${L}" data-edit-field="description" tabindex="0" title="Click to edit">${E}</div>
|
|
475
|
-
<dl class="ticket-meta" id="ticketMetaGrid" data-ticket-id="${d(i.id)}">
|
|
476
|
-
<div class="ticket-meta-row ticket-meta-row--stack">
|
|
477
|
-
<dt>Labels</dt>
|
|
478
|
-
<dd>
|
|
479
|
-
<div class="label-pills-row" data-other-labels>${f}</div>
|
|
480
|
-
<div class="label-add-row">
|
|
481
|
-
<input type="text" class="label-add-input meta-inline-input" data-label-input list="board-label-suggestions" placeholder="Add label\u2026" aria-label="Add label" />
|
|
482
|
-
<datalist id="board-label-suggestions">${k}</datalist>
|
|
483
|
-
<button type="button" class="ghost meta-add-btn" data-label-add>Add</button>
|
|
484
|
-
</div>
|
|
485
|
-
</dd>
|
|
486
|
-
</div>
|
|
487
|
-
</dl>
|
|
488
|
-
</div>
|
|
489
|
-
|
|
490
|
-
${To(i,n)}
|
|
491
|
-
|
|
492
|
-
${j.attachments?vo(i,s.attachments||[]):""}
|
|
493
|
-
|
|
494
|
-
${Io(i,n)}
|
|
495
|
-
|
|
496
|
-
<div class="section">
|
|
497
|
-
<h3>Related</h3>
|
|
498
|
-
${So(n.relations,i)}
|
|
499
|
-
</div>
|
|
500
|
-
|
|
501
|
-
${U()?.ai_enabled!==0?`
|
|
502
|
-
<details class="section ai-fields" data-ai-plan-toggle data-ticket-id="${d(i.id)}"${yo(i.id)?" open":""}>
|
|
503
|
-
<summary><h3>AI Plan / Implementation Record</h3></summary>
|
|
504
|
-
<div class="ai-fields-grid">
|
|
505
|
-
${Nt({fieldName:"ai_plan",label:"AI-Written Plan",value:i.ai_plan,placeholder:"Paste or let an AI write the plan..."})}
|
|
506
|
-
${Nt({fieldName:"implementation_summary",label:"Implementation Summary",value:i.implementation_summary,placeholder:"What changed, what shipped, what remains..."})}
|
|
507
|
-
${Nt({fieldName:"implementation_updates",label:"Implementation Updates / Lessons",value:i.implementation_updates,placeholder:"Progress notes, mistakes to avoid, discoveries..."})}
|
|
508
|
-
</div>
|
|
509
|
-
</details>`:""}
|
|
510
|
-
|
|
511
|
-
<div class="section">
|
|
512
|
-
<h3>Status History</h3>
|
|
513
|
-
${Lo(r)}
|
|
514
|
-
</div>
|
|
515
|
-
|
|
516
|
-
<div class="section">
|
|
517
|
-
<h3>Comments</h3>
|
|
518
|
-
${o.map(Eo).join("")||'<p class="description">No comments yet.</p>'}
|
|
519
|
-
<form class="comment-form" id="detailCommentForm">
|
|
520
|
-
<textarea name="body" placeholder="Add a comment, decision, or instruction..." required></textarea>
|
|
521
|
-
<button type="submit">Comment</button>
|
|
522
|
-
</form>
|
|
523
|
-
</div>
|
|
524
|
-
`}),go(i),j.attachments&&$o(i),v("#detailCommentForm").addEventListener("submit",async y=>{y.preventDefault();let B=V(new FormData(y.currentTarget).get("body")).trim();B&&(await w(T(`/api/tickets/${i.id}/comments`),{method:"POST",body:{body:B}}),await le(i.id))}),S.querySelectorAll("[data-open-ticket]").forEach(y=>{y.addEventListener("click",async B=>{B.target.closest("[data-detach-child],[data-detach-parent],[data-detach-relation]")||F({boardId:c.boardId,view:"ticket",ticketId:y.dataset.openTicket})})}),S.querySelectorAll("[data-detach-child]").forEach(y=>{y.addEventListener("click",async B=>{B.stopPropagation();let D=y.dataset.detachChild;try{await w(T(`/api/tickets/${D}`),{method:"PATCH",body:{parent_ticket_id:null}})}catch(G){g.error(G.message||"Failed to remove child");return}await le(i.id,{renderBoardAfter:!0}),g.success("Removed from epic")})}),S.querySelectorAll("[data-detach-parent]").forEach(y=>{y.addEventListener("click",async B=>{B.stopPropagation();try{await w(T(`/api/tickets/${i.id}`),{method:"PATCH",body:{parent_ticket_id:null}})}catch(D){g.error(D.message||"Failed to remove parent");return}await le(i.id,{renderBoardAfter:!0}),g.success("Parent epic removed")})}),S.querySelectorAll("[data-detach-relation]").forEach(y=>{y.addEventListener("click",async B=>{B.stopPropagation();let D=y.dataset.detachRelation;try{await w(T(`/api/relations/${D}`),{method:"DELETE"})}catch(G){g.error(G.message||"Failed to remove relation");return}await le(i.id),g.success("Relation removed")})});let R=S.querySelector("[data-ai-plan-toggle]");R&&R.addEventListener("toggle",()=>{let y=R.dataset.ticketId;R.open?localStorage.setItem(`mab_ai_plan_open:${y}`,"1"):localStorage.removeItem(`mab_ai_plan_open:${y}`)});let q=S.querySelector("#parentEpicForm");if(q){let y=q.querySelector("[name=target]"),B=q.querySelector("[data-parent-epic-clear]"),D=()=>{q.classList.toggle("has-value",y.value.length>0)};y.addEventListener("input",D),D(),B.addEventListener("click",()=>{y.value="",D(),y.focus()}),q.addEventListener("submit",async G=>{G.preventDefault();let ee=String(new FormData(G.currentTarget).get("target")||"").trim();if(!ee)return;let Y=Fn(ee,i.id);if(!Y){g.warning("Pick an epic from the suggestions");return}let oe=X().find(W=>W.id===Y);if(!oe||O(oe.type)!=="epic"){g.warning("Parent must be an epic");return}try{await w(T(`/api/tickets/${i.id}`),{method:"PATCH",body:{parent_ticket_id:Y}})}catch(W){g.error(W.message||"Failed to set parent epic");return}await le(i.id,{renderBoardAfter:!0}),g.success("Parent epic set")})}let _=S.querySelector("#relatedAddForm");if(_){let y=_.querySelector("[name=target]"),B=_.querySelector("[data-related-clear]"),D=()=>{_.classList.toggle("has-value",y.value.length>0)};y.addEventListener("input",D),D(),B.addEventListener("click",()=>{y.value="",D(),y.focus()}),_.addEventListener("submit",async G=>{G.preventDefault();let ee=new FormData(G.currentTarget),Y=String(ee.get("target")||"").trim(),oe=String(ee.get("type")||"relates_to");if(!Y)return;let W=Fn(Y,i.id);if(!W){g.warning("Pick a ticket from the suggestions");return}try{await w(T("/api/relations"),{method:"POST",body:{source_ticket_id:i.id,target_ticket_id:W,type:oe}})}catch(Ce){g.error(Ce.message||"Failed to add relation");return}await le(i.id)})}ma()}function yo(e){return localStorage.getItem(`mab_ai_plan_open:${e}`)==="1"}function vo(e,t=[]){let a=t.length?`<div class="attachment-grid">${t.map(n=>wo(e,n)).join("")}</div>`:'<p class="description">No images attached yet.</p>';return`
|
|
525
|
-
<div class="section attachments-section" data-attachment-section data-ticket-id="${d(e.id)}">
|
|
526
|
-
<div class="attachment-heading-row">
|
|
527
|
-
<h3>Images</h3>
|
|
528
|
-
<label class="ghost attachment-upload-button">
|
|
529
|
-
Upload
|
|
530
|
-
<input type="file" accept="image/*" multiple data-attachment-input />
|
|
531
|
-
</label>
|
|
532
|
-
</div>
|
|
533
|
-
<div class="attachment-dropzone" data-attachment-dropzone tabindex="0">
|
|
534
|
-
<strong>Paste, drag, or upload images</strong>
|
|
535
|
-
<span>PNG, JPG, GIF, WebP, SVG, BMP, or AVIF up to 10 MB each.</span>
|
|
536
|
-
</div>
|
|
537
|
-
${a}
|
|
538
|
-
</div>
|
|
539
|
-
`}function wo(e,t){let a=d(t.original_name||"image"),n=`${ko(t.size_bytes)} \xB7 ${d(t.mime_type||"image")}`;if(t.missing)return`
|
|
540
|
-
<article class="attachment-card is-missing">
|
|
541
|
-
<div class="attachment-missing-thumb">Missing</div>
|
|
542
|
-
<div class="attachment-card-meta"><strong>${a}</strong><span>${n}</span></div>
|
|
543
|
-
<button type="button" class="attachment-delete" data-delete-attachment="${d(t.id)}" aria-label="Remove missing image">\xD7</button>
|
|
544
|
-
</article>
|
|
545
|
-
`;let r=T(t.content_url||`/api/tickets/${e.id}/attachments/${t.id}/content`);return`
|
|
546
|
-
<article class="attachment-card">
|
|
547
|
-
<button type="button" class="attachment-thumb-button" data-open-lightbox="${d(r)}" data-lightbox-title="${a}">
|
|
548
|
-
<img src="${d(r)}" alt="${a}" loading="lazy" />
|
|
549
|
-
</button>
|
|
550
|
-
<div class="attachment-card-meta"><strong>${a}</strong><span>${n}</span></div>
|
|
551
|
-
<button type="button" class="attachment-delete" data-delete-attachment="${d(t.id)}" aria-label="Remove image">\xD7</button>
|
|
552
|
-
</article>
|
|
553
|
-
`}function ko(e){let t=Number(e||0);return t<1024?`${t} B`:t<1024*1024?`${(t/1024).toFixed(1)} KB`:`${(t/(1024*1024)).toFixed(1)} MB`}function Rn(e){return[...e||[]].filter(t=>t&&String(t.type||"").startsWith("image/"))}async function Ca(e,t){let a=Rn(t);if(!a.length){g.warning("No image files found");return}for(let n of a){let r=await fetch(T(`/api/tickets/${e.id}/attachments?filename=${encodeURIComponent(n.name||"image")}`),{method:"POST",headers:{"Content-Type":n.type||"application/octet-stream","X-File-Name":n.name||"image"},body:n});if(!r.ok){let o={};try{o=await r.json()}catch{}throw new Error(o.error||`Upload failed (${r.status})`)}}await le(e.id),g.success(a.length===1?"Image attached":`${a.length} images attached`)}function $o(e){let t=S.querySelector("[data-attachment-section]");if(!t)return;let a=t.querySelector("[data-attachment-input]");a?.addEventListener("change",async()=>{try{await Ca(e,a.files),a.value=""}catch(r){g.error(r.message||"Upload failed")}});let n=t.querySelector("[data-attachment-dropzone]");n?.addEventListener("dragover",r=>{r.preventDefault(),n.classList.add("is-dragover")}),n?.addEventListener("dragleave",()=>n.classList.remove("is-dragover")),n?.addEventListener("drop",async r=>{r.preventDefault(),n.classList.remove("is-dragover");try{await Ca(e,r.dataTransfer?.files||[])}catch(o){g.error(o.message||"Upload failed")}}),S.onpaste=async r=>{if(r.target.closest("input, textarea, [contenteditable='true']"))return;let o=Rn(r.clipboardData?.files||[]);if(o.length){r.preventDefault();try{await Ca(e,o)}catch(s){g.error(s.message||"Paste upload failed")}}},t.querySelectorAll("[data-delete-attachment]").forEach(r=>{r.addEventListener("click",async()=>{try{await w(T(`/api/tickets/${e.id}/attachments/${r.dataset.deleteAttachment}`),{method:"DELETE"}),await le(e.id),g.success("Image removed")}catch(o){g.error(o.message||"Delete failed")}})}),t.querySelectorAll("[data-open-lightbox]").forEach(r=>{r.addEventListener("click",()=>xo(r.dataset.openLightbox,r.dataset.lightboxTitle||"Image"))})}function xo(e,t){document.querySelector(".attachment-lightbox")?.remove();let n=document.createElement("div");n.className="attachment-lightbox",n.innerHTML=`
|
|
554
|
-
<div class="attachment-lightbox-panel" role="dialog" aria-modal="true" aria-label="${d(t)}">
|
|
555
|
-
<button type="button" class="attachment-lightbox-close" aria-label="Close image">\xD7</button>
|
|
556
|
-
<img src="${d(e)}" alt="${d(t)}" />
|
|
557
|
-
<p>${d(t)}</p>
|
|
558
|
-
</div>
|
|
559
|
-
`;let r=()=>{document.removeEventListener("keydown",o),n.remove()};function o(s){s.key==="Escape"&&r()}n.addEventListener("click",s=>{(s.target===n||s.target.closest(".attachment-lightbox-close"))&&r()}),document.addEventListener("keydown",o),document.body.append(n)}function Fn(e,t){let a=e.trim(),n=a.match(/^#?(\d+)\b/),r=X().filter(s=>s.id!==t);if(n){let s=Number(n[1]),i=r.find(l=>l.number===s);if(i)return i.id}let o=r.find(s=>`#${s.number} \u2014 ${s.title}`===a);return o?o.id:""}function Lo(e){return!e||e.length===0?'<p class="description">No status changes yet.</p>':e.map(t=>{let a=t.body,n=a.from?d(a.from):"?",r=d(a.to||a.state||a.next_state||"?"),o=d(_a({actor:t.actor,actorType:a.actor_type||"human",actorId:a.actor_id}));return`<div class="comment status-change">
|
|
560
|
-
<div class="comment-meta">
|
|
561
|
-
<span class="status-route">${n} \u2192 ${r}</span>
|
|
562
|
-
<span>${o} \xB7 ${Ve(t.created_at)}</span>
|
|
563
|
-
</div>
|
|
564
|
-
</div>`}).join("")}function Eo(e){return`
|
|
565
|
-
<div class="comment ${e.kind==="checkpoint"?"checkpoint":""}">
|
|
566
|
-
<div class="comment-meta">
|
|
567
|
-
<strong>${d(An(e))}</strong>
|
|
568
|
-
<span>${e.kind==="human_comment"?"":`${d(e.kind)} - `}${Ve(e.created_at)}</span>
|
|
569
|
-
</div>
|
|
570
|
-
<div class="comment-body preserved-text-body">${ce(e.body)}</div>
|
|
571
|
-
</div>
|
|
572
|
-
`}function Nt({fieldName:e,label:t,value:a,placeholder:n}){let r=a||"",o=!!r.trim(),s=o?ce(r):d(n||""),i=o?"":"is-placeholder";return`
|
|
573
|
-
<div class="inline-md-field">
|
|
574
|
-
<span class="inline-md-field-label">${d(t)}</span>
|
|
575
|
-
<div
|
|
576
|
-
class="inline-md-field-body preserved-text-body editable-field ${i}"
|
|
577
|
-
data-edit-field="${d(e)}"
|
|
578
|
-
tabindex="0"
|
|
579
|
-
title="Click to edit"
|
|
580
|
-
role="button"
|
|
581
|
-
aria-label="Edit ${d(t)}"
|
|
582
|
-
>${s}</div>
|
|
583
|
-
</div>
|
|
584
|
-
`}function So(e=[],t){let a=new Set(e.map(l=>l.other_ticket.id)),n=new Set;if(t?.parent_ticket_id&&n.add(t.parent_ticket_id),t?.id)for(let l of X())l.parent_ticket_id===t.id&&n.add(l.id);let o=X().filter(l=>l.id!==t?.id&&!a.has(l.id)&&!n.has(l.id)).map(l=>`<option value="#${l.number} \u2014 ${d(l.title)}"></option>`).join(""),s=e.length?`<div class="detail-card-grid">${e.map(l=>_o(l)).join("")}</div>`:"",i=`
|
|
585
|
-
<form id="relatedAddForm" class="related-add-row">
|
|
586
|
-
<div class="related-add-input-wrap">
|
|
587
|
-
<input type="text" name="target" class="related-add-input meta-inline-input" list="related-ticket-suggestions" placeholder="Add related ticket\u2026" aria-label="Add related ticket" autocomplete="off" />
|
|
588
|
-
<button type="button" class="related-add-clear" data-related-clear aria-label="Clear" tabindex="-1">\xD7</button>
|
|
589
|
-
<datalist id="related-ticket-suggestions">${o}</datalist>
|
|
590
|
-
</div>
|
|
591
|
-
<select name="type" class="related-add-type meta-inline" aria-label="Relation type">
|
|
592
|
-
<option value="relates_to">relates to</option>
|
|
593
|
-
<option value="blocks">blocks</option>
|
|
594
|
-
<option value="blocked_by">blocked by</option>
|
|
595
|
-
</select>
|
|
596
|
-
<button type="submit" class="ghost meta-add-btn">Add</button>
|
|
597
|
-
</form>
|
|
598
|
-
`;return s+i}function To(e,t){if(O(e.type)==="epic"){let n=t.child_tickets||[];return`
|
|
599
|
-
<div class="section">
|
|
600
|
-
<h3>Features inside this Epic</h3>
|
|
601
|
-
${n.length?`<div class="detail-card-grid">${n.map(o=>Ue(o,{detach:{mode:"child",id:o.id}})).join("")}</div>`:'<p class="description">No child features yet. Create a feature / task card and set this epic as its parent.</p>'}
|
|
602
|
-
</div>
|
|
603
|
-
`}return""}function Io(e,t){if(O(e.type)==="epic")return"";let n=X().filter(o=>o.type==="epic"&&o.id!==e.id).map(o=>`<option value="#${o.number} \u2014 ${d(o.title)}"></option>`).join("");return`
|
|
604
|
-
<div class="section">
|
|
605
|
-
<h3>Epic</h3>
|
|
606
|
-
${t.parent_ticket?`<div class="detail-card-grid detail-card-grid--single">${Ue(t.parent_ticket,{detach:{mode:"parent"}})}</div>`:`
|
|
607
|
-
<form id="parentEpicForm" class="related-add-row">
|
|
608
|
-
<div class="related-add-input-wrap">
|
|
609
|
-
<input type="text" name="target" class="related-add-input meta-inline-input" list="parent-epic-suggestions" placeholder="Set parent epic\u2026" aria-label="Set parent epic" autocomplete="off" />
|
|
610
|
-
<button type="button" class="related-add-clear" data-parent-epic-clear aria-label="Clear" tabindex="-1">\xD7</button>
|
|
611
|
-
<datalist id="parent-epic-suggestions">${n}</datalist>
|
|
612
|
-
</div>
|
|
613
|
-
<button type="submit" class="ghost meta-add-btn">Set</button>
|
|
614
|
-
</form>
|
|
615
|
-
`}
|
|
616
|
-
</div>
|
|
617
|
-
`}function Ue(e,t={}){let a=O(e.type),n=Oe(e.priority),r=Qe(e),o=De(e.type).toUpperCase(),s=t.eyebrow?`<span class="card-eyebrow">${d(t.eyebrow)}</span>`:"",i="";if(t.detach){let{mode:p,id:m}=t.detach,f="",b="";p==="child"?(f=`data-detach-child="${d(m)}"`,b="Remove from epic"):p==="parent"?(f='data-detach-parent="1"',b="Remove parent epic"):p==="relation"&&(f=`data-detach-relation="${d(m)}"`,b="Remove relation"),i=`<button type="button" class="card-detach-btn" ${f} aria-label="${b}" title="${b}">\xD7</button>`}else if(t.archive){let p=d(t.archive.id);i=`
|
|
618
|
-
<div class="card-archive-actions">
|
|
619
|
-
<button type="button" class="card-archive-btn card-archive-btn--restore" data-archive-restore="${p}" aria-label="Restore to board" title="Restore to board"><svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M3 12a9 9 0 1 0 3-6.7"/><path d="M3 4v5h5"/></svg></button>
|
|
620
|
-
<button type="button" class="card-archive-btn card-archive-btn--delete" data-archive-delete="${p}" aria-label="Delete permanently" title="Delete permanently"><svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M3 6h18"/><path d="M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"/><path d="M19 6l-1 14a2 2 0 0 1-2 2H8a2 2 0 0 1-2-2L5 6"/><path d="M10 11v6"/><path d="M14 11v6"/></svg></button>
|
|
621
|
-
</div>
|
|
622
|
-
`}let l=_t(e),u=l===0?"":l===1?'<span class="card-unread-dot" role="status" aria-label="1 unread update"></span>':`<span class="card-unread-dot has-count" role="status" aria-label="${l} unread updates">${l>99?"99+":l}</span>`;return`
|
|
623
|
-
<article class="card card--detail type-${d(a)} priority-${d(n)}" data-variant="${d(a)}"${t.disableOpen?"":` data-open-ticket="${d(e.id)}"`}>
|
|
624
|
-
${u}
|
|
625
|
-
${i}
|
|
626
|
-
${s}
|
|
627
|
-
<h3>${d(e.title)}</h3>
|
|
628
|
-
<div class="card-meta">
|
|
629
|
-
<div class="card-expand-trigger card-expand-trigger--static">
|
|
630
|
-
<span class="ticket-number">${d(ae(e))}</span>
|
|
631
|
-
<div class="card-type-id type-pill-${d(a)}">
|
|
632
|
-
${Pt(e.type)}
|
|
633
|
-
<span class="card-type-label">${d(o)}</span>
|
|
634
|
-
</div>
|
|
635
|
-
<span class="detail-card-state" data-variant="${d(r)}">${d(e.state_name||"State")}</span>
|
|
636
|
-
${c.showPriority?La(e.priority):""}
|
|
637
|
-
</div>
|
|
638
|
-
</div>
|
|
639
|
-
</article>
|
|
640
|
-
`}function _o(e){let t=String(e.type||"").replace(/_/g," "),a=e.direction==="incoming"?"from":"to";return Ue(e.other_ticket,{eyebrow:`${t} ${a}`,detach:{mode:"relation",id:e.id}})}var Dt=P(()=>{z();ie();ne();it();xt();he();Q();qe();me();Cn();rt();Bn()});function Ma(){ze&&(clearTimeout(ze),ze=null),c.eventSource&&(c.eventSource.close(),c.eventSource=null);let e=new URLSearchParams;c.boardId&&e.set("board_id",c.boardId);let t=`/api/events/stream${e.toString()?`?${e}`:""}`,a=new EventSource(t);c.eventSource=a,a.addEventListener("open",()=>{Ot=1e3,jt&&(g.success("Live updates reconnected"),jt=!1)}),a.addEventListener("board",async n=>{let r;try{r=JSON.parse(n.data)}catch{return}let o=r.type,s=()=>c.data?.tickets?.find(u=>u.id===r.ticket_id),i=c.data?.actor?.name,l=r.actor&&i&&r.actor===i;if(r.ticket_id&&(l?Ct(r.ticket_id,r.timestamp):o==="ticket_deleted"?gn(r.ticket_id):Co.has(o)&&bn(r.ticket_id)),o==="ticket_created")g.success(`Card created: ${r.data.title||"New card"}`),ve();else if(o==="state_changed"){let u=s(),p=u?`#${u.number} ${u.title}`:"Card";g.info(`${p} \u2192 ${r.data.to}`),ve()}else if(o==="ticket_updated"){let u=s(),p=u?`#${u.number}`:"Card",m=r.data.fields?Object.keys(r.data.fields).join(", "):"";g.info(`${p} updated${m?`: ${m}`:""}`),ve()}else if(o==="comment_created"){let u=s(),p=u?`#${u.number}`:"ticket";g.info(`New comment on ${p}`),ve()}else if(o==="agent_claimed"){let u=s();g.info(`Agent claimed ${u?`#${u.number} ${u.title}`:"a ticket"}`),ve()}else if(o==="checkpoint_requested"){let u=s();g.warning(`Checkpoint on ${u?`#${u.number}`:"ticket"} \u2014 needs human input`),ve()}else if(o==="agent_completed"){let u=s();g.success(`Agent completed ${u?`#${u.number} ${u.title}`:"a ticket"}`),ve()}else(o==="ticket_deleted"||o==="states_reordered"||o==="state_created"||o==="state_deleted"||o==="board_updated"||o==="board_imported")&&ve()}),a.onerror=()=>{if(a.readyState!==EventSource.CLOSED||(jt||(g.warning("Live updates disconnected \u2014 retrying\u2026"),jt=!0),ze))return;let n=Ot;Ot=Math.min(Ot*2,3e4),ze=setTimeout(()=>{ze=null,Ma()},n)}}var Co,Ot,ze,jt,ve,Nn=P(()=>{z();Q();me();fe();rt();Co=new Set(["ticket_created","state_changed","ticket_updated","comment_created","agent_claimed","checkpoint_requested","agent_completed"]),Ot=1e3,ze=null,jt=!1;ve=wt(async()=>{let e=c.selectedTicketId,t=c.detailMode;c.data=await w(Ze()),xe(),c.selectedTicketId=e,c.detailMode=t,await Ht()},300)});function Po(e){return V(e||"").split(`
|
|
641
|
-
`).map(t=>t.trim()).filter(Boolean).join(" ").replace(/\s+/g," ").trim()}function Ao(e={}){return Po(e.project_notes)||Pa}function Bo(e,t){if(!e?.id||!t?.data?.boards)return;let a=t.data.boards.findIndex(n=>n.id===e.id);a>=0&&t.data.boards.splice(a,1,{...t.data.boards[a],...e})}function Fo(e){let t=e?.project_notes||"",a=!!t.trim(),n=a?"":" is-placeholder",r=a?ce(t):d(Mo);return`
|
|
642
|
-
<div
|
|
643
|
-
class="inline-md-field-body preserved-text-body editable-field brand-focus-notes-edit${n}"
|
|
644
|
-
data-edit-field="project_notes"
|
|
645
|
-
tabindex="0"
|
|
646
|
-
title="Click to edit"
|
|
647
|
-
role="button"
|
|
648
|
-
aria-label="Edit board notes"
|
|
649
|
-
>${r}</div>
|
|
650
|
-
`}function Ge(e=Z){Z=e||{};let t=Ao(Z),a=document.getElementById("brandNotesBtn"),n=document.getElementById("brandNotesText"),r=document.getElementById("brandFocusNotes");a&&(a.hidden=!1,a.dataset.empty=t===Pa?"true":"false",a.setAttribute("aria-label",`Show board notes: ${t}`)),n&&(n.textContent=t===Pa?"":t),r&&(r.innerHTML=Fo(Z))}function st(e){let t=[document.getElementById("brandFocusBtn"),document.getElementById("brandNotesBtn")].filter(Boolean),a=document.getElementById("brandFocusPopover");if(a){for(let n of t)n.setAttribute("aria-expanded",e?"true":"false"),n.dataset.state=e?"open":"closed";a.hidden=!e}}function On(){let e=document.getElementById("brandFocusPopover");Ge(),st(!!e?.hidden)}async function jn(e){let t=document.querySelector('#brandFocusPopover [data-edit-field="project_notes"]');if(!t||!Z?.id)return;let{startInlineEdit:a}=await Promise.resolve().then(()=>(Dt(),Dn));a(t,{fieldName:"project_notes",multiline:!0,initialValue:Z.project_notes||"",ariaLabel:"Edit board notes",sourceEvent:e,rerender:async()=>{Ge(Z),st(!0)},commit:async n=>{let[{api:r},{state:o}]=await Promise.all([Promise.resolve().then(()=>(Q(),rn)),Promise.resolve().then(()=>(z(),Wa))]),s=await r(`/api/boards/${encodeURIComponent(Z.id||o.boardId)}`,{method:"PATCH",body:{project_notes:V(n)}});Z={...Z,...s},Bo(Z,o),Ge(Z),st(!0)}})}function Hn(){let e=document.getElementById("brandFocusBtn"),t=document.getElementById("brandNotesBtn"),a=document.getElementById("brandFocusPopover");!e||!t||!a||(e.addEventListener("click",n=>{n.stopPropagation(),On()}),t.addEventListener("click",n=>{n.stopPropagation(),On()}),a.addEventListener("click",n=>{n.stopPropagation(),n.target.closest('[data-edit-field="project_notes"]')&&jn(n)}),a.addEventListener("keydown",n=>{n.key!=="Enter"&&n.key!==" "||n.target.closest('[data-edit-field="project_notes"]')&&(n.preventDefault(),jn(n))}),document.addEventListener("click",n=>{n.target.closest("#brandFocusBtn")||n.target.closest("#brandNotesBtn")||n.target.closest("#brandFocusPopover")||st(!1)}),document.addEventListener("keydown",n=>{n.key==="Escape"&&st(!1)}))}var Pa,Mo,Z,Aa=P(()=>{ne();Pa="No board notes yet",Mo="Add board notes for yourself and your agents\u2026";Z={}});var Un={};pt(Un,{load:()=>C,render:()=>Ht,renderDetailOnly:()=>Ro});async function C(){se(),c.data=await w(Ze()),xe(),yn(c.boardId,c.data?.tickets||[]),await Ht(),j.sse&&c.boardId!==qn&&(qn=c.boardId,Ma())}async function Ht(){xe(),Ba(),Ge(U()),je(),await ye()}async function Ro(){xe(),Ba(),Ge(U()),wn(),await ye()}var qn,fe=P(()=>{z();Q();it();Dt();ct();Nn();rt();qe();Aa();qn=null});function Ra(){return Me?.classList.contains("is-open")}function At(e){clearTimeout(Fa),se(),kt(),Xt.innerHTML=Do(e||""),No(),v("#createFlyoutClose")?.addEventListener("click",()=>N()),Me.hidden=!1,ke.hidden=!1,requestAnimationFrame(()=>{Me.classList.add("is-open"),ke.classList.add("is-visible")}),requestAnimationFrame(()=>{v("#createTicketTitle")?.focus()})}function N(){clearTimeout(Fa),Me.classList.remove("is-open"),ke.classList.remove("is-visible"),Fa=setTimeout(()=>{Me.hidden=!0,ke.hidden=!0,Xt.innerHTML=""},220)}function Do(e){let t=Le(),a=t.find(s=>s.is_default)||t[0],n=e&&t.some(s=>s.id===e)?e:a?.id||"",r=t.map(s=>`<option value="${d(s.id)}" ${s.id===n?"selected":""}>${d(s.name)}</option>`).join(""),o=X().filter(s=>s.type==="epic").map(s=>`<option value="${d(s.id)}">${d(ae(s))}</option>`).join("");return`
|
|
651
|
-
<div class="create-flyout-head">
|
|
652
|
-
<h2>New card</h2>
|
|
653
|
-
<button type="button" class="create-flyout-close ghost" id="createFlyoutClose" aria-label="Close">\xD7</button>
|
|
654
|
-
</div>
|
|
655
|
-
<form id="createTicketForm" class="create-flyout-form">
|
|
656
|
-
<input id="createTicketTitle" name="title" type="text" placeholder="Title \u2014 what is this card?" autocomplete="off" required />
|
|
657
|
-
<textarea id="createTicketDescription" name="description" placeholder="Description (optional)"></textarea>
|
|
658
|
-
<div class="create-flyout-grid">
|
|
659
|
-
<label>
|
|
660
|
-
Lane
|
|
661
|
-
<select id="createTicketState" name="state" class="select-chevron-field" aria-label="Lane">${r}</select>
|
|
662
|
-
</label>
|
|
663
|
-
<label>
|
|
664
|
-
Type
|
|
665
|
-
<select id="createTicketType" name="type" class="select-chevron-field" aria-label="Ticket type">
|
|
666
|
-
<option value="epic">Epic</option>
|
|
667
|
-
<option value="feature">Feature</option>
|
|
668
|
-
<option value="task" selected>Task</option>
|
|
669
|
-
<option value="bug">Bug</option>
|
|
670
|
-
</select>
|
|
671
|
-
</label>
|
|
672
|
-
<label>
|
|
673
|
-
Priority
|
|
674
|
-
<select id="createTicketPriority" name="priority" class="select-chevron-field" aria-label="Priority">
|
|
675
|
-
<option value="0">MAYBE</option>
|
|
676
|
-
<option value="1">LOW</option>
|
|
677
|
-
<option value="2" selected>MED</option>
|
|
678
|
-
<option value="3">HIGH</option>
|
|
679
|
-
<option value="4">URGENT</option>
|
|
680
|
-
</select>
|
|
681
|
-
</label>
|
|
682
|
-
</div>
|
|
683
|
-
<label>
|
|
684
|
-
Parent epic
|
|
685
|
-
<select id="createTicketParent" name="parent_ticket_id" class="select-chevron-field" aria-label="Parent epic">
|
|
686
|
-
<option value="">None</option>
|
|
687
|
-
${o}
|
|
688
|
-
</select>
|
|
689
|
-
</label>
|
|
690
|
-
<input id="createTicketLabels" name="labels" type="text" placeholder="Labels (comma-separated)" />
|
|
691
|
-
<button type="submit">Create card</button>
|
|
692
|
-
</form>
|
|
693
|
-
`}function No(){let e=v("#createTicketForm");e&&e.addEventListener("submit",Oo)}async function Oo(e){e.preventDefault();let t=e.currentTarget,a=new FormData(t),n=String(a.get("labels")||"").split(",").map(o=>o.trim()).filter(Boolean),r=await w("/api/tickets",{method:"POST",body:{board_id:c.boardId,title:a.get("title"),description:a.get("description"),type:a.get("type"),parent_ticket_id:a.get("parent_ticket_id")||null,state_id:a.get("state"),priority:Number(a.get("priority")),labels:n}});N(),c.selectedTicketId=r.id,c.detailMode="ticket",await C(),Ke()}var Fa,He=P(()=>{ie();z();ne();Q();he();xt();ct();fe();Fa=0});function dt(){te&&(te.hidden=!0,te.innerHTML="",ue?.setAttribute("aria-expanded","false"))}function se(){dt()}function Ba(){if(!c.data)return;let e=(c.data.boards||[]).find(t=>t.id===c.boardId);if(ue){let t=e?.name||"Board";ue.innerHTML=`${jo}<span class="topbar-chip-label">${d(t)}</span>`,ue.title=e?`${e.name} \u2014 slug: ${e.slug}`:"Choose board"}}function Ho(){let a=(c.data.boards||[]).map(r=>`
|
|
694
|
-
<button type="button" class="menu-flyout-item ${r.id===c.boardId?"is-current":""}" data-variant="menu-item" data-pick-board="${d(r.id)}" role="menuitem">
|
|
695
|
-
<span class="menu-flyout-item-title">${d(r.name)}</span>
|
|
696
|
-
<span class="menu-flyout-item-meta">${d(r.slug)}</span>
|
|
697
|
-
</button>`).join("")||'<p class="menu-flyout-hint menu-flyout-hint--empty">No boards yet. Create one below if you can.</p>',n=j.multiBoard?`
|
|
698
|
-
<div class="menu-flyout-section">
|
|
699
|
-
<h3 class="menu-flyout-heading">New board</h3>
|
|
700
|
-
<form id="createBoardForm" class="menu-flyout-form">
|
|
701
|
-
<input name="name" type="text" required placeholder="Board name" autocomplete="off" />
|
|
702
|
-
<div class="folder-picker-field">
|
|
703
|
-
<input id="repoPathInput" name="repo_path" type="text" readonly placeholder="Coding project folder (optional)" autocomplete="off" />
|
|
704
|
-
<button type="button" id="pickRepoFolderBtn">Browse</button>
|
|
705
|
-
</div>
|
|
706
|
-
<div id="helperFilesReveal" hidden>
|
|
707
|
-
<p class="menu-flyout-hint menu-flyout-hint--intro">Orbit writes <code>SKILL-ORBIT.md</code> and <code>AGENTS.md</code> into this folder for your AI coding agent.</p>
|
|
708
|
-
<label class="menu-flyout-check">
|
|
709
|
-
<input id="helperFilesCheckbox" name="manage_helper_files" type="checkbox" checked />
|
|
710
|
-
<span>Generate AI helper files (<code>SKILL-ORBIT.md</code>, <code>AGENTS.md</code>)</span>
|
|
711
|
-
</label>
|
|
712
|
-
</div>
|
|
713
|
-
<input name="slug" type="text" placeholder="Slug (optional)" autocomplete="off" />
|
|
714
|
-
<input name="default_branch" type="text" placeholder="Default branch (optional)" autocomplete="off" />
|
|
715
|
-
<input name="repo_url" type="text" placeholder="Repo URL (optional)" autocomplete="off" />
|
|
716
|
-
<button type="submit">Create board</button>
|
|
717
|
-
</form>
|
|
718
|
-
</div>`:"";return`
|
|
719
|
-
<div class="menu-flyout-head">Board</div>
|
|
720
|
-
<div class="menu-flyout-list">${a}</div>
|
|
721
|
-
${n}
|
|
722
|
-
`}function qo(){te.querySelectorAll("[data-pick-board]").forEach(t=>{t.addEventListener("click",async a=>{a.stopPropagation();let n=t.getAttribute("data-pick-board");dt(),n!==c.boardId&&(N(),await F({boardId:n,view:"board"}))})});let e=te.querySelector("#createBoardForm");if(e){let t=e.querySelector("#pickRepoFolderBtn"),a=e.querySelector("#repoPathInput"),n=e.querySelector("#helperFilesReveal"),r=()=>{n&&(n.hidden=!a.value.trim())};r(),t?.addEventListener("click",async o=>{o.preventDefault(),t.disabled=!0;try{let s=await w("/api/system/pick-folder",{method:"POST"});s.path&&(a.value=s.path,a.dispatchEvent(new Event("input",{bubbles:!0})),r())}catch(s){g.error(s?.message||"Folder picker unavailable")}finally{t.disabled=!1}}),e.addEventListener("submit",async o=>{o.preventDefault();let s=new FormData(e),i=String(s.get("slug")||"").trim(),l=String(s.get("default_branch")||"").trim(),u=String(s.get("repo_url")||"").trim(),p=String(s.get("repo_path")||"").trim(),m=await w("/api/boards",{method:"POST",body:{name:s.get("name"),...p?{repo_path:p,manage_helper_files:s.get("manage_helper_files")==="on"}:{},...i?{slug:i}:{},...l?{default_branch:l}:{},...u?{repo_url:u}:{}}});dt(),c.boardId=m.id,c.selectedTicketId="",c.detailMode="settings",await C(),Ke(),g.success("Board created")})}}function zn(){N(),te.innerHTML=Ho(),te.hidden=!1,ue?.setAttribute("aria-expanded","true"),qo()}var jo,ct=P(()=>{ie();z();ne();Q();he();He();me();fe();qe();jo=`
|
|
723
|
-
<svg
|
|
724
|
-
class="topbar-icon"
|
|
725
|
-
width="16"
|
|
726
|
-
height="16"
|
|
727
|
-
viewBox="0 0 24 24"
|
|
728
|
-
fill="none"
|
|
729
|
-
aria-hidden="true"
|
|
730
|
-
>
|
|
731
|
-
<rect x="4" y="4" width="6" height="16" rx="0.75" stroke="currentColor" stroke-width="2" />
|
|
732
|
-
<rect x="14" y="4" width="6" height="16" rx="0.75" stroke="currentColor" stroke-width="2" />
|
|
733
|
-
</svg>`});function Gn(){return{...Uo}}function Na(e=globalThis.location){if(typeof e=="string"){let t=new URL(e,"http://orbit.local");return{pathname:t.pathname||"/",search:t.search||"",hash:t.hash||""}}return{pathname:e?.pathname||"/",search:e?.search||"",hash:e?.hash||""}}function Da(e){try{return decodeURIComponent(e)}catch{return e}}function zo(e){return String(e||"").replace(/^#/,"").replace(/^\/+/,"").replace(/\/+$/,"").split("/").filter(Boolean)}function Go(e){if(!e.length)return null;let t=Gn(),a=0;if(e[a]==="b"){if(!e[a+1])return null;t.boardSlug=Da(e[a+1]),a+=2}else if(e[a]!=="t"&&e[a]!=="settings")return null;if(e[a]==="t"&&e[a+1])t.view="ticket",t.ticketId=Da(e[a+1]);else if(e[a]==="settings"){t.view="settings";let n=e[a+1]?Da(e[a+1]):"";n&>.has(n)&&(t.tab=n)}return t}function Kn(e){let t=String(e||"");return!t||t==="#"||t==="#/"?null:Go(zo(t))}function qt(e=globalThis.location){let t=Na(e);return Kn(t.hash)||Gn()}function lt(e=globalThis.location){let t=Na(e);return!!Kn(t.hash)}function Je({boardSlug:e="",view:t="board",ticketId:a="",tab:n=""}={}){let r=[];return e&&r.push("b",encodeURIComponent(e)),t==="ticket"&&a?r.push("t",encodeURIComponent(a)):t==="settings"&&(r.push("settings"),n&>.has(n)&&r.push(n)),"#/"+r.join("/")}function Ut(e=globalThis.location,t=qt(e)){return Na(e).hash===Je(t)}var Uo,Oa=P(()=>{yt();Uo=Object.freeze({boardSlug:"",view:"board",ticketId:"",tab:""})});function Jn(e){if(!e)return null;let t=c.data?.boards||[];return t.find(a=>a.slug===e)||t.find(a=>a.id===e)||null}function Ko(e={}){return e.boardSlug?e.boardSlug:e.boardId?Jn(e.boardId)?.slug||e.boardId:U()?.slug||c.boardSlug||""}function Jo(e={}){return{...e,boardSlug:Ko(e)}}function Xo(){let e="board";return c.detailMode==="ticket"&&c.selectedTicketId?e="ticket":c.detailMode==="settings"&&(e="settings"),{boardSlug:U()?.slug||c.boardSlug,view:e,ticketId:c.selectedTicketId,tab:e==="settings"?We(c.settingsTab):""}}function Xn(e){zt=e}function ja(){return qt(location)}async function F(e,{replace:t=!1}={}){let a=Jo(e),n=Je(a);if(Ut(location,a)){zt&&await ut();return}t?history.replaceState(null,"",n):history.pushState(null,"",n),zt&&await ut()}function Ke({replace:e=!1}={}){let t=Xo(),a=Je(t);Ut(location,t)||(e?history.replaceState(null,"",a):history.pushState(null,"",a))}async function ut(){let{load:e,renderDetailOnly:t}=await Promise.resolve().then(()=>(fe(),Un)),a=ja(),n=lt(location),r=c.boardId,s=Jn(a.boardSlug)||(a.boardSlug?U():null);s?(c.boardId=s.id,c.boardSlug=s.slug):a.boardSlug&&(c.boardSlug=a.boardSlug);let i=s?{...a,boardSlug:s.slug}:a;if(n&&!Ut(location,i)&&history.replaceState(null,"",Je(i)),a.view==="ticket")c.selectedTicketId=a.ticketId||"",c.detailMode=a.ticketId?"ticket":"empty";else if(a.view==="settings"){if(c.selectedTicketId="",c.detailMode="settings",a.tab){c.settingsTab=a.tab;try{localStorage.setItem("mab_settings_tab",a.tab)}catch{}}}else c.selectedTicketId="",c.detailMode="empty";if(se(),N(),c.boardId&&c.boardId!==r){await e();return}await t()}var zt,he=P(()=>{z();yt();ct();He();Oa();Oa();zt=!1;window.addEventListener("popstate",()=>{zt&&ut()})});ie();Qt();ta();Ka(),Xe();var tr=ar();aa();{let e=()=>{document.body.classList.toggle("is-scrolled",window.scrollY>4)};window.addEventListener("scroll",e,{passive:!0}),e()}Xa();Ha?.addEventListener("click",()=>{Ja()});window.matchMedia("(prefers-color-scheme: dark)").addEventListener("change",e=>{bt()||Ye(e.matches?"dark":"light",{notify:!0})});window.addEventListener(ht,()=>{Xa(),tr.sync()});function Xa(){if(!Yt)return;let e=$e()==="dark";Yt.innerHTML=e?'<path d="M21 12.79A9 9 0 1111.21 3 7 7 0 0021 12.79z" />':'<circle cx="12" cy="12" r="5" /><path d="M12 1v2m0 18v2M4.2 4.2l1.4 1.4m12.8 12.8l1.4 1.4M1 12h2m18 0h2M4.2 19.8l1.4-1.4M18.4 5.6l1.4-1.4" />'}function ar(){let e=document.querySelector(".grain");if(!e)return{sync:()=>{}};nr(e);let t=document.createElement("canvas");t.className="starfield-canvas",t.setAttribute("aria-hidden","true");let a=e.querySelector(".milky-way");a&&a.nextSibling?e.insertBefore(t,a.nextSibling):a?e.appendChild(t):e.insertBefore(t,e.firstChild);let n=t.getContext("2d"),r=Math.min(window.devicePixelRatio||1,2),o=0,s=0,i=[],l=0,u=!1,p={x:0,y:0,tx:0,ty:0};function m(){o=window.innerWidth,s=window.innerHeight,t.width=Math.round(o*r),t.height=Math.round(s*r),t.style.width=o+"px",t.style.height=s+"px",n.setTransform(r,0,0,r,0,0),f()}function f(){let L=o*s/1296e3,I=[{count:Math.round(320*L),depth:.12,sizes:[[1,.9],[1.4,.1]],glow:0},{count:Math.round(160*L),depth:.3,sizes:[[1,.5],[1.6,.4],[2.4,.1]],glow:1.8},{count:Math.round(44*L),depth:.58,sizes:[[1.8,.5],[2.6,.38],[3.6,.12]],glow:2.4}],R=Ya(12648430);i=[];for(let q of I)for(let _=0;_<q.count;_++){let y=or(R(),q.sizes);i.push({x:R()*o,y:R()*s,size:y,depth:q.depth,glow:y>=2?q.glow:0,rgb:b(R()),period:2.2+R()*5.4,phase:R()*Math.PI*2,amp:.25+R()*.5,baseAlpha:y<1.5?.45+R()*.28:.55+R()*.22})}}function b(L){return L<.8?[255,255,255]:L<.93?[255,222,186]:[195,218,255]}function k(L){!o||!s||(p.tx=L.clientX/o-.5,p.ty=L.clientY/s-.5)}function x(L){p.x+=(p.tx-p.x)*.06,p.y+=(p.ty-p.y)*.06,n.clearRect(0,0,o,s),n.globalCompositeOperation="lighter";let I=L/1e3,R=70;for(let q=0;q<i.length;q++){let _=i[q],y=.5+.5*Math.sin(I*(2*Math.PI/_.period)+_.phase),B=_.baseAlpha*(1-_.amp+_.amp*y),D=_.x-p.x*_.depth*R,G=_.y-p.y*_.depth*R,[ee,Y,oe]=_.rgb;if(_.glow>0){let W=_.size*_.glow,Ce=n.createRadialGradient(D,G,0,D,G,W);Ce.addColorStop(0,`rgba(${ee},${Y},${oe},${B*.85})`),Ce.addColorStop(.35,`rgba(${ee},${Y},${oe},${B*.3})`),Ce.addColorStop(1,`rgba(${ee},${Y},${oe},0)`),n.fillStyle=Ce,n.beginPath(),n.arc(D,G,W,0,Math.PI*2),n.fill(),n.fillStyle=`rgba(${ee},${Y},${oe},${B})`,n.beginPath(),n.arc(D,G,_.size/2,0,Math.PI*2),n.fill()}else{let W=_.size/2;n.fillStyle=`rgba(${ee},${Y},${oe},${B})`,n.fillRect(D-W,G-W,_.size,_.size)}}n.globalCompositeOperation="source-over",u&&(l=requestAnimationFrame(x))}function A(){n.clearRect(0,0,o,s),n.globalCompositeOperation="lighter";for(let L of i){let[I,R,q]=L.rgb;if(n.fillStyle=`rgba(${I},${R},${q},${L.baseAlpha})`,L.glow>0)n.beginPath(),n.arc(L.x,L.y,L.size/2,0,Math.PI*2),n.fill();else{let _=L.size/2;n.fillRect(L.x-_,L.y-_,L.size,L.size)}}n.globalCompositeOperation="source-over"}function M(){u||(u=!0,l=requestAnimationFrame(x))}function h(){u=!1,cancelAnimationFrame(l)}function E(){let L=$e()==="dark",I=Ae();if(!L){h(),n.clearRect(0,0,o,s);return}i.length||m(),I||document.hidden?(h(),A()):M()}return window.addEventListener("resize",()=>{m(),E()},{passive:!0}),window.addEventListener("pointermove",k,{passive:!0}),document.addEventListener("visibilitychange",E),window.matchMedia("(prefers-reduced-motion: reduce)").addEventListener("change",()=>{Xe(),E()}),window.addEventListener("orbit:motion-preference-change",E),m(),E(),{sync:E}}function nr(e){e.querySelectorAll(".signature-star").forEach(n=>n.remove());let t=Ya(6070757),a=7;for(let n=0;n<a;n++){let r=document.createElement("div");r.className="signature-star",r.setAttribute("aria-hidden","true"),r.style.left=(6+t()*88).toFixed(2)+"%",r.style.top=(8+t()*78).toFixed(2)+"%",r.style.animationDelay=(-t()*4.8).toFixed(2)+"s",e.appendChild(r)}}function aa(){let e=14e3+Math.random()*28e3;setTimeout(rr,e)}function rr(){let e=$e()==="dark",t=Ae(),a=document.querySelector(".grain");if(!e||t||document.hidden||!a){aa();return}let n=window.innerWidth,r=window.innerHeight,o=Math.random()*n*.6,s=Math.random()*r*.55,i=380+Math.random()*520,l=18+Math.random()*26,u=l*Math.PI/180,p=o+Math.cos(u)*i,m=s+Math.sin(u)*i,f=document.createElement("div");f.className="meteor",f.setAttribute("aria-hidden","true"),f.style.setProperty("--from-x",o+"px"),f.style.setProperty("--from-y",s+"px"),f.style.setProperty("--to-x",p+"px"),f.style.setProperty("--to-y",m+"px"),f.style.setProperty("--angle",l+"deg"),a.appendChild(f),f.addEventListener("animationend",()=>f.remove(),{once:!0}),aa()}function or(e,t){let a=0;for(let[n,r]of t)if(a+=r,e<a)return n;return t[t.length-1][0]}function Ya(e){let t=e>>>0;return function(){t=t+1831565813>>>0;let a=t;return a=Math.imul(a^a>>>15,a|1),a^=a+Math.imul(a^a>>>7,a|61),((a^a>>>14)>>>0)/4294967296}}ie();z();Q();me();he();ct();He();it();ie();z();Q();he();ne();He();async function Yn(){let e=mt.value.trim();if(e.length<2){Gt();return}let t=U();if(!t)return;let a=await w(`/api/search?q=${encodeURIComponent(e)}&board=${encodeURIComponent(t.slug)}`);if(a.results.length===0){pe.hidden=!1,pe.innerHTML='<div class="search-hit">No results</div>';return}pe.hidden=!1,pe.innerHTML=a.results.map(n=>`
|
|
734
|
-
<div class="search-hit" data-ticket-id="${n.id}">
|
|
735
|
-
<span class="search-hit-main">
|
|
736
|
-
<strong>${d(ae(n))}</strong>
|
|
737
|
-
<span class="search-hit-title">${d(n.title)}</span>
|
|
738
|
-
</span>
|
|
739
|
-
<span class="search-hit-state" data-variant="${d(Qe(n))}">${d(n.state_name||"State")}</span>
|
|
740
|
-
</div>
|
|
741
|
-
`).join(""),pe.querySelectorAll("[data-ticket-id]").forEach(n=>{n.addEventListener("click",async()=>{N(),Gt(),F({boardId:c.boardId,view:"ticket",ticketId:n.dataset.ticketId})})})}function Gt(){pe.hidden=!0,pe.innerHTML=""}fe();qe();function Kt(e){e?.showModal()}function Wn(e){e?.open&&e.close()}function Jt(e){e&&(e.addEventListener("click",t=>{t.target===e&&Wn(e)}),e.querySelectorAll("[data-modal-close]").forEach(t=>{t.addEventListener("click",()=>Wn(e))}))}Aa();async function Yo(e){if(e)try{let t=await fetch("./version.json",{cache:"no-store"});if(!t.ok)return;let a=await t.json();a?.version&&(e.textContent=`v${a.version}`)}catch{}}function Vn(){let e=document.getElementById("helpDialog"),t=document.getElementById("helpBtn");!e||!t||(Jt(e),Yo(document.getElementById("helpDialogVersion")),t.addEventListener("click",()=>Kt(e)))}async function Wo(){let e=document.getElementById("welcomeDialog");Jt(e),Hn(),Vn(),Te==="preview"&&Kt(e),v("#settingsBtn").addEventListener("click",async()=>{N(),se(),F({boardId:c.boardId,view:"settings",tab:c.settingsTab||"lanes"})}),ue?.addEventListener("click",a=>{if(a.stopPropagation(),!te.hidden){dt();return}zn()}),v("#newTicketBtn").addEventListener("click",()=>{if(Ra()){N();return}At("")}),ke.addEventListener("click",()=>{N()}),v("#drawerCloseBtn").addEventListener("click",()=>{F({boardId:c.boardId,view:"board"})}),v("#drawerArchiveBtn").addEventListener("click",async()=>{let a=c.selectedTicketId;if(!a||c.detailMode!=="ticket")return;let r=c.data?.tickets?.find(o=>o.id===a)?.title||"card";await w(T(`/api/tickets/${encodeURIComponent(a)}/archive`),{method:"POST"}),g.error(`Archived: ${r}`),await C(),F({boardId:c.boardId,view:"board"})}),we.addEventListener("click",()=>{F({boardId:c.boardId,view:"board"})}),document.addEventListener("keydown",a=>{if(a.key!=="Escape")return;if(!te.hidden){se();return}if(Ra()){N();return}if(!K.classList.contains("is-open"))return;let n=document.activeElement;n?.classList?.contains("inline-title-editor")||n?.classList?.contains("inline-desc-editor")||F({boardId:c.boardId,view:"board"})}),mt.addEventListener("input",wt(Yn,220)),document.addEventListener("click",a=>{a.target.closest("#topbarSearch")||Gt(),a.target.closest(".topbar-menu")||se()}),$n(),vn();let t=ja();t.boardSlug&&(c.boardSlug=t.boardSlug),await C(),Xn(!0),lt()?await ut():Ke({replace:!0})}Wo();
|
|
742
|
-
//# sourceMappingURL=app.js.map
|