hanoman 0.3.0 → 0.3.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/build-info.json +3 -3
- package/dist/cli.js +426 -77
- package/dist/server.js +3103 -2038
- package/package.json +1 -1
- package/prisma/migrations/20260905120000_agent_evidence_identity/migration.sql +3 -0
- package/prisma/schema.prisma +2 -0
- package/web/assets/{ChangelogScreen-DLlZe3rp.js → ChangelogScreen-D_-RmJkz.js} +1 -1
- package/web/assets/{DalangHanomanScreen-R7FUpJF_.js → DalangHanomanScreen-pVfnLx9z.js} +1 -1
- package/web/assets/{DocPreviewModal-DrVk9Jat.js → DocPreviewModal-ZFjISCL0.js} +1 -1
- package/web/assets/{DocsWorkspace-B9v_jrMO.js → DocsWorkspace-Vp_vik3v.js} +1 -1
- package/web/assets/IdeScreen-DQSRs3fr.js +2 -0
- package/web/assets/{LeadScreen-S8AJWFTm.js → LeadScreen-Bv5LiudD.js} +1 -1
- package/web/assets/{ReviewScreen-BRXl6u_X.js → ReviewScreen-Cime4Tci.js} +1 -1
- package/web/assets/SchedulerScreen-DKmRNbTs.js +1 -0
- package/web/assets/SettingsScreen-Bh8XhyVQ.js +62 -0
- package/web/assets/{TeamScreen-CFj0bFS7.js → TeamScreen-5ugoXsOv.js} +1 -1
- package/web/assets/TerminalScreen-DsAn5dlH.js +9 -0
- package/web/assets/{TriageScreen-CC6U7Hog.js → TriageScreen-BajACF5K.js} +1 -1
- package/web/assets/{VpsScreen-CeAUGPqE.js → VpsScreen-C7muNRX5.js} +1 -1
- package/web/assets/{diff-view-Brg2N-Y9.js → diff-view-CsZPBznT.js} +1 -1
- package/web/assets/index-DI7G_sit.js +923 -0
- package/web/assets/{live-BhsIWS2g.js → live-DVDstDzi.js} +1 -1
- package/web/index.html +1 -1
- package/web/assets/IdeScreen-CyRuZ5dQ.js +0 -2
- package/web/assets/SchedulerScreen-BfIF1e2Y.js +0 -1
- package/web/assets/SettingsScreen-CVEuvhVa.js +0 -62
- package/web/assets/TerminalScreen-DNAcMRWA.js +0 -9
- package/web/assets/index-DSFIYjSl.js +0 -915
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import{j as t,d as it,e as _,A as Xt,M as Be,S as pe,G as Vt,J as At,f as st,B as tt,I as ve,w as Jt,D as Qt,a as re,K as Zt,N as en,O as mt,Q as ht,c as Xe,U as tn,V as nn,W as rn,X as an,Y as sn,Z as on,_ as $e,$ as zt,a0 as ot,a1 as ln,h as Ne,a2 as Lt,a3 as cn,a4 as un,a5 as dn,g as Ve,a6 as Nt,l as pn,x as fn,a7 as Je,p as mn,a8 as hn,a9 as De,aa as gn,ab as gt,ac as xn,ad as bn}from"./index-DI7G_sit.js";import{R as l,r as H}from"./react-DfGhg7ZW.js";import"./markdown-CWEY34jk.js";import{D as vn,o as yn}from"./xterm-3VOAfa_q.js";function lt(e){return e.endedAt?e.endedReason==="reconciled"?"interrupted":e.exitCode===null||e.exitCode===0?"completed":"failed":"running"}const kn=new RegExp(["\\x1b\\[[?>][0-9;]*c","\\x1b\\[\\??[0-9]+;[0-9]+R","\\x1b\\[\\??[0-9;]*n","\\x1b\\[\\??[0-9;]*\\$y","\\x1b\\][0-9][0-9;]*;[^\\x07\\x1b]*(?:\\x07|\\x1b\\\\)","\\x1bP[0-9]*[$+>][a-z|][^\\x1b]*\\x1b\\\\"].join("|"),"g"),jn=e=>e.length>0&&e.replace(kn,"")==="";function wn(e,n){if(e.type!=="keydown")return null;const a=e.key.toLowerCase();return e.metaKey||e.ctrlKey&&e.shiftKey?a==="c"?n?"copy":null:a==="v"?"paste":null:null}const Sn=new Set(["image/png","image/jpeg","image/webp"]);function xt(e){return(e!=null&&e.files?Array.from(e.files):[]).filter(a=>Sn.has(a.type))}function Cn(e){return e!=null&&e.types?Array.from(e.types).includes("Files"):!1}const In=96,En=50,Rn=2,Tn=2;function An(e,n,a){if(!Number.isFinite(e)||e<=0)return n;const i=a+Rn,s=Math.floor((e-In-En-Tn*i)/i);return s>=n?n:Math.max(0,s-1)}const zn=/enter to select/i,Ln=/to navigate/i,Nn=/^\s*[❯>*]?\s*(\d)\.\s/;function Dn(e,n){var s;const a=e.join(`
|
|
2
|
+
`);if(!zn.test(a)||!Ln.test(a))return null;const i=e[n];return i?((s=Nn.exec(i))==null?void 0:s[1])??null:null}const Dt=10,Bt=24,ct=13,Bn=15;function nt(e){return Number.isFinite(e)?Math.min(Bt,Math.max(Dt,Math.round(e))):ct}const $n=[{id:"esc",label:"Esc",seq:"\x1B",aria:"Kirim Escape ke terminal"},{id:"tab",label:"Tab",seq:" ",aria:"Kirim Tab ke terminal"},{id:"up",label:"↑",seq:"\x1B[A",aria:"Kirim panah atas ke terminal"},{id:"down",label:"↓",seq:"\x1B[B",aria:"Kirim panah bawah ke terminal"},{id:"left",label:"←",seq:"\x1B[D",aria:"Kirim panah kiri ke terminal"},{id:"right",label:"→",seq:"\x1B[C",aria:"Kirim panah kanan ke terminal"},{id:"enter",label:"Enter",seq:"\r",aria:"Kirim Enter ke terminal"}],Mn=/[\x00-\x1f\x7f]/;function ut(e){return!e||Mn.test(e)?"control":[...e].length>1?"bulk":"text"}function $t(e){return e?`\x1B[4m${e}\x1B[24m`:""}function Ue(e){return e>0?`\x1B[${e}D\x1B[K`:""}const Fn=500,Pn=5e3,On=64,Wn=2;function Mt(){return{pending:"",since:null,altScreen:!1,suspendedUntil:0,typed:"",unechoed:"",gen:0,parsed:0}}const _n=e=>e.gen!==e.parsed;function Kn(e,n){return{...e,altScreen:n}}const Hn=/(password|passphrase|pass|pin)\s*(?:for\s+\S+\s*)?:\s*$/i;function qn(e){return Hn.test(e)}function Ft(e,n,a,i,s){return!s||!a.deliverable||e.altScreen||i<e.suspendedUntil||ut(n)!=="text"||a.cursorX+Wn+1>a.cols||a.line.slice(a.cursorX).trim().length>0?!1:!qn(a.line.trimEnd())}function Gn(e,n){for(let a=n.length;a>0;a-=1)if(e.endsWith(n.slice(0,a)))return a;return 0}function Un(e,n,a,i,s){const u=ut(n);if(u==="text"&&_n(e)&&s&&a.deliverable&&!e.altScreen&&i>=e.suspendedUntil)return e.unechoed.length>=On?{state:e,write:""}:{state:{...e,unechoed:e.unechoed+n,typed:""},write:"",deferred:!0};if(!Ft(e,n,a,i,s)){const h=i<e.suspendedUntil&&u==="text"?(e.typed+n).slice(-32):"";return h===e.typed&&!e.unechoed?{state:e,write:""}:{state:{...e,typed:h,unechoed:""},write:""}}return{state:{...e,pending:e.pending+n,unechoed:e.unechoed+n,since:null,typed:""},write:$t(n)}}function Yn(e,n){if(!n)return!1;const a=n.slice(-Math.min(2,n.length));return e.endsWith(a)}function Xn(e,n,a){return a>=e.suspendedUntil?e.typed?{...e,typed:""}:e:Yn(n,e.typed)?{...e,suspendedUntil:0,typed:""}:e}function Vn(e,n,a){return{state:{...e,pending:"",since:null,gen:e.gen+1},write:Ue(e.pending.length)+n}}function Jn(e,n,a,i,s){if(n!==e.gen)return{state:e,write:""};const u=a.line.slice(0,a.cursorX),v=Xn({...e,parsed:n},u,i);if(!v.unechoed)return{state:v,write:""};const h=v.unechoed.slice(Gn(u,v.unechoed));if(!h)return{state:{...v,unechoed:""},write:""};const I=Zn({...v,pending:""},h,a,i,s);return I.write?{state:{...I.state,unechoed:h},write:I.write}:{state:{...v,pending:"",unechoed:""},write:""}}function Qn(e,n){return!e.pending||e.since!==null?e:{...e,since:n}}function Zn(e,n,a,i,s){if(!n)return{state:e,write:""};const u=[...n];for(let v=0;v<u.length;v+=1){const h={...a,cursorX:a.cursorX+v};if(!Ft({...e},u[v],h,i,s))return{state:e,write:""}}return{state:{...e,pending:n,since:null},write:$t(n)}}function er(e,n){return!e.pending||e.since===null||n<e.since+Fn?{state:e,write:"",missed:!1}:{state:{...e,pending:"",since:null,suspendedUntil:n+Pn,typed:"",unechoed:""},write:Ue(e.pending.length),missed:!0}}function bt(e){const n=((e==null?void 0:e.gen)??0)+1;return{...Mt(),gen:n,parsed:n}}const tr=16;function nr(e){let n="",a;const i=()=>{if(a&&(clearTimeout(a),a=void 0),!n)return;const s=n;n="",e(s)};return{push(s,u){if(!u||ut(s)!=="text"){i(),s&&e(s);return}n+=s,a||(a=setTimeout(i,tr))},flush:i,dispose(){i()}}}const rr=250,ar=512,ir={"\x1B":"\\e","\r":"\\r","\n":"\\n"," ":"\\t","\b":"\\b","":"\\x7f"};function vt(e){let n="";for(const a of e){const i=ir[a];if(i){n+=i;continue}const s=a.codePointAt(0);n+=s<32||s===127?`\\x${s.toString(16).padStart(2,"0")}`:a}return n}function sr(e){const n=e.batchMs??rr,a=e.max??ar;let i=null,s=[],u,v=!1;const h=()=>{if(u&&(clearTimeout(u),u=void 0),!s.length)return;const I=s;s=[],e.send(I)};return{record(I,T,g){if(v)return;const b=e.now();i===null&&(i=b);const D={t:b-i,k:I,v:T};g!==void 0&&(D.n=g),s.push(D),s.length>a&&(s=s.slice(s.length-a)),u||(u=setTimeout(h,n))},flush:h,dispose(){h(),v=!0}}}const or="",lr=350,cr=1e3;function dt(){return{text:"",sentPrefix:""}}function ur(e,n){const a=[...e],i=[...n];let s=0;for(;s<a.length&&s<i.length&&a[s]===i[s];)s+=1;return s}function pt(e,n){const a=ur(e,n);return or.repeat([...e].length-a)+[...n].slice(a).join("")}function dr(e,n){return{...e,text:n}}function pr(e){return{state:{...e,sentPrefix:e.text},send:pt(e.sentPrefix,e.text)}}function fr(e){return{state:dt(),send:pt(e.sentPrefix,e.text)+"\r"}}function mr(e){return{state:dt(),send:pt(e.sentPrefix,e.text)}}function hr(e,n){return n.held?{kind:"held",text:"tertahan — Kirim di atas"}:n.n>0?{kind:"queued",text:`diantre ${n.n}`}:e==="open"?{kind:"sent",text:"terkirim"}:null}function gr({sessionId:e,send:n,external:a,linkState:i,queue:s}){const[u,v]=l.useState(""),h=l.useRef(dt()),I=l.useRef(n);I.current=n;const T=l.useRef(void 0),g=l.useRef(void 0),b=()=>{clearTimeout(T.current),T.current=void 0,clearTimeout(g.current),g.current=void 0},D=C=>{b(),h.current=C.state,C.send&&I.current(C.send)},z=()=>D(pr(h.current));a.current=()=>{D(mr(h.current)),v("")},l.useEffect(()=>()=>{a.current=()=>{}},[a]),l.useEffect(()=>b,[]);const E=C=>{h.current=dr(h.current,C),v(C),clearTimeout(T.current),T.current=setTimeout(z,lr),g.current||(g.current=setTimeout(z,cr))},k=()=>{D(fr(h.current)),v("")},f=hr(i,s);return t.jsxs("div",{className:"hn-terminal-composer",children:[t.jsx(it,{size:"lg",mono:!0,value:u,"data-testid":"terminal-composer","aria-label":`Ketik untuk sesi ${e}`,placeholder:"mis. pnpm vitest --run",autoCapitalize:"off",autoCorrect:"off",spellCheck:!1,autoComplete:"off",enterKeyHint:"send",style:{flex:"1 1 160px",minWidth:0},onChange:C=>E(C.target.value),onBlur:()=>z(),onKeyDown:C=>{C.key!=="Enter"||C.nativeEvent.isComposing||(C.preventDefault(),k())}}),f&&t.jsx("span",{"data-testid":"terminal-composer-status",className:`hn-terminal-composer-status hn-terminal-composer-status--${f.kind}`,children:f.text})]})}const Pt=[500,1e3,2e3,4e3,8e3,8e3,8e3,8e3,8e3,8e3,8e3,8e3],yt=Pt.length,xr=4096,br=/[\r\n]/;function Ot({sessionId:e,onExit:n,onPhases:a,fontSize:i=ct,showKeys:s=!1,predict:u=!0,diag:v=!1}){const h=l.useRef(null),I=l.useRef(i);I.current=i;const T=l.useRef(u);T.current=u;const g=l.useRef(v);g.current=v;const b=l.useRef(null),D=l.useRef(n);D.current=n;const z=l.useRef(a);z.current=a;const[E,k]=l.useState({state:"connecting"}),[f,C]=l.useState({n:0,held:!1,full:!1}),S=l.useRef(()=>{}),y=l.useRef(()=>{}),P=l.useRef(()=>{}),j=l.useRef(()=>{}),B=l.useRef(()=>{}),d=l.useRef(()=>{});return l.useEffect(()=>{const c=h.current;if(!c)return;const N=getComputedStyle(document.documentElement),M=(p,R)=>N.getPropertyValue(p).trim()||R,x=new vn({fontFamily:M("--font-mono","monospace"),fontSize:nt(I.current),cursorBlink:!0,macOptionClickForcesSelection:!0,theme:{background:M("--term-bg","#1c1810"),foreground:M("--term-fg","#e9e0cd")}}),G=new yn;x.loadAddon(G),x.open(c);const U=()=>{const p=c.getBoundingClientRect();return p.width>0&&p.height>0?p:null};U()&&G.fit();let L,Y=!1,ae=0,ie,X=!1;const le=p=>{(L==null?void 0:L.readyState)===WebSocket.OPEN&&L.send(JSON.stringify(p))};b.current={term:x,fit:G,send:le};const Q=sr({now:()=>Date.now(),send:p=>le({t:"diag",ev:p})}),Z=(p,R,r)=>{g.current&&Q.record(p,R,r)};let V="",J=!1,ee=!1,se=0,ce=0,fe=!1;const ue=new Map,K=p=>{if(se+=1,ce+=1,g.current){if(ue.size>256)for(const R of[...ue.keys()].slice(0,128))ue.delete(R);ue.set(se,Date.now())}le({t:"in",d:p,seq:se})},O=()=>C({n:V.length,held:J,full:ee}),Fe=p=>{if(!J&&!V&&(L==null?void 0:L.readyState)===WebSocket.OPEN){K(p);return}if(!(fe||jn(p))){if(V.length+p.length>xr){ee=!0,O();return}V+=p,O()}};let w=Mt();const q=nr(Fe),ye=p=>q.push(p,!1);y.current=ye;const te=p=>{B.current(),ye(p)};d.current=te;const de=()=>{var R;const p=x.buffer.active;return{cursorX:p.cursorX,cols:x.cols,deliverable:!fe&&!ee,line:((R=p.getLine(p.viewportY+p.cursorY))==null?void 0:R.translateToString(!0))??""}},ke=()=>{ce===0&&(L==null?void 0:L.readyState)===WebSocket.OPEN&&(w=Qn(w,Date.now()))},je=()=>{if(!V||(L==null?void 0:L.readyState)!==WebSocket.OPEN){O();return}const p=V;V="",ee=!1,O(),K(p)},Ye=()=>{if(q.flush(),!V){O();return}if(br.test(V)){J=!0,O();return}je()};P.current=()=>{J=!1,je()},j.current=()=>{V="",J=!1,ee=!1,O()};const Ae=p=>{B.current();const R=w.pending.length>0;Z("data",vt(p));const r=de(),o=Un(w,p,r,Date.now(),T.current);w=o.state,o.write?x.write(o.write):o.deferred?Z("pred","tangguh: frame server in flight"):Z("pred",`tolak cx=${r.cursorX}/${r.cols} alt=${w.altScreen?1:0} deliverable=${r.deliverable?1:0} suspend=${Math.max(0,w.suspendedUntil-Date.now())}`),q.push(p,R||o.write.length>0||o.deferred===!0)},Se=setInterval(()=>{const p=er(w,Date.now());w=p.state,p.write&&x.write(p.write)},100),me=()=>{_.issueWsTicket(`terminal:${e}`).then(({ticket:p})=>{if(Y)return;const R=location.protocol==="https:"?"wss:":"ws:",r=new WebSocket(`${R}//${location.host}${Xt.terminalWs(e)}`,[`hanoman-ticket.${p}`]);L=r,r.onopen=()=>{ae=0,se=0,ce=0;const o=Ue(w.pending.length);o&&x.write(o),w=bt(w),k({state:"open"}),U()&&((typeof window.matchMedia!="function"||window.matchMedia("(hover: hover) and (pointer: fine)").matches)&&x.focus(),le({t:"resize",cols:x.cols,rows:x.rows})),Ye()},r.onmessage=o=>{var A;const m=JSON.parse(o.data);if(m.t==="data"){const F=Vn(w,m.d??"");w=F.state;const oe=w.gen;x.write(F.write,()=>{if(Y)return;const ne=Jn(w,oe,de(),Date.now(),T.current);w=ne.state,ne.write&&x.write(ne.write),ke()}),ke()}else if(m.t==="ack"){if(ce=Math.max(0,ce-1),typeof m.seq=="number"){const F=ue.get(m.seq);F!==void 0&&(ue.delete(m.seq),Z("ack",String(m.seq),Date.now()-F))}ke()}else m.t==="phase"?(A=z.current)==null||A.call(z,m.phases??[],m.complete===!0):m.t==="alt"?w=Kn(w,m.on===!0):m.t==="exit"&&(X=!0,x.write(`\r
|
|
3
|
+
\x1B[33m— sesi berakhir (exit ${m.code}) —\x1B[0m\r
|
|
4
|
+
`),D.current(m.code??0))},r.onclose=o=>{if(!(Y||X)){if(o.code===4004){fe=!0;const m=Ue(w.pending.length);m&&x.write(m),w=bt(w),V="",J=!1,ee=!1,O(),k({state:"gone"});return}Pe()}},r.onerror=()=>{}}).catch(()=>{Y||(x.write(`\r
|
|
5
|
+
\x1B[31mWebSocket admission gagal\x1B[0m\r
|
|
6
|
+
`),Pe())})},Pe=()=>{if(ae>=yt){k({state:"lost"});return}const p=Pt[ae];ae+=1,k({state:"retrying",attempt:ae}),ie=setTimeout(me,p)};S.current=()=>{Y||(clearTimeout(ie),ae=0,k({state:"retrying",attempt:1}),me())},me(),x.attachCustomKeyEventHandler(p=>{var r,o;const R=wn(p,x.hasSelection());return R==="copy"?((r=navigator.clipboard)==null||r.writeText(x.getSelection()),!1):R==="paste"?((o=navigator.clipboard)==null||o.readText().then(m=>{m&&te(m)}),!1):!0}),x.attachCustomWheelEventHandler(p=>{if(!p.shiftKey)return!0;const R=U();if(!R||x.rows<=0)return!0;const r=R.height/x.rows,o=Math.trunc(p.deltaY/r)||Math.sign(p.deltaY);return o&&x.scrollLines(o),!1});const Oe=x.onData(Ae),$=x.textarea,ze=p=>Z("key",p.key,p.keyCode),he=p=>Z("comp",`${p.type}:${vt(p.data??"")}`);$==null||$.addEventListener("keydown",ze),$==null||$.addEventListener("compositionstart",he),$==null||$.addEventListener("compositionupdate",he),$==null||$.addEventListener("compositionend",he);let ge=null,xe=0,Ce=!1;const we=()=>{ge=null,xe=0,Ce=!1},We=p=>{if(p.touches.length!==1){we();return}ge=p.touches[0].clientY,xe=0,Ce=!1},_e=p=>{if(ge===null||p.touches.length!==1){we();return}const R=U();if(!R||x.rows<=0)return;const r=p.touches[0].clientY;xe+=ge-r,ge=r;const o=R.height/x.rows,m=Math.trunc(xe/o);m!==0&&(x.scrollLines(m),xe-=m*o,Ce=!0),p.preventDefault()},Ke=p=>{var ne,Ee;const R=ge!==null&&!Ce,r=((Ee=(ne=p.changedTouches)==null?void 0:ne[0])==null?void 0:Ee.clientY)??ge;if(we(),!R||r===null||r===void 0)return;const o=U();if(!o||x.rows<=0)return;const m=Math.floor((r-o.top)/(o.height/x.rows)),A=x.buffer.active,F=Array.from({length:x.rows},(Hr,Yt)=>{var ft;return((ft=A.getLine(A.viewportY+Yt))==null?void 0:ft.translateToString(!0))??""}),oe=Dn(F,m);oe&&te(oe)},Ie=async p=>{for(const R of p)try{const{path:r}=await _.uploadTerminalAttachment(e,R);te(`${r} `)}catch(r){x.write(`\r
|
|
7
|
+
\x1B[31mlampiran gagal: ${r.message}\x1B[0m\r
|
|
8
|
+
`)}},W=p=>{const R=xt(p.clipboardData);R.length&&(p.preventDefault(),Ie(R))},Le=p=>{Cn(p.dataTransfer)&&p.preventDefault()},He=p=>{const R=xt(p.dataTransfer);R.length&&(p.preventDefault(),Ie(R))};c.addEventListener("paste",W),c.addEventListener("dragover",Le),c.addEventListener("drop",He),c.addEventListener("touchstart",We,{passive:!0}),c.addEventListener("touchmove",_e,{passive:!1}),c.addEventListener("touchend",Ke,{passive:!0}),c.addEventListener("touchcancel",we,{passive:!0});const qe=new ResizeObserver(p=>{var r;const R=((r=p[0])==null?void 0:r.contentRect)??c.getBoundingClientRect();R.width<=0||R.height<=0||(G.fit(),le({t:"resize",cols:x.cols,rows:x.rows}))});return qe.observe(c),()=>{Y=!0,clearTimeout(ie),S.current=()=>{},y.current=()=>{},d.current=()=>{},P.current=()=>{},j.current=()=>{},b.current=null,c.removeEventListener("paste",W),c.removeEventListener("dragover",Le),c.removeEventListener("drop",He),c.removeEventListener("touchstart",We),c.removeEventListener("touchmove",_e),c.removeEventListener("touchend",Ke),c.removeEventListener("touchcancel",we),qe.disconnect(),clearInterval(Se),q.dispose(),Q.dispose(),$==null||$.removeEventListener("keydown",ze),$==null||$.removeEventListener("compositionstart",he),$==null||$.removeEventListener("compositionupdate",he),$==null||$.removeEventListener("compositionend",he),Oe.dispose(),L==null||L.close(),x.dispose()}},[e]),l.useEffect(()=>{const c=b.current,N=h.current;if(!c||!N)return;const M=nt(i);if(c.term.options.fontSize===M)return;c.term.options.fontSize=M;const x=N.getBoundingClientRect();x.width<=0||x.height<=0||(c.fit.fit(),c.send({t:"resize",cols:c.term.cols,rows:c.term.rows}))},[i]),l.useEffect(()=>{const c=b.current,N=h.current;if(!c||!N)return;const M=N.getBoundingClientRect();M.width<=0||M.height<=0||(c.fit.fit(),c.send({t:"resize",cols:c.term.cols,rows:c.term.rows}))},[s]),t.jsxs("div",{style:{display:"flex",flexDirection:"column",height:"100%",minHeight:0},children:[(E.state!=="open"&&E.state!=="connecting"||f.held||f.full)&&t.jsxs("div",{"data-testid":"terminal-link",style:{display:"flex",alignItems:"center",gap:8,flex:"0 0 auto",flexWrap:"wrap",padding:"3px 8px",fontFamily:"var(--font-mono)",fontSize:11,background:E.state==="retrying"||f.held?"var(--status-warn-tint)":"var(--status-err-tint)",color:"var(--text-body)"},children:[E.state==="retrying"&&t.jsxs("span",{children:["menyambung ulang… (",E.attempt,"/",yt,")"]}),E.state==="gone"&&t.jsx("span",{children:"sesi tidak ditemukan di tmux"}),E.state==="lost"&&t.jsxs(t.Fragment,{children:[t.jsx("span",{children:"terputus"}),t.jsx("button",{type:"button",className:"hn-terminal-action hn-terminal-action--text",onClick:()=>S.current(),children:"Sambungkan lagi"})]}),f.n>0&&!f.held&&t.jsxs("span",{"data-testid":"terminal-queue",children:[f.n," ketikan diantre"]}),f.held&&t.jsxs(t.Fragment,{children:[t.jsxs("span",{"data-testid":"terminal-held",children:[f.n," ketikan tertahan — belum dikirim"]}),t.jsx("button",{type:"button",className:"hn-terminal-action hn-terminal-action--text",onClick:()=>P.current(),children:"Kirim"}),t.jsx("button",{type:"button",className:"hn-terminal-action hn-terminal-action--text",onClick:()=>j.current(),children:"Buang"})]}),f.full&&t.jsx("span",{"data-testid":"terminal-queue-full",children:"antrean penuh"})]}),t.jsx("div",{ref:h,"data-testid":"terminal-host",style:{flex:1,minHeight:0,width:"100%",background:"var(--term-bg)",padding:8,borderRadius:"var(--radius-sm)",touchAction:"pan-x pinch-zoom",overscrollBehavior:"contain"}}),s&&t.jsx(gr,{sessionId:e,send:c=>y.current(c),external:B,linkState:E.state,queue:f}),s&&t.jsx(vr,{onKey:c=>d.current(c)})]})}function vr({onKey:e}){return t.jsx("div",{className:"hn-terminal-keys",role:"group","aria-label":"Tombol terminal",children:$n.map(n=>t.jsx("button",{type:"button",className:"hn-terminal-key","aria-label":n.aria,title:n.aria,onClick:()=>e(n.seq),children:n.label},n.id))})}const kt=20;function yr(e,n){if(!n)return"—";const a=new Date(n).getTime()-new Date(e).getTime();if(!Number.isFinite(a)||a<0)return"—";const i=Math.round(a/1e3);if(i<60)return`${i} dtk`;const s=Math.round(i/60);return s<60?`${s} mnt`:`${Math.floor(s/60)} jam ${s%60} mnt`}function kr(e){switch(lt(e)){case"running":return{label:"berjalan",tone:"neutral"};case"interrupted":return{label:"terputus",tone:"warn"};case"failed":return{label:`exit ${e.exitCode}`,tone:"err"};default:return{label:"selesai",tone:"ok"}}}const Wt=e=>lt(e)==="interrupted"?"—":yr(e.startedAt,e.endedAt),_t=e=>At[e]??e;function jr({projects:e,onClose:n,onRestart:a}){const[i,s]=l.useState([]),[u,v]=l.useState(0),[h,I]=l.useState(1),[T,g]=l.useState(!1),[b,D]=l.useState(""),[z,E]=l.useState(""),[k,f]=l.useState(""),[C,S]=l.useState(""),[y,P]=l.useState(null);l.useEffect(()=>{const d=setTimeout(()=>S(k.trim()),250);return()=>clearTimeout(d)},[k]),l.useEffect(()=>{I(1)},[b,z,C]),l.useEffect(()=>{let d=!0;return g(!0),_.listSessionHistory({projectId:b||void 0,kind:z||void 0,q:C||void 0,page:h,limit:kt}).then(c=>{d&&(v(c.total),s(c.items))}).catch(()=>{d&&(s([]),v(0))}).finally(()=>{d&&g(!1)}),()=>{d=!1}},[b,z,C,h]);const j=Qt(u,h,kt),B=d=>{var c;return((c=e.find(N=>N.id===d))==null?void 0:c.name)??d};return t.jsxs(Be,{open:!0,title:"Riwayat sesi",icon:"history",onClose:n,width:900,children:[t.jsxs("div",{style:{display:"flex",alignItems:"center",gap:10,flexWrap:"wrap",marginBottom:10},children:[t.jsx(it,{size:"sm",leftIcon:"search",placeholder:"mis. spec-412 atau reverse","aria-label":"Cari riwayat sesi",value:k,onChange:d=>f(d.target.value),style:{flex:"1 1 200px"}}),t.jsx(pe,{size:"sm","aria-label":"Filter project",value:b,onChange:d=>D(d.target.value),options:[{value:"",label:"Semua project"}].concat(e.map(d=>({value:d.id,label:d.name})))}),t.jsx(pe,{size:"sm","aria-label":"Filter jenis",value:z,onChange:d=>E(d.target.value),options:[{value:"",label:"Semua jenis"}].concat(Vt.map(d=>({value:d,label:At[d]})))})]}),i.length===0&&!T?t.jsx(st,{kind:"empty",icon:"history",title:"Belum ada riwayat sesi",hint:"Riwayat terisi sendiri saat sesi terminal dibuka lalu ditutup — termasuk sesi backlog, terminal biasa, dan sesi project-level."}):t.jsxs("div",{style:{display:"flex",flexDirection:"column",maxHeight:"60vh",overflowY:"auto"},children:[i.map(d=>{const c=kr(d);return t.jsx("button",{onClick:()=>P(d),style:{cursor:"pointer",display:"block",width:"100%",flex:"0 0 auto",font:"inherit",color:"inherit",textAlign:"left",background:"transparent",padding:"9px 8px",border:"none",borderBottom:"1px solid var(--border-hair)"},children:t.jsxs("span",{className:"hn-dense-row hn-picker-row",style:{display:"flex",alignItems:"center",gap:10,width:"100%"},children:[t.jsx("span",{style:{fontFamily:"var(--font-mono)",fontSize:11,color:"var(--text-subtle)",flex:"0 0 132px"},children:new Date(d.startedAt).toLocaleString("id-ID")}),t.jsx(tt,{size:"sm",tone:"neutral",children:_t(d.kind)}),t.jsx("span",{className:"hn-picker-title",style:{flex:1,minWidth:0,fontSize:13,color:"var(--text-strong)",overflow:"hidden",textOverflow:"ellipsis",whiteSpace:"nowrap"},children:d.title??d.specId??B(d.projectId)}),d.transcriptBytes!==null&&t.jsx(ve,{name:"file-text",size:12,color:"var(--text-subtle)"}),t.jsx("span",{style:{fontFamily:"var(--font-mono)",fontSize:11,color:"var(--text-muted)",flex:"0 0 72px"},children:Wt(d)}),t.jsx(tt,{size:"sm",tone:c.tone,children:c.label})]})},d.id)}),T&&t.jsx("div",{style:{padding:"10px 8px",textAlign:"center",fontSize:11,color:"var(--text-subtle)"},children:"memuat…"})]}),t.jsx(Jt,{page:j.page,pageCount:j.pageCount,total:u,from:j.from,to:j.to,onPage:I,unit:"sesi"}),y&&t.jsx(wr,{row:y,projectName:B(y.projectId),onBack:()=>P(null),onRestart:a})]})}function wr({row:e,projectName:n,onBack:a,onRestart:i}){const[s,u]=l.useState(null),[v,h]=l.useState("idle");l.useEffect(()=>{if(e.transcriptBytes===null){h("none"),u(null);return}let g=!0;return h("loading"),_.sessionTranscript(e.id).then(b=>{g&&(u(b.text),h("idle"))}).catch(()=>{g&&(u(null),h("error"))}),()=>{g=!1}},[e.id,e.transcriptBytes]);const I=lt(e)==="interrupted",T=[["Project",n],["Sesi",e.sessionId],["Jenis",_t(e.kind)],["Agen",[e.agent,e.model,e.effort].filter(Boolean).join(" · ")],["Mulai",new Date(e.startedAt).toLocaleString("id-ID")],[I?"Terakhir terlihat hidup":"Selesai",e.endedAt?new Date(e.endedAt).toLocaleString("id-ID"):"berjalan"],...I&&e.reconciledAt?[["Terdeteksi mati",new Date(e.reconciledAt).toLocaleString("id-ID")]]:[],["Durasi",Wt(e)],["Direktori",e.cwd]];return e.specId&&T.splice(1,0,["Backlog",`${e.specId}${e.title?` · ${e.title}`:""}`]),e.branch&&T.push(["Branch",e.branch]),t.jsxs(Be,{open:!0,title:e.title??e.specId??e.sessionId,icon:"history",onClose:a,width:1e3,children:[t.jsxs("div",{style:{display:"flex",gap:8,alignItems:"center",marginBottom:10},children:[t.jsx(re,{size:"sm",variant:"ghost",leftIcon:"arrow-left",onClick:a,children:"Kembali"}),t.jsx("div",{style:{flex:1}}),s&&t.jsx(re,{size:"sm",variant:"secondary",leftIcon:"copy",onClick:()=>{var g;return void((g=navigator.clipboard)==null?void 0:g.writeText(s))},children:"Salin transkrip"}),Zt(e.kind)&&t.jsx(re,{size:"sm",leftIcon:"play",onClick:()=>i(e),children:"Mulai lagi"})]}),I&&t.jsxs(en,{tone:"warn",title:"Sesi terputus — hasilnya tak diketahui",style:{marginBottom:12},children:["Panenya sudah lenyap saat hanoman menyala lagi (reboot, ",t.jsx("code",{children:"tmux kill-server"}),", atau host mati), jadi sesi ini tak meninggalkan exit code dan transkripnya kemungkinan besar tak sempat diambil — capture berjalan tepat sebelum pane dibunuh, dan di jalur ini sudah tak ada pane untuk dibaca. Periksa worktree & branch sesi ini sebelum menganggapnya selesai, lalu mulai lagi bila pekerjaannya belum tuntas."]}),t.jsx("div",{style:{display:"grid",gridTemplateColumns:"auto 1fr",gap:"4px 12px",marginBottom:12,fontSize:12},children:T.map(([g,b])=>t.jsxs(l.Fragment,{children:[t.jsx("span",{style:{color:"var(--text-subtle)"},children:g}),t.jsx("span",{style:{fontFamily:"var(--font-mono)",color:"var(--text-body)",wordBreak:"break-all"},children:b})]},g))}),v==="loading"&&t.jsx("div",{style:{fontSize:12,color:"var(--text-subtle)"},children:"memuat transkrip…"}),v==="none"&&t.jsx("div",{style:{fontSize:12,color:"var(--text-subtle)"},children:I?"Tanpa transkrip — panenya sudah lenyap sebelum hanoman sempat mengambilnya.":"Tanpa transkrip — sesi ini ditutup sebelum fitur riwayat ada, atau panenya tak menyisakan keluaran."}),v==="error"&&t.jsx("div",{style:{fontSize:12,color:"var(--clay-600)"},children:"Transkrip tak terbaca lagi di server."}),s!==null&&t.jsx("pre",{style:{maxHeight:"52vh",overflow:"auto",margin:0,padding:10,background:"var(--bone-200)",border:"1px solid var(--border-hair)",borderRadius:"var(--radius-sm)",fontFamily:"var(--font-mono)",fontSize:11,whiteSpace:"pre-wrap",wordBreak:"break-word",color:"var(--text-body)"},children:s})]})}function Sr({open:e,projectId:n,projectName:a,onClose:i,onCreated:s}){var P;const[u,v]=l.useState("claude"),[h,I]=l.useState("claude-opus-5"),[T,g]=l.useState("xhigh"),[b,D]=l.useState({claude:{model:"claude-opus-5",effort:"xhigh"},codex:{...mt}}),[z,E]=l.useState(!1),[k,f]=l.useState(null);l.useEffect(()=>{e&&(_.getSettings().then(j=>{const B={claude:{model:j.model,effort:j.effort},codex:{...mt,...j.codex??{}}},d=j.agent==="codex"?"codex":"claude",c=ht(B,d);D(B),v(d),I(c.model),g(c.effort)}).catch(()=>{}),_.getCodexVersion().then(j=>f(j.version)).catch(()=>{}))},[e]);const C=j=>{v(j);const B=ht(b,j);I(B.model),g(B.effort)},S=j=>{I(j),g(B=>u==="codex"?sn(j,B):on(j,B))};async function y(){E(!0);try{const{id:j}=await _.createTerminal(n,{agent:u,model:h,effort:T});s(j),i()}catch{}finally{E(!1)}}return t.jsxs(Be,{open:e,onClose:i,icon:"plus",eyebrow:a,title:"Sesi baru",footer:t.jsxs(t.Fragment,{children:[t.jsx(re,{variant:"ghost",onClick:i,children:"Batal"}),t.jsx(re,{leftIcon:"play",disabled:z,onClick:()=>void y(),children:"Buka sesi"})]}),children:[t.jsxs("div",{style:{fontSize:12.5,color:"var(--text-muted)",marginBottom:12,lineHeight:1.5},children:["Runtime untuk sesi ini. Default dari setelan global; ubah bila perlu. Sesi lahir dengan pilihan ini untuk seluruh hidupnya — ",t.jsx("code",{children:"/model"})," di terminal tetap bisa mengubahnya."]}),t.jsx(Xe,{label:"Agen",hint:"Mesin yang menjalankan sesi ini. Perilaku sesi sama; hanya CLI-nya berbeda.",children:t.jsx(pe,{"aria-label":"Agen",value:u,style:{width:"100%"},options:[{value:"claude",label:"Claude Code"},{value:"codex",label:"Codex CLI"}],onChange:j=>C(j.target.value)})}),t.jsx(Xe,{label:"Model",children:t.jsx(pe,{"aria-label":"Model",value:h,style:{width:"100%"},options:tn(u).map(j=>({value:j.id,label:j.label})),onChange:j=>S(j.target.value)})}),t.jsx(Xe,{label:"Effort",children:t.jsx(pe,{"aria-label":"Effort",value:T,style:{width:"100%"},options:nn(u,h).map(j=>({value:j,label:j})),onChange:j=>g(j.target.value)})}),u==="codex"&&rn(h,k)&&t.jsxs("div",{"data-testid":"codex-version-note",style:{fontSize:12,lineHeight:1.5,marginBottom:12,padding:"8px 10px",borderRadius:8,background:"var(--warn-bg, #fdf6e3)",color:"var(--text-muted)"},children:["Codex CLI terpasang ",t.jsx("b",{children:k}),", sedangkan ",t.jsx("b",{children:h})," butuh ",t.jsx("b",{children:(P=an(h))==null?void 0:P.minClient}),". Sesi tetap boleh dijalankan, tapi modelnya belum tentu dikenali CLI ini."]})]})}const Cr=()=>({rows:1,cols:1,cells:[null]}),jt=e=>({...e,rows:e.rows+1,cells:[...e.cells,...Array(e.cols).fill(null)]});function wt(e){const n=e.cols+1,a=[];for(let i=0;i<e.rows;i++)for(let s=0;s<n;s++)a.push(s<e.cols?e.cells[i*e.cols+s]??null:null);return{rows:e.rows,cols:n,cells:a}}function St(e,n){if(e.rows===1||n<0||n>=e.rows)return e;const a=[...e.cells];return a.splice(n*e.cols,e.cols),{...e,rows:e.rows-1,cells:a}}function Ct(e,n){if(e.cols===1||n<0||n>=e.cols)return e;const a=e.cols-1,i=[];for(let s=0;s<e.rows;s++)for(let u=0;u<e.cols;u++)u!==n&&i.push(e.cells[s*e.cols+u]??null);return{rows:e.rows,cols:a,cells:i}}function rt(e,n,a){if(n<0||n>=e.cells.length)return e;const i=e.cells.map(s=>a!==null&&s===a?null:s);return i[n]=a,{...e,cells:i}}const Ir=(e,n)=>({...e,cells:e.cells.map(a=>a&&n.has(a)?a:null)}),Kt=e=>({id:crypto.randomUUID(),name:e,layout:Cr()});function It(){const e=Kt("Utama");return{groups:[e],active:e.id}}const Me=e=>e.groups.find(n=>n.id===e.active)??e.groups[0];function Er(e,n){const a=Kt(n);return{groups:[...e.groups,a],active:a.id}}const Rr=(e,n,a)=>({...e,groups:e.groups.map(i=>i.id===n?{...i,name:a}:i)});function Tr(e,n){if(e.groups.length===1)return e;const a=e.groups.filter(i=>i.id!==n);return a.length===e.groups.length?e:{groups:a,active:e.active===n?a[0].id:e.active}}const Ar=(e,n)=>e.groups.some(a=>a.id===n)?{...e,active:n}:e;function be(e,n){const a=Me(e);return{...e,groups:e.groups.map(i=>i.id===a.id?{...i,layout:n(i.layout)}:i)}}function at(e,n,a){const i=Me(e),s=a===null?e.groups:e.groups.map(u=>u.id===i.id?u:{...u,layout:rt(u.layout,u.layout.cells.indexOf(a),null)});return{...e,groups:s.map(u=>u.id===i.id?{...u,layout:rt(u.layout,n,a)}:u)}}function Re(e,n){const a=Me(e).layout.cells.indexOf(null);return a===-1?e:at(e,a,n)}const zr=(e,n)=>({...e,groups:e.groups.map(a=>({...a,layout:rt(a.layout,a.layout.cells.indexOf(n),null)}))}),Et=e=>new Set(e.groups.flatMap(n=>n.layout.cells.filter(a=>a!==null))),Rt=(e,n)=>({...e,groups:e.groups.map(a=>({...a,layout:Ir(a.layout,n)}))}),Ht="hanoman.terminal.workspace",qt="hanoman.terminal.layout",Te=e=>$e.parse({version:1,groups:e.groups});function Ge(e,n){const a=e.groups,i=n&&a.some(s=>s.id===n)?n:a[0].id;return{groups:a,active:i}}function Lr(e){try{const n=JSON.parse(e);if(!n||typeof n!="object")return null;const a=n,i=$e.parse({version:1,groups:a.groups});return{workspace:i,active:typeof a.active=="string"&&i.groups.some(s=>s.id===a.active)?a.active:i.groups[0].id}}catch{return null}}function Nr(){try{const e=localStorage.getItem(Ht);if(e)return Lr(e);const n=localStorage.getItem(qt);if(!n)return null;const a=JSON.parse(n),i={id:crypto.randomUUID(),name:"Utama",layout:a};return{workspace:$e.parse({version:1,groups:[i]}),active:i.id}}catch{return null}}function Qe(){try{localStorage.removeItem(Ht),localStorage.removeItem(qt)}catch{}}const Gt=e=>`hanoman.terminal.workspace.v2.${encodeURIComponent(e)}`;function Dr(e){try{const n=localStorage.getItem(Gt(e));if(!n)return null;const a=JSON.parse(n),i=$e.parse(a.workspace);if(!Number.isInteger(a.revision)||(a.revision??-1)<0)return null;const s=typeof a.active=="string"&&i.groups.some(u=>u.id===a.active)?a.active:i.groups[0].id;return{workspace:i,revision:a.revision,active:s}}catch{return null}}function Ze(e,n){try{const a=$e.parse(n.workspace);if(!Number.isInteger(n.revision)||n.revision<0)return;const i=a.groups.some(s=>s.id===n.active)?n.active:a.groups[0].id;localStorage.setItem(Gt(e),JSON.stringify({workspace:a,revision:n.revision,active:i}))}catch{}}function et(e){if(!(e instanceof ot)||e.status!==409)return null;const n=e.detail;if((n==null?void 0:n.code)!=="revision-conflict")return null;const a=ln.safeParse(n.current);return a.success?a.data:null}function Br(e){const n=H.useRef(null);n.current||(n.current=It());const[a,i]=H.useState(n.current),[s,u]=H.useState("loading"),[v,h]=H.useState(null),[I,T]=H.useState(!1),g=H.useRef(a),b=H.useRef(0),D=H.useRef(!1),z=H.useRef(Promise.resolve()),E=H.useRef(0),k=H.useCallback(d=>{g.current=d,i(d)},[]),f=H.useCallback(d=>{D.current=d,T(d)},[]),C=H.useCallback(d=>{const c=z.current.then(d,d);return z.current=c.then(()=>{},()=>{}),c},[]),S=H.useCallback((d,c="ready",N=null,M=g.current.active)=>{const x=d.workspace?Ge(d.workspace,M):It();b.current=d.revision,k(x),u(c),h(N),f(!0),d.workspace&&Ze(e,{workspace:d.workspace,revision:d.revision,active:x.active})},[k,f,e]),y=H.useCallback(d=>{const c=Dr(e);c&&(b.current=c.revision,k(Ge(c.workspace,c.active))),f(!1),u("recovering"),h(d instanceof Error?d.message:"Layout server belum tersambung")},[k,f,e]),P=H.useCallback(()=>C(async()=>{try{S(await _.getTerminalWorkspace())}catch(d){y(d)}}),[S,C,y]);H.useEffect(()=>{const d=++E.current;return u("loading"),h(null),f(!1),C(async()=>{try{const c=await _.getTerminalWorkspace();if(d!==E.current)return;if(c.workspace){S(c),Qe();return}const N=Nr();if(!N){S(c);return}try{const M=await _.putTerminalWorkspace({baseRevision:c.revision,workspace:N.workspace});if(d!==E.current)return;k(Ge(M.workspace,N.active)),b.current=M.revision,Ze(e,{workspace:M.workspace,revision:M.revision,active:N.active}),Qe(),u("ready"),h(null),f(!0)}catch(M){const x=et(M);x!=null&&x.workspace?(S(x,"conflict","Layout server lebih baru; layout lokal lama tidak diunggah"),Qe()):y(M)}}catch(c){d===E.current&&y(c)}}),()=>{E.current+=1}},[S,C,y,k,f,e]),H.useEffect(()=>{const d=()=>{P()},c=()=>{document.visibilityState==="visible"&&P()};return window.addEventListener("focus",d),document.addEventListener("visibilitychange",c),()=>{window.removeEventListener("focus",d),document.removeEventListener("visibilitychange",c)}},[P]);const j=H.useCallback(d=>C(async()=>{if(!D.current)return!1;const c=d(g.current);let N,M;try{N=Te(c),M=Te(g.current)}catch{return u("conflict"),h("Layout tidak valid dan tidak disimpan"),!1}if(zt(N,M))return!0;try{return S(await _.putTerminalWorkspace({baseRevision:b.current,workspace:N}),"ready",null,c.active),!0}catch(x){const G=et(x);if(!(G!=null&&G.workspace))return y(x),!1;const U=d(Ge(G.workspace,g.current.active));try{const L=await _.putTerminalWorkspace({baseRevision:G.revision,workspace:Te(U)});return S(L,"conflict","Layout berubah di perangkat lain; perubahan ini diterapkan ulang",U.active),!0}catch(L){if(!et(L)&&!(L instanceof ot&&L.status===409))return y(L),!1;try{S(await _.getTerminalWorkspace(),"conflict","Layout berubah lagi di perangkat lain; state terbaru dimuat")}catch(Y){y(Y)}return!1}}}),[S,C,y]),B=H.useCallback(d=>{const c=Ar(g.current,d);k(c);const N=Te(c);Ze(e,{workspace:N,revision:b.current,active:c.active})},[k,e]);return{workspace:a,status:s,message:v,writable:I,mutate:j,setActive:B,refresh:P}}function Xr({userId:e="test-user",projects:n,backlog:a=[],focusSession:i,onOpenReview:s,onOpenSessionReview:u,titleOf:v,onIntegrate:h,onIntegrateSession:I,specOf:T}){var R;const[g,b]=l.useState([]),[D,z]=l.useState([]),E=Br(e),{workspace:k,status:f,message:C,writable:S,mutate:y,setActive:P,refresh:j}=E,[B,d]=Ne("terminal","project",((R=n[0])==null?void 0:R.id)??"",mn),c=Lt(),[N,M]=Ne("terminal","fontSize",c?Bn:ct,fn),[x,G]=Ne("terminal","keys",c,Je),[U,L]=Ne("terminal","predict",!0,Je),[Y,ae]=Ne("terminal","diag",!1,Je),ie=r=>M(o=>nt(o+r)),[X,le]=l.useState(!1),[Q,Z]=l.useState(null),[V,J]=l.useState(!1),[ee,se]=l.useState(null),[ce,fe]=l.useState(!1),[ue,K]=l.useState(!1),O=cn(),w=un()==="mobile",[q,ye]=l.useState(0),[te,de]=l.useState(null),ke=l.useRef(null),[je,Ye]=l.useState(!1);l.useEffect(()=>{_.listTerminals().then(r=>{b(r),Ye(!0)}).catch(()=>{})},[]),l.useEffect(()=>dn(r=>{r.t==="sessions"?b(r.sessions):r.t==="cleanups"&&z(r.cleanups)}),[]),l.useEffect(()=>{if(!je||!S)return;const r=new Set(g.map(m=>m.id)),o=Rt(k,r);zt(Te(o),Te(k))||y(m=>Rt(m,r))},[y,g,je,S,k]),l.useEffect(()=>{if(!i){ke.current=null;return}!je||ke.current===i||g.some(r=>r.id===i&&!r.exited)&&(ke.current=i,de(i))},[i,g,je]),l.useEffect(()=>{if(!te)return;const r=k.groups.find(o=>o.layout.cells.includes(te));if(r){r.id!==k.active&&P(r.id);return}S&&y(o=>{if(Et(o).has(te))return o;const m=Re(o,te);return m!==o||!w?m:at(o,q,te)})},[q,w,y,te,P,S,k]),l.useEffect(()=>{Q&&!g.some(r=>r.id===Q)&&Z(null)},[Q,g]);const Ae=D.filter(r=>r.error),Se=r=>g.find(o=>o.id===r)??null,me=r=>{var o;return((o=n.find(m=>m.id===r))==null?void 0:o.name)??r};function Pe(r){b(o=>o.some(m=>m.id===r)?o:[...o,{id:r,projectId:B,cwd:"",exited:!1}]),y(o=>Re(o,r)),de(r)}async function Oe(){if(!B)return;const{id:r}=await _.createShell(B);b(o=>[...o,{id:r,projectId:B,cwd:"",exited:!1}]),y(o=>Re(o,r)),de(r)}async function $(r,o){const m=bn(r.source);try{const{id:A}=await _.startSession({spec:r.id,flow:m,...o?{force:o}:{}});b(F=>F.some(oe=>oe.id===A)?F:[...F,{id:A,projectId:r.projectId,specId:r.id,flow:m,cwd:"",exited:!1}]),y(F=>Re(F,A)),de(A),J(!1),se(null)}catch(A){if(O.offerRetry(A,r.id,oe=>$(r,oe)))return;const F=A instanceof ot&&(A.status===400||A.status===422);se(`${r.id} · gagal mulai${F?" · project belum punya repoDir":""}`)}}async function ze(r,o){try{const m=r.specId?await _.startSession({spec:r.specId,flow:r.flow??"feature",...o?{force:o}:{}}):r.kind==="shell"?await _.createShell(r.projectId):r.kind==="terminal"?await _.createTerminal(r.projectId,{agent:r.agent==="codex"?"codex":"claude",...r.model?{model:r.model}:{},...r.effort?{effort:r.effort}:{}}):await(o?_.createTerminalFlow(r.projectId,r.kind,{force:o}):_.createTerminalFlow(r.projectId,r.kind));b(A=>A.some(F=>F.id===m.id)?A:[...A,{id:m.id,projectId:r.projectId,specId:r.specId??void 0,cwd:"",exited:!1}]),y(A=>Re(A,m.id)),de(m.id),K(!1)}catch(m){if((r.specId||r.kind!=="shell"&&r.kind!=="terminal")&&O.offerRetry(m,`${r.projectId} · ${r.title??r.specId??r.kind}`,A=>ze(r,A)))return}}const he=new Set(g.filter(r=>r.specId&&!r.exited).map(r=>r.specId)),ge=a.filter(r=>r.stage!=="done"&&!he.has(r.id));function xe(r){b(o=>o.filter(m=>m.id!==r)),_.deleteTerminal(r).catch(()=>{})}const Ce=l.useCallback((r,o)=>{b(m=>m.map(A=>A.id===r?{...A,exited:!0,exitCode:o}:A))},[]),we=(r,o)=>{ye(r),y(m=>at(m,r,o))},We=r=>{de(r),y(o=>Re(o,r))},_e=r=>{y(o=>zr(o,r))},Ke=Et(k),Ie=g.filter(r=>!Ke.has(r.id)),W=Me(k).layout;l.useEffect(()=>{if(!te)return;const r=W.cells.indexOf(te);r<0||(ye(r),de(null))},[W.cells,te]),l.useEffect(()=>{q>=W.cells.length&&ye(Math.max(0,W.cells.length-1))},[q,W.cells.length]);const Le=W.rows===1&&W.cols===1&&!W.cells[0]&&g.length===0,He=t.jsxs("div",{style:{display:"flex",flexDirection:"column",gap:10,marginBottom:10},children:[t.jsxs("div",{className:"hn-dense-row",style:{display:"flex",alignItems:"center",gap:8},children:[t.jsx("span",{style:{flex:1,minWidth:0,fontSize:12,color:"var(--text-muted)"},children:"Ukuran teks terminal"}),t.jsx(Ve,{size:"sm",icon:"minus",label:"Perkecil teks terminal",disabled:N<=Dt,onClick:()=>ie(-1)}),t.jsxs("span",{style:{fontFamily:"var(--font-mono)",fontSize:12,minWidth:44,textAlign:"center"},children:[N,"px"]}),t.jsx(Ve,{size:"sm",icon:"plus",label:"Perbesar teks terminal",disabled:N>=Bt,onClick:()=>ie(1)})]}),t.jsxs("div",{className:"hn-dense-row",style:{display:"flex",alignItems:"center",gap:8},children:[t.jsx("span",{style:{flex:1,minWidth:0,fontSize:12,color:"var(--text-muted)"},children:"Papan tombol layar (Esc · panah · Enter)"}),t.jsx(re,{size:"sm",variant:"secondary","aria-pressed":x,onClick:()=>G(r=>!r),children:x?"Sembunyikan":"Tampilkan"})]}),t.jsxs("div",{className:"hn-dense-row",style:{display:"flex",alignItems:"center",gap:8},children:[t.jsx("span",{style:{flex:1,minWidth:0,fontSize:12,color:"var(--text-muted)"},children:"Ketik responsif (huruf tampil sebelum echo server)"}),t.jsx(re,{size:"sm",variant:"secondary","aria-pressed":U,"aria-label":`${U?"Matikan":"Nyalakan"} ketik responsif`,onClick:()=>L(r=>!r),children:U?"Matikan":"Nyalakan"})]}),t.jsxs("div",{className:"hn-dense-row",style:{display:"flex",alignItems:"center",gap:8},children:[t.jsx("span",{style:{flex:1,minWidth:0,fontSize:12,color:"var(--text-muted)"},children:"Rekam jalur ketik (diagnostik — merekam setiap tombol)"}),t.jsx(re,{size:"sm",variant:"secondary","aria-pressed":Y,"aria-label":`${Y?"Matikan":"Nyalakan"} rekam jalur ketik`,onClick:()=>ae(r=>!r),children:Y?"Matikan":"Nyalakan"})]}),w&&t.jsx(pe,{size:"sm","aria-label":"Project sesi baru",value:B,onChange:r=>d(r.target.value),options:n.map(r=>({value:r.id,label:r.name}))})]}),qe=[{key:"backlog",label:"Ambil backlog",icon:"inbox",onSelect:()=>{se(null),J(!0)}},{key:"history",label:"Riwayat sesi",icon:"history",onSelect:()=>K(!0)},{key:"shell",label:"Terminal biasa",icon:"terminal",onSelect:()=>void Oe()},{key:"col+",label:"+ Kolom",icon:"columns-2",disabled:!S,onSelect:()=>void y(r=>be(r,wt))},{key:"row+",label:"+ Baris",icon:"rows-2",disabled:!S,onSelect:()=>void y(r=>be(r,jt))},{key:"col-",label:"Hapus kolom aktif",icon:"columns-2",disabled:!S||W.cols===1,onSelect:()=>void y(r=>be(r,o=>Ct(o,q%o.cols)))},{key:"row-",label:"Hapus baris aktif",icon:"rows-2",disabled:!S||W.rows===1,onSelect:()=>void y(r=>be(r,o=>St(o,Math.floor(q/o.cols))))}],p={display:"flex",flexDirection:"column",gap:X?8:12,...X?{position:"fixed",inset:0,zIndex:100,background:"var(--surface-page)",paddingTop:"max(12px, var(--safe-top))",paddingRight:"max(12px, var(--safe-right))",paddingBottom:"max(12px, var(--safe-bottom))",paddingLeft:"max(12px, var(--safe-left))"}:{flex:"1 1 0",minHeight:640}};return t.jsxs("div",{"data-testid":"terminal-root",style:p,children:[t.jsxs("div",{style:{display:"flex",gap:8,flexDirection:X?"row":"column",alignItems:X?"center":"stretch"},children:[t.jsx(Mr,{compact:X,ws:k,writable:S,onSelect:P,onAdd:()=>void y(r=>Er(r,`Grup ${r.groups.length+1}`)),onRename:(r,o)=>void y(m=>Rr(m,r,o)),onRemove:r=>void y(o=>Tr(o,r))}),t.jsxs("div",{style:{display:"flex",alignItems:"center",gap:8,flexWrap:"wrap",...X?{flex:1,minWidth:0}:{}},children:[!w&&t.jsxs(t.Fragment,{children:[t.jsx(re,{size:"sm",variant:"ghost",disabled:!S,onClick:()=>void y(r=>be(r,wt)),children:"+ Kolom"}),t.jsx(re,{size:"sm",variant:"ghost",disabled:!S,onClick:()=>void y(r=>be(r,jt)),children:"+ Baris"})]}),t.jsx("div",{style:{flex:1,minWidth:0}}),f!=="ready"&&t.jsx("span",{"data-testid":"terminal-workspace-status",title:C??void 0,style:{fontSize:12,color:f==="conflict"?"var(--status-warn)":"var(--text-muted)"},children:f==="loading"?"Memuat layout server…":f==="recovering"?t.jsxs(t.Fragment,{children:[t.jsx("span",{children:"Layout server belum tersambung"})," ",t.jsx("button",{type:"button",onClick:()=>void j(),children:"Retry"})]}):C??"Layout berubah di perangkat lain"}),D.length>0&&t.jsx("span",{"data-testid":"worktree-cleanups",title:D.map(r=>`${r.sessionId}${r.error?` — ${r.error}`:""}`).join(`
|
|
9
|
+
`),style:{fontSize:12,color:Ae.length?"var(--status-err)":"var(--text-muted)"},children:Ae.length?`${Ae.length} worktree gagal dibersihkan`:`membersihkan ${D.length} worktree…`}),!w&&t.jsxs(t.Fragment,{children:[t.jsx(pe,{size:"sm",value:B,onChange:r=>d(r.target.value),options:n.map(r=>({value:r.id,label:r.name}))}),t.jsx(re,{size:"sm",variant:"secondary",leftIcon:"inbox",onClick:()=>{se(null),J(!0)},children:"Ambil backlog"}),t.jsx(re,{size:"sm",variant:"secondary",leftIcon:"history",title:"Riwayat sesi yang sudah berlalu — buka kembali atau baca transkripnya",onClick:()=>K(!0),children:"Riwayat"}),t.jsx(re,{size:"sm",variant:"secondary",leftIcon:"terminal",title:"Buka shell tmux tanpa Claude di project terpilih — jalankan command di project",onClick:()=>void Oe(),children:"Terminal biasa"})]}),t.jsx(re,{size:"sm",leftIcon:"plus",onClick:()=>fe(!0),children:"Sesi baru"}),t.jsx(Nt,{label:w?"Aksi terminal lain":"Tampilan terminal",items:w?qe:[],children:He}),t.jsx(Ve,{size:"sm",icon:X?"minimize-2":"maximize-2",label:X?"Keluar layar penuh":"Layar penuh","aria-pressed":X,onClick:()=>le(r=>!r)})]})]}),Ie.length>0&&t.jsxs("div",{style:{display:"flex",gap:6,flexWrap:"wrap",alignItems:"center"},children:[t.jsx("span",{style:{fontSize:11,color:"var(--text-subtle)"},children:"Belum di grid:"}),Ie.map(r=>t.jsxs("span",{style:{display:"inline-flex",alignItems:"center",gap:6,padding:"4px 8px",borderRadius:"var(--radius-sm)",background:"var(--bone-200)",border:"1px solid var(--border-hair)",fontFamily:"var(--font-mono)",fontSize:11},children:[t.jsxs("button",{className:"hn-terminal-unplaced-action",disabled:!S,onClick:()=>We(r.id),title:"Taruh di sel kosong pertama grup ini",style:{all:"unset",cursor:"pointer"},children:[r.specId??me(r.projectId)," · ",r.id.slice(0,6)]}),t.jsx("button",{type:"button",className:"hn-terminal-action","aria-label":`Tutup sesi ${r.id}`,onClick:()=>void xe(r.id),children:"×"})]},r.id))]}),w&&!Le&&t.jsx("div",{className:"hn-stack-mobile",style:{display:"flex",alignItems:"center",gap:8},children:t.jsx(pn,{"aria-label":"Panel terminal",variant:"pill",value:String(q),onChange:r=>ye(Number(r)),tabs:W.cells.map((r,o)=>({value:String(o),label:`Panel ${o+1}${r?` · ${r.slice(0,6)}`:" · kosong"}`}))})}),Le?t.jsx(st,{kind:"empty",icon:"terminal",title:"Belum ada sesi terminal",hint:"Pilih project lalu buka sesi — 'Sesi baru' menjalankan claude --dangerously-skip-permissions di direktori project; 'Terminal biasa' membuka shell tmux polos untuk menjalankan command."}):t.jsxs("div",{style:{flex:1,minHeight:0,display:"grid",gap:8,gridTemplateColumns:w?"minmax(0, 1fr)":`18px repeat(${W.cols}, minmax(0, 1fr))`,gridTemplateRows:w?"minmax(0, 1fr)":`16px repeat(${W.rows}, minmax(0, 1fr))`},children:[!w&&t.jsx("div",{}),!w&&Array.from({length:W.cols},(r,o)=>t.jsx(Tt,{label:`Tutup kolom ${o+1}`,disabled:!S||W.cols===1,onClick:()=>void y(m=>be(m,A=>Ct(A,o)))},`col-${o}`)),Array.from({length:W.rows},(r,o)=>t.jsxs(l.Fragment,{children:[!w&&t.jsx(Tt,{label:`Tutup baris ${o+1}`,disabled:!S||W.rows===1,onClick:()=>void y(m=>be(m,A=>St(A,o)))}),Array.from({length:W.cols},(m,A)=>{const F=o*W.cols+A,oe=W.cells[F]??null,ne=oe?Se(oe):null;return t.jsx("div",{"data-terminal-cell-index":F,"aria-hidden":w&&q!==F?"true":"false",style:{minHeight:0,minWidth:0,display:w&&q!==F?"none":"flex",flexDirection:"column",border:"1px solid var(--border-hair)",borderRadius:"var(--radius-sm)",overflow:"hidden"},children:ne?t.jsx(Wr,{session:ne,nameOf:me,onClose:()=>void xe(ne.id),canArrange:S,onDetach:()=>_e(ne.id),onExit:Ee=>Ce(ne.id,Ee),onReview:s,onSessionReview:u,titleOf:v,onIntegrate:h,onIntegrateSession:I,specOf:T,fontSize:N,showKeys:x,predict:U,diag:Y,fullscreen:Q===ne.id,onFullscreen:()=>Z(ne.id)}):t.jsx(Kr,{disabled:!S,unplaced:Ie,nameOf:me,onPick:Ee=>we(F,Ee)})},oe??`empty-${F}`)})]},`row-${o}`))]}),V&&t.jsx($r,{seed:ge,activeIds:he,error:ee,onPick:r=>void $(r),onClose:()=>J(!1)}),ce&&t.jsx(Sr,{open:!0,projectId:B,projectName:me(B),onClose:()=>fe(!1),onCreated:Pe}),ue&&t.jsx(jr,{projects:n,onClose:()=>K(!1),onRestart:r=>void ze(r)}),O.dialog,Q&&Se(Q)&&t.jsx(_r,{session:Se(Q),label:Ut(Se(Q),me,v),fontSize:N,showKeys:x,predict:U,diag:Y,onClose:()=>Z(null)})]})}function Ut(e,n,a){const i=n(e.projectId),s=e.specId?a==null?void 0:a(e.specId):void 0;return e.specId?`${i} · ${e.specId}${s?` · ${s}`:""}`:e.id.startsWith("xaudit-")?`${i} · audit lintas`:i}function $r({seed:e,activeIds:n,error:a,onPick:i,onClose:s}){const[u,v]=l.useState(""),[h,I]=l.useState("all"),[T,g]=l.useState("all"),[b,D]=l.useState(e),[z,E]=l.useState("");l.useEffect(()=>{const f=setTimeout(()=>E(u.trim()),250);return()=>clearTimeout(f)},[u]),l.useEffect(()=>{var S,y;let f=!0;const C=(y=(S=_).listSpecs)==null?void 0:y.call(S,{startable:!0,q:z||void 0,stage:h==="all"?void 0:h,priority:T==="all"?void 0:T});return C==null||C.then(P=>{f&&D(P.items)}).catch(()=>{}),()=>{f=!1}},[z,h,T]);const k=b.filter(f=>!n.has(f.id));return t.jsxs(Be,{open:!0,title:"Ambil backlog",icon:"inbox",onClose:s,width:760,children:[a&&t.jsx("div",{style:{marginBottom:10,padding:"8px 10px",borderRadius:"var(--radius-sm)",background:"var(--clay-100)",color:"var(--clay-600)",fontSize:12},children:a}),t.jsxs("div",{style:{display:"flex",alignItems:"center",gap:10,flexWrap:"wrap",marginBottom:10},children:[t.jsx(it,{size:"sm",leftIcon:"search",placeholder:"mis. invoice atau SPEC-412","aria-label":"Cari backlog",value:u,onChange:f=>v(f.target.value),style:{flex:"1 1 220px"}}),t.jsx(pe,{size:"sm","aria-label":"Filter stage",value:h,onChange:f=>I(f.target.value),options:[{value:"all",label:"Semua stage"}].concat(xn.filter(f=>f.key!=="done").map(f=>({value:f.key,label:f.label})))}),t.jsx(pe,{size:"sm","aria-label":"Filter prioritas",value:T,onChange:f=>g(f.target.value),options:[{value:"all",label:"Semua prioritas"},{value:"tinggi",label:"Tinggi"},{value:"sedang",label:"Sedang"},{value:"rendah",label:"Rendah"}]})]}),k.length===0?t.jsx(st,{kind:"empty",icon:"inbox",title:"Tak ada backlog untuk diambil",hint:"Semua item sudah selesai/aktif atau tak cocok filter — buat brief baru di halaman Backlog."}):t.jsx("div",{style:{display:"flex",flexDirection:"column",maxHeight:"62vh",overflowY:"auto"},children:k.map(f=>t.jsx("button",{onClick:()=>i(f),style:{cursor:"pointer",display:"block",width:"100%",flex:"0 0 auto",font:"inherit",color:"inherit",textAlign:"left",background:"transparent",padding:"9px 8px",border:"none",borderBottom:"1px solid var(--border-hair)"},children:t.jsxs("span",{className:"hn-dense-row hn-picker-row",style:{display:"flex",alignItems:"center",gap:10,width:"100%"},children:[t.jsx(ve,{name:f.source==="qa"?"bug":f.source==="audit"?"search":"lightbulb",size:14,color:f.source==="qa"?"var(--clay-500)":f.source==="audit"?"var(--wind-600)":"var(--brass-500)"}),t.jsx("span",{style:{fontFamily:"var(--font-mono)",fontSize:12,color:"var(--text-subtle)",flex:"0 0 78px"},children:f.id}),t.jsx("span",{className:"hn-picker-title",style:{flex:1,minWidth:0,fontSize:13,color:"var(--text-strong)",overflow:"hidden",textOverflow:"ellipsis",whiteSpace:"nowrap"},children:f.title}),t.jsx(tt,{tone:f.priority==="tinggi"?"err":"neutral",size:"sm",children:f.priority}),t.jsx("span",{style:{fontFamily:"var(--font-mono)",fontSize:11,flex:"0 1 auto",minWidth:0,overflow:"hidden",textOverflow:"ellipsis",whiteSpace:"nowrap",color:"var(--text-muted)"},children:f.projectId})]})},f.id))})]})}function Mr({ws:e,compact:n=!1,writable:a,onSelect:i,onAdd:s,onRename:u,onRemove:v}){const[h,I]=l.useState(null),T=Me(e),g=e.groups.length===1;return t.jsxs("div",{role:"tablist","aria-label":"Grup terminal",style:{display:"flex",alignItems:"center",gap:4,flexWrap:"wrap",...n?{}:{borderBottom:"1px solid var(--border-hair)",paddingBottom:4}},children:[e.groups.map((b,D)=>{const z=b.id===T.id;return h===b.id?t.jsx(Fr,{initial:b.name,onCommit:E=>{E.trim()&&u(b.id,E.trim()),I(null)},onCancel:()=>I(null)},b.id):t.jsxs("span",{style:{display:"inline-flex",alignItems:"center",gap:4,padding:"3px 6px",borderRadius:"var(--radius-sm)",fontSize:12,background:z?"var(--bone-200)":"transparent",border:`1px solid ${z?"var(--border-hair)":"transparent"}`},children:[t.jsx("button",{className:"hn-terminal-group-control",role:"tab","aria-selected":z,tabIndex:z?0:-1,onClick:()=>i(b.id),onKeyDown:E=>{var f,C;let k=null;E.key==="ArrowRight"?k=(D+1)%e.groups.length:E.key==="ArrowLeft"?k=(D-1+e.groups.length)%e.groups.length:E.key==="Home"?k=0:E.key==="End"&&(k=e.groups.length-1),k!==null&&(E.preventDefault(),i(e.groups[k].id),(C=(f=E.currentTarget.closest('[role="tablist"]'))==null?void 0:f.querySelectorAll('[role="tab"]')[k])==null||C.focus())},style:{border:0,padding:0,background:"transparent",font:"inherit",cursor:"pointer",color:z?"var(--text-strong)":"var(--text-muted)"},children:b.name}),z&&a&&t.jsxs(t.Fragment,{children:[t.jsx("button",{className:"hn-terminal-group-control","aria-label":`Ganti nama grup ${b.name}`,title:"Ganti nama",onClick:()=>I(b.id),style:{border:0,padding:0,background:"transparent",cursor:"pointer",color:"var(--text-subtle)",fontSize:10},children:"✎"}),t.jsx("button",{className:"hn-terminal-group-control","aria-label":`Hapus grup ${b.name}`,title:g?"Grup terakhir tak bisa dihapus":"Hapus grup (sesi tetap hidup)",disabled:g,onClick:()=>v(b.id),style:{border:0,padding:0,background:"transparent",cursor:g?"not-allowed":"pointer",color:"var(--text-subtle)",opacity:g?.35:1},children:"×"})]})]},b.id)}),t.jsx("button",{className:"hn-terminal-group-control","aria-label":"Grup baru",title:"Grup baru",disabled:!a,onClick:s,style:{border:0,background:"transparent",cursor:"pointer",padding:"3px 8px",color:"var(--text-subtle)",fontSize:12},children:"+"})]})}function Tt({label:e,disabled:n,onClick:a}){return t.jsx("button",{type:"button","aria-label":e,title:n?"Grid tak boleh menyusut ke nol":e,disabled:n,onClick:a,style:{all:"unset",display:"grid",placeItems:"center",fontSize:11,lineHeight:1,color:"var(--text-subtle)",opacity:n?.3:1,cursor:n?"not-allowed":"pointer"},children:"×"})}function Fr({initial:e,onCommit:n,onCancel:a}){const[i,s]=l.useState(e);return t.jsx("input",{autoFocus:!0,"aria-label":"Nama grup",value:i,placeholder:"mis. Rilis",onChange:u=>s(u.target.value),onBlur:()=>n(i),onKeyDown:u=>{u.key==="Enter"?n(i):u.key==="Escape"&&a()},style:{width:100,padding:"3px 6px",fontSize:12,fontFamily:"var(--font-ui)",border:"1px solid var(--border-strong)",borderRadius:"var(--radius-sm)",background:"var(--surface-card)",color:"var(--text-strong)"}})}const Pr={done:"var(--brass)",active:"var(--text-strong)",skipped:"var(--text-subtle)",pending:"var(--text-subtle)"};function Or({phases:e}){return e!=null&&e.length?t.jsx("div",{style:{display:"flex",alignItems:"center",gap:8,padding:"3px 8px",flex:"0 0 auto",borderBottom:"1px solid var(--border-hair)",fontSize:10,fontFamily:"var(--font-mono)"},children:e.map(n=>t.jsx("span",{"data-state":n.state,title:n.state,style:{color:Pr[n.state],fontWeight:n.state==="active"?600:400,textDecoration:n.state==="skipped"?"line-through":"none",opacity:n.state==="pending"?.5:1},children:n.name},n.name))}):null}function Wr({session:e,nameOf:n,onClose:a,canArrange:i,onDetach:s,onExit:u,onReview:v,onSessionReview:h,titleOf:I,onIntegrate:T,onIntegrateSession:g,specOf:b,fontSize:D,showKeys:z,predict:E,diag:k,fullscreen:f,onFullscreen:C}){const[S,y]=l.useState(null),P=l.useRef(null),[j,B]=l.useState(Number.POSITIVE_INFINITY),d=Lt();l.useEffect(()=>{const K=P.current;if(!K||typeof ResizeObserver!="function")return;const O=new ResizeObserver(Fe=>{var q;const w=((q=Fe[0])==null?void 0:q.contentRect.width)??K.getBoundingClientRect().width;w>0&&B(w)});return O.observe(K),()=>O.disconnect()},[]);const[c,N]=l.useState(!1),M=l.useCallback((K,O)=>{y(K),N(O)},[]),[x,G]=l.useState(!1),[U,L]=l.useState(!1),[Y,ae]=l.useState(!1),ie=e.specId?b==null?void 0:b(e.specId):void 0,X=!e.specId&&!!e.branch,le=Ut(e,n,I),Q=!e.exited&&!!e.decision,Z=!e.exited&&!!e.deciding,V=Q||Z,J=e.exited&&!!e.exitCode,ee=!e.exited&&c,se=J?null:e.exited||ee?"PST-005":V?"PST-004":"PST-003",ce=[...e.specId?[{key:"docs",label:"Lihat dokumen",icon:"file-text",title:"Lihat dokumen (audit/spec/plan)",onSelect:()=>G(!0),render:t.jsx("button",{type:"button",className:"hn-terminal-action",onClick:()=>G(!0),"aria-label":`Lihat dokumen sesi ${e.id}`,title:"Lihat dokumen (audit/spec/plan)",children:t.jsx(ve,{name:"file-text",size:12})},"docs")}]:[],...e.specId&&v?[{key:"review",label:"Review perubahan",icon:"git-compare",title:"Review perubahan (diff worktree)",onSelect:()=>v(e.specId),render:t.jsx("button",{type:"button",className:"hn-terminal-action",onClick:()=>v(e.specId),"aria-label":`Review sesi ${e.id}`,title:"Review perubahan (diff worktree)",children:t.jsx(ve,{name:"git-compare",size:12})},"review")}]:[],...X&&h?[{key:"review-session",label:"Review perubahan",icon:"git-compare",title:"Review perubahan (diff worktree sesi)",onSelect:()=>h(e.id,le),render:t.jsx("button",{type:"button",className:"hn-terminal-action",onClick:()=>h(e.id,le),"aria-label":`Review sesi ${e.id}`,title:"Review perubahan (diff worktree sesi)",children:t.jsx(ve,{name:"git-compare",size:12})},"review-session")}]:[],...ie&&T?[{key:"integrate",label:"Rebase / Merge branch",icon:"git-merge",title:"Rebase / Merge branch spec",onSelect:()=>L(!0),render:t.jsx("button",{type:"button",className:"hn-terminal-action",onClick:()=>L(!0),"aria-label":`Integrasikan sesi ${e.id}`,title:"Rebase / Merge branch spec",children:t.jsx(ve,{name:"git-merge",size:12})},"integrate")}]:[],...X&&g?[{key:"integrate-session",label:"Rebase / Merge branch",icon:"git-merge",title:"Rebase / Merge branch sesi",onSelect:()=>ae(!0),render:t.jsx("button",{type:"button",className:"hn-terminal-action",onClick:()=>ae(!0),"aria-label":`Integrasikan sesi ${e.id}`,title:"Rebase / Merge branch sesi",children:t.jsx(ve,{name:"git-merge",size:12})},"integrate-session")}]:[],{key:"detach",label:"Lepas dari grid",icon:"unlink",disabled:!i,title:"Lepas dari grid (sesi tetap hidup)",onSelect:s,render:t.jsx("button",{type:"button",className:"hn-terminal-action hn-terminal-action--text",onClick:s,disabled:!i,title:"Lepas dari grid (sesi tetap hidup)",children:"lepas"},"detach")}],fe=An(j,ce.length,d?44:28),ue=ce.slice(fe);return t.jsxs(t.Fragment,{children:[t.jsxs("div",{ref:P,className:"hn-terminal-cell-header",style:{display:"flex",alignItems:"center",gap:8,padding:"4px 8px",flex:"0 0 auto",background:J?"var(--status-err-tint)":e.exited||ee?"var(--status-ok-tint)":V?"var(--status-warn-tint)":"var(--bone-200)",borderBottom:"1px solid var(--border-hair)",fontFamily:"var(--font-mono)",fontSize:11,color:e.exited?"var(--text-muted)":"var(--text-body)"},children:[se&&t.jsx(hn,{id:se,decorative:!0,style:{width:34,flex:"0 0 auto",borderRadius:"var(--radius-sm)"}}),t.jsxs("span",{style:{flex:1,minWidth:0,overflow:"hidden",textOverflow:"ellipsis",whiteSpace:"nowrap"},children:[le," · ",e.id.slice(0,6)]}),e.exited&&(J?t.jsx(De,{status:"failed",size:"sm",children:`Gagal · exit ${e.exitCode}`}):t.jsx(De,{status:"done",size:"sm",children:"Selesai"})),ee&&t.jsx(De,{status:"done",size:"sm",children:"Selesai"}),Z&&!ee&&t.jsx(De,{status:"running",size:"sm",children:"Lead memutuskan"}),Q&&!Z&&!ee&&t.jsx(De,{status:"awaiting",size:"sm"}),t.jsxs("span",{className:"hn-terminal-actions",children:[ce.slice(0,fe).map(K=>K.render),ue.length>0&&t.jsx(Nt,{label:`Aksi lain sesi ${e.id}`,items:ue.map(({render:K,...O})=>O)}),t.jsx("button",{type:"button",className:"hn-terminal-action",onClick:C,title:"Layar penuh — fokus 1 terminal","aria-label":`Layar penuh sesi ${e.id}`,children:t.jsx(ve,{name:"fullscreen",size:12})}),t.jsx("button",{type:"button",className:"hn-terminal-action","aria-label":`Tutup sesi ${e.id}`,onClick:a,children:"×"})]})]}),t.jsxs("div",{style:{display:"flex",flexDirection:"column",flex:1,minHeight:0,opacity:e.exited?.6:1},children:[t.jsx(Or,{phases:S}),t.jsx("div",{style:{flex:1,minHeight:0},children:f?t.jsx("div",{style:{height:"100%",display:"grid",placeItems:"center",padding:12,color:"var(--text-subtle)",fontSize:12,textAlign:"center"},children:"Terbuka di layar penuh"}):t.jsx(Ot,{sessionId:e.id,onExit:u,onPhases:M,fontSize:D,showKeys:z,predict:E,diag:k},e.id)})]}),x&&e.specId&&t.jsx(gn,{specId:e.specId,onClose:()=>G(!1)}),U&&ie&&T&&t.jsx(gt,{projectId:ie.projectId,ownBranch:`hanoman/${ie.id.toLowerCase().replace(/[^a-z0-9_-]/g,"_")}`,eyebrow:ie.id,onClose:()=>L(!1),onIntegrate:(K,O)=>{L(!1),T(ie,K,O)}}),Y&&X&&g&&t.jsx(gt,{projectId:e.projectId,ownBranch:e.branch,eyebrow:e.id.slice(0,16),onClose:()=>ae(!1),onIntegrate:(K,O)=>{ae(!1),g(e,K,O)}})]})}function _r({session:e,label:n,fontSize:a,showKeys:i,predict:s,diag:u,onClose:v}){return t.jsx(Be,{open:!0,icon:"terminal",title:n,onClose:v,closeOnEscape:!1,width:1600,children:t.jsx("div",{style:{height:"min(72vh, calc(100dvh - 180px))",minHeight:0,display:"flex",flexDirection:"column",opacity:e.exited?.6:1},children:t.jsx(Ot,{sessionId:e.id,onExit:()=>{},fontSize:a,showKeys:i,predict:s,diag:u},e.id)})})}function Kr({unplaced:e,nameOf:n,onPick:a,disabled:i}){return t.jsx("div",{style:{flex:1,display:"grid",placeItems:"center",padding:12},children:t.jsx(pe,{size:"sm",value:"","aria-label":"Pilih sesi untuk sel",disabled:i||!e.length,onChange:s=>s.target.value&&a(s.target.value),options:[{value:"",label:e.length?"Pilih sesi…":"tidak ada sesi bebas"}].concat(e.map(s=>({value:s.id,label:`${s.specId??n(s.projectId)} · ${s.id.slice(0,6)}`})))})})}export{Or as PhaseStrip,Xr as TerminalScreen};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{e as y,j as e,a as d,f as T,B as C,h as H,o as V,r as Y,t as X,q as Z,S as F,d as U,m as ee,R as te,v as ae,w as ie,p as A,x as se,I as le,y as ne,u as re,c as W,H as oe,z as O,A as q,C as ce,D as de}from"./index-DSFIYjSl.js";import{R as l}from"./react-DfGhg7ZW.js";import{L as ue}from"./live-BhsIWS2g.js";import"./markdown-CWEY34jk.js";function pe(s,c){return s==="rejected"?"Ditutup":s!=="accepted"?"Sedang ditinjau":c==="done"?"Selesai":c==="executing"?"Sedang dikerjakan":"Diterima"}const he=5e3,$=20,me=400;function M({total:s,page:c,onPage:j,unit:p="tiket"}){const n=de(s,c,$);return e.jsx(ie,{page:n.page,pageCount:n.pageCount,total:s,from:n.from,to:n.to,onPage:j,unit:p})}function Q(s,c=Date.now()){const j=Math.max(0,c-new Date(s).getTime()),p=Math.floor(j/6e4);if(p<1)return"baru saja";if(p<60)return`${p}m`;const n=Math.floor(p/60);return n<24?`${n}j`:`${Math.floor(n/24)}h`}const K={new:"warn",accepted:"ok",rejected:"neutral"},J={new:"belum ditinjau",accepted:"diterima",rejected:"ditutup"};function ge({t:s,onOpen:c}){return e.jsxs("button",{onClick:()=>c(s.id),className:"hn-dense-row",style:{display:"flex",alignItems:"center",gap:12,width:"100%",textAlign:"left",padding:"12px 14px",border:"1px solid var(--border-hair)",borderRadius:"var(--radius-md)",background:"var(--surface-card)",cursor:"pointer",marginBottom:8},children:[e.jsxs("span",{style:{flex:1,minWidth:0},children:[e.jsxs("span",{style:{display:"flex",alignItems:"center",gap:8},children:[e.jsxs("span",{style:{fontFamily:"var(--font-mono)",fontWeight:600,color:"var(--text-strong)"},children:["#",s.number]}),e.jsx(C,{tone:"neutral",size:"sm",children:s.category}),e.jsx(C,{tone:K[s.status]??"neutral",size:"sm",children:J[s.status]??s.status})]}),e.jsx("span",{style:{display:"block",color:"var(--text-body)",fontSize:"var(--text-sm)",marginTop:2,overflow:"hidden",textOverflow:"ellipsis",whiteSpace:"nowrap"},children:s.title}),e.jsxs("span",{style:{fontSize:"var(--text-xs)",color:"var(--text-subtle)",marginTop:2,display:"block"},children:[s.projectId," · ",s.reporterEmail," · ",Q(s.createdAt)," lalu",s.attachmentCount>0?` · ${s.attachmentCount} lampiran`:""]})]}),s.specId&&e.jsxs(C,{tone:"ok",icon:"link",children:["→ ",s.specId]}),e.jsx(le,{name:"chevron-right",size:16,color:"var(--text-subtle)"})]})}function xe({id:s,onBack:c,onAccepted:j,onDeleted:p,onToast:n}){var R;const[i,k]=l.useState(null),[h,z]=l.useState("loading"),[m,u]=l.useState(!1),[g,x]=l.useState("sedang"),[P,b]=l.useState(!1),[f,B]=l.useState(!1),{confirm:v,dialog:S}=re(),[r,I]=l.useState({title:"",detail:"",category:"bug",status:"new"}),w=l.useCallback(()=>{y.getTicket(s).then(t=>{k(t),z("ready")}).catch(()=>z("error"))},[s]);if(l.useEffect(()=>{w()},[w]),h==="loading")return e.jsx(T,{kind:"loading"});if(h==="error"||!i)return e.jsx(T,{kind:"error",hint:"Gagal memuat tiket.",action:w,actionLabel:"Coba lagi"});async function L(){u(!0);try{const t=await y.acceptTicket(s,g);j(t.spec,!!t.alreadyPromoted)}catch{n("Gagal menerima tiket","err","x-circle")}finally{u(!1)}}async function E(){if(await v({title:`Tolak & tutup tiket #${i.number}?`,message:`"${i.title}" ditutup tanpa membuat backlog item.`,confirmLabel:"Tolak tiket",icon:"x-circle"})){u(!0);try{await y.rejectTicket(s),k({...i,status:"rejected"}),n("Tiket ditutup","ok","check")}catch{n("Gagal menolak tiket","err","x-circle")}finally{u(!1)}}}async function a(){u(!0);try{const t=await y.unlinkTicket(s);k({...i,specId:t.specId,spec:null,status:t.status}),n("Tautan backlog dilepas","ok","unlink")}catch{n("Gagal melepas tautan","err","x-circle")}finally{u(!1)}}function o(){I({title:i.title,detail:i.detail,category:i.category,status:i.status}),b(!0)}async function D(){u(!0);try{const t=await y.editTicket(s,{title:r.title,detail:r.detail,category:r.category,status:r.status});k(t),b(!1),n("Tiket diperbarui","ok")}catch{n("Gagal menyimpan","err","x-circle")}finally{u(!1)}}async function N(){u(!0);try{await y.deleteTicket(s),n("Tiket dihapus","ok","trash-2"),p()}catch{n("Gagal menghapus","err","x-circle"),u(!1)}}if(P)return e.jsxs("div",{style:{display:"flex",flexDirection:"column",gap:14},children:[e.jsxs("div",{style:{display:"flex",alignItems:"center",gap:10},children:[e.jsx(d,{size:"sm",variant:"ghost",leftIcon:"arrow-left",onClick:()=>b(!1),disabled:m,children:"Batal"}),e.jsx("span",{style:{flex:1}}),e.jsx(d,{size:"sm",variant:"primary",leftIcon:"check",onClick:D,disabled:m,children:"Simpan"})]}),e.jsx(W,{label:"Judul",children:e.jsx(U,{value:r.title,placeholder:"mis. Tombol Simpan tak berfungsi di HP",onChange:t=>I({...r,title:t.target.value})})}),e.jsxs("div",{style:{display:"flex",gap:10,flexWrap:"wrap"},children:[e.jsx(W,{label:"Kategori",children:e.jsx(F,{value:r.category,onChange:t=>I({...r,category:t.target.value}),options:[{value:"bug",label:"bug"},{value:"fitur",label:"fitur"},{value:"pertanyaan",label:"pertanyaan"},{value:"lainnya",label:"lainnya"}]})}),e.jsx(W,{label:"Status",children:e.jsx(F,{value:r.status,onChange:t=>I({...r,status:t.target.value}),options:[{value:"new",label:"belum ditinjau"},{value:"accepted",label:"diterima"},{value:"rejected",label:"ditutup"}]})})]}),e.jsx(W,{label:"Detail keluhan",children:e.jsx(oe,{value:r.detail,rows:6,placeholder:"mis. Buka halaman Pesanan di HP, tekan Simpan — layar diam dan datanya tak tersimpan.",onChange:t=>I({...r,detail:t.target.value})})})]});const _=i.status!=="new";return e.jsxs("div",{style:{display:"flex",flexDirection:"column",gap:14},children:[e.jsxs("div",{style:{display:"flex",alignItems:"center",gap:10,flexWrap:"wrap"},children:[e.jsx(d,{size:"sm",variant:"ghost",leftIcon:"arrow-left",onClick:c,children:"Kembali"}),e.jsx(C,{tone:K[i.status]??"neutral",children:J[i.status]??i.status}),e.jsx("span",{style:{flex:1}}),e.jsx(d,{size:"sm",variant:"ghost",leftIcon:"pencil",onClick:o,disabled:m,children:"Ubah"}),e.jsx(d,{size:"sm",variant:"ghost",leftIcon:"trash-2",onClick:()=>B(!0),disabled:m,children:"Hapus"}),i.publicStatusUrl&&e.jsxs(e.Fragment,{children:[e.jsx(d,{size:"sm",variant:"ghost",leftIcon:"share-2",onClick:()=>window.open(i.publicStatusUrl,"_blank","noreferrer"),children:"Buka status publik"}),e.jsx(d,{size:"sm",variant:"ghost",leftIcon:"link-2",onClick:()=>{var t;(t=navigator.clipboard)==null||t.writeText(i.publicStatusUrl),n("Link publik disalin","ok","copy")},children:"Salin link publik"})]}),i.specId?e.jsxs(e.Fragment,{children:[e.jsxs(C,{tone:"ok",icon:"link",children:["→ ",i.specId]}),e.jsx(C,{tone:"neutral",size:"sm",children:pe(i.status,(R=i.spec)==null?void 0:R.stage)}),e.jsx(d,{size:"sm",variant:"ghost",leftIcon:"external-link",onClick:()=>window.open(O(i.specId),"_blank","noreferrer"),children:"Buka backlog"}),e.jsx(d,{size:"sm",variant:"ghost",leftIcon:"copy",onClick:()=>{var t;(t=navigator.clipboard)==null||t.writeText(O(i.specId)),n("Link backlog disalin","ok","copy")},children:"Salin link"}),e.jsx(d,{size:"sm",variant:"ghost",leftIcon:"unlink",onClick:a,disabled:m,children:"Lepas tautan"})]}):!_&&e.jsxs(e.Fragment,{children:[e.jsx(F,{size:"sm",value:g,onChange:t=>x(t.target.value),options:[{value:"tinggi",label:"Prioritas tinggi"},{value:"sedang",label:"Prioritas sedang"},{value:"rendah",label:"Prioritas rendah"}]}),e.jsx(d,{size:"sm",leftIcon:"arrow-up-right",onClick:L,disabled:m,children:"Terima → backlog"}),e.jsx(d,{size:"sm",variant:"ghost",leftIcon:"ban",onClick:E,disabled:m,children:"Tolak"})]})]}),e.jsxs("div",{children:[e.jsxs("div",{style:{display:"flex",alignItems:"center",gap:8},children:[e.jsxs("span",{style:{fontFamily:"var(--font-mono)",fontWeight:600,color:"var(--text-strong)"},children:["#",i.number]}),e.jsx(C,{tone:"neutral",size:"sm",children:i.category})]}),e.jsx("div",{style:{fontWeight:600,fontSize:"var(--text-lg)",color:"var(--text-strong)",marginTop:4},children:i.title})]}),e.jsxs("div",{style:{display:"flex",gap:18,flexWrap:"wrap",fontSize:"var(--text-sm)",color:"var(--text-muted)"},children:[e.jsxs("span",{children:["pelapor: ",e.jsx("b",{style:{color:"var(--text-body)"},children:i.reporterEmail})]}),e.jsxs("span",{children:["project: ",e.jsx("b",{style:{color:"var(--text-body)"},children:i.projectId})]}),e.jsxs("span",{children:["masuk: ",Q(i.createdAt)," lalu"]})]}),e.jsxs("div",{children:[e.jsx("div",{className:"hn-eyebrow",style:{marginBottom:6},children:"Detail keluhan"}),e.jsx("div",{style:{whiteSpace:"pre-wrap",color:"var(--text-body)",fontSize:"var(--text-sm)",lineHeight:1.55},children:i.detail})]}),i.attachments.length>0&&e.jsxs("div",{children:[e.jsx("div",{className:"hn-eyebrow",style:{marginBottom:6},children:"Lampiran"}),e.jsx("div",{style:{display:"flex",gap:10,flexWrap:"wrap"},children:i.attachments.map(t=>e.jsx("a",{href:q.ticketAttachment(i.id,t.id),target:"_blank",rel:"noreferrer",style:{display:"block",border:"1px solid var(--border-hair)",borderRadius:"var(--radius-sm)",overflow:"hidden"},children:e.jsx("img",{src:q.ticketAttachment(i.id,t.id),alt:t.filename,style:{display:"block",maxWidth:180,maxHeight:140,objectFit:"cover"}})},t.id))})]}),e.jsx(ce,{open:f,title:"Hapus tiket?",eyebrow:`#${i.number}`,message:`Tiket "${i.title}" dan seluruh lampirannya akan dihapus permanen. Tindakan ini tak bisa dibatalkan.`,busy:m,onCancel:()=>B(!1),onConfirm:N}),S]})}function fe({projectId:s,onAccepted:c}){const[j,p]=l.useState([]),[n,i]=l.useState("loading"),[k,h]=l.useState(!1),[z,m]=l.useState(null),[u,g]=l.useState(null),[x,P]=l.useState([]),[b,f]=l.useState(0),[B,v]=l.useState(1),S=l.useCallback(async()=>{try{const a=await y.listGithubIssues(s,{page:B,limit:$});p(a.items),f(a.total),i("ready")}catch{i("error")}},[s,B]);l.useEffect(()=>{S()},[S]);const r=a=>{var D;const o=(D=a.detail)==null?void 0:D.error;return typeof o=="string"?o:a.message};async function I(){h(!0),g(null),m(null);try{const a=await y.pullGithubIssues(s);m(`${a.repo}: ${a.created} baru, ${a.updated} diperbarui`+(a.skippedPullRequests?` · ${a.skippedPullRequests} pull request dilewati`:"")),await S()}catch(a){g(r(a))}finally{h(!1)}}async function w(){h(!0),g(null);try{const a=await y.acceptGithubIssues(x,void 0);P([]),c==null||c(a.created),await S()}catch(a){g(r(a))}finally{h(!1)}}async function L(a){h(!0),g(null);try{await y.rejectGithubIssue(a),await S()}catch(o){g(r(o))}finally{h(!1)}}const E=a=>P(o=>o.includes(a)?o.filter(D=>D!==a):[...o,a]);return e.jsxs("div",{style:{display:"flex",flexDirection:"column",gap:12,minHeight:0,flex:1},children:[e.jsxs("div",{style:{display:"flex",gap:8,alignItems:"center",flexWrap:"wrap"},children:[e.jsx(d,{size:"sm",onClick:I,disabled:k,children:"Tarik issue"}),e.jsxs(d,{size:"sm",variant:"primary",onClick:w,disabled:k||x.length===0,children:["Terima terpilih",x.length?` (${x.length})`:""]}),z&&e.jsx("span",{style:{fontSize:12,color:"var(--text-muted)"},children:z})]}),u&&e.jsx("div",{role:"alert",style:{fontSize:12,color:"var(--danger, #b00)"},children:u}),n==="loading"?e.jsx(T,{kind:"loading"}):n==="error"?e.jsx(T,{kind:"error",hint:"Gagal memuat daftar issue.",action:()=>void S(),actionLabel:"Coba lagi"}):j.length===0?e.jsx(T,{kind:"empty",icon:"inbox",title:"Belum ada issue tertarik",hint:"Tekan “Tarik issue” untuk menariknya dari repo GitHub project ini."}):e.jsxs(e.Fragment,{children:[e.jsx("div",{style:{overflowY:"auto",minHeight:0},children:j.map(a=>e.jsxs("div",{className:"hn-dense-row",style:{display:"flex",gap:8,alignItems:"baseline",padding:"8px 0",borderBottom:"1px solid var(--border-hair)"},children:[a.status==="new"&&e.jsx("input",{type:"checkbox","aria-label":`Pilih issue ${a.number}`,checked:x.includes(a.id),onChange:()=>E(a.id)}),e.jsxs("span",{style:{fontFamily:"var(--font-mono)",fontSize:12,color:"var(--text-muted)"},children:["#",a.number]}),e.jsx("a",{href:a.url,target:"_blank",rel:"noreferrer",style:{flex:1,minWidth:0},children:a.title}),e.jsxs("span",{style:{fontSize:12,color:"var(--text-muted)"},children:["@",a.authorLogin]}),a.labels.map(o=>e.jsx(C,{children:o},o)),a.status==="rejected"&&e.jsx(C,{tone:"neutral",children:"ditutup"}),a.specId&&e.jsx("span",{style:{fontFamily:"var(--font-mono)",fontSize:12},children:a.specId}),a.status==="new"&&e.jsx(d,{size:"sm",variant:"ghost",onClick:()=>L(a.id),disabled:k,children:"Tolak"})]},a.id))}),e.jsx(M,{total:b,page:B,onPage:v,unit:"issue"})]})]})}function ve({projects:s,onAccepted:c,onToast:j}){const[p,n]=l.useState([]),[i,k]=l.useState(0),[h,z]=H("triage","page",1,se),[m,u]=l.useState(0),[g,x]=l.useState("loading"),[P,b]=H("triage","openId",null,ne),[f,B]=H("triage","project","",A),[v,S]=H("triage","status","",A),[r,I]=H("triage","q","",A),[w,L]=H("triage","tab","tiket",V("tiket","issue")),E=[f!=="",v!=="",r.trim()!==""].filter(Boolean).length,a=Y("triage","scroll",p.length>0),o=l.useCallback((t=!1)=>{t||x("loading"),y.listTickets({project:f||void 0,status:v||void 0,q:r||void 0,page:String(h),limit:String($)}).then(G=>{n(G.items),k(G.total),u(G.unreviewed),x("ready")}).catch(()=>{t||x("error")})},[f,v,r,h]);l.useEffect(()=>{o()},[o]),X(JSON.stringify([f,v,r]),()=>z(1));const[D,N]=l.useState(r);l.useEffect(()=>{const t=setTimeout(()=>N(r),me);return()=>clearTimeout(t)},[r]),Z({topic:"tickets",params:{project:f||void 0,status:v||void 0,q:D||void 0,page:h,limit:$},apply:t=>{n(t.data.items),k(t.data.total),u(t.data.unreviewed),x("ready")},refetch:()=>o(!0),pollMs:he});const _=e.jsx("div",{style:{display:"flex",flexDirection:"column",gap:12,minHeight:0,flex:1},children:f?e.jsx(fe,{projectId:f,onAccepted:t=>t.forEach(G=>c(G,!1))}):e.jsx(T,{kind:"empty",icon:"inbox",title:"Pilih satu project",hint:"Issue GitHub milik satu repo, jadi pilih project-nya lebih dulu di penyaring di atas."})}),R=e.jsx("div",{style:{display:"flex",flexDirection:"column",flex:1,minHeight:0},children:g==="loading"?e.jsx(T,{kind:"loading"}):g==="error"?e.jsx(T,{kind:"error",hint:"Gagal memuat tiket.",action:()=>o(),actionLabel:"Coba lagi"}):p.length===0?e.jsx(T,{kind:"empty",icon:"inbox",title:"Belum ada keluhan",hint:"Aktifkan Help Center di detail project, lalu sebar link publiknya agar keluhan mulai masuk."}):e.jsxs(e.Fragment,{children:[e.jsx("div",{ref:a,"data-testid":"triage-scroll",style:{overflowY:"auto",minHeight:0,flex:"1 1 auto"},children:p.map(t=>e.jsx(ge,{t,onOpen:b},t.id))}),e.jsx(M,{total:i,page:h,onPage:z})]})});return e.jsxs("div",{style:{display:"flex",flexDirection:"column",gap:14,minHeight:0,flex:1},children:[e.jsxs("div",{className:"hn-wrap-mobile",style:{display:"flex",gap:8,alignItems:"center"},children:[e.jsx(d,{size:"sm",variant:w==="tiket"?"primary":"ghost",onClick:()=>L("tiket"),children:"Tiket Help Center"}),e.jsx(d,{size:"sm",variant:w==="issue"?"primary":"ghost",onClick:()=>L("issue"),children:"Issue GitHub"})]}),e.jsxs("div",{style:{display:"flex",gap:10,flexWrap:"wrap",alignItems:"center"},children:[e.jsx(F,{size:"sm",value:f,"aria-label":"Project triase",onChange:t=>B(t.target.value),options:[{value:"",label:"Semua project"},...s.map(t=>({value:t.id,label:t.name}))]}),w==="tiket"&&e.jsxs(e.Fragment,{children:[e.jsx(F,{size:"sm",value:v,"aria-label":"Status tiket",onChange:t=>S(t.target.value),options:[{value:"",label:"Semua status"},{value:"new",label:"belum ditinjau"},{value:"accepted",label:"diterima"},{value:"rejected",label:"ditutup"}]}),e.jsx(U,{size:"sm",value:r,"aria-label":"Cari tiket",onChange:t=>I(t.target.value),placeholder:"mis. gagal login atau budi@contoh.id",style:{flex:1,minWidth:160}}),m>0&&e.jsxs(C,{tone:"warn",children:[m," belum ditinjau"]}),e.jsx(ee,{onDone:()=>o(!0),onToast:j}),e.jsx(te,{screen:"triage",active:E}),e.jsx(ue,{})]})]}),w==="issue"?_:e.jsx(ae,{ariaLabel:"Panel triase",active:P?"detail":"list",onActiveChange:t=>{t==="list"&&b(null)},splitAt:"tablet",masterWidth:360,panels:[{id:"list",label:"Daftar",content:R,className:"hn-panel-flex"},...P?[{id:"detail",label:"Detail",className:"hn-panel-flex",content:e.jsx(xe,{id:P,onBack:()=>{b(null),o(!0)},onAccepted:c,onDeleted:()=>{b(null),o(!0)},onToast:j})}]:[]]})]})}export{fe as GithubIssuesPanel,ve as TriageScreen};
|
|
1
|
+
import{e as y,j as e,a as d,f as T,B as C,h as H,o as V,r as Y,t as X,q as Z,S as F,d as U,m as ee,R as te,v as ae,w as ie,p as A,x as se,I as le,y as ne,u as re,c as W,H as oe,z as O,A as q,C as ce,D as de}from"./index-DI7G_sit.js";import{R as l}from"./react-DfGhg7ZW.js";import{L as ue}from"./live-DVDstDzi.js";import"./markdown-CWEY34jk.js";function pe(s,c){return s==="rejected"?"Ditutup":s!=="accepted"?"Sedang ditinjau":c==="done"?"Selesai":c==="executing"?"Sedang dikerjakan":"Diterima"}const he=5e3,$=20,me=400;function M({total:s,page:c,onPage:j,unit:p="tiket"}){const n=de(s,c,$);return e.jsx(ie,{page:n.page,pageCount:n.pageCount,total:s,from:n.from,to:n.to,onPage:j,unit:p})}function Q(s,c=Date.now()){const j=Math.max(0,c-new Date(s).getTime()),p=Math.floor(j/6e4);if(p<1)return"baru saja";if(p<60)return`${p}m`;const n=Math.floor(p/60);return n<24?`${n}j`:`${Math.floor(n/24)}h`}const K={new:"warn",accepted:"ok",rejected:"neutral"},J={new:"belum ditinjau",accepted:"diterima",rejected:"ditutup"};function ge({t:s,onOpen:c}){return e.jsxs("button",{onClick:()=>c(s.id),className:"hn-dense-row",style:{display:"flex",alignItems:"center",gap:12,width:"100%",textAlign:"left",padding:"12px 14px",border:"1px solid var(--border-hair)",borderRadius:"var(--radius-md)",background:"var(--surface-card)",cursor:"pointer",marginBottom:8},children:[e.jsxs("span",{style:{flex:1,minWidth:0},children:[e.jsxs("span",{style:{display:"flex",alignItems:"center",gap:8},children:[e.jsxs("span",{style:{fontFamily:"var(--font-mono)",fontWeight:600,color:"var(--text-strong)"},children:["#",s.number]}),e.jsx(C,{tone:"neutral",size:"sm",children:s.category}),e.jsx(C,{tone:K[s.status]??"neutral",size:"sm",children:J[s.status]??s.status})]}),e.jsx("span",{style:{display:"block",color:"var(--text-body)",fontSize:"var(--text-sm)",marginTop:2,overflow:"hidden",textOverflow:"ellipsis",whiteSpace:"nowrap"},children:s.title}),e.jsxs("span",{style:{fontSize:"var(--text-xs)",color:"var(--text-subtle)",marginTop:2,display:"block"},children:[s.projectId," · ",s.reporterEmail," · ",Q(s.createdAt)," lalu",s.attachmentCount>0?` · ${s.attachmentCount} lampiran`:""]})]}),s.specId&&e.jsxs(C,{tone:"ok",icon:"link",children:["→ ",s.specId]}),e.jsx(le,{name:"chevron-right",size:16,color:"var(--text-subtle)"})]})}function xe({id:s,onBack:c,onAccepted:j,onDeleted:p,onToast:n}){var R;const[i,k]=l.useState(null),[h,z]=l.useState("loading"),[m,u]=l.useState(!1),[g,x]=l.useState("sedang"),[P,b]=l.useState(!1),[f,B]=l.useState(!1),{confirm:v,dialog:S}=re(),[r,I]=l.useState({title:"",detail:"",category:"bug",status:"new"}),w=l.useCallback(()=>{y.getTicket(s).then(t=>{k(t),z("ready")}).catch(()=>z("error"))},[s]);if(l.useEffect(()=>{w()},[w]),h==="loading")return e.jsx(T,{kind:"loading"});if(h==="error"||!i)return e.jsx(T,{kind:"error",hint:"Gagal memuat tiket.",action:w,actionLabel:"Coba lagi"});async function L(){u(!0);try{const t=await y.acceptTicket(s,g);j(t.spec,!!t.alreadyPromoted)}catch{n("Gagal menerima tiket","err","x-circle")}finally{u(!1)}}async function E(){if(await v({title:`Tolak & tutup tiket #${i.number}?`,message:`"${i.title}" ditutup tanpa membuat backlog item.`,confirmLabel:"Tolak tiket",icon:"x-circle"})){u(!0);try{await y.rejectTicket(s),k({...i,status:"rejected"}),n("Tiket ditutup","ok","check")}catch{n("Gagal menolak tiket","err","x-circle")}finally{u(!1)}}}async function a(){u(!0);try{const t=await y.unlinkTicket(s);k({...i,specId:t.specId,spec:null,status:t.status}),n("Tautan backlog dilepas","ok","unlink")}catch{n("Gagal melepas tautan","err","x-circle")}finally{u(!1)}}function o(){I({title:i.title,detail:i.detail,category:i.category,status:i.status}),b(!0)}async function D(){u(!0);try{const t=await y.editTicket(s,{title:r.title,detail:r.detail,category:r.category,status:r.status});k(t),b(!1),n("Tiket diperbarui","ok")}catch{n("Gagal menyimpan","err","x-circle")}finally{u(!1)}}async function N(){u(!0);try{await y.deleteTicket(s),n("Tiket dihapus","ok","trash-2"),p()}catch{n("Gagal menghapus","err","x-circle"),u(!1)}}if(P)return e.jsxs("div",{style:{display:"flex",flexDirection:"column",gap:14},children:[e.jsxs("div",{style:{display:"flex",alignItems:"center",gap:10},children:[e.jsx(d,{size:"sm",variant:"ghost",leftIcon:"arrow-left",onClick:()=>b(!1),disabled:m,children:"Batal"}),e.jsx("span",{style:{flex:1}}),e.jsx(d,{size:"sm",variant:"primary",leftIcon:"check",onClick:D,disabled:m,children:"Simpan"})]}),e.jsx(W,{label:"Judul",children:e.jsx(U,{value:r.title,placeholder:"mis. Tombol Simpan tak berfungsi di HP",onChange:t=>I({...r,title:t.target.value})})}),e.jsxs("div",{style:{display:"flex",gap:10,flexWrap:"wrap"},children:[e.jsx(W,{label:"Kategori",children:e.jsx(F,{value:r.category,onChange:t=>I({...r,category:t.target.value}),options:[{value:"bug",label:"bug"},{value:"fitur",label:"fitur"},{value:"pertanyaan",label:"pertanyaan"},{value:"lainnya",label:"lainnya"}]})}),e.jsx(W,{label:"Status",children:e.jsx(F,{value:r.status,onChange:t=>I({...r,status:t.target.value}),options:[{value:"new",label:"belum ditinjau"},{value:"accepted",label:"diterima"},{value:"rejected",label:"ditutup"}]})})]}),e.jsx(W,{label:"Detail keluhan",children:e.jsx(oe,{value:r.detail,rows:6,placeholder:"mis. Buka halaman Pesanan di HP, tekan Simpan — layar diam dan datanya tak tersimpan.",onChange:t=>I({...r,detail:t.target.value})})})]});const _=i.status!=="new";return e.jsxs("div",{style:{display:"flex",flexDirection:"column",gap:14},children:[e.jsxs("div",{style:{display:"flex",alignItems:"center",gap:10,flexWrap:"wrap"},children:[e.jsx(d,{size:"sm",variant:"ghost",leftIcon:"arrow-left",onClick:c,children:"Kembali"}),e.jsx(C,{tone:K[i.status]??"neutral",children:J[i.status]??i.status}),e.jsx("span",{style:{flex:1}}),e.jsx(d,{size:"sm",variant:"ghost",leftIcon:"pencil",onClick:o,disabled:m,children:"Ubah"}),e.jsx(d,{size:"sm",variant:"ghost",leftIcon:"trash-2",onClick:()=>B(!0),disabled:m,children:"Hapus"}),i.publicStatusUrl&&e.jsxs(e.Fragment,{children:[e.jsx(d,{size:"sm",variant:"ghost",leftIcon:"share-2",onClick:()=>window.open(i.publicStatusUrl,"_blank","noreferrer"),children:"Buka status publik"}),e.jsx(d,{size:"sm",variant:"ghost",leftIcon:"link-2",onClick:()=>{var t;(t=navigator.clipboard)==null||t.writeText(i.publicStatusUrl),n("Link publik disalin","ok","copy")},children:"Salin link publik"})]}),i.specId?e.jsxs(e.Fragment,{children:[e.jsxs(C,{tone:"ok",icon:"link",children:["→ ",i.specId]}),e.jsx(C,{tone:"neutral",size:"sm",children:pe(i.status,(R=i.spec)==null?void 0:R.stage)}),e.jsx(d,{size:"sm",variant:"ghost",leftIcon:"external-link",onClick:()=>window.open(O(i.specId),"_blank","noreferrer"),children:"Buka backlog"}),e.jsx(d,{size:"sm",variant:"ghost",leftIcon:"copy",onClick:()=>{var t;(t=navigator.clipboard)==null||t.writeText(O(i.specId)),n("Link backlog disalin","ok","copy")},children:"Salin link"}),e.jsx(d,{size:"sm",variant:"ghost",leftIcon:"unlink",onClick:a,disabled:m,children:"Lepas tautan"})]}):!_&&e.jsxs(e.Fragment,{children:[e.jsx(F,{size:"sm",value:g,onChange:t=>x(t.target.value),options:[{value:"tinggi",label:"Prioritas tinggi"},{value:"sedang",label:"Prioritas sedang"},{value:"rendah",label:"Prioritas rendah"}]}),e.jsx(d,{size:"sm",leftIcon:"arrow-up-right",onClick:L,disabled:m,children:"Terima → backlog"}),e.jsx(d,{size:"sm",variant:"ghost",leftIcon:"ban",onClick:E,disabled:m,children:"Tolak"})]})]}),e.jsxs("div",{children:[e.jsxs("div",{style:{display:"flex",alignItems:"center",gap:8},children:[e.jsxs("span",{style:{fontFamily:"var(--font-mono)",fontWeight:600,color:"var(--text-strong)"},children:["#",i.number]}),e.jsx(C,{tone:"neutral",size:"sm",children:i.category})]}),e.jsx("div",{style:{fontWeight:600,fontSize:"var(--text-lg)",color:"var(--text-strong)",marginTop:4},children:i.title})]}),e.jsxs("div",{style:{display:"flex",gap:18,flexWrap:"wrap",fontSize:"var(--text-sm)",color:"var(--text-muted)"},children:[e.jsxs("span",{children:["pelapor: ",e.jsx("b",{style:{color:"var(--text-body)"},children:i.reporterEmail})]}),e.jsxs("span",{children:["project: ",e.jsx("b",{style:{color:"var(--text-body)"},children:i.projectId})]}),e.jsxs("span",{children:["masuk: ",Q(i.createdAt)," lalu"]})]}),e.jsxs("div",{children:[e.jsx("div",{className:"hn-eyebrow",style:{marginBottom:6},children:"Detail keluhan"}),e.jsx("div",{style:{whiteSpace:"pre-wrap",color:"var(--text-body)",fontSize:"var(--text-sm)",lineHeight:1.55},children:i.detail})]}),i.attachments.length>0&&e.jsxs("div",{children:[e.jsx("div",{className:"hn-eyebrow",style:{marginBottom:6},children:"Lampiran"}),e.jsx("div",{style:{display:"flex",gap:10,flexWrap:"wrap"},children:i.attachments.map(t=>e.jsx("a",{href:q.ticketAttachment(i.id,t.id),target:"_blank",rel:"noreferrer",style:{display:"block",border:"1px solid var(--border-hair)",borderRadius:"var(--radius-sm)",overflow:"hidden"},children:e.jsx("img",{src:q.ticketAttachment(i.id,t.id),alt:t.filename,style:{display:"block",maxWidth:180,maxHeight:140,objectFit:"cover"}})},t.id))})]}),e.jsx(ce,{open:f,title:"Hapus tiket?",eyebrow:`#${i.number}`,message:`Tiket "${i.title}" dan seluruh lampirannya akan dihapus permanen. Tindakan ini tak bisa dibatalkan.`,busy:m,onCancel:()=>B(!1),onConfirm:N}),S]})}function fe({projectId:s,onAccepted:c}){const[j,p]=l.useState([]),[n,i]=l.useState("loading"),[k,h]=l.useState(!1),[z,m]=l.useState(null),[u,g]=l.useState(null),[x,P]=l.useState([]),[b,f]=l.useState(0),[B,v]=l.useState(1),S=l.useCallback(async()=>{try{const a=await y.listGithubIssues(s,{page:B,limit:$});p(a.items),f(a.total),i("ready")}catch{i("error")}},[s,B]);l.useEffect(()=>{S()},[S]);const r=a=>{var D;const o=(D=a.detail)==null?void 0:D.error;return typeof o=="string"?o:a.message};async function I(){h(!0),g(null),m(null);try{const a=await y.pullGithubIssues(s);m(`${a.repo}: ${a.created} baru, ${a.updated} diperbarui`+(a.skippedPullRequests?` · ${a.skippedPullRequests} pull request dilewati`:"")),await S()}catch(a){g(r(a))}finally{h(!1)}}async function w(){h(!0),g(null);try{const a=await y.acceptGithubIssues(x,void 0);P([]),c==null||c(a.created),await S()}catch(a){g(r(a))}finally{h(!1)}}async function L(a){h(!0),g(null);try{await y.rejectGithubIssue(a),await S()}catch(o){g(r(o))}finally{h(!1)}}const E=a=>P(o=>o.includes(a)?o.filter(D=>D!==a):[...o,a]);return e.jsxs("div",{style:{display:"flex",flexDirection:"column",gap:12,minHeight:0,flex:1},children:[e.jsxs("div",{style:{display:"flex",gap:8,alignItems:"center",flexWrap:"wrap"},children:[e.jsx(d,{size:"sm",onClick:I,disabled:k,children:"Tarik issue"}),e.jsxs(d,{size:"sm",variant:"primary",onClick:w,disabled:k||x.length===0,children:["Terima terpilih",x.length?` (${x.length})`:""]}),z&&e.jsx("span",{style:{fontSize:12,color:"var(--text-muted)"},children:z})]}),u&&e.jsx("div",{role:"alert",style:{fontSize:12,color:"var(--danger, #b00)"},children:u}),n==="loading"?e.jsx(T,{kind:"loading"}):n==="error"?e.jsx(T,{kind:"error",hint:"Gagal memuat daftar issue.",action:()=>void S(),actionLabel:"Coba lagi"}):j.length===0?e.jsx(T,{kind:"empty",icon:"inbox",title:"Belum ada issue tertarik",hint:"Tekan “Tarik issue” untuk menariknya dari repo GitHub project ini."}):e.jsxs(e.Fragment,{children:[e.jsx("div",{style:{overflowY:"auto",minHeight:0},children:j.map(a=>e.jsxs("div",{className:"hn-dense-row",style:{display:"flex",gap:8,alignItems:"baseline",padding:"8px 0",borderBottom:"1px solid var(--border-hair)"},children:[a.status==="new"&&e.jsx("input",{type:"checkbox","aria-label":`Pilih issue ${a.number}`,checked:x.includes(a.id),onChange:()=>E(a.id)}),e.jsxs("span",{style:{fontFamily:"var(--font-mono)",fontSize:12,color:"var(--text-muted)"},children:["#",a.number]}),e.jsx("a",{href:a.url,target:"_blank",rel:"noreferrer",style:{flex:1,minWidth:0},children:a.title}),e.jsxs("span",{style:{fontSize:12,color:"var(--text-muted)"},children:["@",a.authorLogin]}),a.labels.map(o=>e.jsx(C,{children:o},o)),a.status==="rejected"&&e.jsx(C,{tone:"neutral",children:"ditutup"}),a.specId&&e.jsx("span",{style:{fontFamily:"var(--font-mono)",fontSize:12},children:a.specId}),a.status==="new"&&e.jsx(d,{size:"sm",variant:"ghost",onClick:()=>L(a.id),disabled:k,children:"Tolak"})]},a.id))}),e.jsx(M,{total:b,page:B,onPage:v,unit:"issue"})]})]})}function ve({projects:s,onAccepted:c,onToast:j}){const[p,n]=l.useState([]),[i,k]=l.useState(0),[h,z]=H("triage","page",1,se),[m,u]=l.useState(0),[g,x]=l.useState("loading"),[P,b]=H("triage","openId",null,ne),[f,B]=H("triage","project","",A),[v,S]=H("triage","status","",A),[r,I]=H("triage","q","",A),[w,L]=H("triage","tab","tiket",V("tiket","issue")),E=[f!=="",v!=="",r.trim()!==""].filter(Boolean).length,a=Y("triage","scroll",p.length>0),o=l.useCallback((t=!1)=>{t||x("loading"),y.listTickets({project:f||void 0,status:v||void 0,q:r||void 0,page:String(h),limit:String($)}).then(G=>{n(G.items),k(G.total),u(G.unreviewed),x("ready")}).catch(()=>{t||x("error")})},[f,v,r,h]);l.useEffect(()=>{o()},[o]),X(JSON.stringify([f,v,r]),()=>z(1));const[D,N]=l.useState(r);l.useEffect(()=>{const t=setTimeout(()=>N(r),me);return()=>clearTimeout(t)},[r]),Z({topic:"tickets",params:{project:f||void 0,status:v||void 0,q:D||void 0,page:h,limit:$},apply:t=>{n(t.data.items),k(t.data.total),u(t.data.unreviewed),x("ready")},refetch:()=>o(!0),pollMs:he});const _=e.jsx("div",{style:{display:"flex",flexDirection:"column",gap:12,minHeight:0,flex:1},children:f?e.jsx(fe,{projectId:f,onAccepted:t=>t.forEach(G=>c(G,!1))}):e.jsx(T,{kind:"empty",icon:"inbox",title:"Pilih satu project",hint:"Issue GitHub milik satu repo, jadi pilih project-nya lebih dulu di penyaring di atas."})}),R=e.jsx("div",{style:{display:"flex",flexDirection:"column",flex:1,minHeight:0},children:g==="loading"?e.jsx(T,{kind:"loading"}):g==="error"?e.jsx(T,{kind:"error",hint:"Gagal memuat tiket.",action:()=>o(),actionLabel:"Coba lagi"}):p.length===0?e.jsx(T,{kind:"empty",icon:"inbox",title:"Belum ada keluhan",hint:"Aktifkan Help Center di detail project, lalu sebar link publiknya agar keluhan mulai masuk."}):e.jsxs(e.Fragment,{children:[e.jsx("div",{ref:a,"data-testid":"triage-scroll",style:{overflowY:"auto",minHeight:0,flex:"1 1 auto"},children:p.map(t=>e.jsx(ge,{t,onOpen:b},t.id))}),e.jsx(M,{total:i,page:h,onPage:z})]})});return e.jsxs("div",{style:{display:"flex",flexDirection:"column",gap:14,minHeight:0,flex:1},children:[e.jsxs("div",{className:"hn-wrap-mobile",style:{display:"flex",gap:8,alignItems:"center"},children:[e.jsx(d,{size:"sm",variant:w==="tiket"?"primary":"ghost",onClick:()=>L("tiket"),children:"Tiket Help Center"}),e.jsx(d,{size:"sm",variant:w==="issue"?"primary":"ghost",onClick:()=>L("issue"),children:"Issue GitHub"})]}),e.jsxs("div",{style:{display:"flex",gap:10,flexWrap:"wrap",alignItems:"center"},children:[e.jsx(F,{size:"sm",value:f,"aria-label":"Project triase",onChange:t=>B(t.target.value),options:[{value:"",label:"Semua project"},...s.map(t=>({value:t.id,label:t.name}))]}),w==="tiket"&&e.jsxs(e.Fragment,{children:[e.jsx(F,{size:"sm",value:v,"aria-label":"Status tiket",onChange:t=>S(t.target.value),options:[{value:"",label:"Semua status"},{value:"new",label:"belum ditinjau"},{value:"accepted",label:"diterima"},{value:"rejected",label:"ditutup"}]}),e.jsx(U,{size:"sm",value:r,"aria-label":"Cari tiket",onChange:t=>I(t.target.value),placeholder:"mis. gagal login atau budi@contoh.id",style:{flex:1,minWidth:160}}),m>0&&e.jsxs(C,{tone:"warn",children:[m," belum ditinjau"]}),e.jsx(ee,{onDone:()=>o(!0),onToast:j}),e.jsx(te,{screen:"triage",active:E}),e.jsx(ue,{})]})]}),w==="issue"?_:e.jsx(ae,{ariaLabel:"Panel triase",active:P?"detail":"list",onActiveChange:t=>{t==="list"&&b(null)},splitAt:"tablet",masterWidth:360,panels:[{id:"list",label:"Daftar",content:R,className:"hn-panel-flex"},...P?[{id:"detail",label:"Detail",className:"hn-panel-flex",content:e.jsx(xe,{id:P,onBack:()=>{b(null),o(!0)},onAccepted:c,onDeleted:()=>{b(null),o(!0)},onToast:j})}]:[]]})]})}export{fe as GithubIssuesPanel,ve as TriageScreen};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{e as v,u as te,j as e,M as oe,f as U,I as W,a as f,h as de,o as fe,ak as be,ad as ke,c as O,d as T,a3 as ye,a7 as se,y as ve}from"./index-DSFIYjSl.js";import{R as p}from"./react-DfGhg7ZW.js";import"./markdown-CWEY34jk.js";const je={pass:"check",fail:"x",warn:"alert-triangle",na:"minus",unknown:"circle"},we={pass:"var(--leaf-600)",fail:"var(--clay-600)",warn:"var(--amber-600)",na:"var(--text-subtle)",unknown:"var(--text-subtle)"},Se={AUTO:"var(--brass-700)",AUDIT:"var(--amber-600)",INFO:"var(--text-subtle)"},Ce={critical:"var(--clay-600)",high:"var(--amber-600)",medium:"var(--text-subtle)",low:"var(--text-subtle)"};function K({text:a,color:s}){return e.jsx("span",{style:{fontSize:10,textTransform:"uppercase",letterSpacing:"0.04em",color:s,border:`1px solid ${s}`,borderRadius:3,padding:"0 4px",whiteSpace:"nowrap"},children:a})}function ce({score:a}){const s=a>=90?"var(--leaf-600)":a>=50?"var(--amber-600)":"var(--clay-600)";return e.jsxs("div",{style:{display:"flex",alignItems:"center",gap:6,minWidth:90},children:[e.jsx("div",{style:{flex:1,height:6,background:"var(--bone-200)",borderRadius:3,overflow:"hidden"},children:e.jsx("div",{style:{width:`${a}%`,height:"100%",background:s}})}),e.jsxs("span",{style:{fontSize:11,fontFamily:"var(--font-mono)",color:"var(--text-subtle)",minWidth:28,textAlign:"right"},children:[a,"%"]})]})}function Pe({item:a,busy:s,selected:l,onToggle:o,onNa:u,onAttest:c}){const n=a.mode==="AUTO"&&!a.na;return e.jsxs("div",{"data-testid":`item-${a.id}`,style:{display:"flex",alignItems:"center",gap:8,padding:"5px 0",borderBottom:"1px solid var(--border-hair)",fontSize:13,opacity:a.na?.55:1},children:[n?e.jsx("input",{type:"checkbox","aria-label":`pilih ${a.id}`,checked:l,onChange:()=>o(a)}):e.jsx("span",{style:{display:"inline-block",width:13}}),e.jsx(W,{name:je[a.status],size:14,color:we[a.status]}),e.jsx("span",{style:{flex:1,minWidth:0},children:a.title}),a.drifted&&e.jsx(K,{text:"drift",color:"var(--clay-600)"}),e.jsx(K,{text:a.mode,color:Se[a.mode]}),e.jsx(K,{text:a.severity,color:Ce[a.severity]}),a.mode==="INFO"&&!a.attested&&e.jsx(f,{size:"sm",variant:"ghost",leftIcon:"check-circle",loading:s,onClick:()=>c(a),children:"Attest"}),e.jsx(f,{size:"sm",variant:"ghost",leftIcon:a.na?"rotate-ccw":"minus-circle",loading:s,onClick:()=>u(a,!a.na),children:a.na?"Batal N/A":"N/A"})]})}const ee={section:"",mode:"",status:"",severity:""};function J({value:a,onChange:s,options:l,label:o}){return e.jsxs("select",{"aria-label":o,value:a,onChange:u=>s(u.target.value),style:{fontSize:12,padding:"3px 6px",border:"1px solid var(--border-hair)",borderRadius:"var(--radius-sm)",background:"var(--bone-50)",color:"var(--text)"},children:[e.jsxs("option",{value:"",children:[o,": semua"]}),l.map(([u,c])=>e.jsx("option",{value:u,children:c},u))]})}function ze(a){let s=0,l=0,o=0,u=0;for(const n of a)n.status==="fail"?s++:n.status==="warn"?l++:n.status==="unknown"&&o++,n.drifted&&u++;const c=[s&&`${s} fail`,l&&`${l} warn`,o&&`${o} unknown`].filter(Boolean);return{text:c.length?c.join(" "):"semua pass",drift:u}}function $e({section:a,items:s,expanded:l,onToggle:o,busy:u,selected:c,onToggleItem:n,onNa:b,onAttest:g,onSectionNa:k}){const S=ze(a.items),h=!!a.suggestion&&!a.suggestion.applicable;return e.jsxs("div",{style:{marginBottom:8,border:"1px solid var(--border-hair)",borderRadius:"var(--radius-sm)",overflow:"hidden"},children:[e.jsxs("button",{"data-testid":`section-${a.id}`,"aria-expanded":l,onClick:()=>o(a.id),style:{display:"flex",alignItems:"center",gap:8,width:"100%",padding:"8px 10px",textAlign:"left",background:l?"var(--bone-100)":"transparent",border:"none",cursor:"pointer"},children:[e.jsx(W,{name:l?"chevron-down":"chevron-right",size:15,color:"var(--text-subtle)"}),e.jsx("span",{style:{fontSize:14},children:a.icon}),e.jsx("span",{style:{fontSize:13,fontWeight:600,flex:1,minWidth:0},children:a.title}),e.jsx("span",{style:{fontSize:11,color:"var(--text-subtle)",whiteSpace:"nowrap"},children:S.text}),S.drift>0&&e.jsx(K,{text:"drift",color:"var(--clay-600)"}),h&&e.jsx(K,{text:"saran N/A",color:"var(--brass-700)"}),e.jsx(ce,{score:a.score})]}),l&&e.jsxs("div",{style:{padding:"2px 10px 8px"},children:[h&&e.jsxs("div",{"data-testid":`suggestion-${a.id}`,style:{display:"flex",alignItems:"center",gap:8,margin:"6px 0",padding:"6px 10px",fontSize:12,color:"var(--text-subtle)",background:"var(--bone-50)",border:"1px dashed var(--border-hair)",borderRadius:"var(--radius-sm)"},children:[e.jsx(W,{name:"info",size:13,color:"var(--brass-700)"}),e.jsxs("span",{style:{flex:1},children:["Stack tak terdeteksi (",a.suggestion.detail,") — kemungkinan N/A. Cek Docker manual bila ragu."]}),e.jsx(f,{size:"sm",variant:"ghost",leftIcon:"minus-circle",loading:u===`section:${a.id}`,onClick:()=>k(a),children:"Tandai seksi N/A"})]}),s.map(y=>e.jsx(Pe,{item:y,busy:u===y.id,selected:c.has(y.id),onToggle:n,onNa:b,onAttest:g},y.id))]})]})}function Ae({vpsId:a,vpsName:s,lastAuditAt:l,health:o,provisioning:u,onClose:c,onToast:n}){const[b,g]=p.useState(null),[k,S]=p.useState("loading"),[h,y]=p.useState(ee),[P,w]=p.useState(""),[B,E]=p.useState(new Set),[$,C]=p.useState(null),[R,V]=p.useState(new Set),[F,D]=p.useState(null),[A,L]=p.useState(""),I=p.useCallback(()=>{S("loading"),v.vpsChecklist(a).then(r=>{g(r),S("ready")}).catch(()=>S("error"))},[a]);p.useEffect(()=>{I(),V(new Set),D(null),E(new Set),w(""),y(ee)},[I]);const t=r=>V(j=>{const d=new Set(j);return d.has(r.id)?d.delete(r.id):d.add(r.id),d}),x=()=>{V(new Set),D(null)},m=r=>E(j=>{const d=new Set(j);return d.has(r)?d.delete(r):d.add(r),d}),{confirm:H,dialog:X}=te();async function M(){L("preview");try{D((await v.remediatePreview(a,[...R])).steps)}catch{n("Preview remediasi gagal","err","x-circle")}finally{L("")}}async function Y(){if(await H({title:`Terapkan ${R.size} item AUTO ke VPS ini?`,message:"Remediasi dijalankan langsung di server yang terdaftar.",impact:["Langkahnya idempoten dan anti-lockout.","Checklist diaudit ulang setelah selesai."],confirmLabel:"Terapkan",icon:"shield"})){L("apply");try{await v.remediate(a,[...R]),x(),I(),n("Remediasi diterapkan · audit ulang","ok","shield")}catch{n("Remediasi gagal","err","x-circle")}finally{L("")}}}async function _(r,j,d){C(r.id);try{await j(),I(),n(d,"ok","shield")}catch{n(`Gagal memperbarui ${r.id}`,"err","x-circle")}finally{C(null)}}const i=(r,j)=>_(r,()=>v.markNa(a,r.id,j,j?"ditandai dari checklist":void 0),j?`${r.id} ditandai N/A`:`${r.id} kembali applicable`),z=r=>_(r,()=>v.attestItem(a,r.id),`${r.id} di-attest`);async function N(r){const j=r.items.map(d=>d.id);if(await H({title:`Tandai ${j.length} item seksi "${r.title}" sebagai N/A?`,message:"Stack-nya tak terdeteksi — cek Docker manual bila ragu.",confirmLabel:"Tandai N/A",icon:"shield"})){C(`section:${r.id}`);try{await v.markNaBulk(a,j,!0,"app-layer: stack tak terdeteksi"),I(),n(`Seksi ${r.title} ditandai N/A`,"ok","shield")}catch{n("Gagal tandai seksi N/A","err","x-circle")}finally{C(null)}}}const G=P.trim().toLowerCase(),q=!!(h.section||h.mode||h.status||h.severity)||G!=="",me=r=>(!h.section||r.section===h.section)&&(!h.mode||r.mode===h.mode)&&(!h.status||r.status===h.status)&&(!h.severity||r.severity===h.severity)&&(!G||r.title.toLowerCase().includes(G)||r.id.toLowerCase().includes(G)||(r.code??"").toLowerCase().includes(G)),Q=r=>j=>y(d=>({...d,[r]:j}));function ge(){if(k==="loading")return e.jsx(U,{kind:"loading",compact:!0,title:"Memuat checklist…"});if(k==="error"||!b)return e.jsx(U,{kind:"error",compact:!0,title:"Gagal memuat checklist",action:I});const r=b.sections.reduce((d,Z)=>d+Z.items.filter(xe=>xe.drifted).length,0),j=b.sections.map(d=>({section:d,matched:d.items.filter(me)})).filter(d=>!q||d.matched.length>0);return e.jsxs("div",{children:[e.jsxs("div",{style:{position:"sticky",top:0,zIndex:1,background:"var(--surface-card)",paddingBottom:10},children:[e.jsxs("div",{style:{display:"flex",alignItems:"center",gap:10,marginBottom:10},children:[e.jsxs("div",{"data-testid":"score-total",style:{fontSize:22,fontWeight:700,fontFamily:"var(--font-mono)"},children:[b.scoreTotal,"%"]}),e.jsx("div",{style:{flex:1},children:e.jsx(ce,{score:b.scoreTotal})}),e.jsx("span",{style:{fontSize:11,color:"var(--text-subtle)"},children:"skor kepatuhan"})]}),r>0&&e.jsxs("div",{"data-testid":"drift-summary",style:{display:"flex",alignItems:"center",gap:6,marginBottom:10,padding:"6px 10px",fontSize:12,color:"var(--clay-700)",background:"var(--clay-50, var(--bone-100))",border:"1px solid var(--clay-600)",borderRadius:"var(--radius-sm)"},children:[e.jsx(W,{name:"alert-triangle",size:14,color:"var(--clay-600)"}),r," item drift (regresi) sejak audit sebelumnya"]}),e.jsxs("div",{style:{display:"flex",flexWrap:"wrap",gap:6,alignItems:"center"},children:[e.jsxs("div",{style:{display:"flex",alignItems:"center",gap:4,flex:"1 1 180px",border:"1px solid var(--border-hair)",borderRadius:"var(--radius-sm)",padding:"2px 8px",background:"var(--bone-50)"},children:[e.jsx(W,{name:"search",size:13,color:"var(--text-subtle)"}),e.jsx("input",{"aria-label":"cari item",value:P,onChange:d=>w(d.target.value),placeholder:"mis. ssh atau 5.2.1",style:{flex:1,border:"none",background:"transparent",fontSize:12,color:"var(--text)",outline:"none"}})]}),e.jsx(J,{label:"seksi",value:h.section,onChange:Q("section"),options:b.sections.map(d=>[d.id,d.title])}),e.jsx(J,{label:"mode",value:h.mode,onChange:Q("mode"),options:[["AUTO","AUTO"],["AUDIT","AUDIT"],["INFO","INFO"]]}),e.jsx(J,{label:"status",value:h.status,onChange:Q("status"),options:[["pass","pass"],["fail","fail"],["warn","warn"],["na","na"],["unknown","unknown"]]}),e.jsx(J,{label:"severity",value:h.severity,onChange:Q("severity"),options:[["critical","critical"],["high","high"],["medium","medium"],["low","low"]]}),q&&e.jsx(f,{size:"sm",variant:"ghost",onClick:()=>{y(ee),w("")},children:"Reset"})]}),R.size>0&&e.jsxs("div",{style:{display:"flex",alignItems:"center",gap:8,marginTop:10,padding:"8px 10px",background:"var(--bone-100)",border:"1px solid var(--brass-300)",borderRadius:"var(--radius-sm)"},children:[e.jsxs("span",{style:{fontSize:12,flex:1},children:[R.size," item AUTO dipilih"]}),e.jsx(f,{size:"sm",variant:"secondary",leftIcon:"eye",loading:A==="preview",onClick:M,children:"Preview"}),e.jsx(f,{size:"sm",leftIcon:"shield",loading:A==="apply",onClick:Y,children:"Apply"}),e.jsx(f,{size:"sm",variant:"ghost",onClick:x,children:"Batal"})]}),F&&e.jsxs("div",{"data-testid":"remediate-preview",style:{marginTop:10,padding:"8px 10px",fontSize:12,fontFamily:"var(--font-mono)",background:"var(--bone-50)",border:"1px solid var(--border-hair)",borderRadius:"var(--radius-sm)"},children:[e.jsx("div",{style:{fontWeight:600,marginBottom:4},children:"Pratinjau (dry-run) — belum diterapkan:"}),F.map(d=>e.jsxs("div",{style:{color:"var(--text-subtle)"},children:[d.item," · ",d.status," ",d.detail]},d.item))]})]}),j.length===0?e.jsx(U,{kind:"empty",compact:!0,title:"Tak ada item cocok",hint:"Ubah kata kunci atau reset filter."}):j.map(({section:d,matched:Z})=>e.jsx($e,{section:d,items:q?Z:d.items,expanded:q?!0:B.has(d.id),onToggle:m,busy:$,selected:R,onToggleItem:t,onNa:i,onAttest:z,onSectionNa:N},d.id))]})}return e.jsxs(oe,{open:!0,width:960,icon:"clipboard-list",eyebrow:s??"VPS",title:"Checklist kepatuhan",onClose:c,children:[e.jsxs("div",{"data-testid":"vps-detail",style:{fontSize:12,color:"var(--text-subtle)",marginBottom:12,paddingBottom:10,borderBottom:"1px solid var(--border-hair)"},children:[l?`Audit terakhir ${new Date(l).toLocaleString()}`:"Belum pernah diaudit",o&&` · disk ${o.disk} · mem ${o.mem} · load ${o.load}`]}),u&&e.jsx("div",{"data-testid":"vps-provisioning",style:{marginBottom:12,paddingBottom:10,borderBottom:"1px solid var(--border-hair)"},children:u}),ge(),X]})}const ne={ok:"terpasang",partial:"belum siap",absent:"belum ada"},ue={ok:"var(--leaf-600)",partial:"var(--amber-600)",absent:"var(--text-subtle)"};function pe(a,s){if(s.status==="partial"&&s.detail.startsWith("not-logged-in"))return`${a} · belum login`;if(s.status==="partial")return`${a} · ${s.detail||ne.partial}`;const l=s.status==="ok"&&s.detail?` ${s.detail}`:"";return`${a} · ${ne[s.status]??s.status}${l}`}const Ie={ok:"terpasang",partial:"belum siap",absent:"belum ada"};function he({status:a,children:s,title:l}){const o=ue[a]??"var(--text-subtle)";return e.jsxs("span",{title:l,style:{display:"inline-flex",alignItems:"center",gap:5,fontSize:11,lineHeight:"18px",color:"var(--text-primary)",background:"var(--surface-sunken)",border:"1px solid var(--border-hair)",borderRadius:999,padding:"0 8px",whiteSpace:"nowrap"},children:[e.jsx("span",{"aria-hidden":!0,style:{width:6,height:6,borderRadius:"50%",background:o,flex:"0 0 auto"}}),s]})}function Be({components:a,checkedAt:s}){return!a||!s?e.jsx("span",{style:{fontSize:11,color:"var(--text-subtle)"},children:"Komponen belum diperiksa"}):e.jsxs("div",{style:{display:"flex",flexWrap:"wrap",gap:6,alignItems:"center"},children:[Object.entries(a).map(([l,o])=>e.jsx(he,{status:o.status,children:pe(l,o)},l)),e.jsxs("span",{style:{fontSize:11,color:"var(--text-subtle)"},children:["diperiksa ",new Date(s).toLocaleString("id-ID")]})]})}const Re=a=>new Date(a).toLocaleString("id-ID",{day:"numeric",month:"short",hour:"2-digit",minute:"2-digit"});function Le({components:a,checkedAt:s}){if(!a||!s)return e.jsx("span",{style:{fontSize:11,color:"var(--text-subtle)"},children:"Komponen belum diperiksa — buka detail untuk memeriksa"});const l=Object.entries(a),o=l.filter(([,c])=>c.status!=="ok"),u=l.length-o.length;return e.jsxs("div",{style:{display:"flex",flexWrap:"wrap",gap:8,alignItems:"center",minWidth:0},children:[e.jsx("span",{"aria-hidden":!0,style:{display:"flex",gap:2,alignItems:"center"},children:l.map(([c,n])=>e.jsx("span",{style:{width:12,height:4,borderRadius:2,background:n.status==="absent"?"var(--border-strong)":ue[n.status]}},c))}),e.jsxs("span",{style:{fontSize:11,color:"var(--text-subtle)",whiteSpace:"nowrap"},children:[e.jsxs("strong",{style:{color:"var(--text-primary)",fontWeight:600},children:[u,"/",l.length]})," terpasang"]}),o.map(([c,n])=>e.jsxs(he,{status:n.status,title:pe(c,n),children:[c," · ",n.status==="partial"&&n.detail.startsWith("not-logged-in")?"belum login":Ie[n.status]??n.status]},c)),e.jsxs("span",{style:{fontSize:11,color:"var(--text-subtle)",whiteSpace:"nowrap"},children:["diperiksa ",Re(s)]})]})}function Ne(a,s,l){const o=new Map(s.map(n=>[n.id,n])),u=new Set,c=n=>{var b;if(!u.has(n)){u.add(n);for(const g of((b=o.get(n))==null?void 0:b.requires[l])??[])c(g)}};for(const n of a)c(n);return u}function De({vps:a,onToast:s,onGotoTerminal:l}){const[o,u]=p.useState([]),[c,n]=de("vps",`provisionProfile@${a.id}`,"lab",fe("lab","production")),[b,g]=p.useState(new Set),[k,S]=p.useState(""),[h,y]=p.useState(null),[P,w]=p.useState(null),[B,E]=p.useState(null),[$,C]=p.useState(null),{confirm:R,dialog:V}=te();p.useEffect(()=>{v.listVpsComponents().then(i=>u(i.components)).catch(()=>u([]))},[]);const F=o.filter(i=>i.profiles.includes(c)),D=Ne(b,o,c),A=[...D],L=A.some(i=>{var z;return(z=o.find(N=>N.id===i))==null?void 0:z.needsDomain}),I=A.length>0&&(!L||k.trim().length>0);function t(i){g(z=>{const N=new Set(z);return N.has(i)?N.delete(i):N.add(i),N})}async function x(){C("probe");try{w(await v.probeVps(a.id)),s("Komponen diperiksa","ok","server")}catch{s("Probe gagal","err","x-circle")}finally{C(null)}}async function m(){C("preview");try{y((await v.provisionPreview(a.id,{items:A,profile:c,domain:k||void 0})).steps)}catch{s("Pratinjau gagal","err","x-circle")}finally{C(null)}}async function H(){if(await R({title:`Pasang ${A.length} komponen di "${a.name}"?`,message:`Profil ${c}. Langkah dijalankan lewat SSH dan bisa memakan beberapa menit.`,impact:A.map(i=>{var z;return((z=o.find(N=>N.id===i))==null?void 0:z.label)??i}),confirmLabel:"Pasang",icon:"server"})){C("apply");try{const i=await v.provisionVps(a.id,{items:A,profile:c,domain:k||void 0,confirm:!0});y(i.steps),w({components:i.components,checkedAt:i.checkedAt}),E(i.setup),s("Provisioning selesai","ok","server")}catch{s("Provisioning gagal","err","x-circle")}finally{C(null)}}}const X=async()=>{try{const{id:i}=await v.vpsConsole(a.id);l(i)}catch{s("Gagal membuka console","err","x-circle")}},M=P?Object.fromEntries(P.components.map(i=>[i.id,{status:i.status,detail:i.detail}])):a.components??null,Y=(P==null?void 0:P.checkedAt)??a.componentsCheckedAt??null,_=M?Object.entries(M).filter(([,i])=>i.status==="partial"&&i.detail.startsWith("not-logged-in")):[];return e.jsxs("div",{style:{display:"grid",gap:12},children:[e.jsxs("div",{style:{display:"flex",gap:8,alignItems:"center",flexWrap:"wrap"},children:[e.jsx(Be,{components:M,checkedAt:Y}),e.jsx(f,{size:"sm",variant:"ghost",onClick:x,disabled:$!==null,children:"Periksa"})]}),e.jsx("div",{style:{display:"flex",gap:16},children:["lab","production"].map(i=>e.jsx(be,{"aria-label":i,label:i,checked:c===i,onChange:()=>n(i)},i))}),e.jsx("div",{style:{display:"grid",gap:6},children:F.map(i=>{const z=D.has(i.id)&&!b.has(i.id);return e.jsxs("div",{style:{display:"flex",gap:6,alignItems:"center"},children:[e.jsx(ke,{"aria-label":i.label,label:i.label,checked:D.has(i.id),disabled:z,onChange:()=>t(i.id)}),z&&e.jsx("span",{style:{fontSize:10,color:"var(--text-subtle)"},children:"prasyarat"})]},i.id)})}),L&&e.jsx(O,{label:"Domain",hint:"A record harus sudah menunjuk ke IP VPS ini",children:e.jsx(T,{"aria-label":"Domain",value:k,onChange:i=>S(i.currentTarget.value),placeholder:"hanoman.contoh.id"})}),e.jsxs("div",{style:{display:"flex",gap:8},children:[e.jsx(f,{variant:"ghost",onClick:m,disabled:!I||$!==null,children:"Pratinjau"}),e.jsx(f,{onClick:H,disabled:!I||$!==null,children:"Pasang"})]}),h&&e.jsx("pre",{style:{fontSize:11,fontFamily:"var(--font-mono)",maxHeight:220,overflow:"auto",background:"var(--surface-sunken)",padding:8,borderRadius:4},children:h.map(i=>`${i.item.padEnd(14)} ${i.status.padEnd(6)} ${i.detail}`).join(`
|
|
1
|
+
import{e as v,u as te,j as e,M as oe,f as U,I as W,a as f,h as de,o as fe,am as be,af as ke,c as O,d as T,a5 as ye,a9 as se,y as ve}from"./index-DI7G_sit.js";import{R as p}from"./react-DfGhg7ZW.js";import"./markdown-CWEY34jk.js";const je={pass:"check",fail:"x",warn:"alert-triangle",na:"minus",unknown:"circle"},we={pass:"var(--leaf-600)",fail:"var(--clay-600)",warn:"var(--amber-600)",na:"var(--text-subtle)",unknown:"var(--text-subtle)"},Se={AUTO:"var(--brass-700)",AUDIT:"var(--amber-600)",INFO:"var(--text-subtle)"},Ce={critical:"var(--clay-600)",high:"var(--amber-600)",medium:"var(--text-subtle)",low:"var(--text-subtle)"};function K({text:a,color:s}){return e.jsx("span",{style:{fontSize:10,textTransform:"uppercase",letterSpacing:"0.04em",color:s,border:`1px solid ${s}`,borderRadius:3,padding:"0 4px",whiteSpace:"nowrap"},children:a})}function ce({score:a}){const s=a>=90?"var(--leaf-600)":a>=50?"var(--amber-600)":"var(--clay-600)";return e.jsxs("div",{style:{display:"flex",alignItems:"center",gap:6,minWidth:90},children:[e.jsx("div",{style:{flex:1,height:6,background:"var(--bone-200)",borderRadius:3,overflow:"hidden"},children:e.jsx("div",{style:{width:`${a}%`,height:"100%",background:s}})}),e.jsxs("span",{style:{fontSize:11,fontFamily:"var(--font-mono)",color:"var(--text-subtle)",minWidth:28,textAlign:"right"},children:[a,"%"]})]})}function Pe({item:a,busy:s,selected:l,onToggle:o,onNa:u,onAttest:c}){const n=a.mode==="AUTO"&&!a.na;return e.jsxs("div",{"data-testid":`item-${a.id}`,style:{display:"flex",alignItems:"center",gap:8,padding:"5px 0",borderBottom:"1px solid var(--border-hair)",fontSize:13,opacity:a.na?.55:1},children:[n?e.jsx("input",{type:"checkbox","aria-label":`pilih ${a.id}`,checked:l,onChange:()=>o(a)}):e.jsx("span",{style:{display:"inline-block",width:13}}),e.jsx(W,{name:je[a.status],size:14,color:we[a.status]}),e.jsx("span",{style:{flex:1,minWidth:0},children:a.title}),a.drifted&&e.jsx(K,{text:"drift",color:"var(--clay-600)"}),e.jsx(K,{text:a.mode,color:Se[a.mode]}),e.jsx(K,{text:a.severity,color:Ce[a.severity]}),a.mode==="INFO"&&!a.attested&&e.jsx(f,{size:"sm",variant:"ghost",leftIcon:"check-circle",loading:s,onClick:()=>c(a),children:"Attest"}),e.jsx(f,{size:"sm",variant:"ghost",leftIcon:a.na?"rotate-ccw":"minus-circle",loading:s,onClick:()=>u(a,!a.na),children:a.na?"Batal N/A":"N/A"})]})}const ee={section:"",mode:"",status:"",severity:""};function J({value:a,onChange:s,options:l,label:o}){return e.jsxs("select",{"aria-label":o,value:a,onChange:u=>s(u.target.value),style:{fontSize:12,padding:"3px 6px",border:"1px solid var(--border-hair)",borderRadius:"var(--radius-sm)",background:"var(--bone-50)",color:"var(--text)"},children:[e.jsxs("option",{value:"",children:[o,": semua"]}),l.map(([u,c])=>e.jsx("option",{value:u,children:c},u))]})}function ze(a){let s=0,l=0,o=0,u=0;for(const n of a)n.status==="fail"?s++:n.status==="warn"?l++:n.status==="unknown"&&o++,n.drifted&&u++;const c=[s&&`${s} fail`,l&&`${l} warn`,o&&`${o} unknown`].filter(Boolean);return{text:c.length?c.join(" "):"semua pass",drift:u}}function $e({section:a,items:s,expanded:l,onToggle:o,busy:u,selected:c,onToggleItem:n,onNa:b,onAttest:g,onSectionNa:k}){const S=ze(a.items),h=!!a.suggestion&&!a.suggestion.applicable;return e.jsxs("div",{style:{marginBottom:8,border:"1px solid var(--border-hair)",borderRadius:"var(--radius-sm)",overflow:"hidden"},children:[e.jsxs("button",{"data-testid":`section-${a.id}`,"aria-expanded":l,onClick:()=>o(a.id),style:{display:"flex",alignItems:"center",gap:8,width:"100%",padding:"8px 10px",textAlign:"left",background:l?"var(--bone-100)":"transparent",border:"none",cursor:"pointer"},children:[e.jsx(W,{name:l?"chevron-down":"chevron-right",size:15,color:"var(--text-subtle)"}),e.jsx("span",{style:{fontSize:14},children:a.icon}),e.jsx("span",{style:{fontSize:13,fontWeight:600,flex:1,minWidth:0},children:a.title}),e.jsx("span",{style:{fontSize:11,color:"var(--text-subtle)",whiteSpace:"nowrap"},children:S.text}),S.drift>0&&e.jsx(K,{text:"drift",color:"var(--clay-600)"}),h&&e.jsx(K,{text:"saran N/A",color:"var(--brass-700)"}),e.jsx(ce,{score:a.score})]}),l&&e.jsxs("div",{style:{padding:"2px 10px 8px"},children:[h&&e.jsxs("div",{"data-testid":`suggestion-${a.id}`,style:{display:"flex",alignItems:"center",gap:8,margin:"6px 0",padding:"6px 10px",fontSize:12,color:"var(--text-subtle)",background:"var(--bone-50)",border:"1px dashed var(--border-hair)",borderRadius:"var(--radius-sm)"},children:[e.jsx(W,{name:"info",size:13,color:"var(--brass-700)"}),e.jsxs("span",{style:{flex:1},children:["Stack tak terdeteksi (",a.suggestion.detail,") — kemungkinan N/A. Cek Docker manual bila ragu."]}),e.jsx(f,{size:"sm",variant:"ghost",leftIcon:"minus-circle",loading:u===`section:${a.id}`,onClick:()=>k(a),children:"Tandai seksi N/A"})]}),s.map(y=>e.jsx(Pe,{item:y,busy:u===y.id,selected:c.has(y.id),onToggle:n,onNa:b,onAttest:g},y.id))]})]})}function Ae({vpsId:a,vpsName:s,lastAuditAt:l,health:o,provisioning:u,onClose:c,onToast:n}){const[b,g]=p.useState(null),[k,S]=p.useState("loading"),[h,y]=p.useState(ee),[P,w]=p.useState(""),[B,E]=p.useState(new Set),[$,C]=p.useState(null),[R,V]=p.useState(new Set),[F,D]=p.useState(null),[A,L]=p.useState(""),I=p.useCallback(()=>{S("loading"),v.vpsChecklist(a).then(r=>{g(r),S("ready")}).catch(()=>S("error"))},[a]);p.useEffect(()=>{I(),V(new Set),D(null),E(new Set),w(""),y(ee)},[I]);const t=r=>V(j=>{const d=new Set(j);return d.has(r.id)?d.delete(r.id):d.add(r.id),d}),x=()=>{V(new Set),D(null)},m=r=>E(j=>{const d=new Set(j);return d.has(r)?d.delete(r):d.add(r),d}),{confirm:H,dialog:X}=te();async function M(){L("preview");try{D((await v.remediatePreview(a,[...R])).steps)}catch{n("Preview remediasi gagal","err","x-circle")}finally{L("")}}async function Y(){if(await H({title:`Terapkan ${R.size} item AUTO ke VPS ini?`,message:"Remediasi dijalankan langsung di server yang terdaftar.",impact:["Langkahnya idempoten dan anti-lockout.","Checklist diaudit ulang setelah selesai."],confirmLabel:"Terapkan",icon:"shield"})){L("apply");try{await v.remediate(a,[...R]),x(),I(),n("Remediasi diterapkan · audit ulang","ok","shield")}catch{n("Remediasi gagal","err","x-circle")}finally{L("")}}}async function _(r,j,d){C(r.id);try{await j(),I(),n(d,"ok","shield")}catch{n(`Gagal memperbarui ${r.id}`,"err","x-circle")}finally{C(null)}}const i=(r,j)=>_(r,()=>v.markNa(a,r.id,j,j?"ditandai dari checklist":void 0),j?`${r.id} ditandai N/A`:`${r.id} kembali applicable`),z=r=>_(r,()=>v.attestItem(a,r.id),`${r.id} di-attest`);async function N(r){const j=r.items.map(d=>d.id);if(await H({title:`Tandai ${j.length} item seksi "${r.title}" sebagai N/A?`,message:"Stack-nya tak terdeteksi — cek Docker manual bila ragu.",confirmLabel:"Tandai N/A",icon:"shield"})){C(`section:${r.id}`);try{await v.markNaBulk(a,j,!0,"app-layer: stack tak terdeteksi"),I(),n(`Seksi ${r.title} ditandai N/A`,"ok","shield")}catch{n("Gagal tandai seksi N/A","err","x-circle")}finally{C(null)}}}const G=P.trim().toLowerCase(),q=!!(h.section||h.mode||h.status||h.severity)||G!=="",me=r=>(!h.section||r.section===h.section)&&(!h.mode||r.mode===h.mode)&&(!h.status||r.status===h.status)&&(!h.severity||r.severity===h.severity)&&(!G||r.title.toLowerCase().includes(G)||r.id.toLowerCase().includes(G)||(r.code??"").toLowerCase().includes(G)),Q=r=>j=>y(d=>({...d,[r]:j}));function ge(){if(k==="loading")return e.jsx(U,{kind:"loading",compact:!0,title:"Memuat checklist…"});if(k==="error"||!b)return e.jsx(U,{kind:"error",compact:!0,title:"Gagal memuat checklist",action:I});const r=b.sections.reduce((d,Z)=>d+Z.items.filter(xe=>xe.drifted).length,0),j=b.sections.map(d=>({section:d,matched:d.items.filter(me)})).filter(d=>!q||d.matched.length>0);return e.jsxs("div",{children:[e.jsxs("div",{style:{position:"sticky",top:0,zIndex:1,background:"var(--surface-card)",paddingBottom:10},children:[e.jsxs("div",{style:{display:"flex",alignItems:"center",gap:10,marginBottom:10},children:[e.jsxs("div",{"data-testid":"score-total",style:{fontSize:22,fontWeight:700,fontFamily:"var(--font-mono)"},children:[b.scoreTotal,"%"]}),e.jsx("div",{style:{flex:1},children:e.jsx(ce,{score:b.scoreTotal})}),e.jsx("span",{style:{fontSize:11,color:"var(--text-subtle)"},children:"skor kepatuhan"})]}),r>0&&e.jsxs("div",{"data-testid":"drift-summary",style:{display:"flex",alignItems:"center",gap:6,marginBottom:10,padding:"6px 10px",fontSize:12,color:"var(--clay-700)",background:"var(--clay-50, var(--bone-100))",border:"1px solid var(--clay-600)",borderRadius:"var(--radius-sm)"},children:[e.jsx(W,{name:"alert-triangle",size:14,color:"var(--clay-600)"}),r," item drift (regresi) sejak audit sebelumnya"]}),e.jsxs("div",{style:{display:"flex",flexWrap:"wrap",gap:6,alignItems:"center"},children:[e.jsxs("div",{style:{display:"flex",alignItems:"center",gap:4,flex:"1 1 180px",border:"1px solid var(--border-hair)",borderRadius:"var(--radius-sm)",padding:"2px 8px",background:"var(--bone-50)"},children:[e.jsx(W,{name:"search",size:13,color:"var(--text-subtle)"}),e.jsx("input",{"aria-label":"cari item",value:P,onChange:d=>w(d.target.value),placeholder:"mis. ssh atau 5.2.1",style:{flex:1,border:"none",background:"transparent",fontSize:12,color:"var(--text)",outline:"none"}})]}),e.jsx(J,{label:"seksi",value:h.section,onChange:Q("section"),options:b.sections.map(d=>[d.id,d.title])}),e.jsx(J,{label:"mode",value:h.mode,onChange:Q("mode"),options:[["AUTO","AUTO"],["AUDIT","AUDIT"],["INFO","INFO"]]}),e.jsx(J,{label:"status",value:h.status,onChange:Q("status"),options:[["pass","pass"],["fail","fail"],["warn","warn"],["na","na"],["unknown","unknown"]]}),e.jsx(J,{label:"severity",value:h.severity,onChange:Q("severity"),options:[["critical","critical"],["high","high"],["medium","medium"],["low","low"]]}),q&&e.jsx(f,{size:"sm",variant:"ghost",onClick:()=>{y(ee),w("")},children:"Reset"})]}),R.size>0&&e.jsxs("div",{style:{display:"flex",alignItems:"center",gap:8,marginTop:10,padding:"8px 10px",background:"var(--bone-100)",border:"1px solid var(--brass-300)",borderRadius:"var(--radius-sm)"},children:[e.jsxs("span",{style:{fontSize:12,flex:1},children:[R.size," item AUTO dipilih"]}),e.jsx(f,{size:"sm",variant:"secondary",leftIcon:"eye",loading:A==="preview",onClick:M,children:"Preview"}),e.jsx(f,{size:"sm",leftIcon:"shield",loading:A==="apply",onClick:Y,children:"Apply"}),e.jsx(f,{size:"sm",variant:"ghost",onClick:x,children:"Batal"})]}),F&&e.jsxs("div",{"data-testid":"remediate-preview",style:{marginTop:10,padding:"8px 10px",fontSize:12,fontFamily:"var(--font-mono)",background:"var(--bone-50)",border:"1px solid var(--border-hair)",borderRadius:"var(--radius-sm)"},children:[e.jsx("div",{style:{fontWeight:600,marginBottom:4},children:"Pratinjau (dry-run) — belum diterapkan:"}),F.map(d=>e.jsxs("div",{style:{color:"var(--text-subtle)"},children:[d.item," · ",d.status," ",d.detail]},d.item))]})]}),j.length===0?e.jsx(U,{kind:"empty",compact:!0,title:"Tak ada item cocok",hint:"Ubah kata kunci atau reset filter."}):j.map(({section:d,matched:Z})=>e.jsx($e,{section:d,items:q?Z:d.items,expanded:q?!0:B.has(d.id),onToggle:m,busy:$,selected:R,onToggleItem:t,onNa:i,onAttest:z,onSectionNa:N},d.id))]})}return e.jsxs(oe,{open:!0,width:960,icon:"clipboard-list",eyebrow:s??"VPS",title:"Checklist kepatuhan",onClose:c,children:[e.jsxs("div",{"data-testid":"vps-detail",style:{fontSize:12,color:"var(--text-subtle)",marginBottom:12,paddingBottom:10,borderBottom:"1px solid var(--border-hair)"},children:[l?`Audit terakhir ${new Date(l).toLocaleString()}`:"Belum pernah diaudit",o&&` · disk ${o.disk} · mem ${o.mem} · load ${o.load}`]}),u&&e.jsx("div",{"data-testid":"vps-provisioning",style:{marginBottom:12,paddingBottom:10,borderBottom:"1px solid var(--border-hair)"},children:u}),ge(),X]})}const ne={ok:"terpasang",partial:"belum siap",absent:"belum ada"},ue={ok:"var(--leaf-600)",partial:"var(--amber-600)",absent:"var(--text-subtle)"};function pe(a,s){if(s.status==="partial"&&s.detail.startsWith("not-logged-in"))return`${a} · belum login`;if(s.status==="partial")return`${a} · ${s.detail||ne.partial}`;const l=s.status==="ok"&&s.detail?` ${s.detail}`:"";return`${a} · ${ne[s.status]??s.status}${l}`}const Ie={ok:"terpasang",partial:"belum siap",absent:"belum ada"};function he({status:a,children:s,title:l}){const o=ue[a]??"var(--text-subtle)";return e.jsxs("span",{title:l,style:{display:"inline-flex",alignItems:"center",gap:5,fontSize:11,lineHeight:"18px",color:"var(--text-primary)",background:"var(--surface-sunken)",border:"1px solid var(--border-hair)",borderRadius:999,padding:"0 8px",whiteSpace:"nowrap"},children:[e.jsx("span",{"aria-hidden":!0,style:{width:6,height:6,borderRadius:"50%",background:o,flex:"0 0 auto"}}),s]})}function Be({components:a,checkedAt:s}){return!a||!s?e.jsx("span",{style:{fontSize:11,color:"var(--text-subtle)"},children:"Komponen belum diperiksa"}):e.jsxs("div",{style:{display:"flex",flexWrap:"wrap",gap:6,alignItems:"center"},children:[Object.entries(a).map(([l,o])=>e.jsx(he,{status:o.status,children:pe(l,o)},l)),e.jsxs("span",{style:{fontSize:11,color:"var(--text-subtle)"},children:["diperiksa ",new Date(s).toLocaleString("id-ID")]})]})}const Re=a=>new Date(a).toLocaleString("id-ID",{day:"numeric",month:"short",hour:"2-digit",minute:"2-digit"});function Le({components:a,checkedAt:s}){if(!a||!s)return e.jsx("span",{style:{fontSize:11,color:"var(--text-subtle)"},children:"Komponen belum diperiksa — buka detail untuk memeriksa"});const l=Object.entries(a),o=l.filter(([,c])=>c.status!=="ok"),u=l.length-o.length;return e.jsxs("div",{style:{display:"flex",flexWrap:"wrap",gap:8,alignItems:"center",minWidth:0},children:[e.jsx("span",{"aria-hidden":!0,style:{display:"flex",gap:2,alignItems:"center"},children:l.map(([c,n])=>e.jsx("span",{style:{width:12,height:4,borderRadius:2,background:n.status==="absent"?"var(--border-strong)":ue[n.status]}},c))}),e.jsxs("span",{style:{fontSize:11,color:"var(--text-subtle)",whiteSpace:"nowrap"},children:[e.jsxs("strong",{style:{color:"var(--text-primary)",fontWeight:600},children:[u,"/",l.length]})," terpasang"]}),o.map(([c,n])=>e.jsxs(he,{status:n.status,title:pe(c,n),children:[c," · ",n.status==="partial"&&n.detail.startsWith("not-logged-in")?"belum login":Ie[n.status]??n.status]},c)),e.jsxs("span",{style:{fontSize:11,color:"var(--text-subtle)",whiteSpace:"nowrap"},children:["diperiksa ",Re(s)]})]})}function Ne(a,s,l){const o=new Map(s.map(n=>[n.id,n])),u=new Set,c=n=>{var b;if(!u.has(n)){u.add(n);for(const g of((b=o.get(n))==null?void 0:b.requires[l])??[])c(g)}};for(const n of a)c(n);return u}function De({vps:a,onToast:s,onGotoTerminal:l}){const[o,u]=p.useState([]),[c,n]=de("vps",`provisionProfile@${a.id}`,"lab",fe("lab","production")),[b,g]=p.useState(new Set),[k,S]=p.useState(""),[h,y]=p.useState(null),[P,w]=p.useState(null),[B,E]=p.useState(null),[$,C]=p.useState(null),{confirm:R,dialog:V}=te();p.useEffect(()=>{v.listVpsComponents().then(i=>u(i.components)).catch(()=>u([]))},[]);const F=o.filter(i=>i.profiles.includes(c)),D=Ne(b,o,c),A=[...D],L=A.some(i=>{var z;return(z=o.find(N=>N.id===i))==null?void 0:z.needsDomain}),I=A.length>0&&(!L||k.trim().length>0);function t(i){g(z=>{const N=new Set(z);return N.has(i)?N.delete(i):N.add(i),N})}async function x(){C("probe");try{w(await v.probeVps(a.id)),s("Komponen diperiksa","ok","server")}catch{s("Probe gagal","err","x-circle")}finally{C(null)}}async function m(){C("preview");try{y((await v.provisionPreview(a.id,{items:A,profile:c,domain:k||void 0})).steps)}catch{s("Pratinjau gagal","err","x-circle")}finally{C(null)}}async function H(){if(await R({title:`Pasang ${A.length} komponen di "${a.name}"?`,message:`Profil ${c}. Langkah dijalankan lewat SSH dan bisa memakan beberapa menit.`,impact:A.map(i=>{var z;return((z=o.find(N=>N.id===i))==null?void 0:z.label)??i}),confirmLabel:"Pasang",icon:"server"})){C("apply");try{const i=await v.provisionVps(a.id,{items:A,profile:c,domain:k||void 0,confirm:!0});y(i.steps),w({components:i.components,checkedAt:i.checkedAt}),E(i.setup),s("Provisioning selesai","ok","server")}catch{s("Provisioning gagal","err","x-circle")}finally{C(null)}}}const X=async()=>{try{const{id:i}=await v.vpsConsole(a.id);l(i)}catch{s("Gagal membuka console","err","x-circle")}},M=P?Object.fromEntries(P.components.map(i=>[i.id,{status:i.status,detail:i.detail}])):a.components??null,Y=(P==null?void 0:P.checkedAt)??a.componentsCheckedAt??null,_=M?Object.entries(M).filter(([,i])=>i.status==="partial"&&i.detail.startsWith("not-logged-in")):[];return e.jsxs("div",{style:{display:"grid",gap:12},children:[e.jsxs("div",{style:{display:"flex",gap:8,alignItems:"center",flexWrap:"wrap"},children:[e.jsx(Be,{components:M,checkedAt:Y}),e.jsx(f,{size:"sm",variant:"ghost",onClick:x,disabled:$!==null,children:"Periksa"})]}),e.jsx("div",{style:{display:"flex",gap:16},children:["lab","production"].map(i=>e.jsx(be,{"aria-label":i,label:i,checked:c===i,onChange:()=>n(i)},i))}),e.jsx("div",{style:{display:"grid",gap:6},children:F.map(i=>{const z=D.has(i.id)&&!b.has(i.id);return e.jsxs("div",{style:{display:"flex",gap:6,alignItems:"center"},children:[e.jsx(ke,{"aria-label":i.label,label:i.label,checked:D.has(i.id),disabled:z,onChange:()=>t(i.id)}),z&&e.jsx("span",{style:{fontSize:10,color:"var(--text-subtle)"},children:"prasyarat"})]},i.id)})}),L&&e.jsx(O,{label:"Domain",hint:"A record harus sudah menunjuk ke IP VPS ini",children:e.jsx(T,{"aria-label":"Domain",value:k,onChange:i=>S(i.currentTarget.value),placeholder:"hanoman.contoh.id"})}),e.jsxs("div",{style:{display:"flex",gap:8},children:[e.jsx(f,{variant:"ghost",onClick:m,disabled:!I||$!==null,children:"Pratinjau"}),e.jsx(f,{onClick:H,disabled:!I||$!==null,children:"Pasang"})]}),h&&e.jsx("pre",{style:{fontSize:11,fontFamily:"var(--font-mono)",maxHeight:220,overflow:"auto",background:"var(--surface-sunken)",padding:8,borderRadius:4},children:h.map(i=>`${i.item.padEnd(14)} ${i.status.padEnd(6)} ${i.detail}`).join(`
|
|
2
2
|
`)}),B&&e.jsxs("div",{style:{display:"grid",gap:4,border:"1px solid var(--border-strong)",borderRadius:4,padding:8},children:[e.jsx("strong",{style:{fontSize:12},children:"Buat admin pertama"}),e.jsx("a",{href:B.url,target:"_blank",rel:"noreferrer",style:{fontSize:12,wordBreak:"break-all"},children:B.url}),e.jsxs("span",{style:{fontSize:11,color:"var(--text-subtle)"},children:["berlaku sampai ",new Date(B.expiresAt).toLocaleTimeString("id-ID")]}),e.jsx("div",{children:e.jsx(f,{size:"sm",variant:"ghost",onClick:()=>{var i;return void((i=navigator.clipboard)==null?void 0:i.writeText(B.url))},children:"Salin"})})]}),_.length>0&&e.jsxs("div",{style:{display:"flex",gap:8,alignItems:"center",fontSize:12},children:[e.jsx(W,{name:"alert-triangle"}),e.jsxs("span",{children:[_.map(([i])=>i).join(", ")," terpasang tapi belum login."]}),e.jsx(f,{size:"sm",variant:"ghost",onClick:X,children:"Login lewat Console"})]}),V]})}const ie=(a,s=Date.now())=>!!a.lastSeenAt&&s-new Date(a.lastSeenAt).getTime()<10*6e4,Ve=a=>a.lastAuditAt?a.hardened?"hardened":"belum":"unknown",Oe={hardened:{status:"ok",label:"hardened"},belum:{status:"broken",label:"belum hardened"},unknown:{status:"idle",label:"belum diaudit"}};function re(a){const s={name:a.name.trim(),host:a.host.trim(),user:a.user.trim(),port:Number(a.port)||22};return a.keyPath.trim()&&(s.keyPath=a.keyPath.trim()),a.password&&(s.password=a.password),s}const Te="opsional — dipakai sekali untuk memasang key hanoman, tidak disimpan";function ae({open:a,title:s,submitLabel:l,initial:o,onClose:u,onSubmit:c}){const[n,b]=p.useState(o);p.useEffect(()=>{a&&b(o)},[a,o]);const g=S=>h=>b(y=>({...y,[S]:h.target.value})),k=!!(n.name.trim()&&n.host.trim()&&n.user.trim());return e.jsxs(oe,{open:a,onClose:u,icon:"server",eyebrow:"infra",title:s,footer:e.jsxs(e.Fragment,{children:[e.jsx(f,{variant:"ghost",size:"sm",onClick:u,children:"Batal"}),e.jsx(f,{size:"sm",leftIcon:"check",onClick:()=>k&&c(n),children:l})]}),children:[e.jsx(O,{label:"Nama",children:e.jsx(T,{value:n.name,onChange:g("name"),placeholder:"mis. web-1",style:{width:"100%"}})}),e.jsx(O,{label:"Host",hint:"hostname atau IP — tanpa user@",children:e.jsx(T,{value:n.host,onChange:g("host"),mono:!0,placeholder:"203.0.113.10",style:{width:"100%"}})}),e.jsxs("div",{className:"hn-grid-mobile",style:{display:"grid",gridTemplateColumns:"1.4fr 1fr",gap:12},children:[e.jsx(O,{label:"User SSH",hint:"root atau user ber-passwordless-sudo",children:e.jsx(T,{value:n.user,onChange:g("user"),mono:!0,placeholder:"deploy",style:{width:"100%"}})}),e.jsx(O,{label:"Port",children:e.jsx(T,{value:n.port,onChange:g("port"),mono:!0,placeholder:"22",style:{width:"100%"}})})]}),e.jsx(O,{label:"Password SSH",hint:Te,children:e.jsx(T,{type:"password",value:n.password,onChange:g("password"),placeholder:"••••••••",style:{width:"100%"}})}),e.jsx(O,{label:"Key path",hint:"kosongkan bila memakai password di atas, atau key default mesin server",children:e.jsx(T,{value:n.keyPath,onChange:g("keyPath"),mono:!0,placeholder:"~/.ssh/id_ed25519",style:{width:"100%"}})})]})}const le={name:"",host:"",user:"",port:"22",keyPath:"",password:""},We=a=>({name:a.name,host:a.host,user:a.user,port:String(a.port),keyPath:a.keyPath??"",password:""});function Me({onToast:a,onGotoTerminal:s}){const[l,o]=p.useState([]),[u,c]=p.useState("loading"),[n,b]=p.useState(null),[g,k]=p.useState(null),[S,h]=de("vps","detailId",null,ve),y=p.useMemo(()=>l.find(t=>t.id===S)??null,[l,S]),P=p.useCallback(t=>h(t?t.id:null),[h]),w=p.useCallback(()=>{v.listVps().then(t=>{o(t),c("ready")}).catch(()=>c("error"))},[]);p.useEffect(()=>(w(),ye(t=>{t.t==="vps"&&(o(t.vps),c("ready"))})),[w]);const{confirm:B,dialog:E}=te();async function $(t,x,m,H){b(`${t}:${x}`);try{await m(),w(),a(H,"ok","server")}catch{a(`Gagal ${t}`,"err","x-circle")}finally{b(null)}}const C=t=>$("audit",t.id,()=>v.auditVps(t.id),`${t.name} · audit selesai`);async function R(t){await B({title:`Harden "${t.name}"?`,message:"Pastikan akses key SSH non-password kamu sudah bekerja sebelum melanjutkan.",impact:[`Firewall: izinkan ${t.port}/80/443.`,"fail2ban & auto security update dipasang.","PermitRootLogin & PasswordAuthentication dimatikan.","NTP disinkronkan."],confirmLabel:"Harden",icon:"shield"})&&$("harden",t.id,()=>v.hardenVps(t.id),`${t.name} · harden selesai`)}const V=t=>$("sesi",t.id,async()=>{const{id:x}=await v.vpsSession(t.id);s(x)},`${t.name} · sesi Claude dibuka`),F=t=>$("test",t.id,async()=>{const x=await v.testVps(t.id);if(!x.ok)throw new Error(x.out)},`${t.name} · koneksi ok`),D=t=>$("console",t.id,async()=>{const{id:x}=await v.vpsConsole(t.id);s(x)},`${t.name} · console dibuka`);async function A(t){try{if(!await B({title:`Hapus registrasi VPS "${t.name}"?`,message:"Server-nya sendiri tak disentuh — hanya pendaftarannya di dashboard ini yang dihapus.",confirmLabel:"Hapus registrasi",run:()=>v.deleteVps(t.id)}))return;w()}catch{a("Gagal hapus","err","x-circle")}}async function L(t){try{const x=await v.createVps(re(t));k(null),w(),a(t.password?`${x.name} terdaftar · key hanoman terpasang · password dibuang`:`${x.name} terdaftar · jalankan audit`,"ok","server")}catch{a("Gagal mendaftarkan VPS — cek host/user, atau password SSH-nya","err","x-circle")}}async function I(t,x){try{const m=await v.updateVps(t.id,re(x));k(null),w(),a(x.password?`${m.name} diperbarui · key hanoman terpasang · password dibuang`:`${m.name} diperbarui`,"ok","server")}catch{a("Gagal memperbarui VPS","err","x-circle")}}return u==="loading"?e.jsx(U,{kind:"loading",title:"Memuat daftar VPS…"}):u==="error"?e.jsx(U,{kind:"error",title:"Gagal memuat daftar VPS",hint:"Pastikan server hanoman berjalan.",action:w}):l.length===0?e.jsxs(e.Fragment,{children:[e.jsx(U,{kind:"empty",icon:"server",title:"Belum ada VPS",hint:"Daftarkan VPS untuk mulai audit & hardening.",action:()=>k("new"),actionLabel:"Daftarkan VPS"}),e.jsx(ae,{open:g==="new",title:"Daftarkan VPS",submitLabel:"Daftarkan",initial:le,onClose:()=>k(null),onSubmit:L})]}):e.jsxs("div",{children:[e.jsxs("div",{children:[e.jsx("div",{style:{display:"flex",justifyContent:"flex-end",marginBottom:10},children:e.jsx(f,{size:"sm",leftIcon:"plus",onClick:()=>k("new"),children:"Daftarkan VPS"})}),l.map(t=>{const x=Oe[Ve(t)];return e.jsxs("div",{className:"hn-vps-row",onClick:()=>P(t),style:{padding:"10px 12px",cursor:"pointer",border:"1px solid var(--border-hair)",borderRadius:"var(--radius-sm)",marginBottom:8},children:[e.jsxs("div",{className:"hn-vps-main",children:[e.jsxs("button",{type:"button","aria-label":`Buka detail ${t.name}`,onClick:m=>{m.stopPropagation(),P(t)},style:{display:"flex",alignItems:"center",gap:10,flex:"1 1 220px",minWidth:0,cursor:"pointer",font:"inherit",color:"inherit",textAlign:"left",background:"transparent",padding:0,border:"none"},children:[e.jsx(W,{name:"server",size:16,color:"var(--brass-700)"}),e.jsxs("span",{style:{minWidth:0},children:[e.jsx("span",{style:{display:"block",fontSize:13,fontWeight:600,overflow:"hidden",textOverflow:"ellipsis",whiteSpace:"nowrap"},children:t.name}),e.jsxs("span",{style:{display:"block",fontSize:12,fontFamily:"var(--font-mono)",color:"var(--text-subtle)",overflow:"hidden",textOverflow:"ellipsis",whiteSpace:"nowrap"},children:[t.user,"@",t.host,t.port!==22?`:${t.port}`:""]})]})]}),e.jsxs("div",{className:"hn-vps-pills",style:{display:"flex",gap:6,alignItems:"center",flexShrink:0},children:[e.jsx(se,{size:"sm",status:ie(t)?"ok":"broken",children:ie(t)?"reachable":"unreachable"}),e.jsx(se,{size:"sm",status:x.status,children:x.label})]}),e.jsxs("div",{className:"hn-vps-actions",children:[e.jsx(f,{size:"sm",variant:"ghost",leftIcon:"plug-zap",loading:n===`test:${t.id}`,onClick:m=>{m.stopPropagation(),F(t)},children:"Test"}),e.jsx(f,{size:"sm",variant:"ghost",leftIcon:"terminal-square",loading:n===`console:${t.id}`,onClick:m=>{m.stopPropagation(),D(t)},children:"Console"}),e.jsx(f,{size:"sm",variant:"ghost",leftIcon:"terminal",loading:n===`sesi:${t.id}`,onClick:m=>{m.stopPropagation(),V(t)},children:"Sesi Claude"}),e.jsx(f,{size:"sm",variant:"secondary",leftIcon:"radar",loading:n===`audit:${t.id}`,onClick:m=>{m.stopPropagation(),C(t)},children:"Audit"}),e.jsx(f,{size:"sm",leftIcon:"shield",loading:n===`harden:${t.id}`,onClick:m=>{m.stopPropagation(),R(t)},children:"Harden"}),e.jsx("span",{"aria-hidden":!0,className:"hn-vps-sep"}),e.jsx(f,{size:"sm",variant:"ghost",leftIcon:"pencil",title:`Edit ${t.name}`,onClick:m=>{m.stopPropagation(),k(t)}}),e.jsx(f,{size:"sm",variant:"ghost",leftIcon:"trash-2",title:`Hapus ${t.name}`,onClick:m=>{m.stopPropagation(),A(t)}})]})]}),e.jsx("div",{style:{marginTop:8,paddingTop:8,borderTop:"1px solid var(--border-hair)"},children:e.jsx(Le,{components:t.components??null,checkedAt:t.componentsCheckedAt??null})})]},t.id)})]}),y&&e.jsx(Ae,{vpsId:y.id,vpsName:y.name,lastAuditAt:y.lastAuditAt,health:y.health,provisioning:e.jsx(De,{vps:y,onToast:a,onGotoTerminal:s}),onClose:()=>{P(null),w()},onToast:a}),e.jsx(ae,{open:g==="new",title:"Daftarkan VPS",submitLabel:"Daftarkan",initial:le,onClose:()=>k(null),onSubmit:L}),g&&g!=="new"&&e.jsx(ae,{open:!0,title:`Edit ${g.name}`,submitLabel:"Simpan",initial:We(g),onClose:()=>k(null),onSubmit:t=>I(g,t)}),E]})}export{Me as VpsScreen,Ve as hardenedLabel,ie as isReachable,re as vpsFormToBody};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{j as t,I as v,f as W}from"./index-
|
|
1
|
+
import{j as t,I as v,f as W}from"./index-DI7G_sit.js";import{R as g}from"./react-DfGhg7ZW.js";import"./markdown-CWEY34jk.js";function F(s,n=[]){const i={path:"",kids:[]},r=(o,p)=>{let e=i;const c=o.split("/").filter(Boolean);c.forEach((a,x)=>{const y=p&&x===c.length-1,m=e.path?e.path+"/"+a:a;let d=e.kids.find(u=>u.name===a&&u.leaf===y);d||(d={name:a,path:m,kids:[],leaf:y},e.kids.push(d)),e=d})};for(const o of s)r(o,!0);for(const o of n)r(o,!1);const l=o=>{o.kids.sort((p,e)=>p.leaf===e.leaf?p.name.localeCompare(e.name):p.leaf?1:-1),o.kids.forEach(l)};return l(i),i.kids}const j={A:"var(--leaf-600)",M:"var(--brass-600)",D:"var(--clay-500)"};function k({node:s,selected:n,onSelect:i,depth:r=0,meta:l,defaultOpen:o=!1,dirSelected:p,onSelectDir:e,ignored:c,onExpand:a}){const[x,y]=g.useState(o),[m,d]=g.useState(!1),u=c!=null&&c.has(s.path)?.62:1;if(s.leaf){const f=s.path===n,h=l==null?void 0:l[s.path];return t.jsxs("button",{onClick:()=>i(s.path),style:{display:"flex",alignItems:"center",gap:8,width:"100%",padding:"5px 8px",paddingLeft:22+r*12,border:"none",cursor:"pointer",textAlign:"left",background:f?"var(--brass-100)":"transparent",opacity:u},children:[h?t.jsx("span",{style:{fontFamily:"var(--font-mono)",fontSize:12,fontWeight:700,color:j[h.status]},children:h.status}):t.jsx(v,{name:"file-text",size:13,color:f?"var(--brass-700)":"var(--text-subtle)"}),t.jsx("span",{style:{flex:1,minWidth:0,fontFamily:"var(--font-mono)",fontSize:12,overflow:"hidden",textOverflow:"ellipsis",whiteSpace:"nowrap",color:f?"var(--brass-700)":"var(--text-body)",fontWeight:f?600:400},children:s.name}),h&&!h.binary&&t.jsxs("span",{style:{fontFamily:"var(--font-mono)",fontSize:11},children:[t.jsxs("span",{style:{color:"var(--leaf-600)"},children:["+",h.add]})," ",t.jsxs("span",{style:{color:"var(--clay-500)"},children:["−",h.del]})]})]})}const b=!!e&&s.path===p,w=!!a&&s.kids.length===0;async function z(){e==null||e(s.path);const f=!x;if(y(f),f&&w&&!m){d(!0);try{await(a==null?void 0:a(s.path))}finally{d(!1)}}}return t.jsxs("div",{children:[t.jsxs("button",{onClick:()=>void z(),style:{display:"flex",alignItems:"center",gap:8,width:"100%",padding:"5px 6px",paddingLeft:6+r*12,border:"none",background:b?"var(--brass-100)":"transparent",cursor:"pointer",textAlign:"left",opacity:u},children:[t.jsx(v,{name:x?"chevron-down":"chevron-right",size:14,color:"var(--text-subtle)"}),t.jsx(v,{name:"folder",size:15,color:b?"var(--brass-700)":"var(--brass-500)"}),t.jsxs("span",{style:{fontFamily:"var(--font-mono)",fontSize:12.5,color:b?"var(--brass-700)":"var(--text-strong)",fontWeight:b?700:500},children:[s.name,"/"]}),m&&t.jsx("span",{style:{fontSize:11,color:"var(--text-subtle)"},children:"memuat…"})]}),x&&s.kids.map(f=>t.jsx(k,{node:f,selected:n,onSelect:i,depth:r+1,meta:l,defaultOpen:o,dirSelected:p,onSelectDir:e,ignored:c,onExpand:a},f.path)),x&&!m&&s.kids.length===0&&t.jsx("div",{style:{padding:"4px 8px",paddingLeft:28+r*12,fontSize:11.5,color:"var(--text-subtle)"},children:"kosong"})]})}function S({cf:s,selected:n,onSelect:i}){const r=s.path===n;return t.jsxs("button",{onClick:()=>i(s.path),style:{display:"flex",alignItems:"center",gap:8,width:"100%",padding:"5px 10px",border:"none",cursor:"pointer",textAlign:"left",background:r?"var(--brass-100)":"transparent"},children:[t.jsx("span",{style:{fontFamily:"var(--font-mono)",fontSize:12,fontWeight:700,color:j[s.status]},children:s.status}),t.jsx("span",{style:{flex:1,minWidth:0,fontFamily:"var(--font-mono)",fontSize:12,overflow:"hidden",textOverflow:"ellipsis",whiteSpace:"nowrap",color:r?"var(--brass-700)":"var(--text-body)"},children:s.path}),!s.binary&&t.jsxs("span",{style:{fontFamily:"var(--font-mono)",fontSize:11},children:[t.jsxs("span",{style:{color:"var(--leaf-600)"},children:["+",s.add]})," ",t.jsxs("span",{style:{color:"var(--clay-500)"},children:["−",s.del]})]})]})}function T({label:s,changed:n,selected:i,onSelect:r,view:l,onView:o,emptyText:p="Tak ada file berubah."}){const e=g.useMemo(()=>F(n.map(a=>a.path)),[n]),c=g.useMemo(()=>Object.fromEntries(n.map(a=>[a.path,a])),[n]);return t.jsxs(t.Fragment,{children:[t.jsxs("div",{className:"hn-eyebrow",style:{display:"flex",alignItems:"center",gap:6,padding:"6px 8px"},children:[t.jsxs("span",{style:{flex:1},children:[s," · ",n.length]}),n.length>0&&["list","tree"].map(a=>t.jsx("button",{"aria-label":`${a==="list"?"List":"Tree"} ${s}`,onClick:()=>o(a),style:{display:"flex",padding:3,border:"none",cursor:"pointer",borderRadius:4,background:l===a?"var(--brass-100)":"transparent"},children:t.jsx(v,{name:a==="list"?"list":"folder-tree",size:14,color:l===a?"var(--brass-700)":"var(--text-subtle)"})},a))]}),n.length===0?t.jsx("div",{style:{padding:"4px 10px",fontSize:12,color:"var(--text-subtle)"},children:p}):l==="tree"?e.map(a=>t.jsx(k,{node:a,selected:i,onSelect:r,meta:c,defaultOpen:!0},a.path)):n.map(a=>t.jsx(S,{cf:a,selected:i,onSelect:r},a.path))]})}function I({diff:s,emptyTitle:n="Tidak ada perubahan pada file ini",emptyHint:i}){return s?t.jsx("pre",{style:{margin:0,fontFamily:"var(--font-mono)",fontSize:12.5,lineHeight:1.6},children:s.split(`
|
|
2
2
|
`).map((r,l)=>{const o=r.startsWith("+")&&!r.startsWith("+++"),p=r.startsWith("-")&&!r.startsWith("---"),e=r.startsWith("@@"),c=o?"var(--leaf-600)":p?"var(--clay-600)":e?"var(--brass-700)":"var(--text-body)",a=o?"color-mix(in srgb, var(--leaf-500) 10%, transparent)":p?"color-mix(in srgb, var(--clay-500) 10%, transparent)":"transparent";return t.jsx("div",{style:{color:c,background:a,padding:"0 12px",whiteSpace:"pre-wrap",wordBreak:"break-word"},children:r||" "},l)})}):t.jsx(W,{kind:"empty",icon:"check",title:n,hint:i})}export{T as C,I as D,k as T,F as b};
|