hanoman 0.9.4 → 0.9.5
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 +33 -33
- package/dist/server.js +33 -33
- package/package.json +1 -1
- package/web/assets/{ChangelogScreen-DV7czksP.js → ChangelogScreen-C-C71Zn_.js} +1 -1
- package/web/assets/{DalangHanomanScreen-gKHFySwO.js → DalangHanomanScreen-Go6ETy3r.js} +1 -1
- package/web/assets/{DocPreviewModal-DCal7m9E.js → DocPreviewModal-CZ4rZ_h-.js} +1 -1
- package/web/assets/{DocsWorkspace-BMAVKbqw.js → DocsWorkspace-BDfP0ML1.js} +1 -1
- package/web/assets/{IdeScreen-ZmtKIwRL.js → IdeScreen-DFRme37j.js} +1 -1
- package/web/assets/{LeadScreen-BGP15mjr.js → LeadScreen-ASzNKRLX.js} +1 -1
- package/web/assets/{ReviewScreen-BB-yKNIm.js → ReviewScreen-CyFWhxL1.js} +1 -1
- package/web/assets/{SchedulerScreen-C1T7kZ5F.js → SchedulerScreen-Bii5m-K1.js} +1 -1
- package/web/assets/{SettingsScreen-JT8uQrhn.js → SettingsScreen-siSgzEnH.js} +1 -1
- package/web/assets/{TeamScreen-CJ-AeCGM.js → TeamScreen-DzKZHKyR.js} +1 -1
- package/web/assets/{TerminalScreen-BTPwK0A4.js → TerminalScreen-mLiyHYQV.js} +1 -1
- package/web/assets/{TriageScreen-HE-JKaXl.js → TriageScreen-D5iyoK-3.js} +1 -1
- package/web/assets/{VpsScreen-CiRV0mMK.js → VpsScreen-BhjULQaT.js} +1 -1
- package/web/assets/{index-B_pRoVeM.js → index-CCJTT5hd.js} +3 -3
- package/web/assets/{live-B0yZ2azt.js → live-Jy46oHWQ.js} +1 -1
- package/web/index.html +1 -1
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{e as L,j as t,M as ke,d as yt,S as J,G as _t,J as kt,f as Ye,B as _e,I as ie,w as qt,D as Ut,a as G,K as Vt,N as Yt,O as lt,Q as ot,c as Pe,U as Jt,V as Xt,W as Qt,X as Zt,Y as ea,Z as ta,_ as je,$ as jt,a0 as Je,a1 as aa,a2 as na,a3 as ia,a4 as qe,a5 as ra,h as be,a6 as wt,a7 as sa,a8 as la,a9 as oa,g as We,aa as ca,ab as da,ac as St,l as ua,ad as ct,ae as pa,x as ma,af as fa,ag as ha,ah as Me,p as xa,ai as ga,aj as ba,ak as It,al as va,am as ve,an as ya,ao as dt,ap as ka}from"./index-B_pRoVeM.js";import{R as o,r as $}from"./react-DfGhg7ZW.js";import"./markdown-CWEY34jk.js";import"./xterm-3VOAfa_q.js";function Xe(e){return e.endedAt?e.endedReason==="reconciled"?"interrupted":e.exitCode===null||e.exitCode===0?"completed":"failed":"running"}const Ae=new Set;let ye;function ja(e){return Ae.add(e),ye||(ye=setInterval(()=>{for(const i of[...Ae])i()},1e3)),()=>{Ae.delete(e),Ae.size===0&&ye&&(clearInterval(ye),ye=void 0)}}const ut=20;function wa(e,i){if(!i)return"—";const n=new Date(i).getTime()-new Date(e).getTime();if(!Number.isFinite(n)||n<0)return"—";const s=Math.round(n/1e3);if(s<60)return`${s} dtk`;const c=Math.round(s/60);return c<60?`${c} mnt`:`${Math.floor(c/60)} jam ${c%60} mnt`}function Sa(e){switch(Xe(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 Ct=e=>Xe(e)==="interrupted"?"—":wa(e.startedAt,e.endedAt),zt=e=>kt[e]??e;function Ia({projects:e,onClose:i,onRestart:n}){const[s,c]=o.useState([]),[d,R]=o.useState(0),[v,T]=o.useState(1),[h,g]=o.useState(!1),[b,u]=o.useState(""),[x,C]=o.useState(""),[w,p]=o.useState(""),[S,z]=o.useState(""),[N,D]=o.useState(null);o.useEffect(()=>{const l=setTimeout(()=>z(w.trim()),250);return()=>clearTimeout(l)},[w]),o.useEffect(()=>{T(1)},[b,x,S]),o.useEffect(()=>{let l=!0;return g(!0),L.listSessionHistory({projectId:b||void 0,kind:x||void 0,q:S||void 0,page:v,limit:ut}).then(f=>{l&&(R(f.total),c(f.items))}).catch(()=>{l&&(c([]),R(0))}).finally(()=>{l&&g(!1)}),()=>{l=!1}},[b,x,S,v]);const k=Ut(d,v,ut),E=l=>{var f;return((f=e.find(I=>I.id===l))==null?void 0:f.name)??l};return t.jsxs(ke,{open:!0,title:"Riwayat sesi",icon:"history",onClose:i,width:900,children:[t.jsxs("div",{style:{display:"flex",alignItems:"center",gap:10,flexWrap:"wrap",marginBottom:10},children:[t.jsx(yt,{size:"sm",leftIcon:"search",placeholder:"mis. spec-412 atau reverse","aria-label":"Cari riwayat sesi",value:w,onChange:l=>p(l.target.value),style:{flex:"1 1 200px"}}),t.jsx(J,{size:"sm","aria-label":"Filter project",value:b,onChange:l=>u(l.target.value),options:[{value:"",label:"Semua project"}].concat(e.map(l=>({value:l.id,label:l.name})))}),t.jsx(J,{size:"sm","aria-label":"Filter jenis",value:x,onChange:l=>C(l.target.value),options:[{value:"",label:"Semua jenis"}].concat(_t.map(l=>({value:l,label:kt[l]})))})]}),s.length===0&&!h?t.jsx(Ye,{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:[s.map(l=>{const f=Sa(l);return t.jsx("button",{onClick:()=>D(l),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(l.startedAt).toLocaleString("id-ID")}),t.jsx(_e,{size:"sm",tone:"neutral",children:zt(l.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:l.title??l.specId??E(l.projectId)}),l.transcriptBytes!==null&&t.jsx(ie,{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:Ct(l)}),t.jsx(_e,{size:"sm",tone:f.tone,children:f.label})]})},l.id)}),h&&t.jsx("div",{style:{padding:"10px 8px",textAlign:"center",fontSize:11,color:"var(--text-subtle)"},children:"memuat…"})]}),t.jsx(qt,{page:k.page,pageCount:k.pageCount,total:d,from:k.from,to:k.to,onPage:T,unit:"sesi"}),N&&t.jsx(Ca,{row:N,projectName:E(N.projectId),onBack:()=>D(null),onRestart:n})]})}function Ca({row:e,projectName:i,onBack:n,onRestart:s}){const[c,d]=o.useState(null),[R,v]=o.useState("idle");o.useEffect(()=>{if(e.transcriptBytes===null){v("none"),d(null);return}let g=!0;return v("loading"),L.sessionTranscript(e.id).then(b=>{g&&(d(b.text),v("idle"))}).catch(()=>{g&&(d(null),v("error"))}),()=>{g=!1}},[e.id,e.transcriptBytes]);const T=Xe(e)==="interrupted",h=[["Project",i],["Sesi",e.sessionId],["Jenis",zt(e.kind)],["Agen",[e.agent,e.model,e.effort].filter(Boolean).join(" · ")],["Mulai",new Date(e.startedAt).toLocaleString("id-ID")],[T?"Terakhir terlihat hidup":"Selesai",e.endedAt?new Date(e.endedAt).toLocaleString("id-ID"):"berjalan"],...T&&e.reconciledAt?[["Terdeteksi mati",new Date(e.reconciledAt).toLocaleString("id-ID")]]:[],["Durasi",Ct(e)],["Direktori",e.cwd]];return e.specId&&h.splice(1,0,["Backlog",`${e.specId}${e.title?` · ${e.title}`:""}`]),e.branch&&h.push(["Branch",e.branch]),t.jsxs(ke,{open:!0,title:e.title??e.specId??e.sessionId,icon:"history",onClose:n,width:1e3,children:[t.jsxs("div",{style:{display:"flex",gap:8,alignItems:"center",marginBottom:10},children:[t.jsx(G,{size:"sm",variant:"ghost",leftIcon:"arrow-left",onClick:n,children:"Kembali"}),t.jsx("div",{style:{flex:1}}),c&&t.jsx(G,{size:"sm",variant:"secondary",leftIcon:"copy",onClick:()=>{var g;return void((g=navigator.clipboard)==null?void 0:g.writeText(c))},children:"Salin transkrip"}),Vt(e.kind)&&t.jsx(G,{size:"sm",leftIcon:"play",onClick:()=>s(e),children:"Mulai lagi"})]}),T&&t.jsxs(Yt,{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:h.map(([g,b])=>t.jsxs(o.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))}),R==="loading"&&t.jsx("div",{style:{fontSize:12,color:"var(--text-subtle)"},children:"memuat transkrip…"}),R==="none"&&t.jsx("div",{style:{fontSize:12,color:"var(--text-subtle)"},children:T?"Tanpa transkrip — panenya sudah lenyap sebelum hanoman sempat mengambilnya.":"Tanpa transkrip — sesi ini ditutup sebelum fitur riwayat ada, atau panenya tak menyisakan keluaran."}),R==="error"&&t.jsx("div",{style:{fontSize:12,color:"var(--clay-600)"},children:"Transkrip tak terbaca lagi di server."}),c!==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:c})]})}function za({open:e,projectId:i,projectName:n,onClose:s,onCreated:c}){var D;const[d,R]=o.useState("claude"),[v,T]=o.useState("sonnet"),[h,g]=o.useState("medium"),[b,u]=o.useState({claude:{model:"sonnet",effort:"medium"},codex:{...lt}}),[x,C]=o.useState(!1),[w,p]=o.useState(null);o.useEffect(()=>{e&&(L.getSettings().then(k=>{const E={claude:{model:k.model,effort:k.effort},codex:{...lt,...k.codex??{}}},l=k.agent==="codex"?"codex":"claude",f=ot(E,l);u(E),R(l),T(f.model),g(f.effort)}).catch(()=>{}),L.getCodexVersion().then(k=>p(k.version)).catch(()=>{}))},[e]);const S=k=>{R(k);const E=ot(b,k);T(E.model),g(E.effort)},z=k=>{T(k),g(E=>d==="codex"?ea(k,E):ta(k,E))};async function N(){C(!0);try{const{id:k}=await L.createTerminal(i,{agent:d,model:v,effort:h});c(k),s()}catch{}finally{C(!1)}}return t.jsxs(ke,{open:e,onClose:s,icon:"plus",eyebrow:n,title:"Sesi baru",footer:t.jsxs(t.Fragment,{children:[t.jsx(G,{variant:"ghost",onClick:s,children:"Batal"}),t.jsx(G,{leftIcon:"play",disabled:x,onClick:()=>void N(),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(Pe,{label:"Agen",hint:"Mesin yang menjalankan sesi ini. Perilaku sesi sama; hanya CLI-nya berbeda.",children:t.jsx(J,{"aria-label":"Agen",value:d,style:{width:"100%"},options:[{value:"claude",label:"Claude Code"},{value:"codex",label:"Codex CLI"}],onChange:k=>S(k.target.value)})}),t.jsx(Pe,{label:"Model",children:t.jsx(J,{"aria-label":"Model",value:v,style:{width:"100%"},options:Jt(d,v),onChange:k=>z(k.target.value)})}),t.jsx(Pe,{label:"Effort",children:t.jsx(J,{"aria-label":"Effort",value:h,style:{width:"100%"},options:Xt(d,v).map(k=>({value:k,label:k})),onChange:k=>g(k.target.value)})}),d==="codex"&&Qt(v,w)&&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:w}),", sedangkan ",t.jsx("b",{children:v})," butuh ",t.jsx("b",{children:(D=Zt(v))==null?void 0:D.minClient}),". Sesi tetap boleh dijalankan, tapi modelnya belum tentu dikenali CLI ini."]})]})}const Ra=()=>({rows:1,cols:1,cells:[null]}),pt=e=>({...e,rows:e.rows+1,cells:[...e.cells,...Array(e.cols).fill(null)]});function mt(e){const i=e.cols+1,n=[];for(let s=0;s<e.rows;s++)for(let c=0;c<i;c++)n.push(c<e.cols?e.cells[s*e.cols+c]??null:null);return{rows:e.rows,cols:i,cells:n}}function ft(e,i){if(e.rows===1||i<0||i>=e.rows)return e;const n=[...e.cells];return n.splice(i*e.cols,e.cols),{...e,rows:e.rows-1,cells:n}}function ht(e,i){if(e.cols===1||i<0||i>=e.cols)return e;const n=e.cols-1,s=[];for(let c=0;c<e.rows;c++)for(let d=0;d<e.cols;d++)d!==i&&s.push(e.cells[c*e.cols+d]??null);return{rows:e.rows,cols:n,cells:s}}function Ue(e,i,n){if(i<0||i>=e.cells.length)return e;const s=e.cells.map(c=>n!==null&&c===n?null:c);return s[i]=n,{...e,cells:s}}const Ta=(e,i)=>({...e,cells:e.cells.map(n=>n&&i.has(n)?n:null)}),Rt=e=>({id:crypto.randomUUID(),name:e,layout:Ra()});function xt(){const e=Rt("Utama");return{groups:[e],active:e.id}}const we=e=>e.groups.find(i=>i.id===e.active)??e.groups[0];function Ea(e,i){const n=Rt(i);return{groups:[...e.groups,n],active:n.id}}const Na=(e,i,n)=>({...e,groups:e.groups.map(s=>s.id===i?{...s,name:n}:s)});function Aa(e,i){if(e.groups.length===1)return e;const n=e.groups.filter(s=>s.id!==i);return n.length===e.groups.length?e:{groups:n,active:e.active===i?n[0].id:e.active}}const La=(e,i)=>e.groups.some(n=>n.id===i)?{...e,active:i}:e;function ne(e,i){const n=we(e);return{...e,groups:e.groups.map(s=>s.id===n.id?{...s,layout:i(s.layout)}:s)}}function Ve(e,i,n){const s=we(e),c=n===null?e.groups:e.groups.map(d=>d.id===s.id?d:{...d,layout:Ue(d.layout,d.layout.cells.indexOf(n),null)});return{...e,groups:c.map(d=>d.id===s.id?{...d,layout:Ue(d.layout,i,n)}:d)}}function ue(e,i){const n=we(e).layout.cells.indexOf(null);return n===-1?e:Ve(e,n,i)}const Fa=(e,i)=>({...e,groups:e.groups.map(n=>({...n,layout:Ue(n.layout,n.layout.cells.indexOf(i),null)}))}),gt=e=>new Set(e.groups.flatMap(i=>i.layout.cells.filter(n=>n!==null))),bt=(e,i)=>({...e,groups:e.groups.map(n=>({...n,layout:Ta(n.layout,i)}))}),Tt="hanoman.terminal.workspace",Et="hanoman.terminal.layout",pe=e=>je.parse({version:1,groups:e.groups});function Le(e,i){const n=e.groups,s=i&&n.some(c=>c.id===i)?i:n[0].id;return{groups:n,active:s}}function $a(e){try{const i=JSON.parse(e);if(!i||typeof i!="object")return null;const n=i,s=je.parse({version:1,groups:n.groups});return{workspace:s,active:typeof n.active=="string"&&s.groups.some(c=>c.id===n.active)?n.active:s.groups[0].id}}catch{return null}}function Ba(){try{const e=localStorage.getItem(Tt);if(e)return $a(e);const i=localStorage.getItem(Et);if(!i)return null;const n=JSON.parse(i),s={id:crypto.randomUUID(),name:"Utama",layout:n};return{workspace:je.parse({version:1,groups:[s]}),active:s.id}}catch{return null}}function He(){try{localStorage.removeItem(Tt),localStorage.removeItem(Et)}catch{}}const Nt=e=>`hanoman.terminal.workspace.v2.${encodeURIComponent(e)}`;function Da(e){try{const i=localStorage.getItem(Nt(e));if(!i)return null;const n=JSON.parse(i),s=je.parse(n.workspace);if(!Number.isInteger(n.revision)||(n.revision??-1)<0)return null;const c=typeof n.active=="string"&&s.groups.some(d=>d.id===n.active)?n.active:s.groups[0].id;return{workspace:s,revision:n.revision,active:c}}catch{return null}}function Ge(e,i){try{const n=je.parse(i.workspace);if(!Number.isInteger(i.revision)||i.revision<0)return;const s=n.groups.some(c=>c.id===i.active)?i.active:n.groups[0].id;localStorage.setItem(Nt(e),JSON.stringify({workspace:n,revision:i.revision,active:s}))}catch{}}function Ke(e){if(!(e instanceof Je)||e.status!==409)return null;const i=e.detail;if((i==null?void 0:i.code)!=="revision-conflict")return null;const n=aa.safeParse(i.current);return n.success?n.data:null}function Oa(e){const i=$.useRef(null);i.current||(i.current=xt());const[n,s]=$.useState(i.current),[c,d]=$.useState("loading"),[R,v]=$.useState(null),[T,h]=$.useState(!1),g=$.useRef(n),b=$.useRef(0),u=$.useRef(!1),x=$.useRef(Promise.resolve()),C=$.useRef(0),w=$.useCallback(l=>{g.current=l,s(l)},[]),p=$.useCallback(l=>{u.current=l,h(l)},[]),S=$.useCallback(l=>{const f=x.current.then(l,l);return x.current=f.then(()=>{},()=>{}),f},[]),z=$.useCallback((l,f="ready",I=null,y=g.current.active)=>{const O=l.workspace?Le(l.workspace,y):xt();b.current=l.revision,w(O),d(f),v(I),p(!0),l.workspace&&Ge(e,{workspace:l.workspace,revision:l.revision,active:O.active})},[w,p,e]),N=$.useCallback(l=>{const f=Da(e);f&&(b.current=f.revision,w(Le(f.workspace,f.active))),p(!1),d("recovering"),v(l instanceof Error?l.message:"Layout server belum tersambung")},[w,p,e]),D=$.useCallback(()=>S(async()=>{try{z(await L.getTerminalWorkspace())}catch(l){N(l)}}),[z,S,N]);$.useEffect(()=>{const l=++C.current;return d("loading"),v(null),p(!1),S(async()=>{try{const f=await L.getTerminalWorkspace();if(l!==C.current)return;if(f.workspace){z(f),He();return}const I=Ba();if(!I){z(f);return}try{const y=await L.putTerminalWorkspace({baseRevision:f.revision,workspace:I.workspace});if(l!==C.current)return;w(Le(y.workspace,I.active)),b.current=y.revision,Ge(e,{workspace:y.workspace,revision:y.revision,active:I.active}),He(),d("ready"),v(null),p(!0)}catch(y){const O=Ke(y);O!=null&&O.workspace?(z(O,"conflict","Layout server lebih baru; layout lokal lama tidak diunggah"),He()):N(y)}}catch(f){l===C.current&&N(f)}}),()=>{C.current+=1}},[z,S,N,w,p,e]),$.useEffect(()=>{const l=()=>{D()},f=()=>{document.visibilityState==="visible"&&D()};return window.addEventListener("focus",l),document.addEventListener("visibilitychange",f),()=>{window.removeEventListener("focus",l),document.removeEventListener("visibilitychange",f)}},[D]);const k=$.useCallback(l=>S(async()=>{if(!u.current)return!1;const f=l(g.current);let I,y;try{I=pe(f),y=pe(g.current)}catch{return d("conflict"),v("Layout tidak valid dan tidak disimpan"),!1}if(jt(I,y))return!0;try{return z(await L.putTerminalWorkspace({baseRevision:b.current,workspace:I}),"ready",null,f.active),!0}catch(O){const X=Ke(O);if(!(X!=null&&X.workspace))return N(O),!1;const M=l(Le(X.workspace,g.current.active));try{const _=await L.putTerminalWorkspace({baseRevision:X.revision,workspace:pe(M)});return z(_,"conflict","Layout berubah di perangkat lain; perubahan ini diterapkan ulang",M.active),!0}catch(_){if(!Ke(_)&&!(_ instanceof Je&&_.status===409))return N(_),!1;try{z(await L.getTerminalWorkspace(),"conflict","Layout berubah lagi di perangkat lain; state terbaru dimuat")}catch(Q){N(Q)}return!1}}}),[z,S,N]),E=$.useCallback(l=>{const f=La(g.current,l);w(f);const I=pe(f);Ge(e,{workspace:I,revision:b.current,active:f.active})},[w,e]);return{workspace:n,status:c,message:R,writable:T,mutate:k,setActive:E,refresh:D}}const Pa=[];function tn({userId:e="test-user",projects:i,backlog:n=Pa,focusSession:s,startedSession:c,onStartedSessionHandled:d,onStartBacklog:R,onOpenReview:v,onOpenSessionReview:T,titleOf:h,onIntegrate:g,onIntegrateSession:b,specOf:u,sessions:x,setSessions:C}){var st;const[w,p]=o.useState([]),S=x??w,z=C??p,[N,D]=o.useState([]),k=Oa(e),{workspace:E,status:l,message:f,writable:I,mutate:y,setActive:O,refresh:X}=k,[M,_]=be("terminal","project",((st=i[0])==null?void 0:st.id)??"",xa),Q=wt(),[re,le]=be("terminal","fontSize",Q?fa:ha,ma),[q,me]=be("terminal","keys",Q,Me),[Z,fe]=be("terminal","predict",!0,Me),[V,Se]=be("terminal","diag",!1,Me),oe=a=>le(r=>pa(r+a)),[B,Ie]=o.useState(!1),[K,he]=o.useState(null),[Ce,te]=o.useState(!1),[H,P]=o.useState(null),[Fe,xe]=o.useState(!1),[ze,Re]=o.useState(!1),$e=sa(),W=la()==="mobile",[Y,Te]=o.useState(0),[ee,ae]=o.useState(null),Be=o.useRef(null),[ce,Lt]=o.useState(!1);o.useEffect(()=>{L.listTerminals().then(a=>{z(a),Lt(!0)}).catch(()=>{})},[]),o.useEffect(()=>oa(a=>{a.t==="sessions"&&!x?z(a.sessions):a.t==="cleanups"&&D(a.cleanups)}),[]),o.useEffect(()=>{if(!ce||!I)return;const a=new Set(S.map(m=>m.id)),r=bt(E,a);jt(pe(r),pe(E))||y(m=>bt(m,a))},[y,S,ce,I,E]),o.useEffect(()=>{!c||c.specId==null||!ce||(z(a=>a.some(r=>r.id===c.id)?a:[...a,{...c,cwd:"",exited:!1}]),ae(c.id),d==null||d())},[d,ce,c]),o.useEffect(()=>{if(!s){Be.current=null;return}!ce||Be.current===s||S.some(a=>a.id===s&&!a.exited)&&(Be.current=s,ae(s))},[s,S,ce]),o.useEffect(()=>{if(!ee)return;const a=E.groups.find(r=>r.layout.cells.includes(ee));if(a){a.id!==E.active&&O(a.id);return}I&&y(r=>{if(gt(r).has(ee))return r;const m=ue(r,ee);return m!==r||!W?m:Ve(r,Y,ee)})},[Y,W,y,ee,O,I,E]),o.useEffect(()=>{K&&!S.some(a=>a.id===K)&&he(null)},[K,S]);const De=N.filter(a=>a.error),Ee=a=>S.find(r=>r.id===a)??null,ge=o.useCallback(a=>{var r;return((r=i.find(m=>m.id===a))==null?void 0:r.name)??a},[i]);function Ft(a){z(r=>r.some(m=>m.id===a)?r:[...r,{id:a,projectId:M,cwd:"",exited:!1}]),y(r=>ue(r,a)),ae(a)}async function Qe(){if(!M)return;const{id:a}=await L.createShell(M);z(r=>[...r,{id:a,projectId:M,cwd:"",exited:!1}]),y(r=>ue(r,a)),ae(a)}async function Ze(a,r){if(R&&!r){te(!1),P(null),R(a);return}const m=ba(a.source);try{const{id:j}=await L.startSession({spec:a.id,flow:m,...r?{force:r}:{}});z(A=>A.some(se=>se.id===j)?A:[...A,{id:j,projectId:a.projectId,specId:a.id,flow:m,cwd:"",exited:!1}]),y(A=>ue(A,j)),ae(j),te(!1),P(null)}catch(j){if($e.offerRetry(j,a.id,se=>Ze(a,se)))return;const A=j instanceof Je&&(j.status===400||j.status===422);P(`${a.id} · gagal mulai${A?" · project belum punya repoDir":""}`)}}async function et(a,r){try{const m=a.specId?await L.startSession({spec:a.specId,flow:a.flow??"feature",agent:a.agent==="codex"?"codex":"claude",...a.model?{model:a.model}:{},...a.effort?{effort:a.effort}:{},...r?{force:r}:{}}):a.kind==="shell"?await L.createShell(a.projectId):a.kind==="terminal"?await L.createTerminal(a.projectId,{agent:a.agent==="codex"?"codex":"claude",...a.model?{model:a.model}:{},...a.effort?{effort:a.effort}:{}}):await(r?L.createTerminalFlow(a.projectId,a.kind,{force:r}):L.createTerminalFlow(a.projectId,a.kind));z(j=>j.some(A=>A.id===m.id)?j:[...j,{id:m.id,projectId:a.projectId,specId:a.specId??void 0,cwd:"",exited:!1}]),y(j=>ue(j,m.id)),ae(m.id),Re(!1)}catch(m){if((a.specId||a.kind!=="shell"&&a.kind!=="terminal")&&$e.offerRetry(m,`${a.projectId} · ${a.title??a.specId??a.kind}`,j=>et(a,j)))return}}const tt=new Set(S.filter(a=>a.specId&&!a.exited).map(a=>a.specId)),$t=n.filter(a=>a.stage!=="done"&&!tt.has(a.id));function at(a){z(r=>r.filter(m=>m.id!==a)),L.deleteTerminal(a).catch(()=>{})}const Bt=o.useCallback((a,r)=>{z(m=>m.map(j=>j.id===a?{...j,exited:!0,exitCode:r}:j))},[]),nt={close:at,detach:a=>{y(r=>Fa(r,a))},markExited:Bt,setFullId:he,props:{onOpenReview:v,onOpenSessionReview:T,titleOf:h,onIntegrate:g,onIntegrateSession:b,specOf:u}},U=o.useRef(nt);U.current=nt;const it=o.useRef(new Map),Dt=a=>{let r=it.current.get(a);return r||(r={onClose:()=>void U.current.close(a),onDetach:()=>U.current.detach(a),onExit:m=>U.current.markExited(a,m),onFullscreen:()=>U.current.setFullId(a)},it.current.set(a,r)),r},de=o.useRef({onOpenReview:a=>{var r,m;return(m=(r=U.current.props).onOpenReview)==null?void 0:m.call(r,a)},onOpenSessionReview:(a,r)=>{var m,j;return(j=(m=U.current.props).onOpenSessionReview)==null?void 0:j.call(m,a,r)},titleOf:a=>{var r,m;return(m=(r=U.current.props).titleOf)==null?void 0:m.call(r,a)},onIntegrate:(a,r,m)=>{var j,A;return(A=(j=U.current.props).onIntegrate)==null?void 0:A.call(j,a,r,m)},onIntegrateSession:(a,r,m)=>{var j,A;return(A=(j=U.current.props).onIntegrateSession)==null?void 0:A.call(j,a,r,m)},specOf:a=>{var r,m;return(m=(r=U.current.props).specOf)==null?void 0:m.call(r,a)}}).current,Ot=(a,r)=>{Te(a),y(m=>Ve(m,a,r))},Pt=a=>{ae(a),y(r=>ue(r,a))},Wt=gt(E),Oe=S.filter(a=>!Wt.has(a.id)),F=we(E).layout;o.useEffect(()=>{if(!ee)return;const a=F.cells.indexOf(ee);a<0||(Te(a),ae(null))},[F.cells,ee]),o.useEffect(()=>{Y>=F.cells.length&&Te(Math.max(0,F.cells.length-1))},[Y,F.cells.length]);const rt=F.rows===1&&F.cols===1&&!F.cells[0]&&S.length===0,Mt=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(We,{size:"sm",icon:"minus",label:"Perkecil teks terminal",disabled:re<=ca,onClick:()=>oe(-1)}),t.jsxs("span",{style:{fontFamily:"var(--font-mono)",fontSize:12,minWidth:44,textAlign:"center"},children:[re,"px"]}),t.jsx(We,{size:"sm",icon:"plus",label:"Perbesar teks terminal",disabled:re>=da,onClick:()=>oe(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(G,{size:"sm",variant:"secondary","aria-pressed":q,onClick:()=>me(a=>!a),children:q?"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(G,{size:"sm",variant:"secondary","aria-pressed":Z,"aria-label":`${Z?"Matikan":"Nyalakan"} ketik responsif`,onClick:()=>fe(a=>!a),children:Z?"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(G,{size:"sm",variant:"secondary","aria-pressed":V,"aria-label":`${V?"Matikan":"Nyalakan"} rekam jalur ketik`,onClick:()=>Se(a=>!a),children:V?"Matikan":"Nyalakan"})]}),W&&t.jsx(J,{size:"sm","aria-label":"Project sesi baru",value:M,onChange:a=>_(a.target.value),options:i.map(a=>({value:a.id,label:a.name}))})]}),Ht=[{key:"backlog",label:"Ambil backlog",icon:"inbox",onSelect:()=>{P(null),te(!0)}},{key:"history",label:"Riwayat sesi",icon:"history",onSelect:()=>Re(!0)},{key:"shell",label:"Terminal biasa",icon:"terminal",onSelect:()=>void Qe()},{key:"col+",label:"+ Kolom",icon:"columns-2",disabled:!I,onSelect:()=>void y(a=>ne(a,mt))},{key:"row+",label:"+ Baris",icon:"rows-2",disabled:!I,onSelect:()=>void y(a=>ne(a,pt))},{key:"col-",label:"Hapus kolom aktif",icon:"columns-2",disabled:!I||F.cols===1,onSelect:()=>void y(a=>ne(a,r=>ht(r,Y%r.cols)))},{key:"row-",label:"Hapus baris aktif",icon:"rows-2",disabled:!I||F.rows===1,onSelect:()=>void y(a=>ne(a,r=>ft(r,Math.floor(Y/r.cols))))}],Gt={display:"flex",flexDirection:"column",gap:B?8:12,...B?{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:Gt,children:[t.jsxs("div",{style:{display:"flex",gap:8,flexDirection:B?"row":"column",alignItems:B?"center":"stretch"},children:[t.jsx(Ma,{compact:B,ws:E,writable:I,onSelect:O,onAdd:()=>void y(a=>Ea(a,`Grup ${a.groups.length+1}`)),onRename:(a,r)=>void y(m=>Na(m,a,r)),onRemove:a=>void y(r=>Aa(r,a))}),t.jsxs("div",{style:{display:"flex",alignItems:"center",gap:8,flexWrap:"wrap",...B?{flex:1,minWidth:0}:{}},children:[!W&&t.jsxs(t.Fragment,{children:[t.jsx(G,{size:"sm",variant:"ghost",disabled:!I,onClick:()=>void y(a=>ne(a,mt)),children:"+ Kolom"}),t.jsx(G,{size:"sm",variant:"ghost",disabled:!I,onClick:()=>void y(a=>ne(a,pt)),children:"+ Baris"})]}),t.jsx("div",{style:{flex:1,minWidth:0}}),l!=="ready"&&t.jsx("span",{"data-testid":"terminal-workspace-status",title:f??void 0,style:{fontSize:12,color:l==="conflict"?"var(--status-warn)":"var(--text-muted)"},children:l==="loading"?"Memuat layout server…":l==="recovering"?t.jsxs(t.Fragment,{children:[t.jsx("span",{children:"Layout server belum tersambung"})," ",t.jsx("button",{type:"button",onClick:()=>void X(),children:"Retry"})]}):f??"Layout berubah di perangkat lain"}),N.length>0&&t.jsx("span",{"data-testid":"worktree-cleanups",title:N.map(a=>`${a.sessionId}${a.error?` — ${a.error}`:""}`).join(`
|
|
1
|
+
import{e as L,j as t,M as ke,d as yt,S as J,G as _t,J as kt,f as Ye,B as _e,I as ie,w as qt,D as Ut,a as G,K as Vt,N as Yt,O as lt,Q as ot,c as Pe,U as Jt,V as Xt,W as Qt,X as Zt,Y as ea,Z as ta,_ as je,$ as jt,a0 as Je,a1 as aa,a2 as na,a3 as ia,a4 as qe,a5 as ra,h as be,a6 as wt,a7 as sa,a8 as la,a9 as oa,g as We,aa as ca,ab as da,ac as St,l as ua,ad as ct,ae as pa,x as ma,af as fa,ag as ha,ah as Me,p as xa,ai as ga,aj as ba,ak as It,al as va,am as ve,an as ya,ao as dt,ap as ka}from"./index-CCJTT5hd.js";import{R as o,r as $}from"./react-DfGhg7ZW.js";import"./markdown-CWEY34jk.js";import"./xterm-3VOAfa_q.js";function Xe(e){return e.endedAt?e.endedReason==="reconciled"?"interrupted":e.exitCode===null||e.exitCode===0?"completed":"failed":"running"}const Ae=new Set;let ye;function ja(e){return Ae.add(e),ye||(ye=setInterval(()=>{for(const i of[...Ae])i()},1e3)),()=>{Ae.delete(e),Ae.size===0&&ye&&(clearInterval(ye),ye=void 0)}}const ut=20;function wa(e,i){if(!i)return"—";const n=new Date(i).getTime()-new Date(e).getTime();if(!Number.isFinite(n)||n<0)return"—";const s=Math.round(n/1e3);if(s<60)return`${s} dtk`;const c=Math.round(s/60);return c<60?`${c} mnt`:`${Math.floor(c/60)} jam ${c%60} mnt`}function Sa(e){switch(Xe(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 Ct=e=>Xe(e)==="interrupted"?"—":wa(e.startedAt,e.endedAt),zt=e=>kt[e]??e;function Ia({projects:e,onClose:i,onRestart:n}){const[s,c]=o.useState([]),[d,R]=o.useState(0),[v,T]=o.useState(1),[h,g]=o.useState(!1),[b,u]=o.useState(""),[x,C]=o.useState(""),[w,p]=o.useState(""),[S,z]=o.useState(""),[N,D]=o.useState(null);o.useEffect(()=>{const l=setTimeout(()=>z(w.trim()),250);return()=>clearTimeout(l)},[w]),o.useEffect(()=>{T(1)},[b,x,S]),o.useEffect(()=>{let l=!0;return g(!0),L.listSessionHistory({projectId:b||void 0,kind:x||void 0,q:S||void 0,page:v,limit:ut}).then(f=>{l&&(R(f.total),c(f.items))}).catch(()=>{l&&(c([]),R(0))}).finally(()=>{l&&g(!1)}),()=>{l=!1}},[b,x,S,v]);const k=Ut(d,v,ut),E=l=>{var f;return((f=e.find(I=>I.id===l))==null?void 0:f.name)??l};return t.jsxs(ke,{open:!0,title:"Riwayat sesi",icon:"history",onClose:i,width:900,children:[t.jsxs("div",{style:{display:"flex",alignItems:"center",gap:10,flexWrap:"wrap",marginBottom:10},children:[t.jsx(yt,{size:"sm",leftIcon:"search",placeholder:"mis. spec-412 atau reverse","aria-label":"Cari riwayat sesi",value:w,onChange:l=>p(l.target.value),style:{flex:"1 1 200px"}}),t.jsx(J,{size:"sm","aria-label":"Filter project",value:b,onChange:l=>u(l.target.value),options:[{value:"",label:"Semua project"}].concat(e.map(l=>({value:l.id,label:l.name})))}),t.jsx(J,{size:"sm","aria-label":"Filter jenis",value:x,onChange:l=>C(l.target.value),options:[{value:"",label:"Semua jenis"}].concat(_t.map(l=>({value:l,label:kt[l]})))})]}),s.length===0&&!h?t.jsx(Ye,{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:[s.map(l=>{const f=Sa(l);return t.jsx("button",{onClick:()=>D(l),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(l.startedAt).toLocaleString("id-ID")}),t.jsx(_e,{size:"sm",tone:"neutral",children:zt(l.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:l.title??l.specId??E(l.projectId)}),l.transcriptBytes!==null&&t.jsx(ie,{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:Ct(l)}),t.jsx(_e,{size:"sm",tone:f.tone,children:f.label})]})},l.id)}),h&&t.jsx("div",{style:{padding:"10px 8px",textAlign:"center",fontSize:11,color:"var(--text-subtle)"},children:"memuat…"})]}),t.jsx(qt,{page:k.page,pageCount:k.pageCount,total:d,from:k.from,to:k.to,onPage:T,unit:"sesi"}),N&&t.jsx(Ca,{row:N,projectName:E(N.projectId),onBack:()=>D(null),onRestart:n})]})}function Ca({row:e,projectName:i,onBack:n,onRestart:s}){const[c,d]=o.useState(null),[R,v]=o.useState("idle");o.useEffect(()=>{if(e.transcriptBytes===null){v("none"),d(null);return}let g=!0;return v("loading"),L.sessionTranscript(e.id).then(b=>{g&&(d(b.text),v("idle"))}).catch(()=>{g&&(d(null),v("error"))}),()=>{g=!1}},[e.id,e.transcriptBytes]);const T=Xe(e)==="interrupted",h=[["Project",i],["Sesi",e.sessionId],["Jenis",zt(e.kind)],["Agen",[e.agent,e.model,e.effort].filter(Boolean).join(" · ")],["Mulai",new Date(e.startedAt).toLocaleString("id-ID")],[T?"Terakhir terlihat hidup":"Selesai",e.endedAt?new Date(e.endedAt).toLocaleString("id-ID"):"berjalan"],...T&&e.reconciledAt?[["Terdeteksi mati",new Date(e.reconciledAt).toLocaleString("id-ID")]]:[],["Durasi",Ct(e)],["Direktori",e.cwd]];return e.specId&&h.splice(1,0,["Backlog",`${e.specId}${e.title?` · ${e.title}`:""}`]),e.branch&&h.push(["Branch",e.branch]),t.jsxs(ke,{open:!0,title:e.title??e.specId??e.sessionId,icon:"history",onClose:n,width:1e3,children:[t.jsxs("div",{style:{display:"flex",gap:8,alignItems:"center",marginBottom:10},children:[t.jsx(G,{size:"sm",variant:"ghost",leftIcon:"arrow-left",onClick:n,children:"Kembali"}),t.jsx("div",{style:{flex:1}}),c&&t.jsx(G,{size:"sm",variant:"secondary",leftIcon:"copy",onClick:()=>{var g;return void((g=navigator.clipboard)==null?void 0:g.writeText(c))},children:"Salin transkrip"}),Vt(e.kind)&&t.jsx(G,{size:"sm",leftIcon:"play",onClick:()=>s(e),children:"Mulai lagi"})]}),T&&t.jsxs(Yt,{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:h.map(([g,b])=>t.jsxs(o.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))}),R==="loading"&&t.jsx("div",{style:{fontSize:12,color:"var(--text-subtle)"},children:"memuat transkrip…"}),R==="none"&&t.jsx("div",{style:{fontSize:12,color:"var(--text-subtle)"},children:T?"Tanpa transkrip — panenya sudah lenyap sebelum hanoman sempat mengambilnya.":"Tanpa transkrip — sesi ini ditutup sebelum fitur riwayat ada, atau panenya tak menyisakan keluaran."}),R==="error"&&t.jsx("div",{style:{fontSize:12,color:"var(--clay-600)"},children:"Transkrip tak terbaca lagi di server."}),c!==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:c})]})}function za({open:e,projectId:i,projectName:n,onClose:s,onCreated:c}){var D;const[d,R]=o.useState("claude"),[v,T]=o.useState("sonnet"),[h,g]=o.useState("medium"),[b,u]=o.useState({claude:{model:"sonnet",effort:"medium"},codex:{...lt}}),[x,C]=o.useState(!1),[w,p]=o.useState(null);o.useEffect(()=>{e&&(L.getSettings().then(k=>{const E={claude:{model:k.model,effort:k.effort},codex:{...lt,...k.codex??{}}},l=k.agent==="codex"?"codex":"claude",f=ot(E,l);u(E),R(l),T(f.model),g(f.effort)}).catch(()=>{}),L.getCodexVersion().then(k=>p(k.version)).catch(()=>{}))},[e]);const S=k=>{R(k);const E=ot(b,k);T(E.model),g(E.effort)},z=k=>{T(k),g(E=>d==="codex"?ea(k,E):ta(k,E))};async function N(){C(!0);try{const{id:k}=await L.createTerminal(i,{agent:d,model:v,effort:h});c(k),s()}catch{}finally{C(!1)}}return t.jsxs(ke,{open:e,onClose:s,icon:"plus",eyebrow:n,title:"Sesi baru",footer:t.jsxs(t.Fragment,{children:[t.jsx(G,{variant:"ghost",onClick:s,children:"Batal"}),t.jsx(G,{leftIcon:"play",disabled:x,onClick:()=>void N(),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(Pe,{label:"Agen",hint:"Mesin yang menjalankan sesi ini. Perilaku sesi sama; hanya CLI-nya berbeda.",children:t.jsx(J,{"aria-label":"Agen",value:d,style:{width:"100%"},options:[{value:"claude",label:"Claude Code"},{value:"codex",label:"Codex CLI"}],onChange:k=>S(k.target.value)})}),t.jsx(Pe,{label:"Model",children:t.jsx(J,{"aria-label":"Model",value:v,style:{width:"100%"},options:Jt(d,v),onChange:k=>z(k.target.value)})}),t.jsx(Pe,{label:"Effort",children:t.jsx(J,{"aria-label":"Effort",value:h,style:{width:"100%"},options:Xt(d,v).map(k=>({value:k,label:k})),onChange:k=>g(k.target.value)})}),d==="codex"&&Qt(v,w)&&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:w}),", sedangkan ",t.jsx("b",{children:v})," butuh ",t.jsx("b",{children:(D=Zt(v))==null?void 0:D.minClient}),". Sesi tetap boleh dijalankan, tapi modelnya belum tentu dikenali CLI ini."]})]})}const Ra=()=>({rows:1,cols:1,cells:[null]}),pt=e=>({...e,rows:e.rows+1,cells:[...e.cells,...Array(e.cols).fill(null)]});function mt(e){const i=e.cols+1,n=[];for(let s=0;s<e.rows;s++)for(let c=0;c<i;c++)n.push(c<e.cols?e.cells[s*e.cols+c]??null:null);return{rows:e.rows,cols:i,cells:n}}function ft(e,i){if(e.rows===1||i<0||i>=e.rows)return e;const n=[...e.cells];return n.splice(i*e.cols,e.cols),{...e,rows:e.rows-1,cells:n}}function ht(e,i){if(e.cols===1||i<0||i>=e.cols)return e;const n=e.cols-1,s=[];for(let c=0;c<e.rows;c++)for(let d=0;d<e.cols;d++)d!==i&&s.push(e.cells[c*e.cols+d]??null);return{rows:e.rows,cols:n,cells:s}}function Ue(e,i,n){if(i<0||i>=e.cells.length)return e;const s=e.cells.map(c=>n!==null&&c===n?null:c);return s[i]=n,{...e,cells:s}}const Ta=(e,i)=>({...e,cells:e.cells.map(n=>n&&i.has(n)?n:null)}),Rt=e=>({id:crypto.randomUUID(),name:e,layout:Ra()});function xt(){const e=Rt("Utama");return{groups:[e],active:e.id}}const we=e=>e.groups.find(i=>i.id===e.active)??e.groups[0];function Ea(e,i){const n=Rt(i);return{groups:[...e.groups,n],active:n.id}}const Na=(e,i,n)=>({...e,groups:e.groups.map(s=>s.id===i?{...s,name:n}:s)});function Aa(e,i){if(e.groups.length===1)return e;const n=e.groups.filter(s=>s.id!==i);return n.length===e.groups.length?e:{groups:n,active:e.active===i?n[0].id:e.active}}const La=(e,i)=>e.groups.some(n=>n.id===i)?{...e,active:i}:e;function ne(e,i){const n=we(e);return{...e,groups:e.groups.map(s=>s.id===n.id?{...s,layout:i(s.layout)}:s)}}function Ve(e,i,n){const s=we(e),c=n===null?e.groups:e.groups.map(d=>d.id===s.id?d:{...d,layout:Ue(d.layout,d.layout.cells.indexOf(n),null)});return{...e,groups:c.map(d=>d.id===s.id?{...d,layout:Ue(d.layout,i,n)}:d)}}function ue(e,i){const n=we(e).layout.cells.indexOf(null);return n===-1?e:Ve(e,n,i)}const Fa=(e,i)=>({...e,groups:e.groups.map(n=>({...n,layout:Ue(n.layout,n.layout.cells.indexOf(i),null)}))}),gt=e=>new Set(e.groups.flatMap(i=>i.layout.cells.filter(n=>n!==null))),bt=(e,i)=>({...e,groups:e.groups.map(n=>({...n,layout:Ta(n.layout,i)}))}),Tt="hanoman.terminal.workspace",Et="hanoman.terminal.layout",pe=e=>je.parse({version:1,groups:e.groups});function Le(e,i){const n=e.groups,s=i&&n.some(c=>c.id===i)?i:n[0].id;return{groups:n,active:s}}function $a(e){try{const i=JSON.parse(e);if(!i||typeof i!="object")return null;const n=i,s=je.parse({version:1,groups:n.groups});return{workspace:s,active:typeof n.active=="string"&&s.groups.some(c=>c.id===n.active)?n.active:s.groups[0].id}}catch{return null}}function Ba(){try{const e=localStorage.getItem(Tt);if(e)return $a(e);const i=localStorage.getItem(Et);if(!i)return null;const n=JSON.parse(i),s={id:crypto.randomUUID(),name:"Utama",layout:n};return{workspace:je.parse({version:1,groups:[s]}),active:s.id}}catch{return null}}function He(){try{localStorage.removeItem(Tt),localStorage.removeItem(Et)}catch{}}const Nt=e=>`hanoman.terminal.workspace.v2.${encodeURIComponent(e)}`;function Da(e){try{const i=localStorage.getItem(Nt(e));if(!i)return null;const n=JSON.parse(i),s=je.parse(n.workspace);if(!Number.isInteger(n.revision)||(n.revision??-1)<0)return null;const c=typeof n.active=="string"&&s.groups.some(d=>d.id===n.active)?n.active:s.groups[0].id;return{workspace:s,revision:n.revision,active:c}}catch{return null}}function Ge(e,i){try{const n=je.parse(i.workspace);if(!Number.isInteger(i.revision)||i.revision<0)return;const s=n.groups.some(c=>c.id===i.active)?i.active:n.groups[0].id;localStorage.setItem(Nt(e),JSON.stringify({workspace:n,revision:i.revision,active:s}))}catch{}}function Ke(e){if(!(e instanceof Je)||e.status!==409)return null;const i=e.detail;if((i==null?void 0:i.code)!=="revision-conflict")return null;const n=aa.safeParse(i.current);return n.success?n.data:null}function Oa(e){const i=$.useRef(null);i.current||(i.current=xt());const[n,s]=$.useState(i.current),[c,d]=$.useState("loading"),[R,v]=$.useState(null),[T,h]=$.useState(!1),g=$.useRef(n),b=$.useRef(0),u=$.useRef(!1),x=$.useRef(Promise.resolve()),C=$.useRef(0),w=$.useCallback(l=>{g.current=l,s(l)},[]),p=$.useCallback(l=>{u.current=l,h(l)},[]),S=$.useCallback(l=>{const f=x.current.then(l,l);return x.current=f.then(()=>{},()=>{}),f},[]),z=$.useCallback((l,f="ready",I=null,y=g.current.active)=>{const O=l.workspace?Le(l.workspace,y):xt();b.current=l.revision,w(O),d(f),v(I),p(!0),l.workspace&&Ge(e,{workspace:l.workspace,revision:l.revision,active:O.active})},[w,p,e]),N=$.useCallback(l=>{const f=Da(e);f&&(b.current=f.revision,w(Le(f.workspace,f.active))),p(!1),d("recovering"),v(l instanceof Error?l.message:"Layout server belum tersambung")},[w,p,e]),D=$.useCallback(()=>S(async()=>{try{z(await L.getTerminalWorkspace())}catch(l){N(l)}}),[z,S,N]);$.useEffect(()=>{const l=++C.current;return d("loading"),v(null),p(!1),S(async()=>{try{const f=await L.getTerminalWorkspace();if(l!==C.current)return;if(f.workspace){z(f),He();return}const I=Ba();if(!I){z(f);return}try{const y=await L.putTerminalWorkspace({baseRevision:f.revision,workspace:I.workspace});if(l!==C.current)return;w(Le(y.workspace,I.active)),b.current=y.revision,Ge(e,{workspace:y.workspace,revision:y.revision,active:I.active}),He(),d("ready"),v(null),p(!0)}catch(y){const O=Ke(y);O!=null&&O.workspace?(z(O,"conflict","Layout server lebih baru; layout lokal lama tidak diunggah"),He()):N(y)}}catch(f){l===C.current&&N(f)}}),()=>{C.current+=1}},[z,S,N,w,p,e]),$.useEffect(()=>{const l=()=>{D()},f=()=>{document.visibilityState==="visible"&&D()};return window.addEventListener("focus",l),document.addEventListener("visibilitychange",f),()=>{window.removeEventListener("focus",l),document.removeEventListener("visibilitychange",f)}},[D]);const k=$.useCallback(l=>S(async()=>{if(!u.current)return!1;const f=l(g.current);let I,y;try{I=pe(f),y=pe(g.current)}catch{return d("conflict"),v("Layout tidak valid dan tidak disimpan"),!1}if(jt(I,y))return!0;try{return z(await L.putTerminalWorkspace({baseRevision:b.current,workspace:I}),"ready",null,f.active),!0}catch(O){const X=Ke(O);if(!(X!=null&&X.workspace))return N(O),!1;const M=l(Le(X.workspace,g.current.active));try{const _=await L.putTerminalWorkspace({baseRevision:X.revision,workspace:pe(M)});return z(_,"conflict","Layout berubah di perangkat lain; perubahan ini diterapkan ulang",M.active),!0}catch(_){if(!Ke(_)&&!(_ instanceof Je&&_.status===409))return N(_),!1;try{z(await L.getTerminalWorkspace(),"conflict","Layout berubah lagi di perangkat lain; state terbaru dimuat")}catch(Q){N(Q)}return!1}}}),[z,S,N]),E=$.useCallback(l=>{const f=La(g.current,l);w(f);const I=pe(f);Ge(e,{workspace:I,revision:b.current,active:f.active})},[w,e]);return{workspace:n,status:c,message:R,writable:T,mutate:k,setActive:E,refresh:D}}const Pa=[];function tn({userId:e="test-user",projects:i,backlog:n=Pa,focusSession:s,startedSession:c,onStartedSessionHandled:d,onStartBacklog:R,onOpenReview:v,onOpenSessionReview:T,titleOf:h,onIntegrate:g,onIntegrateSession:b,specOf:u,sessions:x,setSessions:C}){var st;const[w,p]=o.useState([]),S=x??w,z=C??p,[N,D]=o.useState([]),k=Oa(e),{workspace:E,status:l,message:f,writable:I,mutate:y,setActive:O,refresh:X}=k,[M,_]=be("terminal","project",((st=i[0])==null?void 0:st.id)??"",xa),Q=wt(),[re,le]=be("terminal","fontSize",Q?fa:ha,ma),[q,me]=be("terminal","keys",Q,Me),[Z,fe]=be("terminal","predict",!0,Me),[V,Se]=be("terminal","diag",!1,Me),oe=a=>le(r=>pa(r+a)),[B,Ie]=o.useState(!1),[K,he]=o.useState(null),[Ce,te]=o.useState(!1),[H,P]=o.useState(null),[Fe,xe]=o.useState(!1),[ze,Re]=o.useState(!1),$e=sa(),W=la()==="mobile",[Y,Te]=o.useState(0),[ee,ae]=o.useState(null),Be=o.useRef(null),[ce,Lt]=o.useState(!1);o.useEffect(()=>{L.listTerminals().then(a=>{z(a),Lt(!0)}).catch(()=>{})},[]),o.useEffect(()=>oa(a=>{a.t==="sessions"&&!x?z(a.sessions):a.t==="cleanups"&&D(a.cleanups)}),[]),o.useEffect(()=>{if(!ce||!I)return;const a=new Set(S.map(m=>m.id)),r=bt(E,a);jt(pe(r),pe(E))||y(m=>bt(m,a))},[y,S,ce,I,E]),o.useEffect(()=>{!c||c.specId==null||!ce||(z(a=>a.some(r=>r.id===c.id)?a:[...a,{...c,cwd:"",exited:!1}]),ae(c.id),d==null||d())},[d,ce,c]),o.useEffect(()=>{if(!s){Be.current=null;return}!ce||Be.current===s||S.some(a=>a.id===s&&!a.exited)&&(Be.current=s,ae(s))},[s,S,ce]),o.useEffect(()=>{if(!ee)return;const a=E.groups.find(r=>r.layout.cells.includes(ee));if(a){a.id!==E.active&&O(a.id);return}I&&y(r=>{if(gt(r).has(ee))return r;const m=ue(r,ee);return m!==r||!W?m:Ve(r,Y,ee)})},[Y,W,y,ee,O,I,E]),o.useEffect(()=>{K&&!S.some(a=>a.id===K)&&he(null)},[K,S]);const De=N.filter(a=>a.error),Ee=a=>S.find(r=>r.id===a)??null,ge=o.useCallback(a=>{var r;return((r=i.find(m=>m.id===a))==null?void 0:r.name)??a},[i]);function Ft(a){z(r=>r.some(m=>m.id===a)?r:[...r,{id:a,projectId:M,cwd:"",exited:!1}]),y(r=>ue(r,a)),ae(a)}async function Qe(){if(!M)return;const{id:a}=await L.createShell(M);z(r=>[...r,{id:a,projectId:M,cwd:"",exited:!1}]),y(r=>ue(r,a)),ae(a)}async function Ze(a,r){if(R&&!r){te(!1),P(null),R(a);return}const m=ba(a.source);try{const{id:j}=await L.startSession({spec:a.id,flow:m,...r?{force:r}:{}});z(A=>A.some(se=>se.id===j)?A:[...A,{id:j,projectId:a.projectId,specId:a.id,flow:m,cwd:"",exited:!1}]),y(A=>ue(A,j)),ae(j),te(!1),P(null)}catch(j){if($e.offerRetry(j,a.id,se=>Ze(a,se)))return;const A=j instanceof Je&&(j.status===400||j.status===422);P(`${a.id} · gagal mulai${A?" · project belum punya repoDir":""}`)}}async function et(a,r){try{const m=a.specId?await L.startSession({spec:a.specId,flow:a.flow??"feature",agent:a.agent==="codex"?"codex":"claude",...a.model?{model:a.model}:{},...a.effort?{effort:a.effort}:{},...r?{force:r}:{}}):a.kind==="shell"?await L.createShell(a.projectId):a.kind==="terminal"?await L.createTerminal(a.projectId,{agent:a.agent==="codex"?"codex":"claude",...a.model?{model:a.model}:{},...a.effort?{effort:a.effort}:{}}):await(r?L.createTerminalFlow(a.projectId,a.kind,{force:r}):L.createTerminalFlow(a.projectId,a.kind));z(j=>j.some(A=>A.id===m.id)?j:[...j,{id:m.id,projectId:a.projectId,specId:a.specId??void 0,cwd:"",exited:!1}]),y(j=>ue(j,m.id)),ae(m.id),Re(!1)}catch(m){if((a.specId||a.kind!=="shell"&&a.kind!=="terminal")&&$e.offerRetry(m,`${a.projectId} · ${a.title??a.specId??a.kind}`,j=>et(a,j)))return}}const tt=new Set(S.filter(a=>a.specId&&!a.exited).map(a=>a.specId)),$t=n.filter(a=>a.stage!=="done"&&!tt.has(a.id));function at(a){z(r=>r.filter(m=>m.id!==a)),L.deleteTerminal(a).catch(()=>{})}const Bt=o.useCallback((a,r)=>{z(m=>m.map(j=>j.id===a?{...j,exited:!0,exitCode:r}:j))},[]),nt={close:at,detach:a=>{y(r=>Fa(r,a))},markExited:Bt,setFullId:he,props:{onOpenReview:v,onOpenSessionReview:T,titleOf:h,onIntegrate:g,onIntegrateSession:b,specOf:u}},U=o.useRef(nt);U.current=nt;const it=o.useRef(new Map),Dt=a=>{let r=it.current.get(a);return r||(r={onClose:()=>void U.current.close(a),onDetach:()=>U.current.detach(a),onExit:m=>U.current.markExited(a,m),onFullscreen:()=>U.current.setFullId(a)},it.current.set(a,r)),r},de=o.useRef({onOpenReview:a=>{var r,m;return(m=(r=U.current.props).onOpenReview)==null?void 0:m.call(r,a)},onOpenSessionReview:(a,r)=>{var m,j;return(j=(m=U.current.props).onOpenSessionReview)==null?void 0:j.call(m,a,r)},titleOf:a=>{var r,m;return(m=(r=U.current.props).titleOf)==null?void 0:m.call(r,a)},onIntegrate:(a,r,m)=>{var j,A;return(A=(j=U.current.props).onIntegrate)==null?void 0:A.call(j,a,r,m)},onIntegrateSession:(a,r,m)=>{var j,A;return(A=(j=U.current.props).onIntegrateSession)==null?void 0:A.call(j,a,r,m)},specOf:a=>{var r,m;return(m=(r=U.current.props).specOf)==null?void 0:m.call(r,a)}}).current,Ot=(a,r)=>{Te(a),y(m=>Ve(m,a,r))},Pt=a=>{ae(a),y(r=>ue(r,a))},Wt=gt(E),Oe=S.filter(a=>!Wt.has(a.id)),F=we(E).layout;o.useEffect(()=>{if(!ee)return;const a=F.cells.indexOf(ee);a<0||(Te(a),ae(null))},[F.cells,ee]),o.useEffect(()=>{Y>=F.cells.length&&Te(Math.max(0,F.cells.length-1))},[Y,F.cells.length]);const rt=F.rows===1&&F.cols===1&&!F.cells[0]&&S.length===0,Mt=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(We,{size:"sm",icon:"minus",label:"Perkecil teks terminal",disabled:re<=ca,onClick:()=>oe(-1)}),t.jsxs("span",{style:{fontFamily:"var(--font-mono)",fontSize:12,minWidth:44,textAlign:"center"},children:[re,"px"]}),t.jsx(We,{size:"sm",icon:"plus",label:"Perbesar teks terminal",disabled:re>=da,onClick:()=>oe(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(G,{size:"sm",variant:"secondary","aria-pressed":q,onClick:()=>me(a=>!a),children:q?"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(G,{size:"sm",variant:"secondary","aria-pressed":Z,"aria-label":`${Z?"Matikan":"Nyalakan"} ketik responsif`,onClick:()=>fe(a=>!a),children:Z?"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(G,{size:"sm",variant:"secondary","aria-pressed":V,"aria-label":`${V?"Matikan":"Nyalakan"} rekam jalur ketik`,onClick:()=>Se(a=>!a),children:V?"Matikan":"Nyalakan"})]}),W&&t.jsx(J,{size:"sm","aria-label":"Project sesi baru",value:M,onChange:a=>_(a.target.value),options:i.map(a=>({value:a.id,label:a.name}))})]}),Ht=[{key:"backlog",label:"Ambil backlog",icon:"inbox",onSelect:()=>{P(null),te(!0)}},{key:"history",label:"Riwayat sesi",icon:"history",onSelect:()=>Re(!0)},{key:"shell",label:"Terminal biasa",icon:"terminal",onSelect:()=>void Qe()},{key:"col+",label:"+ Kolom",icon:"columns-2",disabled:!I,onSelect:()=>void y(a=>ne(a,mt))},{key:"row+",label:"+ Baris",icon:"rows-2",disabled:!I,onSelect:()=>void y(a=>ne(a,pt))},{key:"col-",label:"Hapus kolom aktif",icon:"columns-2",disabled:!I||F.cols===1,onSelect:()=>void y(a=>ne(a,r=>ht(r,Y%r.cols)))},{key:"row-",label:"Hapus baris aktif",icon:"rows-2",disabled:!I||F.rows===1,onSelect:()=>void y(a=>ne(a,r=>ft(r,Math.floor(Y/r.cols))))}],Gt={display:"flex",flexDirection:"column",gap:B?8:12,...B?{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:Gt,children:[t.jsxs("div",{style:{display:"flex",gap:8,flexDirection:B?"row":"column",alignItems:B?"center":"stretch"},children:[t.jsx(Ma,{compact:B,ws:E,writable:I,onSelect:O,onAdd:()=>void y(a=>Ea(a,`Grup ${a.groups.length+1}`)),onRename:(a,r)=>void y(m=>Na(m,a,r)),onRemove:a=>void y(r=>Aa(r,a))}),t.jsxs("div",{style:{display:"flex",alignItems:"center",gap:8,flexWrap:"wrap",...B?{flex:1,minWidth:0}:{}},children:[!W&&t.jsxs(t.Fragment,{children:[t.jsx(G,{size:"sm",variant:"ghost",disabled:!I,onClick:()=>void y(a=>ne(a,mt)),children:"+ Kolom"}),t.jsx(G,{size:"sm",variant:"ghost",disabled:!I,onClick:()=>void y(a=>ne(a,pt)),children:"+ Baris"})]}),t.jsx("div",{style:{flex:1,minWidth:0}}),l!=="ready"&&t.jsx("span",{"data-testid":"terminal-workspace-status",title:f??void 0,style:{fontSize:12,color:l==="conflict"?"var(--status-warn)":"var(--text-muted)"},children:l==="loading"?"Memuat layout server…":l==="recovering"?t.jsxs(t.Fragment,{children:[t.jsx("span",{children:"Layout server belum tersambung"})," ",t.jsx("button",{type:"button",onClick:()=>void X(),children:"Retry"})]}):f??"Layout berubah di perangkat lain"}),N.length>0&&t.jsx("span",{"data-testid":"worktree-cleanups",title:N.map(a=>`${a.sessionId}${a.error?` — ${a.error}`:""}`).join(`
|
|
2
2
|
`),style:{fontSize:12,color:De.length?"var(--status-err)":"var(--text-muted)"},children:De.length?`${De.length} worktree gagal dibersihkan`:`membersihkan ${N.length} worktree…`}),!W&&t.jsxs(t.Fragment,{children:[t.jsx(J,{size:"sm",value:M,onChange:a=>_(a.target.value),options:i.map(a=>({value:a.id,label:a.name}))}),t.jsx(G,{size:"sm",variant:"secondary",leftIcon:"inbox",onClick:()=>{P(null),te(!0)},children:"Ambil backlog"}),t.jsx(G,{size:"sm",variant:"secondary",leftIcon:"history",title:"Riwayat sesi yang sudah berlalu — buka kembali atau baca transkripnya",onClick:()=>Re(!0),children:"Riwayat"}),t.jsx(G,{size:"sm",variant:"secondary",leftIcon:"terminal",title:"Buka shell tmux tanpa Claude di project terpilih — jalankan command di project",onClick:()=>void Qe(),children:"Terminal biasa"})]}),t.jsx(G,{size:"sm",leftIcon:"plus",onClick:()=>xe(!0),children:"Sesi baru"}),t.jsx(St,{label:W?"Aksi terminal lain":"Tampilan terminal",items:W?Ht:[],children:Mt}),t.jsx(We,{size:"sm",icon:B?"minimize-2":"maximize-2",label:B?"Keluar layar penuh":"Layar penuh","aria-pressed":B,onClick:()=>Ie(a=>!a)})]})]}),Oe.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:"}),Oe.map(a=>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:!I,onClick:()=>Pt(a.id),title:"Taruh di sel kosong pertama grup ini",style:{all:"unset",cursor:"pointer"},children:[a.specId??ge(a.projectId)," · ",a.id.slice(0,6)]}),t.jsx("button",{type:"button",className:"hn-terminal-action","aria-label":`Tutup sesi ${a.id}`,onClick:()=>void at(a.id),children:"×"})]},a.id))]}),W&&!rt&&t.jsx("div",{className:"hn-stack-mobile",style:{display:"flex",alignItems:"center",gap:8},children:t.jsx(ua,{"aria-label":"Panel terminal",variant:"pill",value:String(Y),onChange:a=>Te(Number(a)),tabs:F.cells.map((a,r)=>({value:String(r),label:`Panel ${r+1}${a?` · ${a.slice(0,6)}`:" · kosong"}`}))})}),rt?t.jsx(Ye,{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(${F.cols}, minmax(0, 1fr))`,gridTemplateRows:W?"minmax(0, 1fr)":`16px repeat(${F.rows}, minmax(0, 1fr))`},children:[!W&&t.jsx("div",{}),!W&&Array.from({length:F.cols},(a,r)=>t.jsx(vt,{label:`Tutup kolom ${r+1}`,disabled:!I||F.cols===1,onClick:()=>void y(m=>ne(m,j=>ht(j,r)))},`col-${r}`)),Array.from({length:F.rows},(a,r)=>t.jsxs(o.Fragment,{children:[!W&&t.jsx(vt,{label:`Tutup baris ${r+1}`,disabled:!I||F.rows===1,onClick:()=>void y(m=>ne(m,j=>ft(j,r)))}),Array.from({length:F.cols},(m,j)=>{const A=r*F.cols+j,se=F.cells[A]??null,Ne=se?Ee(se):null;return t.jsx("div",{"data-terminal-cell-index":A,"aria-hidden":W&&Y!==A?"true":"false",style:{minHeight:0,minWidth:0,display:W&&Y!==A?"none":"flex",flexDirection:"column",border:"1px solid var(--border-hair)",borderRadius:"var(--radius-sm)",overflow:"hidden"},children:Ne?t.jsx(qa,{session:Ne,nameOf:ge,...Dt(Ne.id),canArrange:I,onReview:v&&de.onOpenReview,onSessionReview:T&&de.onOpenSessionReview,titleOf:h&&de.titleOf,onIntegrate:g&&de.onIntegrate,onIntegrateSession:b&&de.onIntegrateSession,specOf:u&&de.specOf,backlog:n,fontSize:re,showKeys:q,predict:Z,diag:V,fullscreen:K===Ne.id,paneHidden:W&&Y!==A}):t.jsx(Ya,{disabled:!I,unplaced:Oe,nameOf:ge,onPick:Kt=>Ot(A,Kt)})},se??`empty-${A}`)})]},`row-${r}`))]}),Ce&&t.jsx(Wa,{seed:$t,activeIds:tt,error:H,onPick:a=>void Ze(a),onClose:()=>te(!1)}),Fe&&t.jsx(za,{open:!0,projectId:M,projectName:ge(M),onClose:()=>xe(!1),onCreated:Ft}),ze&&t.jsx(Ia,{projects:i,onClose:()=>Re(!1),onRestart:a=>void et(a)}),$e.dialog,K&&Ee(K)&&t.jsx(Va,{session:Ee(K),label:At(Ee(K),ge,h),fontSize:re,showKeys:q,predict:Z,diag:V,onClose:()=>he(null)})]})}function At(e,i,n){const s=i(e.projectId),c=e.specId?n==null?void 0:n(e.specId):void 0;return e.specId?`${s} · ${e.specId}${c?` · ${c}`:""}`:e.id.startsWith("xaudit-")?`${s} · audit lintas`:s}function Wa({seed:e,activeIds:i,error:n,onPick:s,onClose:c}){const[d,R]=o.useState(""),[v,T]=o.useState("all"),[h,g]=o.useState("all"),[b,u]=o.useState(e),[x,C]=o.useState("");o.useEffect(()=>{const p=setTimeout(()=>C(d.trim()),250);return()=>clearTimeout(p)},[d]),o.useEffect(()=>{var z,N;let p=!0;const S=(N=(z=L).listSpecs)==null?void 0:N.call(z,{startable:!0,q:x||void 0,stage:v==="all"?void 0:v,priority:h==="all"?void 0:h});return S==null||S.then(D=>{p&&u(D.items)}).catch(()=>{}),()=>{p=!1}},[x,v,h]);const w=b.filter(p=>!i.has(p.id));return t.jsxs(ke,{open:!0,title:"Ambil backlog",icon:"inbox",onClose:c,width:760,children:[n&&t.jsx("div",{style:{marginBottom:10,padding:"8px 10px",borderRadius:"var(--radius-sm)",background:"var(--clay-100)",color:"var(--clay-600)",fontSize:12},children:n}),t.jsxs("div",{style:{display:"flex",alignItems:"center",gap:10,flexWrap:"wrap",marginBottom:10},children:[t.jsx(yt,{size:"sm",leftIcon:"search",placeholder:"mis. invoice atau SPEC-412","aria-label":"Cari backlog",value:d,onChange:p=>R(p.target.value),style:{flex:"1 1 220px"}}),t.jsx(J,{size:"sm","aria-label":"Filter stage",value:v,onChange:p=>T(p.target.value),options:[{value:"all",label:"Semua stage"}].concat(ga.filter(p=>p.key!=="done").map(p=>({value:p.key,label:p.label})))}),t.jsx(J,{size:"sm","aria-label":"Filter prioritas",value:h,onChange:p=>g(p.target.value),options:[{value:"all",label:"Semua prioritas"},{value:"tinggi",label:"Tinggi"},{value:"sedang",label:"Sedang"},{value:"rendah",label:"Rendah"}]})]}),w.length===0?t.jsx(Ye,{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:w.map(p=>t.jsx("button",{onClick:()=>s(p),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(ie,{name:p.source==="qa"?"bug":p.source==="audit"?"search":"lightbulb",size:14,color:p.source==="qa"?"var(--clay-500)":p.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:p.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:p.title}),t.jsx(_e,{tone:p.priority==="tinggi"?"err":"neutral",size:"sm",children:p.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:p.projectId})]})},p.id))})]})}function Ma({ws:e,compact:i=!1,writable:n,onSelect:s,onAdd:c,onRename:d,onRemove:R}){const[v,T]=o.useState(null),h=we(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",...i?{}:{borderBottom:"1px solid var(--border-hair)",paddingBottom:4}},children:[e.groups.map((b,u)=>{const x=b.id===h.id;return v===b.id?t.jsx(Ha,{initial:b.name,onCommit:C=>{C.trim()&&d(b.id,C.trim()),T(null)},onCancel:()=>T(null)},b.id):t.jsxs("span",{style:{display:"inline-flex",alignItems:"center",gap:4,padding:"3px 6px",borderRadius:"var(--radius-sm)",fontSize:12,background:x?"var(--bone-200)":"transparent",border:`1px solid ${x?"var(--border-hair)":"transparent"}`},children:[t.jsx("button",{className:"hn-terminal-group-control",role:"tab","aria-selected":x,tabIndex:x?0:-1,onClick:()=>s(b.id),onKeyDown:C=>{var p,S;let w=null;C.key==="ArrowRight"?w=(u+1)%e.groups.length:C.key==="ArrowLeft"?w=(u-1+e.groups.length)%e.groups.length:C.key==="Home"?w=0:C.key==="End"&&(w=e.groups.length-1),w!==null&&(C.preventDefault(),s(e.groups[w].id),(S=(p=C.currentTarget.closest('[role="tablist"]'))==null?void 0:p.querySelectorAll('[role="tab"]')[w])==null||S.focus())},style:{border:0,padding:0,background:"transparent",font:"inherit",cursor:"pointer",color:x?"var(--text-strong)":"var(--text-muted)"},children:b.name}),x&&n&&t.jsxs(t.Fragment,{children:[t.jsx("button",{className:"hn-terminal-group-control","aria-label":`Ganti nama grup ${b.name}`,title:"Ganti nama",onClick:()=>T(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:()=>R(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:!n,onClick:c,style:{border:0,background:"transparent",cursor:"pointer",padding:"3px 8px",color:"var(--text-subtle)",fontSize:12},children:"+"})]})}function vt({label:e,disabled:i,onClick:n}){return t.jsx("button",{type:"button","aria-label":e,title:i?"Grid tak boleh menyusut ke nol":e,disabled:i,onClick:n,style:{all:"unset",display:"grid",placeItems:"center",fontSize:11,lineHeight:1,color:"var(--text-subtle)",opacity:i?.3:1,cursor:i?"not-allowed":"pointer"},children:"×"})}function Ha({initial:e,onCommit:i,onCancel:n}){const[s,c]=o.useState(e);return t.jsx("input",{autoFocus:!0,"aria-label":"Nama grup",value:s,placeholder:"mis. Rilis",onChange:d=>c(d.target.value),onBlur:()=>i(s),onKeyDown:d=>{d.key==="Enter"?i(s):d.key==="Escape"&&n()},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 Ga={done:"var(--brass)",active:"var(--text-strong)",skipped:"var(--text-subtle)",pending:"var(--text-subtle)"},Ka={done:"✓",running:"●",pending:"○",skipped:"–",failed:"✕",abandoned:"⨯"};function _a({phases:e,compact:i=!1,now:n}){const[s,c]=o.useState(null),d=na(s!==null,()=>c(null),"dialog"),[,R]=o.useState(0),v=!!(e!=null&&e.some(u=>{var x;return((x=u.agent)==null?void 0:x.status)==="running"}));if(o.useEffect(()=>{if(!(!v||n!==void 0))return ja(()=>R(u=>u+1))},[v,n]),!(e!=null&&e.length))return null;const T=n??Date.now(),h=e.find(u=>u.name===s&&u.agent),g=u=>({color:Ga[u.state],fontWeight:u.state==="active"?600:400,textDecoration:u.state==="skipped"?"line-through":"none",opacity:u.state==="pending"?.5:1}),b=u=>{const x=u.agent;return x?typeof x.durationMs=="number"?ct(x.durationMs):x.status==="running"&&x.startedAt?ct(T-Date.parse(x.startedAt)):"":""};return t.jsxs("div",{"data-testid":"phase-strip",style:{flex:"0 0 auto",borderBottom:"1px solid var(--border-hair)"},children:[t.jsx("div",{"data-testid":"phase-strip-scroller",style:{display:"flex",alignItems:"center",gap:8,padding:"3px 8px",fontSize:10,fontFamily:"var(--font-mono)",overflowX:"auto",whiteSpace:"nowrap"},children:e.map(u=>{if(!u.agent)return t.jsx("span",{"data-state":u.state,title:u.state,style:g(u),children:u.name},u.name);const x=u.agent,C=ia(u),w=!i||u.state==="active",p=b(u);return t.jsxs("button",{type:"button","data-tone":C,"aria-expanded":s===u.name,ref:s===u.name?d.triggerRef:void 0,"aria-haspopup":"dialog","aria-controls":s===u.name?d.panelId:void 0,"aria-label":ra(u,p),onClick:()=>c(s===u.name?null:u.name),style:{display:"inline-flex",alignItems:"center",gap:4,flex:"0 0 auto",padding:"1px 6px",border:"1px solid var(--border-hair)",borderRadius:"var(--radius-sm)",background:"transparent",font:"inherit",color:"var(--text-body)",cursor:"pointer"},children:[t.jsx("span",{"aria-hidden":!0,children:Ka[C]}),t.jsx("span",{"data-state":u.state,title:u.state,style:g(u),children:u.name}),u.state==="skipped"&&t.jsx("span",{children:"dilewati"}),w&&x.model&&t.jsxs("span",{children:["· ",qe(x.model)]}),w&&x.effort&&t.jsxs("span",{children:["· ",x.effort]}),w&&p&&t.jsxs("span",{children:["· ",p]}),x.attempts>1&&t.jsxs("span",{children:["↻",x.attempts]}),x.evidence==="missing"&&t.jsx("span",{role:"img","aria-label":"bukti subagent tak diterima",title:"bukti subagent tak diterima",style:{color:"var(--status-warn)"},children:"⚠"})]},u.name)})}),(h==null?void 0:h.agent)&&t.jsxs("div",{ref:d.panelRef,id:d.panelId,role:"dialog","aria-label":`Detail fase ${h.name}`,tabIndex:-1,onKeyDown:d.onKeyDown,style:{position:"absolute",marginLeft:8,zIndex:5,minWidth:220,maxWidth:"min(420px, calc(100% - 16px))",maxHeight:"calc(100% - 48px)",overflowY:"auto",boxSizing:"border-box",padding:"8px 10px",background:"var(--surface-card)",border:"1px solid var(--border-hair)",borderRadius:"var(--radius-sm)",whiteSpace:"normal",lineHeight:1.5,fontSize:10,fontFamily:"var(--font-mono)"},children:[t.jsx("div",{children:t.jsx("b",{children:h.agent.name})}),t.jsx("div",{children:[qe(h.agent.model),h.agent.effort,h.agent.status??"belum mulai"].filter(Boolean).join(" · ")}),t.jsxs("div",{children:["durasi ",b(h)||"—"," · percobaan ",h.agent.attempts]}),t.jsxs("div",{children:["token in ",h.agent.inputTokens??"—"," · out ",h.agent.outputTokens??"—"," · cache ",h.agent.cachedTokens??"—"]}),h.agent.resultExcerpt&&t.jsx("pre",{style:{margin:"6px 0 0",whiteSpace:"pre-wrap",maxHeight:160,overflow:"auto"},children:h.agent.resultExcerpt})]})]})}const qa=o.memo(Ua);function Ua({session:e,nameOf:i,onClose:n,canArrange:s,onDetach:c,onExit:d,onReview:R,onSessionReview:v,titleOf:T,onIntegrate:h,onIntegrateSession:g,specOf:b,fontSize:u,showKeys:x,predict:C,diag:w,fullscreen:p,onFullscreen:S,paneHidden:z}){const[N,D]=o.useState(null),k=o.useRef(null),[E,l]=o.useState(Number.POSITIVE_INFINITY),f=wt();o.useEffect(()=>{const H=k.current;if(!H||typeof ResizeObserver!="function")return;const P=new ResizeObserver(Fe=>{var ze;const xe=((ze=Fe[0])==null?void 0:ze.contentRect.width)??H.getBoundingClientRect().width;xe>0&&l(xe)});return P.observe(H),()=>P.disconnect()},[]);const[I,y]=o.useState(!1),O=o.useCallback((H,P)=>{D(H),y(P)},[]),[X,M]=o.useState(!1),[_,Q]=o.useState(!1),[re,le]=o.useState(!1),q=e.specId?b==null?void 0:b(e.specId):void 0,me=!e.specId&&!!e.branch,Z=At(e,i,T),fe=!e.exited&&!!e.decision,V=!e.exited&&!!e.deciding,Se=fe||V,oe=e.exited&&!!e.exitCode,B=!e.exited&&I,Ie=oe?null:e.exited||B?"PST-005":Se?"PST-004":"PST-003",K=[...e.specId?[{key:"docs",label:"Lihat dokumen",icon:"file-text",title:"Lihat dokumen (audit/spec/plan)",onSelect:()=>M(!0),render:t.jsx("button",{type:"button",className:"hn-terminal-action",onClick:()=>M(!0),"aria-label":`Lihat dokumen sesi ${e.id}`,title:"Lihat dokumen (audit/spec/plan)",children:t.jsx(ie,{name:"file-text",size:12})},"docs")}]:[],...e.specId&&R?[{key:"review",label:"Review perubahan",icon:"git-compare",title:"Review perubahan (diff worktree)",onSelect:()=>R(e.specId),render:t.jsx("button",{type:"button",className:"hn-terminal-action",onClick:()=>R(e.specId),"aria-label":`Review sesi ${e.id}`,title:"Review perubahan (diff worktree)",children:t.jsx(ie,{name:"git-compare",size:12})},"review")}]:[],...me&&v?[{key:"review-session",label:"Review perubahan",icon:"git-compare",title:"Review perubahan (diff worktree sesi)",onSelect:()=>v(e.id,Z),render:t.jsx("button",{type:"button",className:"hn-terminal-action",onClick:()=>v(e.id,Z),"aria-label":`Review sesi ${e.id}`,title:"Review perubahan (diff worktree sesi)",children:t.jsx(ie,{name:"git-compare",size:12})},"review-session")}]:[],...q&&h?[{key:"integrate",label:"Rebase / Merge branch",icon:"git-merge",title:"Rebase / Merge branch spec",onSelect:()=>Q(!0),render:t.jsx("button",{type:"button",className:"hn-terminal-action",onClick:()=>Q(!0),"aria-label":`Integrasikan sesi ${e.id}`,title:"Rebase / Merge branch spec",children:t.jsx(ie,{name:"git-merge",size:12})},"integrate")}]:[],...me&&g?[{key:"integrate-session",label:"Rebase / Merge branch",icon:"git-merge",title:"Rebase / Merge branch sesi",onSelect:()=>le(!0),render:t.jsx("button",{type:"button",className:"hn-terminal-action",onClick:()=>le(!0),"aria-label":`Integrasikan sesi ${e.id}`,title:"Rebase / Merge branch sesi",children:t.jsx(ie,{name:"git-merge",size:12})},"integrate-session")}]:[],{key:"detach",label:"Lepas dari grid",icon:"unlink",disabled:!s,title:"Lepas dari grid (sesi tetap hidup)",onSelect:c,render:t.jsx("button",{type:"button",className:"hn-terminal-action hn-terminal-action--text",onClick:c,disabled:!s,title:"Lepas dari grid (sesi tetap hidup)",children:"lepas"},"detach")},{key:"fullscreen",label:"Layar penuh",icon:"fullscreen",title:"Layar penuh — fokus 1 terminal",onSelect:S,render:t.jsx("button",{type:"button",className:"hn-terminal-action",onClick:S,title:"Layar penuh — fokus 1 terminal","aria-label":`Layar penuh sesi ${e.id}`,children:t.jsx(ie,{name:"fullscreen",size:12})},"fullscreen")},{key:"close",label:"Tutup",icon:"x",title:"Tutup sesi",onSelect:n,render:t.jsx("button",{type:"button",className:"hn-terminal-action","aria-label":`Tutup sesi ${e.id}`,onClick:n,children:"×"},"close")}],he=40+(e.orchestrated&&e.model?110:0)+(e.exited||B?110:0)+(V||fe&&!B?130:0),Ce=ka(E,K.length,f?44:28,he),te=K.slice(Ce);return t.jsxs(t.Fragment,{children:[t.jsxs("div",{ref:k,className:"hn-terminal-cell-header",style:{display:"flex",alignItems:"center",gap:8,padding:"4px 8px",flex:"0 0 auto",background:oe?"var(--status-err-tint)":e.exited||B?"var(--status-ok-tint)":Se?"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:[Ie&&t.jsx(va,{id:Ie,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:[Z," · ",e.id.slice(0,6)]}),e.orchestrated&&e.model&&t.jsxs("span",{"data-testid":"orchestrator-chip",title:"Model & effort orchestrator",style:{flex:"0 0 auto",fontSize:10,color:"var(--text-muted)"},children:["orch ",qe(e.model),e.effort?` · ${e.effort}`:""]}),e.exited&&(oe?t.jsx(ve,{status:"failed",size:"sm",children:`Gagal · exit ${e.exitCode}`}):t.jsx(ve,{status:"done",size:"sm",children:"Selesai"})),B&&t.jsx(ve,{status:"done",size:"sm",children:"Selesai"}),V&&!B&&t.jsx(ve,{status:"running",size:"sm",children:"Lead memutuskan"}),fe&&!V&&!B&&t.jsx(ve,{status:"awaiting",size:"sm"}),t.jsxs("span",{className:"hn-terminal-actions",children:[K.slice(0,Ce).map(H=>H.render),te.length>0&&t.jsx(St,{label:`Aksi lain sesi ${e.id}`,items:te.map(({render:H,...P})=>P)})]})]}),t.jsxs("div",{style:{display:"flex",flexDirection:"column",flex:1,minHeight:0,position:"relative",opacity:e.exited?.6:1},children:[t.jsx(_a,{phases:N,compact:E<480}),t.jsx("div",{style:{flex:1,minHeight:0},children:p?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(It,{sessionId:e.id,onExit:d,onPhases:O,fontSize:u,showKeys:x,predict:C,diag:w,hidden:z},e.id)})]}),X&&e.specId&&t.jsx(ya,{specId:e.specId,onClose:()=>M(!1)}),_&&q&&h&&t.jsx(dt,{projectId:q.projectId,ownBranch:`hanoman/${q.id.toLowerCase().replace(/[^a-z0-9_-]/g,"_")}`,eyebrow:q.id,onClose:()=>Q(!1),onIntegrate:(H,P)=>{Q(!1),h(q,H,P)}}),re&&me&&g&&t.jsx(dt,{projectId:e.projectId,ownBranch:e.branch,eyebrow:e.id.slice(0,16),onClose:()=>le(!1),onIntegrate:(H,P)=>{le(!1),g(e,H,P)}})]})}function Va({session:e,label:i,fontSize:n,showKeys:s,predict:c,diag:d,onClose:R}){return t.jsx(ke,{open:!0,icon:"terminal",title:i,onClose:R,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(It,{sessionId:e.id,onExit:()=>{},fontSize:n,showKeys:s,predict:c,diag:d},e.id)})})}function Ya({unplaced:e,nameOf:i,onPick:n,disabled:s}){return t.jsx("div",{style:{flex:1,display:"grid",placeItems:"center",padding:12},children:t.jsx(J,{size:"sm",value:"","aria-label":"Pilih sesi untuk sel",disabled:s||!e.length,onChange:c=>c.target.value&&n(c.target.value),options:[{value:"",label:e.length?"Pilih sesi…":"tidak ada sesi bebas"}].concat(e.map(c=>({value:c.id,label:`${c.specId??i(c.projectId)} · ${c.id.slice(0,6)}`})))})})}export{_a as PhaseStrip,tn 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-B_pRoVeM.js";import{R as l}from"./react-DfGhg7ZW.js";import{L as ue}from"./live-B0yZ2azt.js";import"./markdown-CWEY34jk.js";import"./xterm-3VOAfa_q.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 Se({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,Se 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-CCJTT5hd.js";import{R as l}from"./react-DfGhg7ZW.js";import{L as ue}from"./live-Jy46oHWQ.js";import"./markdown-CWEY34jk.js";import"./xterm-3VOAfa_q.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 Se({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,Se 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,aC as be,ar as ke,c as O,d as T,a9 as ye,am as se,y as ve}from"./index-B_pRoVeM.js";import{R as p}from"./react-DfGhg7ZW.js";import"./markdown-CWEY34jk.js";import"./xterm-3VOAfa_q.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,aC as be,ar as ke,c as O,d as T,a9 as ye,am as se,y as ve}from"./index-CCJTT5hd.js";import{R as p}from"./react-DfGhg7ZW.js";import"./markdown-CWEY34jk.js";import"./xterm-3VOAfa_q.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 _e({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{_e as VpsScreen,Ve as hardenedLabel,ie as isReachable,re as vpsFormToBody};
|