hanoman 0.9.11 → 0.9.13
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 +358 -37
- package/dist/server.js +20667 -17844
- package/package.json +1 -1
- package/prisma/migrations/20261001081455_qa_workspace/migration.sql +85 -0
- package/prisma/migrations/20261001093314_qa_attachment_sync/migration.sql +31 -0
- package/prisma/schema.prisma +97 -0
- package/web/assets/{ChangelogScreen-CYHlMkuo.js → ChangelogScreen-Ceqp0J6L.js} +1 -1
- package/web/assets/{DalangHanomanScreen-BIREPQkt.js → DalangHanomanScreen-CPJtZxV3.js} +1 -1
- package/web/assets/{DocPreviewModal-Dy5PZX3L.js → DocPreviewModal-C_vQOOHV.js} +1 -1
- package/web/assets/{DocsWorkspace-sstV_mwF.js → DocsWorkspace-D4P_5t9b.js} +2 -2
- package/web/assets/{IdeScreen-BoZ21X0r.js → IdeScreen-bD4qiBDt.js} +1 -1
- package/web/assets/{LeadScreen-B8j5AbCq.js → LeadScreen-Db9PHjdT.js} +1 -1
- package/web/assets/{ReviewScreen-9jkwgxsp.js → ReviewScreen-DLlDOQod.js} +1 -1
- package/web/assets/{SchedulerScreen-BmeeP6iC.js → SchedulerScreen-D6ffDlTM.js} +1 -1
- package/web/assets/{SettingsScreen-BpjqRvvn.js → SettingsScreen-72EvmiY4.js} +4 -4
- package/web/assets/{TeamScreen-ftIlQ3wy.js → TeamScreen-CY-5tnPa.js} +1 -1
- package/web/assets/TerminalScreen-CKac8Ti6.js +2 -0
- package/web/assets/{TriageScreen-CMJajN4R.js → TriageScreen-BEb2vxPb.js} +1 -1
- package/web/assets/{VpsScreen-B1tHTxXY.js → VpsScreen-DTJd5Gks.js} +1 -1
- package/web/assets/index-BsjfXxQM.css +32 -0
- package/web/assets/index-DYNYB1Nj.js +1039 -0
- package/web/assets/{live-DZWDT8yU.js → live-nMnpVkPn.js} +1 -1
- package/web/index.html +2 -2
- package/web/assets/TerminalScreen-CQuR2PLL.js +0 -2
- package/web/assets/index-C0hF6fPX.js +0 -1017
- package/web/assets/index-ezlZRsLF.css +0 -32
|
@@ -1 +1 @@
|
|
|
1
|
-
import{T as Ae,j as t,F as G,L as lt,B as ae,I as X,a as B,S as M,u as Ue,M as xe,c as $,d as O,H as ot,e as w,P as Te,E as dt,s as ct,f as H,g as de,h as A,o as we,k as ut,l as mt,m as pt,R as gt,n as ht,p as ce,q as ft}from"./index-C0hF6fPX.js";import{R as m}from"./react-DfGhg7ZW.js";import{L as xt}from"./live-DZWDT8yU.js";import"./markdown-CWEY34jk.js";import"./xterm-3VOAfa_q.js";const bt={backlog:"Backlog",doing:"Dikerjakan",review:"Review",done:"Selesai"},K=Ae.map(e=>({key:e,label:bt[e]})),vt=()=>Object.fromEntries(Ae.map(e=>[e,[]])),pe=(e,a)=>e!==a,He=e=>e.length===0?0:e.reduce((a,n)=>n.order>a?n.order:a,-1/0)+1;function yt(e,a,n,r){if(!pe(n,r))return null;const l=e[n].find(g=>g.id===a);if(!l)return null;const o={status:r,order:He(e[r])},d={...e};return d[n]=e[n].filter(g=>g.id!==a),d[r]=[...e[r],{...l,...o}],{board:d,patch:o}}function ue(e,a){const n={...e};return n[a.status]=e[a.status].map(r=>r.id===a.id?a:r),n}const De=e=>e?e.slice(0,10):"",Ee=e=>/^\d{4}-\d{2}-\d{2}$/.test(e)?`${e}T12:00:00.000Z`:null,F=864e5,ee=e=>Math.floor(e/F)*F,Me=e=>{if(!e)return null;const a=new Date(e).getTime();return Number.isFinite(a)?a:null};function Y(e){const a=Me(e.startDate),n=Me(e.dueDate);if(a===null&&n===null)return null;const r=a??n,l=n??a;return{start:ee(Math.min(r,l)),end:ee(Math.max(r,l))+F,invalid:l<r}}const jt=new Intl.DateTimeFormat("id-ID",{day:"numeric",month:"short",timeZone:"UTC"}),Be=e=>e?jt.format(new Date(e)):null;function Q(e){const a=Be(e.startDate),n=Be(e.dueDate);return a&&n?`${a} → ${n}`:n?`→ ${n}`:a}const Le=["day","week","month"],Ke={day:{cell:34,minTicks:14},week:{cell:56,minTicks:8},month:{cell:84,minTicks:6}},kt=e=>Ke[e].cell,St=120,It=(e,a)=>{const n=ee(e);if(a==="day")return n;if(a==="week")return n-(new Date(n).getUTCDay()+6)%7*F;const r=new Date(n);return Date.UTC(r.getUTCFullYear(),r.getUTCMonth(),1)},Ct=(e,a)=>{if(a==="day")return e+F;if(a==="week")return e+7*F;const n=new Date(e);return Date.UTC(n.getUTCFullYear(),n.getUTCMonth()+1,1)},Tt=new Intl.DateTimeFormat("id-ID",{day:"numeric",timeZone:"UTC"}),$e=new Intl.DateTimeFormat("id-ID",{day:"numeric",month:"short",timeZone:"UTC"}),wt=new Intl.DateTimeFormat("id-ID",{month:"short",timeZone:"UTC"}),Dt=new Intl.DateTimeFormat("id-ID",{month:"short",year:"2-digit",timeZone:"UTC"}),Et=(e,a)=>{const n=new Date(e);return a==="day"?n.getUTCDate()===1:a==="week"?n.getUTCDate()<=7:n.getUTCMonth()===0},Mt=(e,a,n)=>{const r=new Date(e);return a==="day"?(n?$e:Tt).format(r):a==="week"?$e.format(r):(n?Dt:wt).format(r)};function Ge(e,a,n){const r=ee(n);let l=r,o=r+F;for(const c of e)c.start<l&&(l=c.start),c.end>o&&(o=c.end);const d=It(l,a),{minTicks:g}=Ke[a],u=[];let i=d;for(;u.length<St&&(i<o||u.length<g);){const c=Et(i,a);u.push({start:i,label:Mt(i,a,c),major:c}),i=Ct(i,a)}return{from:d,to:i,zoom:a,ticks:u}}function Ye(e,a){const n=a.to-a.from;if(n<=0||e.end<=a.from||e.start>=a.to)return null;const r=Math.max(e.start,a.from),l=Math.min(e.end,a.to);return{left:(r-a.from)/n*100,width:(l-r)/n*100,clippedStart:e.start<a.from,clippedEnd:e.end>a.to,invalid:e.invalid}}function ge(e,a){const n=Y(e);return n?Ye(n,a):null}function Bt(e){let a=1/0,n=-1/0,r=!1;for(const l of e){const o=Y(l);o&&(o.start<a&&(a=o.start),o.end>n&&(n=o.end),o.invalid&&(r=!0))}return a===1/0?null:{start:a,end:n,invalid:r}}function Lt(e,a){const n=ee(a);return n<e.from||n>=e.to?null:(n-e.from)/(e.to-e.from)*100}function $t(e,a){const n=[],r=[],l=[];for(const o of e){const d=Y(o);if(!d){r.push(o);continue}const g=ge(o,a);if(!g){l.push(o);continue}n.push({task:o,geometry:g,start:d.start})}return n.sort((o,d)=>o.start-d.start||o.task.title.localeCompare(d.task.title,"id")||o.task.id.localeCompare(d.task.id)),{rows:n.map(({task:o,geometry:d})=>({task:o,geometry:d})),unscheduled:r,outside:l}}const ze=(e,a)=>e.title.localeCompare(a.title,"id")||e.id.localeCompare(a.id);function zt(e,a,n){const r=Symbol("no-project"),l=new Map;for(const u of e){const i=u.projectId??r,c=l.get(i);c?c.tasks.push(u):l.set(i,{projectId:u.projectId,tasks:[u]})}const o=[...l.values()].map(({projectId:u,tasks:i})=>{const c=Bt(i),p=[],v=[];for(const x of i){const h=Y(x);h?p.push({task:x,start:h.start}):v.push(x)}return p.sort((x,h)=>x.start-h.start||ze(x.task,h.task)),v.sort(ze),{projectId:u,span:c,geometry:c?Ye(c,a):null,tasks:[...p.map(x=>x.task),...v]}}),d=u=>u.geometry?0:u.span?1:2,g=u=>u.projectId===null?[1,""]:[0,u.projectId];return o.sort((u,i)=>{const[c,p]=g(u),[v,x]=g(i);return d(u)-d(i)||(u.span&&i.span?u.span.start-i.span.start:0)||n(u.projectId).localeCompare(n(i.projectId),"id")||c-v||p.localeCompare(x)}),o}const Ot={tinggi:"err",sedang:"neutral",rendah:"neutral"};function Rt({task:e,members:a,dragging:n,onDragStart:r,onDragEnd:l,onOpen:o,onMove:d,onAssign:g,onEscalate:u,onUnlink:i}){var v;const c=((v=a.find(x=>x.id===e.memberId))==null?void 0:v.name)??"belum ditugaskan",p=Q(e);return t.jsxs("div",{draggable:!0,"data-testid":`team-card-${e.id}`,onDragStart:x=>{x.dataTransfer.effectAllowed="move",x.dataTransfer.setData("text/plain",e.id),r()},onDragEnd:l,style:{flex:"0 0 auto",background:"var(--surface-card)",border:"1px solid var(--border-hair)",borderRadius:"var(--radius-md)",padding:10,boxShadow:"var(--shadow-xs)",cursor:"grab",opacity:n?.4:1},children:[t.jsxs("div",{style:{display:"flex",alignItems:"center",gap:6,marginBottom:6},children:[t.jsx(ae,{tone:Ot[e.priority]??"neutral",size:"sm",variant:e.priority==="tinggi"?"soft":"outline",children:e.priority}),t.jsx("span",{style:{flex:1}}),t.jsx("span",{style:{fontFamily:"var(--font-mono)",fontSize:11,color:"var(--text-subtle)",overflow:"hidden",textOverflow:"ellipsis",whiteSpace:"nowrap"},children:e.projectId??"tanpa project"})]}),t.jsx("button",{type:"button",onClick:()=>o(e),style:{display:"block",width:"100%",textAlign:"left",border:"none",background:"none",padding:0,cursor:"pointer",fontFamily:"var(--font-ui)",fontSize:13,fontWeight:"var(--weight-medium)",color:"var(--text-strong)",lineHeight:1.35},children:e.title}),t.jsxs("div",{style:{display:"flex",alignItems:"center",gap:6,marginTop:6,flexWrap:"wrap",fontSize:"var(--text-xs)",color:"var(--text-subtle)"},children:[t.jsx(X,{name:"user",size:12,color:"var(--text-subtle)"}),t.jsx("span",{children:c}),p&&t.jsxs(t.Fragment,{children:[t.jsx("span",{"aria-hidden":"true",children:"·"}),t.jsx("span",{children:p})]})]}),t.jsx("div",{style:{display:"flex",alignItems:"center",gap:6,marginTop:6,flexWrap:"wrap"},children:e.specId?t.jsxs(t.Fragment,{children:[t.jsx(ae,{tone:e.spec?"ok":"warn",size:"sm",icon:e.spec?"link":"unlink",children:e.spec?`${e.spec.id} · ${e.spec.stage}`:"tautan putus"}),t.jsx(B,{size:"sm",variant:"ghost",leftIcon:"unlink","aria-label":`Lepas tautan: ${e.title}`,onClick:()=>i(e),children:"Lepas tautan"})]}):t.jsx(B,{size:"sm",variant:"ghost",leftIcon:"git-branch","aria-label":`Eskalasi ke backlog: ${e.title}`,onClick:()=>u(e),children:"Eskalasi"})}),t.jsxs("div",{style:{display:"flex",gap:6,marginTop:8},children:[t.jsx(M,{size:"sm",value:e.status,"aria-label":`Pindah kolom: ${e.title}`,onChange:x=>d(e,x.target.value),options:K.map(x=>({value:x.key,label:x.label})),style:{flex:1,minWidth:0}}),t.jsx(M,{size:"sm",value:e.memberId??"","aria-label":`Tugaskan: ${e.title}`,onChange:x=>g(e,x.target.value||null),options:[{value:"",label:"Belum ditugaskan"},...a.map(x=>({value:x.id,label:x.name}))],style:{flex:1,minWidth:0}})]})]})}function Pt({board:e,totals:a,columns:n,members:r,onMove:l,onAssign:o,onOpen:d,onEscalate:g,onUnlink:u}){const[i,c]=m.useState(null),[p,v]=m.useState(null),x=h=>{i&&pe(i.from,h)&&l(i.task,h),c(null),v(null)};return t.jsx("div",{"data-testid":"team-board",className:"hn-board-local-overflow",style:{flex:"1 1 auto",minHeight:0,display:"flex",gap:10,overflowX:"auto",overflowY:"hidden",alignItems:"stretch",paddingBottom:4},children:n.map(h=>{const y=e[h.key],f=!!i&&pe(i.from,h.key),k=f&&p===h.key,L=Math.max(0,(a[h.key]??0)-y.length);return t.jsxs("div",{"data-testid":`team-col-${h.key}`,onDragOver:S=>{f&&(S.preventDefault(),S.dataTransfer.dropEffect="move",v(h.key))},onDragLeave:()=>v(S=>S===h.key?null:S),onDrop:S=>{S.preventDefault(),x(h.key)},style:{flex:"0 0 244px",display:"flex",flexDirection:"column",minHeight:0,padding:10,borderRadius:"var(--radius-lg)",background:k?"var(--brass-100)":"var(--bone-100)",border:`1px ${f?"dashed":"solid"} ${k?"var(--brass-500)":"var(--border-hair)"}`,opacity:i&&!f?.5:1,transition:"var(--transition-fast)"},children:[t.jsxs("div",{style:{...G,display:"flex",alignItems:"center",gap:6,marginBottom:8},children:[t.jsx("span",{className:"hn-eyebrow",children:h.label}),t.jsx("span",{style:{flex:1}}),t.jsx("span",{style:{fontFamily:"var(--font-mono)",fontSize:11,color:"var(--text-subtle)"},children:y.length})]}),t.jsx("div",{style:{...lt,display:"flex",flexDirection:"column",gap:8},children:y.map(S=>t.jsx(Rt,{task:S,members:r,dragging:(i==null?void 0:i.task.id)===S.id,onDragStart:()=>c({task:S,from:h.key}),onDragEnd:()=>{c(null),v(null)},onOpen:d,onMove:l,onAssign:o,onEscalate:g,onUnlink:u},S.id))}),L>0&&t.jsxs("div",{style:{...G,marginTop:8,fontSize:"var(--text-xs)",color:"var(--amber-600)"},children:["menampilkan ",y.length," dari ",a[h.key]," — persempit penyaring"]})]},h.key)})})}const U=232,he=34,me=6,_t={brass:{bg:"var(--brass-300)",border:"var(--brass-500)"},err:{bg:"var(--status-err-tint)",border:"var(--status-err)"},muted:{bg:"var(--bone-300)",border:"var(--border-strong)"},envelope:{bg:"var(--bone-200)",border:"var(--border-hair)"}},Oe={position:"sticky",left:0,zIndex:1,flex:`0 0 ${U}px`,width:U,boxSizing:"border-box",padding:"5px 10px",minWidth:0,background:"var(--surface-card)",borderRight:"1px solid var(--border-hair)"},V={overflow:"hidden",textOverflow:"ellipsis",whiteSpace:"nowrap"};function Nt({spec:e}){const a=e.geometry,n=_t[e.tone];return t.jsxs("button",{type:"button","data-testid":`timeline-bar-${e.key}`,"data-tone":e.tone,"data-invalid":a.invalid?"true":"false","data-clipped-start":a.clippedStart?"true":"false","data-clipped-end":a.clippedEnd?"true":"false",title:e.title,"aria-label":e.title,onClick:e.onClick,style:{position:"absolute",top:me,height:he-me*2,left:`${a.left}%`,width:`${a.width}%`,minWidth:3,minHeight:he-me*2,display:"flex",alignItems:"center",padding:0,overflow:"hidden",background:n.bg,border:`1px solid ${n.border}`,borderTopLeftRadius:a.clippedStart?0:"var(--radius-sm)",borderBottomLeftRadius:a.clippedStart?0:"var(--radius-sm)",borderTopRightRadius:a.clippedEnd?0:"var(--radius-sm)",borderBottomRightRadius:a.clippedEnd?0:"var(--radius-sm)",cursor:e.onClick?"pointer":"default"},children:[a.clippedStart&&t.jsx(X,{name:"chevron-left",size:11,color:n.border}),t.jsx("span",{style:{flex:1}}),a.clippedEnd&&t.jsx(X,{name:"chevron-right",size:11,color:n.border})]})}function Ze({window:e,rows:a,today:n,emptyHint:r,testId:l,labelHead:o}){const d=kt(e.zoom),g=e.ticks.length*d,u=Lt(e,n),i={position:"relative",width:g,height:he,flex:`0 0 ${g}px`,backgroundImage:`repeating-linear-gradient(to right, var(--border-hair) 0 1px, transparent 1px ${d}px)`};return t.jsx("div",{"data-testid":l??"team-timeline",className:"hn-timeline-scroll",style:{flex:"1 1 auto",minHeight:0,minWidth:0,maxWidth:"100%",overflowX:"auto",overflowY:"auto"},children:t.jsxs("div",{"data-testid":"timeline-canvas",style:{position:"relative",minWidth:U+g,width:U+g},children:[t.jsxs("div",{style:{display:"flex",position:"sticky",top:0,zIndex:2,background:"var(--bone-100)",borderBottom:"1px solid var(--border-hair)"},children:[t.jsx("div",{style:{...Oe,zIndex:3,background:"var(--bone-100)"},children:t.jsx("span",{className:"hn-eyebrow",children:o??"Tugas"})}),t.jsx("div",{style:{display:"grid",gridTemplateColumns:`repeat(${e.ticks.length}, ${d}px)`,width:g,flex:`0 0 ${g}px`},children:e.ticks.map(c=>t.jsx("div",{"data-testid":"timeline-tick",style:{borderLeft:`1px solid ${c.major?"var(--border-strong)":"var(--border-hair)"}`,padding:"5px 4px",fontFamily:"var(--font-mono)",fontSize:10,...V,color:c.major?"var(--text-body)":"var(--text-subtle)"},children:c.label},c.start))})]}),a.length===0?t.jsx("div",{"data-testid":"timeline-empty",style:{position:"sticky",left:0,width:U,padding:"18px 10px",fontSize:"var(--text-xs)",color:"var(--text-muted)"},children:r??"Tak ada yang bisa dihamparkan di jendela ini."}):a.map(c=>t.jsxs("div",{"data-testid":`timeline-row-${c.key}`,style:{display:"flex",borderBottom:"1px solid var(--border-hair)"},children:[t.jsxs("div",{style:Oe,children:[t.jsx("div",{style:{...V,fontSize:12,fontWeight:"var(--weight-medium)",color:"var(--text-strong)"},children:c.label}),c.meta&&t.jsx("div",{style:{...V,fontSize:10,color:"var(--text-subtle)"},children:c.meta})]}),t.jsx("div",{style:i,children:c.bars.map(p=>t.jsx(Nt,{spec:p},p.key))})]},c.key)),u!==null&&t.jsx("div",{"data-testid":"timeline-today","aria-hidden":"true",style:{position:"absolute",top:0,bottom:0,width:2,pointerEvents:"none",left:U+u/100*g,background:"var(--brass-500)",opacity:.5}})]})})}function Re({testId:e,icon:a,title:n,hint:r,tasks:l,onOpen:o}){return l.length===0?null:t.jsxs("div",{"data-testid":e,style:{...G,marginTop:10,padding:10,background:"var(--bone-100)",border:"1px solid var(--border-hair)",borderRadius:"var(--radius-lg)"},children:[t.jsxs("div",{style:{display:"flex",alignItems:"center",gap:6,marginBottom:6,flexWrap:"wrap"},children:[t.jsx(X,{name:a,size:13,color:"var(--text-subtle)"}),t.jsxs("span",{className:"hn-eyebrow",children:[n," · ",l.length]}),r&&t.jsx("span",{style:{fontSize:"var(--text-xs)",color:"var(--text-muted)"},children:r})]}),t.jsx("div",{style:{display:"flex",flexWrap:"wrap",gap:6},children:l.map(d=>t.jsx("button",{type:"button",onClick:()=>o(d),style:{padding:"3px 10px",background:"var(--surface-card)",border:"1px solid var(--border-hair)",borderRadius:"var(--radius-pill)",fontFamily:"var(--font-ui)",fontSize:12,color:"var(--text-body)",cursor:"pointer"},children:d.title},d.id))})]})}function Ft({tasks:e,members:a,zoom:n,today:r,hidden:l,onOpen:o}){const d=m.useMemo(()=>{const p=e.map(Y).filter(v=>v!==null);return Ge(p,n,r)},[e,n,r]),{rows:g,unscheduled:u,outside:i}=m.useMemo(()=>$t(e,d),[e,d]),c=m.useMemo(()=>g.map(({task:p,geometry:v})=>{var f;const x=((f=a.find(k=>k.id===p.memberId))==null?void 0:f.name)??"belum ditugaskan",h=Q(p),y=[v.invalid?"tenggat mendahului mulai":null,v.clippedStart||v.clippedEnd?"melewati tepi jendela":null].filter(Boolean);return{key:p.id,label:p.title,meta:h?`${x} · ${h}`:x,bars:[{key:p.id,geometry:v,tone:v.invalid?"err":p.status==="done"?"muted":"brass",title:[p.title,h,...y].filter(Boolean).join(" · "),onClick:()=>o(p)}]}}),[g,a,o]);return t.jsxs(t.Fragment,{children:[t.jsx(Ze,{window:d,rows:c,today:r,emptyHint:"Belum ada tugas bertanggal — isi mulai atau tenggat di kartunya."}),l>0&&t.jsxs("div",{"data-testid":"timeline-truncated",style:{...G,marginTop:8,fontSize:"var(--text-xs)",color:"var(--amber-600)"},children:[l," tugas tak termuat karena plafon 200 per kolom — persempit penyaring"]}),t.jsx(Re,{testId:"timeline-unscheduled",icon:"calendar-off",title:"Belum dijadwalkan",tasks:u,onOpen:o}),t.jsx(Re,{testId:"timeline-outside",icon:"chevrons-left-right",title:"Di luar jendela",hint:"pilih zoom yang lebih lebar",tasks:i,onOpen:o})]})}const Wt="__none__",At=16,Pe=(e,a)=>a.invalid?"err":e.status==="done"?"muted":"brass",_e=(e,a,n)=>[e.title,n,a.invalid?"tenggat mendahului mulai":null,a.clippedStart||a.clippedEnd?"melewati tepi jendela":null].filter(Boolean).join(" · ");function Ut({testId:e,open:a,name:n,count:r,onClick:l}){return t.jsxs("button",{type:"button",onClick:l,"data-testid":e,"aria-expanded":a,style:{display:"flex",alignItems:"center",gap:5,width:"100%",padding:0,background:"none",border:"none",cursor:"pointer",textAlign:"left",minHeight:0,fontFamily:"var(--font-ui)",fontSize:12,fontWeight:"var(--weight-medium)",color:"var(--text-strong)"},children:[t.jsx(X,{name:a?"chevron-down":"chevron-right",size:12,color:"var(--text-subtle)"}),t.jsx("span",{style:{...V,flex:1},children:n}),t.jsx("span",{style:{fontFamily:"var(--font-mono)",fontSize:10,color:"var(--text-subtle)"},children:r})]})}function Ht({tasks:e,projects:a,members:n,zoom:r,today:l,hidden:o,expanded:d,onToggle:g,onOpen:u}){const i=m.useMemo(()=>{const h=e.map(Y).filter(y=>y!==null);return Ge(h,r,l)},[e,r,l]),c=m.useCallback(h=>{var y;return h===null?"Tanpa project":((y=a.find(f=>f.id===h))==null?void 0:y.name)??h},[a]),p=m.useMemo(()=>zt(e,i,c),[e,i,c]),v=m.useMemo(()=>new Set(d),[d]),x=m.useMemo(()=>{var y;const h=[];for(const f of p){const k=f.projectId??Wt,L=v.has(k),S=c(f.projectId),b=f.geometry?Q({startDate:new Date(f.span.start).toISOString(),dueDate:new Date(f.span.end-1).toISOString()}):f.span?"di luar jendela · pilih zoom yang lebih lebar":"belum dijadwalkan",D=[];if(f.geometry){D.push({key:`span:${k}`,geometry:f.geometry,tone:f.geometry.invalid?"err":"envelope",title:`${S} · ${b??""}`.trim(),onClick:()=>g(k)});for(const C of f.tasks){const E=ge(C,i);E&&D.push({key:`seg:${C.id}`,geometry:E,tone:Pe(C,E),title:_e(C,E,Q(C)),onClick:()=>u(C)})}}if(h.push({key:`p:${k}`,meta:b,bars:D,label:t.jsx(Ut,{testId:`expand-${k}`,open:L,name:S,count:f.tasks.length,onClick:()=>g(k)})}),!!L)for(const C of f.tasks){const E=ge(C,i),j=((y=n.find(_=>_.id===C.memberId))==null?void 0:y.name)??"belum ditugaskan",P=Q(C);h.push({key:`t:${C.id}`,label:t.jsx("span",{style:{...V,display:"block",paddingLeft:At},children:C.title}),meta:P?`${j} · ${P}`:j,bars:E?[{key:`t:${C.id}`,geometry:E,tone:Pe(C,E),title:_e(C,E,P),onClick:()=>u(C)}]:[]})}}return h},[p,v,c,i,n,g,u]);return t.jsxs(t.Fragment,{children:[t.jsx(Ze,{window:i,rows:x,today:l,testId:"team-projects",labelHead:"Project",emptyHint:"Belum ada project bertanggal — isi mulai atau tenggat di kartunya."}),o>0&&t.jsxs("div",{"data-testid":"projects-truncated",style:{...G,marginTop:8,fontSize:"var(--text-xs)",color:"var(--amber-600)"},children:[o," tugas tak termuat karena plafon 200 per kolom — amplop project bisa lebih pendek dari rentang sebenarnya; persempit kolom, anggota, atau pencarian"]})]})}const fe={tinggi:"Tinggi",sedang:"Sedang",rendah:"Rendah"},Kt=Object.keys(fe).map(e=>({value:e,label:fe[e]})),Ne=(e,a)=>({title:(e==null?void 0:e.title)??"",detail:(e==null?void 0:e.detail)??"",projectId:e?e.projectId??"":a??"",status:(e==null?void 0:e.status)??"backlog",priority:e&&e.priority in fe?e.priority:"sedang",memberId:(e==null?void 0:e.memberId)??"",startDate:De((e==null?void 0:e.startDate)??null),dueDate:De((e==null?void 0:e.dueDate)??null)});function Gt({open:e,task:a,projects:n,members:r,defaultProjectId:l,orderFor:o,onClose:d,onSaved:g,onToast:u}){const[i,c]=m.useState(()=>Ne(a,l)),[p,v]=m.useState(!1),{confirm:x,dialog:h}=Ue(),y=`${e?"1":"0"}:${(a==null?void 0:a.id)??""}`,f=m.useRef(y);if(f.current!==y&&(f.current=y,e&&c(Ne(a,l))),!e)return null;const k=b=>c(D=>({...D,...b}));async function L(){if(!i.title.trim()){u("Judul tugas wajib diisi","err","x-circle");return}v(!0);const b=!a||a.status!==i.status,D={title:i.title.trim(),detail:i.detail.trim()||null,projectId:i.projectId||null,status:i.status,priority:i.priority,memberId:i.memberId||null,startDate:Ee(i.startDate),dueDate:Ee(i.dueDate),...b?{order:o(i.status)}:{}};try{a?await w.patchTask(a.id,D):await w.createTask(D),u(a?"Tugas diperbarui":"Tugas dibuat","ok","check"),g(),d()}catch{u("Gagal menyimpan tugas","err","x-circle")}finally{v(!1)}}async function S(){a&&await x({title:`Hapus "${a.title}"?`,message:"Kartu ini hilang dari papan di semua device yang tersinkron.",confirmLabel:"Hapus tugas",tone:"danger",icon:"trash-2",run:()=>w.deleteTask(a.id)})&&(u("Tugas dihapus","ok","trash-2"),g(),d())}return t.jsxs(t.Fragment,{children:[t.jsxs(xe,{open:e,onClose:d,icon:"clipboard-list",eyebrow:"Papan tim",title:a?"Ubah tugas":"Tugas baru",footer:t.jsxs("div",{style:{display:"flex",gap:8,width:"100%",alignItems:"center"},children:[a&&t.jsx(B,{variant:"ghost",leftIcon:"trash-2",onClick:S,disabled:p,children:"Hapus"}),t.jsx("span",{style:{flex:1}}),t.jsx(B,{variant:"secondary",onClick:d,disabled:p,children:"Batal"}),t.jsx(B,{onClick:L,loading:p,children:a?"Simpan":"Buat tugas"})]}),children:[t.jsx($,{label:"Judul",children:t.jsx(O,{value:i.title,"aria-label":"Judul tugas",placeholder:"mis. Rapikan halaman harga",onChange:b=>k({title:b.target.value}),style:{width:"100%"}})}),t.jsxs("div",{style:{display:"flex",gap:10,flexWrap:"wrap"},children:[t.jsx($,{label:"Project",children:t.jsx(M,{value:i.projectId,"aria-label":"Project tugas",onChange:b=>k({projectId:b.target.value}),options:[{value:"",label:"Tanpa project"},...n.map(b=>({value:b.id,label:b.name}))]})}),t.jsx($,{label:"Kolom",children:t.jsx(M,{value:i.status,"aria-label":"Kolom tugas",onChange:b=>k({status:b.target.value}),options:K.map(b=>({value:b.key,label:b.label}))})}),t.jsx($,{label:"Prioritas",children:t.jsx(M,{value:i.priority,"aria-label":"Prioritas tugas",onChange:b=>k({priority:b.target.value}),options:Kt})})]}),t.jsx($,{label:"Ditugaskan ke",children:t.jsx(M,{value:i.memberId,"aria-label":"Anggota tugas",onChange:b=>k({memberId:b.target.value}),options:[{value:"",label:"Belum ditugaskan"},...r.map(b=>({value:b.id,label:b.role?`${b.name} · ${b.role}`:b.name}))],style:{width:"100%"}})}),t.jsxs("div",{style:{display:"flex",gap:10,flexWrap:"wrap"},children:[t.jsx($,{label:"Mulai",children:t.jsx(O,{type:"date",value:i.startDate,"aria-label":"Tanggal mulai",onChange:b=>k({startDate:b.target.value})})}),t.jsx($,{label:"Tenggat",children:t.jsx(O,{type:"date",value:i.dueDate,"aria-label":"Tanggal tenggat",onChange:b=>k({dueDate:b.target.value})})})]}),t.jsx($,{label:"Detail",hint:"Opsional — konteks yang tak muat di judul.",children:t.jsx(ot,{value:i.detail,"aria-label":"Detail tugas",rows:4,placeholder:"mis. tunggu aset dari klien, deadline ikut jadwal kampanye",onChange:b=>k({detail:b.target.value})})})]}),h]})}const Yt=dt.map(e=>({value:e,label:ct(e).label}));function Zt({task:e,projects:a,onClose:n,onDone:r,onToast:l}){const[o,d]=m.useState("brief"),[g,u]=m.useState(()=>Te.some(f=>f.value===e.priority)?e.priority:"sedang"),[i,c]=m.useState(""),[p,v]=m.useState(!1),x=e.projectId===null,h=e.projectId??i;async function y(){if(!(!h||p)){v(!0);try{const f=await w.escalateTask(e.id,{source:o,priority:g,...e.projectId?{}:{projectId:i}});l(f.created?`Dieskalasi jadi ${f.spec.id}`:`Sudah tertaut ke ${f.spec.id}`,"ok","link"),r(f.task),n()}catch{l("Gagal mengeskalasi kartu","err","x-circle")}finally{v(!1)}}}return t.jsxs(xe,{open:!0,onClose:p?void 0:n,icon:"git-branch",eyebrow:"Papan tim",title:"Eskalasi ke backlog",footer:t.jsxs("div",{style:{display:"flex",gap:8,width:"100%",alignItems:"center"},children:[t.jsx("span",{style:{flex:1}}),t.jsx(B,{variant:"secondary",onClick:n,disabled:p,children:"Batal"}),t.jsx(B,{onClick:y,loading:p,disabled:!h,leftIcon:"git-branch",children:"Eskalasi"})]}),children:[t.jsxs("div",{style:{fontSize:13.5,color:"var(--text-strong)",lineHeight:1.55,marginBottom:14},children:["Kartu ",t.jsx("strong",{children:e.title})," tetap di papan. Yang lahir adalah backlog item baru yang bisa dikerjakan sesi agen, dan kartu ini menampilkan stage-nya."]}),x&&t.jsxs($,{label:"Project",children:[t.jsx(M,{"aria-label":"Project",value:i,style:{width:"100%"},onChange:f=>c(f.target.value),options:[{value:"",label:"Pilih project…"},...a.map(f=>({value:f.id,label:f.name}))]}),t.jsx("div",{style:{marginTop:6,fontSize:"var(--text-xs)",color:"var(--text-subtle)"},children:"Nomor SPEC diambil dari repo project, jadi kartu tanpa project belum bisa dieskalasi."})]}),t.jsx($,{label:"Source",children:t.jsx(M,{"aria-label":"Source",value:o,style:{width:"100%"},onChange:f=>d(f.target.value),options:Yt})}),t.jsx($,{label:"Prioritas",children:t.jsx(M,{"aria-label":"Prioritas",value:g,style:{width:"100%"},onChange:f=>u(f.target.value),options:Te})})]})}function qt({m:e,busy:a,onSave:n,onToggle:r,onDelete:l}){const[o,d]=m.useState(!1),[g,u]=m.useState(e.name),[i,c]=m.useState(e.role??"");return o?t.jsxs("div",{style:{display:"flex",flexDirection:"column",gap:8,padding:"12px 14px",marginBottom:8,border:"1px solid var(--border-strong)",borderRadius:"var(--radius-md)",background:"var(--surface-card)"},children:[t.jsx(O,{size:"sm",value:g,"aria-label":`Nama ${e.name}`,placeholder:"mis. Dena Meidina",onChange:p=>u(p.target.value)}),t.jsx(O,{size:"sm",value:i,"aria-label":`Peran ${e.name}`,placeholder:"mis. desainer",onChange:p=>c(p.target.value)}),t.jsxs("div",{style:{fontSize:"var(--text-xs)",color:"var(--text-subtle)"},children:[e.email," — ganti email berarti hapus lalu buat baru."]}),t.jsxs("div",{style:{display:"flex",gap:8},children:[t.jsx(B,{size:"sm",disabled:a,onClick:()=>{n(e.id,{name:g.trim(),role:i.trim()||null}),d(!1)},children:"Simpan"}),t.jsx(B,{size:"sm",variant:"ghost",onClick:()=>d(!1),children:"Batal"})]})]}):t.jsxs("div",{className:"hn-dense-row",style:{display:"flex",alignItems:"center",gap:10,padding:"10px 14px",marginBottom:8,border:"1px solid var(--border-hair)",borderRadius:"var(--radius-md)",background:"var(--surface-card)",opacity:e.active?1:.6},children:[t.jsxs("span",{style:{flex:1,minWidth:0},children:[t.jsxs("span",{style:{display:"flex",alignItems:"center",gap:8},children:[t.jsx("span",{style:{fontWeight:"var(--weight-semibold)",color:"var(--text-strong)"},children:e.name}),e.role&&t.jsx(ae,{tone:"neutral",size:"sm",children:e.role}),!e.active&&t.jsx(ae,{tone:"warn",size:"sm",children:"nonaktif"})]}),t.jsx("span",{style:{display:"block",fontFamily:"var(--font-mono)",fontSize:"var(--text-xs)",color:"var(--text-subtle)",marginTop:2},children:e.email})]}),t.jsx(de,{icon:"pencil",label:`Ubah ${e.name}`,size:"sm",onClick:()=>d(!0)}),t.jsx(de,{icon:e.active?"user-minus":"user-check",size:"sm",label:`${e.active?"Nonaktifkan":"Aktifkan"} ${e.name}`,onClick:()=>r(e)}),t.jsx(de,{icon:"trash-2",label:`Hapus ${e.name}`,size:"sm",onClick:()=>l(e)})]})}function Jt({open:e,onClose:a,onChanged:n,onToast:r}){const[l,o]=m.useState([]),[d,g]=m.useState("loading"),[u,i]=m.useState(!1),[c,p]=m.useState(""),[v,x]=m.useState(""),[h,y]=m.useState(""),{confirm:f,dialog:k}=Ue(),L=m.useRef(n);L.current=n;const S=m.useCallback(()=>{g("loading"),w.listMembers().then(j=>{o(j.items),g("ready"),L.current(j.items)}).catch(()=>g("error"))},[]);if(m.useEffect(()=>{e&&S()},[e,S]),!e)return null;async function b(){if(!c.trim()||!v.trim()){r("Nama & email wajib diisi","err","x-circle");return}i(!0);try{await w.createMember({name:c.trim(),email:v.trim(),role:h.trim()||null}),p(""),x(""),y(""),r("Anggota ditambahkan","ok","user-plus"),S()}catch{r("Gagal menambah anggota — email mungkin sudah terdaftar","err","x-circle")}finally{i(!1)}}async function D(j,P){i(!0);try{await w.patchMember(j,P),S()}catch{r("Gagal menyimpan anggota","err","x-circle")}finally{i(!1)}}async function C(j){i(!0);try{await w.patchMember(j.id,{active:!j.active}),S()}catch{r("Gagal mengubah status anggota","err","x-circle")}finally{i(!1)}}async function E(j){await f({title:`Hapus ${j.name} dari direktori?`,message:"Tugasnya tidak ikut terhapus — kartu yang ditugaskan padanya jadi 'belum ditugaskan'.",confirmLabel:"Hapus anggota",tone:"danger",icon:"trash-2",run:()=>w.deleteMember(j.id)})&&(r("Anggota dihapus","ok","trash-2"),S())}return t.jsxs(t.Fragment,{children:[t.jsxs(xe,{open:e,onClose:a,icon:"users",eyebrow:"Papan tim",title:"Anggota",width:620,children:[t.jsxs("div",{style:{display:"flex",gap:8,flexWrap:"wrap",alignItems:"flex-end",marginBottom:16,paddingBottom:16,borderBottom:"1px solid var(--border-hair)"},children:[t.jsx(O,{size:"sm",value:c,"aria-label":"Nama anggota baru",placeholder:"Nama",onChange:j=>p(j.target.value),style:{flex:"1 1 140px"}}),t.jsx(O,{size:"sm",value:v,"aria-label":"Email anggota baru",placeholder:"email@nafanesia.id",onChange:j=>x(j.target.value),style:{flex:"1 1 180px"}}),t.jsx(O,{size:"sm",value:h,"aria-label":"Peran anggota baru",placeholder:"Peran (opsional)",onChange:j=>y(j.target.value),style:{flex:"1 1 130px"}}),t.jsx(B,{size:"sm",leftIcon:"user-plus",onClick:b,loading:u,children:"Tambah anggota"})]}),d==="loading"?t.jsx(H,{kind:"loading",compact:!0}):d==="error"?t.jsx(H,{kind:"error",compact:!0,hint:"Gagal memuat anggota.",action:S,actionLabel:"Coba lagi"}):l.length===0?t.jsx(H,{kind:"empty",compact:!0,icon:"users",title:"Belum ada anggota",hint:"Tambahkan orang di atas agar kartu papan bisa ditugaskan."}):l.map(j=>t.jsx(qt,{m:j,busy:u,onSave:D,onToggle:C,onDelete:E},j.id))]}),k]})}const Qt=5e3,Fe=200,Vt=400,We=[{value:"board",label:"Papan",icon:"kanban"},{value:"timeline",label:"Linimasa",icon:"gantt-chart"},{value:"projects",label:"Lintas project",icon:"layers"}],Xt={day:"Hari",week:"Minggu",month:"Bulan"},ea=()=>Object.fromEntries(K.map(e=>[e.key,0]));function ta({status:e,params:a,onData:n,refetch:r}){return ft({topic:"tasks",params:{...a,status:e},apply:l=>n(e,l.data.items,l.data.total),refetch:r,pollMs:Qt}),null}function la({projects:e,projectFilter:a,onProjectFilter:n,onToast:r}){const[l,o]=m.useState(vt),[d,g]=m.useState(ea),[u,i]=m.useState([]),[c,p]=m.useState("loading"),[v,x]=m.useState(!1),[h,y]=m.useState(null),[f,k]=m.useState(!1),[L,S]=m.useState(!1),[b,D]=m.useState(null),[C,E]=A("team","view","board",we(...We.map(s=>s.value))),[j,P]=A("team","q","",ce),[_,qe]=A("team","col","all",ce),[Z,Je]=A("team","member","all",ce),[ne,Qe]=A("team","zoom","week",we(...Le)),[Ve,be]=A("team","expanded",[],ht),Xe=m.useCallback(s=>{be(I=>I.includes(s)?I.filter(T=>T!==s):[...I,s])},[be]),ve=C==="timeline",N=C==="projects",ye=m.useRef(Date.now()).current,R=m.useMemo(()=>_==="all"?K:K.filter(s=>s.key===_),[_]),ie=R.map(s=>s.key).join(","),je=[a!=="all"&&!N,_!=="all",Z!=="all",j.trim()!==""].filter(Boolean).length,re=N||a==="all"?void 0:a,W=m.useMemo(()=>({projectId:re,memberId:Z==="all"?void 0:Z,q:j.trim()||void 0}),[re,Z,j]),te=m.useRef(!1),q=m.useCallback((s=!1)=>{!s&&!te.current&&p("loading");const I=ie?ie.split(","):[];Promise.all(I.map(T=>w.listTasks({...W,status:T,page:1,limit:Fe}))).then(T=>{o(z=>{const J={...z};return I.forEach((le,oe)=>{J[le]=T[oe].items}),J}),g(z=>{const J={...z};return I.forEach((le,oe)=>{J[le]=T[oe].total}),J}),te.current=!0,x(!1),p("ready")}).catch(()=>{if(!te.current){p("error");return}x(!0)})},[W,ie]);m.useEffect(()=>{q()},[q]);const ke=m.useCallback(()=>{w.listMembers().then(s=>i(s.items)).catch(()=>{})},[]);m.useEffect(()=>{ke()},[ke]);const[Se,et]=m.useState(()=>j.trim());m.useEffect(()=>{const s=setTimeout(()=>et(j.trim()),Vt);return()=>clearTimeout(s)},[j]);const tt=m.useCallback((s,I,T)=>{o(z=>({...z,[s]:I})),g(z=>({...z,[s]:T})),te.current=!0,x(!1),p("ready")},[]),at=m.useMemo(()=>({projectId:W.projectId,memberId:W.memberId,q:Se||void 0,page:1,limit:Fe}),[W.projectId,W.memberId,Se]),se=m.useCallback(()=>q(!0),[q]);async function nt(s,I){const T=yt(l,s.id,s.status,I);if(!T)return;const z=l;o(T.board);try{await w.patchTask(s.id,T.patch)}catch{o(z),r("Gagal memindahkan tugas","err","x-circle")}}async function it(s,I){const T=l;o(ue(l,{...s,memberId:I}));try{await w.patchTask(s.id,{memberId:I})}catch{o(T),r("Gagal menugaskan","err","x-circle")}}async function rt(s){const I=l;o(ue(l,{...s,specId:null,spec:null}));try{await w.unlinkTaskSpec(s.id),r("Tautan backlog dilepas","ok","unlink")}catch{o(I),r("Gagal melepas tautan","err","x-circle")}}const st=R.every(s=>l[s.key].length===0),Ie=m.useMemo(()=>R.flatMap(s=>l[s.key]),[l,R]),Ce=R.reduce((s,I)=>s+Math.max(0,(d[I.key]??0)-l[I.key].length),0);return t.jsxs("div",{style:ut,children:[t.jsxs("div",{className:"hn-team-controls",role:"region","aria-label":"Kontrol papan tim",style:{...G,marginBottom:18},children:[t.jsxs("div",{className:"hn-team-topline",style:{display:"flex",alignItems:"center",justifyContent:"space-between",gap:12,flexWrap:"wrap",marginBottom:12},children:[t.jsx(mt,{variant:"pill",value:C,onChange:E,tabs:We,"aria-label":"Mode tampilan"}),t.jsxs("div",{className:"hn-team-view-actions",style:{display:"flex",alignItems:"center",gap:10},children:[t.jsx(B,{size:"sm",leftIcon:"plus",onClick:()=>{y(null),k(!0)},children:"Tugas baru"}),t.jsx(B,{size:"sm",variant:"secondary",leftIcon:"users",onClick:()=>S(!0),children:"Anggota"}),t.jsx(pt,{onDone:se,onToast:r}),t.jsx(gt,{screen:"team",active:je,onReset:N?void 0:()=>n("all")}),t.jsxs("span",{className:"hn-eyebrow",role:"status",style:v?{color:"var(--amber-600)"}:void 0,title:v?"Server tak menjawab saat menyegarkan — angka ini dari muatan terakhir yang berhasil":void 0,children:[R.reduce((s,I)=>s+(d[I.key]??0),0)," tugas",v?" · basi":""]}),t.jsx(xt,{})]})]}),t.jsxs("div",{className:"hn-team-filters",style:{display:"flex",alignItems:"center",gap:10,flexWrap:"wrap"},children:[t.jsx(O,{size:"sm",leftIcon:"search","aria-label":"Cari tugas",value:j,placeholder:"mis. halaman harga atau deploy",onChange:s=>P(s.target.value),style:{flex:"1 1 220px"}}),t.jsx(M,{size:"sm","aria-label":"Filter project",value:a,disabled:N,onChange:s=>n(s.target.value),options:[{value:"all",label:"Semua project"},...e.map(s=>({value:s.id,label:s.name}))]}),N&&t.jsx("span",{"data-testid":"project-filter-note",style:{fontSize:"var(--text-xs)",color:"var(--text-subtle)"},children:"Mode ini melintasi semua project"}),t.jsx(M,{size:"sm","aria-label":"Filter kolom",value:_,onChange:s=>qe(s.target.value),options:[{value:"all",label:"Semua kolom"},...K.map(s=>({value:s.key,label:s.label}))]}),t.jsx(M,{size:"sm","aria-label":"Filter anggota",value:Z,onChange:s=>Je(s.target.value),options:[{value:"all",label:"Semua anggota"},...u.map(s=>({value:s.id,label:s.name}))]}),(ve||N)&&t.jsx(M,{size:"sm","aria-label":"Zoom linimasa",value:ne,onChange:s=>Qe(s.target.value),options:Le.map(s=>({value:s,label:Xt[s]}))})]})]}),R.map(s=>t.jsx(ta,{status:s.key,params:at,onData:tt,refetch:se},s.key)),c==="loading"?t.jsx(H,{kind:"loading"}):c==="error"?t.jsx(H,{kind:"error",hint:"Gagal memuat papan tim.",action:()=>q(),actionLabel:"Coba lagi"}):st&&je===0?t.jsx(H,{kind:"empty",icon:"users",title:"Papan tim masih kosong",hint:"Catat pekerjaan manusia di sekitar sesi agen — desain, meeting klien, deploy, nego.",action:()=>{y(null),k(!0)},actionLabel:"Tugas baru",actionIcon:"plus"}):N?t.jsx(Ht,{tasks:Ie,projects:e,members:u,zoom:ne,today:ye,hidden:Ce,expanded:Ve,onToggle:Xe,onOpen:s=>{y(s),k(!0)}}):ve?t.jsx(Ft,{tasks:Ie,members:u,zoom:ne,today:ye,hidden:Ce,onOpen:s=>{y(s),k(!0)}}):t.jsx(Pt,{board:l,totals:d,columns:R,members:u,onMove:nt,onAssign:it,onEscalate:D,onUnlink:rt,onOpen:s=>{y(s),k(!0)}}),t.jsx(Gt,{open:f,task:h,projects:e,members:u,defaultProjectId:re??null,orderFor:s=>He(l[s]),onClose:()=>{k(!1),y(null)},onSaved:se,onToast:r}),b&&t.jsx(Zt,{task:b,projects:e,onClose:()=>D(null),onDone:s=>o(I=>ue(I,s)),onToast:r}),t.jsx(Jt,{open:L,onClose:()=>S(!1),onChanged:i,onToast:r})]})}export{We as TEAM_VIEWS,la as TeamScreen};
|
|
1
|
+
import{T as Ae,j as t,F as G,L as lt,B as ae,I as X,a as B,S as M,u as Ue,M as xe,c as $,d as O,H as ot,e as w,P as Te,E as dt,s as ct,f as H,g as de,h as A,o as we,k as ut,l as mt,m as pt,R as gt,n as ht,p as ce,q as ft}from"./index-DYNYB1Nj.js";import{R as m}from"./react-DfGhg7ZW.js";import{L as xt}from"./live-nMnpVkPn.js";import"./markdown-CWEY34jk.js";import"./xterm-3VOAfa_q.js";const bt={backlog:"Backlog",doing:"Dikerjakan",review:"Review",done:"Selesai"},K=Ae.map(e=>({key:e,label:bt[e]})),vt=()=>Object.fromEntries(Ae.map(e=>[e,[]])),pe=(e,a)=>e!==a,He=e=>e.length===0?0:e.reduce((a,n)=>n.order>a?n.order:a,-1/0)+1;function yt(e,a,n,r){if(!pe(n,r))return null;const l=e[n].find(g=>g.id===a);if(!l)return null;const o={status:r,order:He(e[r])},d={...e};return d[n]=e[n].filter(g=>g.id!==a),d[r]=[...e[r],{...l,...o}],{board:d,patch:o}}function ue(e,a){const n={...e};return n[a.status]=e[a.status].map(r=>r.id===a.id?a:r),n}const De=e=>e?e.slice(0,10):"",Ee=e=>/^\d{4}-\d{2}-\d{2}$/.test(e)?`${e}T12:00:00.000Z`:null,F=864e5,ee=e=>Math.floor(e/F)*F,Me=e=>{if(!e)return null;const a=new Date(e).getTime();return Number.isFinite(a)?a:null};function Y(e){const a=Me(e.startDate),n=Me(e.dueDate);if(a===null&&n===null)return null;const r=a??n,l=n??a;return{start:ee(Math.min(r,l)),end:ee(Math.max(r,l))+F,invalid:l<r}}const jt=new Intl.DateTimeFormat("id-ID",{day:"numeric",month:"short",timeZone:"UTC"}),Be=e=>e?jt.format(new Date(e)):null;function Q(e){const a=Be(e.startDate),n=Be(e.dueDate);return a&&n?`${a} → ${n}`:n?`→ ${n}`:a}const Le=["day","week","month"],Ke={day:{cell:34,minTicks:14},week:{cell:56,minTicks:8},month:{cell:84,minTicks:6}},kt=e=>Ke[e].cell,St=120,It=(e,a)=>{const n=ee(e);if(a==="day")return n;if(a==="week")return n-(new Date(n).getUTCDay()+6)%7*F;const r=new Date(n);return Date.UTC(r.getUTCFullYear(),r.getUTCMonth(),1)},Ct=(e,a)=>{if(a==="day")return e+F;if(a==="week")return e+7*F;const n=new Date(e);return Date.UTC(n.getUTCFullYear(),n.getUTCMonth()+1,1)},Tt=new Intl.DateTimeFormat("id-ID",{day:"numeric",timeZone:"UTC"}),$e=new Intl.DateTimeFormat("id-ID",{day:"numeric",month:"short",timeZone:"UTC"}),wt=new Intl.DateTimeFormat("id-ID",{month:"short",timeZone:"UTC"}),Dt=new Intl.DateTimeFormat("id-ID",{month:"short",year:"2-digit",timeZone:"UTC"}),Et=(e,a)=>{const n=new Date(e);return a==="day"?n.getUTCDate()===1:a==="week"?n.getUTCDate()<=7:n.getUTCMonth()===0},Mt=(e,a,n)=>{const r=new Date(e);return a==="day"?(n?$e:Tt).format(r):a==="week"?$e.format(r):(n?Dt:wt).format(r)};function Ge(e,a,n){const r=ee(n);let l=r,o=r+F;for(const c of e)c.start<l&&(l=c.start),c.end>o&&(o=c.end);const d=It(l,a),{minTicks:g}=Ke[a],u=[];let i=d;for(;u.length<St&&(i<o||u.length<g);){const c=Et(i,a);u.push({start:i,label:Mt(i,a,c),major:c}),i=Ct(i,a)}return{from:d,to:i,zoom:a,ticks:u}}function Ye(e,a){const n=a.to-a.from;if(n<=0||e.end<=a.from||e.start>=a.to)return null;const r=Math.max(e.start,a.from),l=Math.min(e.end,a.to);return{left:(r-a.from)/n*100,width:(l-r)/n*100,clippedStart:e.start<a.from,clippedEnd:e.end>a.to,invalid:e.invalid}}function ge(e,a){const n=Y(e);return n?Ye(n,a):null}function Bt(e){let a=1/0,n=-1/0,r=!1;for(const l of e){const o=Y(l);o&&(o.start<a&&(a=o.start),o.end>n&&(n=o.end),o.invalid&&(r=!0))}return a===1/0?null:{start:a,end:n,invalid:r}}function Lt(e,a){const n=ee(a);return n<e.from||n>=e.to?null:(n-e.from)/(e.to-e.from)*100}function $t(e,a){const n=[],r=[],l=[];for(const o of e){const d=Y(o);if(!d){r.push(o);continue}const g=ge(o,a);if(!g){l.push(o);continue}n.push({task:o,geometry:g,start:d.start})}return n.sort((o,d)=>o.start-d.start||o.task.title.localeCompare(d.task.title,"id")||o.task.id.localeCompare(d.task.id)),{rows:n.map(({task:o,geometry:d})=>({task:o,geometry:d})),unscheduled:r,outside:l}}const ze=(e,a)=>e.title.localeCompare(a.title,"id")||e.id.localeCompare(a.id);function zt(e,a,n){const r=Symbol("no-project"),l=new Map;for(const u of e){const i=u.projectId??r,c=l.get(i);c?c.tasks.push(u):l.set(i,{projectId:u.projectId,tasks:[u]})}const o=[...l.values()].map(({projectId:u,tasks:i})=>{const c=Bt(i),p=[],v=[];for(const x of i){const h=Y(x);h?p.push({task:x,start:h.start}):v.push(x)}return p.sort((x,h)=>x.start-h.start||ze(x.task,h.task)),v.sort(ze),{projectId:u,span:c,geometry:c?Ye(c,a):null,tasks:[...p.map(x=>x.task),...v]}}),d=u=>u.geometry?0:u.span?1:2,g=u=>u.projectId===null?[1,""]:[0,u.projectId];return o.sort((u,i)=>{const[c,p]=g(u),[v,x]=g(i);return d(u)-d(i)||(u.span&&i.span?u.span.start-i.span.start:0)||n(u.projectId).localeCompare(n(i.projectId),"id")||c-v||p.localeCompare(x)}),o}const Ot={tinggi:"err",sedang:"neutral",rendah:"neutral"};function Rt({task:e,members:a,dragging:n,onDragStart:r,onDragEnd:l,onOpen:o,onMove:d,onAssign:g,onEscalate:u,onUnlink:i}){var v;const c=((v=a.find(x=>x.id===e.memberId))==null?void 0:v.name)??"belum ditugaskan",p=Q(e);return t.jsxs("div",{draggable:!0,"data-testid":`team-card-${e.id}`,onDragStart:x=>{x.dataTransfer.effectAllowed="move",x.dataTransfer.setData("text/plain",e.id),r()},onDragEnd:l,style:{flex:"0 0 auto",background:"var(--surface-card)",border:"1px solid var(--border-hair)",borderRadius:"var(--radius-md)",padding:10,boxShadow:"var(--shadow-xs)",cursor:"grab",opacity:n?.4:1},children:[t.jsxs("div",{style:{display:"flex",alignItems:"center",gap:6,marginBottom:6},children:[t.jsx(ae,{tone:Ot[e.priority]??"neutral",size:"sm",variant:e.priority==="tinggi"?"soft":"outline",children:e.priority}),t.jsx("span",{style:{flex:1}}),t.jsx("span",{style:{fontFamily:"var(--font-mono)",fontSize:11,color:"var(--text-subtle)",overflow:"hidden",textOverflow:"ellipsis",whiteSpace:"nowrap"},children:e.projectId??"tanpa project"})]}),t.jsx("button",{type:"button",onClick:()=>o(e),style:{display:"block",width:"100%",textAlign:"left",border:"none",background:"none",padding:0,cursor:"pointer",fontFamily:"var(--font-ui)",fontSize:13,fontWeight:"var(--weight-medium)",color:"var(--text-strong)",lineHeight:1.35},children:e.title}),t.jsxs("div",{style:{display:"flex",alignItems:"center",gap:6,marginTop:6,flexWrap:"wrap",fontSize:"var(--text-xs)",color:"var(--text-subtle)"},children:[t.jsx(X,{name:"user",size:12,color:"var(--text-subtle)"}),t.jsx("span",{children:c}),p&&t.jsxs(t.Fragment,{children:[t.jsx("span",{"aria-hidden":"true",children:"·"}),t.jsx("span",{children:p})]})]}),t.jsx("div",{style:{display:"flex",alignItems:"center",gap:6,marginTop:6,flexWrap:"wrap"},children:e.specId?t.jsxs(t.Fragment,{children:[t.jsx(ae,{tone:e.spec?"ok":"warn",size:"sm",icon:e.spec?"link":"unlink",children:e.spec?`${e.spec.id} · ${e.spec.stage}`:"tautan putus"}),t.jsx(B,{size:"sm",variant:"ghost",leftIcon:"unlink","aria-label":`Lepas tautan: ${e.title}`,onClick:()=>i(e),children:"Lepas tautan"})]}):t.jsx(B,{size:"sm",variant:"ghost",leftIcon:"git-branch","aria-label":`Eskalasi ke backlog: ${e.title}`,onClick:()=>u(e),children:"Eskalasi"})}),t.jsxs("div",{style:{display:"flex",gap:6,marginTop:8},children:[t.jsx(M,{size:"sm",value:e.status,"aria-label":`Pindah kolom: ${e.title}`,onChange:x=>d(e,x.target.value),options:K.map(x=>({value:x.key,label:x.label})),style:{flex:1,minWidth:0}}),t.jsx(M,{size:"sm",value:e.memberId??"","aria-label":`Tugaskan: ${e.title}`,onChange:x=>g(e,x.target.value||null),options:[{value:"",label:"Belum ditugaskan"},...a.map(x=>({value:x.id,label:x.name}))],style:{flex:1,minWidth:0}})]})]})}function Pt({board:e,totals:a,columns:n,members:r,onMove:l,onAssign:o,onOpen:d,onEscalate:g,onUnlink:u}){const[i,c]=m.useState(null),[p,v]=m.useState(null),x=h=>{i&&pe(i.from,h)&&l(i.task,h),c(null),v(null)};return t.jsx("div",{"data-testid":"team-board",className:"hn-board-local-overflow",style:{flex:"1 1 auto",minHeight:0,display:"flex",gap:10,overflowX:"auto",overflowY:"hidden",alignItems:"stretch",paddingBottom:4},children:n.map(h=>{const y=e[h.key],f=!!i&&pe(i.from,h.key),k=f&&p===h.key,L=Math.max(0,(a[h.key]??0)-y.length);return t.jsxs("div",{"data-testid":`team-col-${h.key}`,onDragOver:S=>{f&&(S.preventDefault(),S.dataTransfer.dropEffect="move",v(h.key))},onDragLeave:()=>v(S=>S===h.key?null:S),onDrop:S=>{S.preventDefault(),x(h.key)},style:{flex:"0 0 244px",display:"flex",flexDirection:"column",minHeight:0,padding:10,borderRadius:"var(--radius-lg)",background:k?"var(--brass-100)":"var(--bone-100)",border:`1px ${f?"dashed":"solid"} ${k?"var(--brass-500)":"var(--border-hair)"}`,opacity:i&&!f?.5:1,transition:"var(--transition-fast)"},children:[t.jsxs("div",{style:{...G,display:"flex",alignItems:"center",gap:6,marginBottom:8},children:[t.jsx("span",{className:"hn-eyebrow",children:h.label}),t.jsx("span",{style:{flex:1}}),t.jsx("span",{style:{fontFamily:"var(--font-mono)",fontSize:11,color:"var(--text-subtle)"},children:y.length})]}),t.jsx("div",{style:{...lt,display:"flex",flexDirection:"column",gap:8},children:y.map(S=>t.jsx(Rt,{task:S,members:r,dragging:(i==null?void 0:i.task.id)===S.id,onDragStart:()=>c({task:S,from:h.key}),onDragEnd:()=>{c(null),v(null)},onOpen:d,onMove:l,onAssign:o,onEscalate:g,onUnlink:u},S.id))}),L>0&&t.jsxs("div",{style:{...G,marginTop:8,fontSize:"var(--text-xs)",color:"var(--amber-600)"},children:["menampilkan ",y.length," dari ",a[h.key]," — persempit penyaring"]})]},h.key)})})}const U=232,he=34,me=6,_t={brass:{bg:"var(--brass-300)",border:"var(--brass-500)"},err:{bg:"var(--status-err-tint)",border:"var(--status-err)"},muted:{bg:"var(--bone-300)",border:"var(--border-strong)"},envelope:{bg:"var(--bone-200)",border:"var(--border-hair)"}},Oe={position:"sticky",left:0,zIndex:1,flex:`0 0 ${U}px`,width:U,boxSizing:"border-box",padding:"5px 10px",minWidth:0,background:"var(--surface-card)",borderRight:"1px solid var(--border-hair)"},V={overflow:"hidden",textOverflow:"ellipsis",whiteSpace:"nowrap"};function Nt({spec:e}){const a=e.geometry,n=_t[e.tone];return t.jsxs("button",{type:"button","data-testid":`timeline-bar-${e.key}`,"data-tone":e.tone,"data-invalid":a.invalid?"true":"false","data-clipped-start":a.clippedStart?"true":"false","data-clipped-end":a.clippedEnd?"true":"false",title:e.title,"aria-label":e.title,onClick:e.onClick,style:{position:"absolute",top:me,height:he-me*2,left:`${a.left}%`,width:`${a.width}%`,minWidth:3,minHeight:he-me*2,display:"flex",alignItems:"center",padding:0,overflow:"hidden",background:n.bg,border:`1px solid ${n.border}`,borderTopLeftRadius:a.clippedStart?0:"var(--radius-sm)",borderBottomLeftRadius:a.clippedStart?0:"var(--radius-sm)",borderTopRightRadius:a.clippedEnd?0:"var(--radius-sm)",borderBottomRightRadius:a.clippedEnd?0:"var(--radius-sm)",cursor:e.onClick?"pointer":"default"},children:[a.clippedStart&&t.jsx(X,{name:"chevron-left",size:11,color:n.border}),t.jsx("span",{style:{flex:1}}),a.clippedEnd&&t.jsx(X,{name:"chevron-right",size:11,color:n.border})]})}function Ze({window:e,rows:a,today:n,emptyHint:r,testId:l,labelHead:o}){const d=kt(e.zoom),g=e.ticks.length*d,u=Lt(e,n),i={position:"relative",width:g,height:he,flex:`0 0 ${g}px`,backgroundImage:`repeating-linear-gradient(to right, var(--border-hair) 0 1px, transparent 1px ${d}px)`};return t.jsx("div",{"data-testid":l??"team-timeline",className:"hn-timeline-scroll",style:{flex:"1 1 auto",minHeight:0,minWidth:0,maxWidth:"100%",overflowX:"auto",overflowY:"auto"},children:t.jsxs("div",{"data-testid":"timeline-canvas",style:{position:"relative",minWidth:U+g,width:U+g},children:[t.jsxs("div",{style:{display:"flex",position:"sticky",top:0,zIndex:2,background:"var(--bone-100)",borderBottom:"1px solid var(--border-hair)"},children:[t.jsx("div",{style:{...Oe,zIndex:3,background:"var(--bone-100)"},children:t.jsx("span",{className:"hn-eyebrow",children:o??"Tugas"})}),t.jsx("div",{style:{display:"grid",gridTemplateColumns:`repeat(${e.ticks.length}, ${d}px)`,width:g,flex:`0 0 ${g}px`},children:e.ticks.map(c=>t.jsx("div",{"data-testid":"timeline-tick",style:{borderLeft:`1px solid ${c.major?"var(--border-strong)":"var(--border-hair)"}`,padding:"5px 4px",fontFamily:"var(--font-mono)",fontSize:10,...V,color:c.major?"var(--text-body)":"var(--text-subtle)"},children:c.label},c.start))})]}),a.length===0?t.jsx("div",{"data-testid":"timeline-empty",style:{position:"sticky",left:0,width:U,padding:"18px 10px",fontSize:"var(--text-xs)",color:"var(--text-muted)"},children:r??"Tak ada yang bisa dihamparkan di jendela ini."}):a.map(c=>t.jsxs("div",{"data-testid":`timeline-row-${c.key}`,style:{display:"flex",borderBottom:"1px solid var(--border-hair)"},children:[t.jsxs("div",{style:Oe,children:[t.jsx("div",{style:{...V,fontSize:12,fontWeight:"var(--weight-medium)",color:"var(--text-strong)"},children:c.label}),c.meta&&t.jsx("div",{style:{...V,fontSize:10,color:"var(--text-subtle)"},children:c.meta})]}),t.jsx("div",{style:i,children:c.bars.map(p=>t.jsx(Nt,{spec:p},p.key))})]},c.key)),u!==null&&t.jsx("div",{"data-testid":"timeline-today","aria-hidden":"true",style:{position:"absolute",top:0,bottom:0,width:2,pointerEvents:"none",left:U+u/100*g,background:"var(--brass-500)",opacity:.5}})]})})}function Re({testId:e,icon:a,title:n,hint:r,tasks:l,onOpen:o}){return l.length===0?null:t.jsxs("div",{"data-testid":e,style:{...G,marginTop:10,padding:10,background:"var(--bone-100)",border:"1px solid var(--border-hair)",borderRadius:"var(--radius-lg)"},children:[t.jsxs("div",{style:{display:"flex",alignItems:"center",gap:6,marginBottom:6,flexWrap:"wrap"},children:[t.jsx(X,{name:a,size:13,color:"var(--text-subtle)"}),t.jsxs("span",{className:"hn-eyebrow",children:[n," · ",l.length]}),r&&t.jsx("span",{style:{fontSize:"var(--text-xs)",color:"var(--text-muted)"},children:r})]}),t.jsx("div",{style:{display:"flex",flexWrap:"wrap",gap:6},children:l.map(d=>t.jsx("button",{type:"button",onClick:()=>o(d),style:{padding:"3px 10px",background:"var(--surface-card)",border:"1px solid var(--border-hair)",borderRadius:"var(--radius-pill)",fontFamily:"var(--font-ui)",fontSize:12,color:"var(--text-body)",cursor:"pointer"},children:d.title},d.id))})]})}function Ft({tasks:e,members:a,zoom:n,today:r,hidden:l,onOpen:o}){const d=m.useMemo(()=>{const p=e.map(Y).filter(v=>v!==null);return Ge(p,n,r)},[e,n,r]),{rows:g,unscheduled:u,outside:i}=m.useMemo(()=>$t(e,d),[e,d]),c=m.useMemo(()=>g.map(({task:p,geometry:v})=>{var f;const x=((f=a.find(k=>k.id===p.memberId))==null?void 0:f.name)??"belum ditugaskan",h=Q(p),y=[v.invalid?"tenggat mendahului mulai":null,v.clippedStart||v.clippedEnd?"melewati tepi jendela":null].filter(Boolean);return{key:p.id,label:p.title,meta:h?`${x} · ${h}`:x,bars:[{key:p.id,geometry:v,tone:v.invalid?"err":p.status==="done"?"muted":"brass",title:[p.title,h,...y].filter(Boolean).join(" · "),onClick:()=>o(p)}]}}),[g,a,o]);return t.jsxs(t.Fragment,{children:[t.jsx(Ze,{window:d,rows:c,today:r,emptyHint:"Belum ada tugas bertanggal — isi mulai atau tenggat di kartunya."}),l>0&&t.jsxs("div",{"data-testid":"timeline-truncated",style:{...G,marginTop:8,fontSize:"var(--text-xs)",color:"var(--amber-600)"},children:[l," tugas tak termuat karena plafon 200 per kolom — persempit penyaring"]}),t.jsx(Re,{testId:"timeline-unscheduled",icon:"calendar-off",title:"Belum dijadwalkan",tasks:u,onOpen:o}),t.jsx(Re,{testId:"timeline-outside",icon:"chevrons-left-right",title:"Di luar jendela",hint:"pilih zoom yang lebih lebar",tasks:i,onOpen:o})]})}const Wt="__none__",At=16,Pe=(e,a)=>a.invalid?"err":e.status==="done"?"muted":"brass",_e=(e,a,n)=>[e.title,n,a.invalid?"tenggat mendahului mulai":null,a.clippedStart||a.clippedEnd?"melewati tepi jendela":null].filter(Boolean).join(" · ");function Ut({testId:e,open:a,name:n,count:r,onClick:l}){return t.jsxs("button",{type:"button",onClick:l,"data-testid":e,"aria-expanded":a,style:{display:"flex",alignItems:"center",gap:5,width:"100%",padding:0,background:"none",border:"none",cursor:"pointer",textAlign:"left",minHeight:0,fontFamily:"var(--font-ui)",fontSize:12,fontWeight:"var(--weight-medium)",color:"var(--text-strong)"},children:[t.jsx(X,{name:a?"chevron-down":"chevron-right",size:12,color:"var(--text-subtle)"}),t.jsx("span",{style:{...V,flex:1},children:n}),t.jsx("span",{style:{fontFamily:"var(--font-mono)",fontSize:10,color:"var(--text-subtle)"},children:r})]})}function Ht({tasks:e,projects:a,members:n,zoom:r,today:l,hidden:o,expanded:d,onToggle:g,onOpen:u}){const i=m.useMemo(()=>{const h=e.map(Y).filter(y=>y!==null);return Ge(h,r,l)},[e,r,l]),c=m.useCallback(h=>{var y;return h===null?"Tanpa project":((y=a.find(f=>f.id===h))==null?void 0:y.name)??h},[a]),p=m.useMemo(()=>zt(e,i,c),[e,i,c]),v=m.useMemo(()=>new Set(d),[d]),x=m.useMemo(()=>{var y;const h=[];for(const f of p){const k=f.projectId??Wt,L=v.has(k),S=c(f.projectId),b=f.geometry?Q({startDate:new Date(f.span.start).toISOString(),dueDate:new Date(f.span.end-1).toISOString()}):f.span?"di luar jendela · pilih zoom yang lebih lebar":"belum dijadwalkan",D=[];if(f.geometry){D.push({key:`span:${k}`,geometry:f.geometry,tone:f.geometry.invalid?"err":"envelope",title:`${S} · ${b??""}`.trim(),onClick:()=>g(k)});for(const C of f.tasks){const E=ge(C,i);E&&D.push({key:`seg:${C.id}`,geometry:E,tone:Pe(C,E),title:_e(C,E,Q(C)),onClick:()=>u(C)})}}if(h.push({key:`p:${k}`,meta:b,bars:D,label:t.jsx(Ut,{testId:`expand-${k}`,open:L,name:S,count:f.tasks.length,onClick:()=>g(k)})}),!!L)for(const C of f.tasks){const E=ge(C,i),j=((y=n.find(_=>_.id===C.memberId))==null?void 0:y.name)??"belum ditugaskan",P=Q(C);h.push({key:`t:${C.id}`,label:t.jsx("span",{style:{...V,display:"block",paddingLeft:At},children:C.title}),meta:P?`${j} · ${P}`:j,bars:E?[{key:`t:${C.id}`,geometry:E,tone:Pe(C,E),title:_e(C,E,P),onClick:()=>u(C)}]:[]})}}return h},[p,v,c,i,n,g,u]);return t.jsxs(t.Fragment,{children:[t.jsx(Ze,{window:i,rows:x,today:l,testId:"team-projects",labelHead:"Project",emptyHint:"Belum ada project bertanggal — isi mulai atau tenggat di kartunya."}),o>0&&t.jsxs("div",{"data-testid":"projects-truncated",style:{...G,marginTop:8,fontSize:"var(--text-xs)",color:"var(--amber-600)"},children:[o," tugas tak termuat karena plafon 200 per kolom — amplop project bisa lebih pendek dari rentang sebenarnya; persempit kolom, anggota, atau pencarian"]})]})}const fe={tinggi:"Tinggi",sedang:"Sedang",rendah:"Rendah"},Kt=Object.keys(fe).map(e=>({value:e,label:fe[e]})),Ne=(e,a)=>({title:(e==null?void 0:e.title)??"",detail:(e==null?void 0:e.detail)??"",projectId:e?e.projectId??"":a??"",status:(e==null?void 0:e.status)??"backlog",priority:e&&e.priority in fe?e.priority:"sedang",memberId:(e==null?void 0:e.memberId)??"",startDate:De((e==null?void 0:e.startDate)??null),dueDate:De((e==null?void 0:e.dueDate)??null)});function Gt({open:e,task:a,projects:n,members:r,defaultProjectId:l,orderFor:o,onClose:d,onSaved:g,onToast:u}){const[i,c]=m.useState(()=>Ne(a,l)),[p,v]=m.useState(!1),{confirm:x,dialog:h}=Ue(),y=`${e?"1":"0"}:${(a==null?void 0:a.id)??""}`,f=m.useRef(y);if(f.current!==y&&(f.current=y,e&&c(Ne(a,l))),!e)return null;const k=b=>c(D=>({...D,...b}));async function L(){if(!i.title.trim()){u("Judul tugas wajib diisi","err","x-circle");return}v(!0);const b=!a||a.status!==i.status,D={title:i.title.trim(),detail:i.detail.trim()||null,projectId:i.projectId||null,status:i.status,priority:i.priority,memberId:i.memberId||null,startDate:Ee(i.startDate),dueDate:Ee(i.dueDate),...b?{order:o(i.status)}:{}};try{a?await w.patchTask(a.id,D):await w.createTask(D),u(a?"Tugas diperbarui":"Tugas dibuat","ok","check"),g(),d()}catch{u("Gagal menyimpan tugas","err","x-circle")}finally{v(!1)}}async function S(){a&&await x({title:`Hapus "${a.title}"?`,message:"Kartu ini hilang dari papan di semua device yang tersinkron.",confirmLabel:"Hapus tugas",tone:"danger",icon:"trash-2",run:()=>w.deleteTask(a.id)})&&(u("Tugas dihapus","ok","trash-2"),g(),d())}return t.jsxs(t.Fragment,{children:[t.jsxs(xe,{open:e,onClose:d,icon:"clipboard-list",eyebrow:"Papan tim",title:a?"Ubah tugas":"Tugas baru",footer:t.jsxs("div",{style:{display:"flex",gap:8,width:"100%",alignItems:"center"},children:[a&&t.jsx(B,{variant:"ghost",leftIcon:"trash-2",onClick:S,disabled:p,children:"Hapus"}),t.jsx("span",{style:{flex:1}}),t.jsx(B,{variant:"secondary",onClick:d,disabled:p,children:"Batal"}),t.jsx(B,{onClick:L,loading:p,children:a?"Simpan":"Buat tugas"})]}),children:[t.jsx($,{label:"Judul",children:t.jsx(O,{value:i.title,"aria-label":"Judul tugas",placeholder:"mis. Rapikan halaman harga",onChange:b=>k({title:b.target.value}),style:{width:"100%"}})}),t.jsxs("div",{style:{display:"flex",gap:10,flexWrap:"wrap"},children:[t.jsx($,{label:"Project",children:t.jsx(M,{value:i.projectId,"aria-label":"Project tugas",onChange:b=>k({projectId:b.target.value}),options:[{value:"",label:"Tanpa project"},...n.map(b=>({value:b.id,label:b.name}))]})}),t.jsx($,{label:"Kolom",children:t.jsx(M,{value:i.status,"aria-label":"Kolom tugas",onChange:b=>k({status:b.target.value}),options:K.map(b=>({value:b.key,label:b.label}))})}),t.jsx($,{label:"Prioritas",children:t.jsx(M,{value:i.priority,"aria-label":"Prioritas tugas",onChange:b=>k({priority:b.target.value}),options:Kt})})]}),t.jsx($,{label:"Ditugaskan ke",children:t.jsx(M,{value:i.memberId,"aria-label":"Anggota tugas",onChange:b=>k({memberId:b.target.value}),options:[{value:"",label:"Belum ditugaskan"},...r.map(b=>({value:b.id,label:b.role?`${b.name} · ${b.role}`:b.name}))],style:{width:"100%"}})}),t.jsxs("div",{style:{display:"flex",gap:10,flexWrap:"wrap"},children:[t.jsx($,{label:"Mulai",children:t.jsx(O,{type:"date",value:i.startDate,"aria-label":"Tanggal mulai",onChange:b=>k({startDate:b.target.value})})}),t.jsx($,{label:"Tenggat",children:t.jsx(O,{type:"date",value:i.dueDate,"aria-label":"Tanggal tenggat",onChange:b=>k({dueDate:b.target.value})})})]}),t.jsx($,{label:"Detail",hint:"Opsional — konteks yang tak muat di judul.",children:t.jsx(ot,{value:i.detail,"aria-label":"Detail tugas",rows:4,placeholder:"mis. tunggu aset dari klien, deadline ikut jadwal kampanye",onChange:b=>k({detail:b.target.value})})})]}),h]})}const Yt=dt.map(e=>({value:e,label:ct(e).label}));function Zt({task:e,projects:a,onClose:n,onDone:r,onToast:l}){const[o,d]=m.useState("brief"),[g,u]=m.useState(()=>Te.some(f=>f.value===e.priority)?e.priority:"sedang"),[i,c]=m.useState(""),[p,v]=m.useState(!1),x=e.projectId===null,h=e.projectId??i;async function y(){if(!(!h||p)){v(!0);try{const f=await w.escalateTask(e.id,{source:o,priority:g,...e.projectId?{}:{projectId:i}});l(f.created?`Dieskalasi jadi ${f.spec.id}`:`Sudah tertaut ke ${f.spec.id}`,"ok","link"),r(f.task),n()}catch{l("Gagal mengeskalasi kartu","err","x-circle")}finally{v(!1)}}}return t.jsxs(xe,{open:!0,onClose:p?void 0:n,icon:"git-branch",eyebrow:"Papan tim",title:"Eskalasi ke backlog",footer:t.jsxs("div",{style:{display:"flex",gap:8,width:"100%",alignItems:"center"},children:[t.jsx("span",{style:{flex:1}}),t.jsx(B,{variant:"secondary",onClick:n,disabled:p,children:"Batal"}),t.jsx(B,{onClick:y,loading:p,disabled:!h,leftIcon:"git-branch",children:"Eskalasi"})]}),children:[t.jsxs("div",{style:{fontSize:13.5,color:"var(--text-strong)",lineHeight:1.55,marginBottom:14},children:["Kartu ",t.jsx("strong",{children:e.title})," tetap di papan. Yang lahir adalah backlog item baru yang bisa dikerjakan sesi agen, dan kartu ini menampilkan stage-nya."]}),x&&t.jsxs($,{label:"Project",children:[t.jsx(M,{"aria-label":"Project",value:i,style:{width:"100%"},onChange:f=>c(f.target.value),options:[{value:"",label:"Pilih project…"},...a.map(f=>({value:f.id,label:f.name}))]}),t.jsx("div",{style:{marginTop:6,fontSize:"var(--text-xs)",color:"var(--text-subtle)"},children:"Nomor SPEC diambil dari repo project, jadi kartu tanpa project belum bisa dieskalasi."})]}),t.jsx($,{label:"Source",children:t.jsx(M,{"aria-label":"Source",value:o,style:{width:"100%"},onChange:f=>d(f.target.value),options:Yt})}),t.jsx($,{label:"Prioritas",children:t.jsx(M,{"aria-label":"Prioritas",value:g,style:{width:"100%"},onChange:f=>u(f.target.value),options:Te})})]})}function qt({m:e,busy:a,onSave:n,onToggle:r,onDelete:l}){const[o,d]=m.useState(!1),[g,u]=m.useState(e.name),[i,c]=m.useState(e.role??"");return o?t.jsxs("div",{style:{display:"flex",flexDirection:"column",gap:8,padding:"12px 14px",marginBottom:8,border:"1px solid var(--border-strong)",borderRadius:"var(--radius-md)",background:"var(--surface-card)"},children:[t.jsx(O,{size:"sm",value:g,"aria-label":`Nama ${e.name}`,placeholder:"mis. Dena Meidina",onChange:p=>u(p.target.value)}),t.jsx(O,{size:"sm",value:i,"aria-label":`Peran ${e.name}`,placeholder:"mis. desainer",onChange:p=>c(p.target.value)}),t.jsxs("div",{style:{fontSize:"var(--text-xs)",color:"var(--text-subtle)"},children:[e.email," — ganti email berarti hapus lalu buat baru."]}),t.jsxs("div",{style:{display:"flex",gap:8},children:[t.jsx(B,{size:"sm",disabled:a,onClick:()=>{n(e.id,{name:g.trim(),role:i.trim()||null}),d(!1)},children:"Simpan"}),t.jsx(B,{size:"sm",variant:"ghost",onClick:()=>d(!1),children:"Batal"})]})]}):t.jsxs("div",{className:"hn-dense-row",style:{display:"flex",alignItems:"center",gap:10,padding:"10px 14px",marginBottom:8,border:"1px solid var(--border-hair)",borderRadius:"var(--radius-md)",background:"var(--surface-card)",opacity:e.active?1:.6},children:[t.jsxs("span",{style:{flex:1,minWidth:0},children:[t.jsxs("span",{style:{display:"flex",alignItems:"center",gap:8},children:[t.jsx("span",{style:{fontWeight:"var(--weight-semibold)",color:"var(--text-strong)"},children:e.name}),e.role&&t.jsx(ae,{tone:"neutral",size:"sm",children:e.role}),!e.active&&t.jsx(ae,{tone:"warn",size:"sm",children:"nonaktif"})]}),t.jsx("span",{style:{display:"block",fontFamily:"var(--font-mono)",fontSize:"var(--text-xs)",color:"var(--text-subtle)",marginTop:2},children:e.email})]}),t.jsx(de,{icon:"pencil",label:`Ubah ${e.name}`,size:"sm",onClick:()=>d(!0)}),t.jsx(de,{icon:e.active?"user-minus":"user-check",size:"sm",label:`${e.active?"Nonaktifkan":"Aktifkan"} ${e.name}`,onClick:()=>r(e)}),t.jsx(de,{icon:"trash-2",label:`Hapus ${e.name}`,size:"sm",onClick:()=>l(e)})]})}function Jt({open:e,onClose:a,onChanged:n,onToast:r}){const[l,o]=m.useState([]),[d,g]=m.useState("loading"),[u,i]=m.useState(!1),[c,p]=m.useState(""),[v,x]=m.useState(""),[h,y]=m.useState(""),{confirm:f,dialog:k}=Ue(),L=m.useRef(n);L.current=n;const S=m.useCallback(()=>{g("loading"),w.listMembers().then(j=>{o(j.items),g("ready"),L.current(j.items)}).catch(()=>g("error"))},[]);if(m.useEffect(()=>{e&&S()},[e,S]),!e)return null;async function b(){if(!c.trim()||!v.trim()){r("Nama & email wajib diisi","err","x-circle");return}i(!0);try{await w.createMember({name:c.trim(),email:v.trim(),role:h.trim()||null}),p(""),x(""),y(""),r("Anggota ditambahkan","ok","user-plus"),S()}catch{r("Gagal menambah anggota — email mungkin sudah terdaftar","err","x-circle")}finally{i(!1)}}async function D(j,P){i(!0);try{await w.patchMember(j,P),S()}catch{r("Gagal menyimpan anggota","err","x-circle")}finally{i(!1)}}async function C(j){i(!0);try{await w.patchMember(j.id,{active:!j.active}),S()}catch{r("Gagal mengubah status anggota","err","x-circle")}finally{i(!1)}}async function E(j){await f({title:`Hapus ${j.name} dari direktori?`,message:"Tugasnya tidak ikut terhapus — kartu yang ditugaskan padanya jadi 'belum ditugaskan'.",confirmLabel:"Hapus anggota",tone:"danger",icon:"trash-2",run:()=>w.deleteMember(j.id)})&&(r("Anggota dihapus","ok","trash-2"),S())}return t.jsxs(t.Fragment,{children:[t.jsxs(xe,{open:e,onClose:a,icon:"users",eyebrow:"Papan tim",title:"Anggota",width:620,children:[t.jsxs("div",{style:{display:"flex",gap:8,flexWrap:"wrap",alignItems:"flex-end",marginBottom:16,paddingBottom:16,borderBottom:"1px solid var(--border-hair)"},children:[t.jsx(O,{size:"sm",value:c,"aria-label":"Nama anggota baru",placeholder:"Nama",onChange:j=>p(j.target.value),style:{flex:"1 1 140px"}}),t.jsx(O,{size:"sm",value:v,"aria-label":"Email anggota baru",placeholder:"email@nafanesia.id",onChange:j=>x(j.target.value),style:{flex:"1 1 180px"}}),t.jsx(O,{size:"sm",value:h,"aria-label":"Peran anggota baru",placeholder:"Peran (opsional)",onChange:j=>y(j.target.value),style:{flex:"1 1 130px"}}),t.jsx(B,{size:"sm",leftIcon:"user-plus",onClick:b,loading:u,children:"Tambah anggota"})]}),d==="loading"?t.jsx(H,{kind:"loading",compact:!0}):d==="error"?t.jsx(H,{kind:"error",compact:!0,hint:"Gagal memuat anggota.",action:S,actionLabel:"Coba lagi"}):l.length===0?t.jsx(H,{kind:"empty",compact:!0,icon:"users",title:"Belum ada anggota",hint:"Tambahkan orang di atas agar kartu papan bisa ditugaskan."}):l.map(j=>t.jsx(qt,{m:j,busy:u,onSave:D,onToggle:C,onDelete:E},j.id))]}),k]})}const Qt=5e3,Fe=200,Vt=400,We=[{value:"board",label:"Papan",icon:"kanban"},{value:"timeline",label:"Linimasa",icon:"gantt-chart"},{value:"projects",label:"Lintas project",icon:"layers"}],Xt={day:"Hari",week:"Minggu",month:"Bulan"},ea=()=>Object.fromEntries(K.map(e=>[e.key,0]));function ta({status:e,params:a,onData:n,refetch:r}){return ft({topic:"tasks",params:{...a,status:e},apply:l=>n(e,l.data.items,l.data.total),refetch:r,pollMs:Qt}),null}function la({projects:e,projectFilter:a,onProjectFilter:n,onToast:r}){const[l,o]=m.useState(vt),[d,g]=m.useState(ea),[u,i]=m.useState([]),[c,p]=m.useState("loading"),[v,x]=m.useState(!1),[h,y]=m.useState(null),[f,k]=m.useState(!1),[L,S]=m.useState(!1),[b,D]=m.useState(null),[C,E]=A("team","view","board",we(...We.map(s=>s.value))),[j,P]=A("team","q","",ce),[_,qe]=A("team","col","all",ce),[Z,Je]=A("team","member","all",ce),[ne,Qe]=A("team","zoom","week",we(...Le)),[Ve,be]=A("team","expanded",[],ht),Xe=m.useCallback(s=>{be(I=>I.includes(s)?I.filter(T=>T!==s):[...I,s])},[be]),ve=C==="timeline",N=C==="projects",ye=m.useRef(Date.now()).current,R=m.useMemo(()=>_==="all"?K:K.filter(s=>s.key===_),[_]),ie=R.map(s=>s.key).join(","),je=[a!=="all"&&!N,_!=="all",Z!=="all",j.trim()!==""].filter(Boolean).length,re=N||a==="all"?void 0:a,W=m.useMemo(()=>({projectId:re,memberId:Z==="all"?void 0:Z,q:j.trim()||void 0}),[re,Z,j]),te=m.useRef(!1),q=m.useCallback((s=!1)=>{!s&&!te.current&&p("loading");const I=ie?ie.split(","):[];Promise.all(I.map(T=>w.listTasks({...W,status:T,page:1,limit:Fe}))).then(T=>{o(z=>{const J={...z};return I.forEach((le,oe)=>{J[le]=T[oe].items}),J}),g(z=>{const J={...z};return I.forEach((le,oe)=>{J[le]=T[oe].total}),J}),te.current=!0,x(!1),p("ready")}).catch(()=>{if(!te.current){p("error");return}x(!0)})},[W,ie]);m.useEffect(()=>{q()},[q]);const ke=m.useCallback(()=>{w.listMembers().then(s=>i(s.items)).catch(()=>{})},[]);m.useEffect(()=>{ke()},[ke]);const[Se,et]=m.useState(()=>j.trim());m.useEffect(()=>{const s=setTimeout(()=>et(j.trim()),Vt);return()=>clearTimeout(s)},[j]);const tt=m.useCallback((s,I,T)=>{o(z=>({...z,[s]:I})),g(z=>({...z,[s]:T})),te.current=!0,x(!1),p("ready")},[]),at=m.useMemo(()=>({projectId:W.projectId,memberId:W.memberId,q:Se||void 0,page:1,limit:Fe}),[W.projectId,W.memberId,Se]),se=m.useCallback(()=>q(!0),[q]);async function nt(s,I){const T=yt(l,s.id,s.status,I);if(!T)return;const z=l;o(T.board);try{await w.patchTask(s.id,T.patch)}catch{o(z),r("Gagal memindahkan tugas","err","x-circle")}}async function it(s,I){const T=l;o(ue(l,{...s,memberId:I}));try{await w.patchTask(s.id,{memberId:I})}catch{o(T),r("Gagal menugaskan","err","x-circle")}}async function rt(s){const I=l;o(ue(l,{...s,specId:null,spec:null}));try{await w.unlinkTaskSpec(s.id),r("Tautan backlog dilepas","ok","unlink")}catch{o(I),r("Gagal melepas tautan","err","x-circle")}}const st=R.every(s=>l[s.key].length===0),Ie=m.useMemo(()=>R.flatMap(s=>l[s.key]),[l,R]),Ce=R.reduce((s,I)=>s+Math.max(0,(d[I.key]??0)-l[I.key].length),0);return t.jsxs("div",{style:ut,children:[t.jsxs("div",{className:"hn-team-controls",role:"region","aria-label":"Kontrol papan tim",style:{...G,marginBottom:18},children:[t.jsxs("div",{className:"hn-team-topline",style:{display:"flex",alignItems:"center",justifyContent:"space-between",gap:12,flexWrap:"wrap",marginBottom:12},children:[t.jsx(mt,{variant:"pill",value:C,onChange:E,tabs:We,"aria-label":"Mode tampilan"}),t.jsxs("div",{className:"hn-team-view-actions",style:{display:"flex",alignItems:"center",gap:10},children:[t.jsx(B,{size:"sm",leftIcon:"plus",onClick:()=>{y(null),k(!0)},children:"Tugas baru"}),t.jsx(B,{size:"sm",variant:"secondary",leftIcon:"users",onClick:()=>S(!0),children:"Anggota"}),t.jsx(pt,{onDone:se,onToast:r}),t.jsx(gt,{screen:"team",active:je,onReset:N?void 0:()=>n("all")}),t.jsxs("span",{className:"hn-eyebrow",role:"status",style:v?{color:"var(--amber-600)"}:void 0,title:v?"Server tak menjawab saat menyegarkan — angka ini dari muatan terakhir yang berhasil":void 0,children:[R.reduce((s,I)=>s+(d[I.key]??0),0)," tugas",v?" · basi":""]}),t.jsx(xt,{})]})]}),t.jsxs("div",{className:"hn-team-filters",style:{display:"flex",alignItems:"center",gap:10,flexWrap:"wrap"},children:[t.jsx(O,{size:"sm",leftIcon:"search","aria-label":"Cari tugas",value:j,placeholder:"mis. halaman harga atau deploy",onChange:s=>P(s.target.value),style:{flex:"1 1 220px"}}),t.jsx(M,{size:"sm","aria-label":"Filter project",value:a,disabled:N,onChange:s=>n(s.target.value),options:[{value:"all",label:"Semua project"},...e.map(s=>({value:s.id,label:s.name}))]}),N&&t.jsx("span",{"data-testid":"project-filter-note",style:{fontSize:"var(--text-xs)",color:"var(--text-subtle)"},children:"Mode ini melintasi semua project"}),t.jsx(M,{size:"sm","aria-label":"Filter kolom",value:_,onChange:s=>qe(s.target.value),options:[{value:"all",label:"Semua kolom"},...K.map(s=>({value:s.key,label:s.label}))]}),t.jsx(M,{size:"sm","aria-label":"Filter anggota",value:Z,onChange:s=>Je(s.target.value),options:[{value:"all",label:"Semua anggota"},...u.map(s=>({value:s.id,label:s.name}))]}),(ve||N)&&t.jsx(M,{size:"sm","aria-label":"Zoom linimasa",value:ne,onChange:s=>Qe(s.target.value),options:Le.map(s=>({value:s,label:Xt[s]}))})]})]}),R.map(s=>t.jsx(ta,{status:s.key,params:at,onData:tt,refetch:se},s.key)),c==="loading"?t.jsx(H,{kind:"loading"}):c==="error"?t.jsx(H,{kind:"error",hint:"Gagal memuat papan tim.",action:()=>q(),actionLabel:"Coba lagi"}):st&&je===0?t.jsx(H,{kind:"empty",icon:"users",title:"Papan tim masih kosong",hint:"Catat pekerjaan manusia di sekitar sesi agen — desain, meeting klien, deploy, nego.",action:()=>{y(null),k(!0)},actionLabel:"Tugas baru",actionIcon:"plus"}):N?t.jsx(Ht,{tasks:Ie,projects:e,members:u,zoom:ne,today:ye,hidden:Ce,expanded:Ve,onToggle:Xe,onOpen:s=>{y(s),k(!0)}}):ve?t.jsx(Ft,{tasks:Ie,members:u,zoom:ne,today:ye,hidden:Ce,onOpen:s=>{y(s),k(!0)}}):t.jsx(Pt,{board:l,totals:d,columns:R,members:u,onMove:nt,onAssign:it,onEscalate:D,onUnlink:rt,onOpen:s=>{y(s),k(!0)}}),t.jsx(Gt,{open:f,task:h,projects:e,members:u,defaultProjectId:re??null,orderFor:s=>He(l[s]),onClose:()=>{k(!1),y(null)},onSaved:se,onToast:r}),b&&t.jsx(Zt,{task:b,projects:e,onClose:()=>D(null),onDone:s=>o(I=>ue(I,s)),onToast:r}),t.jsx(Jt,{open:L,onClose:()=>S(!1),onChanged:i,onToast:r})]})}export{We as TEAM_VIEWS,la as TeamScreen};
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{e as P,j as a,M as Se,d as Lt,S as Z,G as ga,J as Ft,f as nt,B as Ze,I as oe,w as xa,D as ba,a as K,K as va,N as ya,O as kt,Q as jt,c as Ue,U as ka,V as ja,W as wa,X as Sa,Y as Ia,Z as Ca,_ as Ie,$ as Bt,a0 as it,a1 as za,a2 as Ra,a3 as Ta,a4 as et,a5 as Ea,h as ke,a6 as Ot,a7 as Aa,a8 as Na,a9 as Da,aa as $a,g as Ye,ab as Pa,ac as La,ad as Mt,l as Fa,ae as wt,af as Ba,ag as Oa,x as Ma,ah as Wa,ai as _a,aj as Ve,p as Ka,ak as Ha,al as Ga,am as Wt,an as qa,ao as je,ap as Ua,aq as St,ar as Ya}from"./index-DYNYB1Nj.js";import{R as d,r as L}from"./react-DfGhg7ZW.js";import"./markdown-CWEY34jk.js";import"./xterm-3VOAfa_q.js";function rt(e){return e.endedAt?e.endedReason==="reconciled"?"interrupted":e.exitCode===null||e.exitCode===0?"completed":"failed":"running"}const Pe=new Set;let we;function Va(e){return Pe.add(e),we||(we=setInterval(()=>{for(const i of[...Pe])i()},1e3)),()=>{Pe.delete(e),Pe.size===0&&we&&(clearInterval(we),we=void 0)}}const It=20;function Xa(e,i){if(!i)return"—";const r=new Date(i).getTime()-new Date(e).getTime();if(!Number.isFinite(r)||r<0)return"—";const s=Math.round(r/1e3);if(s<60)return`${s} dtk`;const o=Math.round(s/60);return o<60?`${o} mnt`:`${Math.floor(o/60)} jam ${o%60} mnt`}function Ja(e){switch(rt(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 _t=e=>rt(e)==="interrupted"?"—":Xa(e.startedAt,e.endedAt),Kt=e=>Ft[e]??e;function Qa({projects:e,onClose:i,onRestart:r}){const[s,o]=d.useState([]),[c,I]=d.useState(0),[h,R]=d.useState(1),[g,x]=d.useState(!1),[b,m]=d.useState(""),[y,T]=d.useState(""),[C,f]=d.useState(""),[z,E]=d.useState(""),[D,O]=d.useState(null);d.useEffect(()=>{const u=setTimeout(()=>E(C.trim()),250);return()=>clearTimeout(u)},[C]),d.useEffect(()=>{R(1)},[b,y,z]),d.useEffect(()=>{let u=!0;return x(!0),P.listSessionHistory({projectId:b||void 0,kind:y||void 0,q:z||void 0,page:h,limit:It}).then(v=>{u&&(I(v.total),o(v.items))}).catch(()=>{u&&(o([]),I(0))}).finally(()=>{u&&x(!1)}),()=>{u=!1}},[b,y,z,h]);const w=ba(c,h,It),N=u=>{var v;return((v=e.find(j=>j.id===u))==null?void 0:v.name)??u};return a.jsxs(Se,{open:!0,title:"Riwayat sesi",icon:"history",onClose:i,width:900,children:[a.jsxs("div",{style:{display:"flex",alignItems:"center",gap:10,flexWrap:"wrap",marginBottom:10},children:[a.jsx(Lt,{size:"sm",leftIcon:"search",placeholder:"mis. spec-412 atau reverse","aria-label":"Cari riwayat sesi",value:C,onChange:u=>f(u.target.value),style:{flex:"1 1 200px"}}),a.jsx(Z,{size:"sm","aria-label":"Filter project",value:b,onChange:u=>m(u.target.value),options:[{value:"",label:"Semua project"}].concat(e.map(u=>({value:u.id,label:u.name})))}),a.jsx(Z,{size:"sm","aria-label":"Filter jenis",value:y,onChange:u=>T(u.target.value),options:[{value:"",label:"Semua jenis"}].concat(ga.map(u=>({value:u,label:Ft[u]})))})]}),s.length===0&&!g?a.jsx(nt,{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."}):a.jsxs("div",{style:{display:"flex",flexDirection:"column",maxHeight:"60vh",overflowY:"auto"},children:[s.map(u=>{const v=Ja(u);return a.jsx("button",{onClick:()=>O(u),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:a.jsxs("span",{className:"hn-dense-row hn-picker-row",style:{display:"flex",alignItems:"center",gap:10,width:"100%"},children:[a.jsx("span",{style:{fontFamily:"var(--font-mono)",fontSize:11,color:"var(--text-subtle)",flex:"0 0 132px"},children:new Date(u.startedAt).toLocaleString("id-ID")}),a.jsx(Ze,{size:"sm",tone:"neutral",children:Kt(u.kind)}),a.jsx("span",{className:"hn-picker-title",style:{flex:1,minWidth:0,fontSize:13,color:"var(--text-strong)",overflow:"hidden",textOverflow:"ellipsis",whiteSpace:"nowrap"},children:u.title??u.specId??N(u.projectId)}),u.transcriptBytes!==null&&a.jsx(oe,{name:"file-text",size:12,color:"var(--text-subtle)"}),a.jsx("span",{style:{fontFamily:"var(--font-mono)",fontSize:11,color:"var(--text-muted)",flex:"0 0 72px"},children:_t(u)}),a.jsx(Ze,{size:"sm",tone:v.tone,children:v.label})]})},u.id)}),g&&a.jsx("div",{style:{padding:"10px 8px",textAlign:"center",fontSize:11,color:"var(--text-subtle)"},children:"memuat…"})]}),a.jsx(xa,{page:w.page,pageCount:w.pageCount,total:c,from:w.from,to:w.to,onPage:R,unit:"sesi"}),D&&a.jsx(Za,{row:D,projectName:N(D.projectId),onBack:()=>O(null),onRestart:r})]})}function Za({row:e,projectName:i,onBack:r,onRestart:s}){const[o,c]=d.useState(null),[I,h]=d.useState("idle");d.useEffect(()=>{if(e.transcriptBytes===null){h("none"),c(null);return}let x=!0;return h("loading"),P.sessionTranscript(e.id).then(b=>{x&&(c(b.text),h("idle"))}).catch(()=>{x&&(c(null),h("error"))}),()=>{x=!1}},[e.id,e.transcriptBytes]);const R=rt(e)==="interrupted",g=[["Project",i],["Sesi",e.sessionId],["Jenis",Kt(e.kind)],["Agen",[e.agent,e.model,e.effort].filter(Boolean).join(" · ")],["Mulai",new Date(e.startedAt).toLocaleString("id-ID")],[R?"Terakhir terlihat hidup":"Selesai",e.endedAt?new Date(e.endedAt).toLocaleString("id-ID"):"berjalan"],...R&&e.reconciledAt?[["Terdeteksi mati",new Date(e.reconciledAt).toLocaleString("id-ID")]]:[],["Durasi",_t(e)],["Direktori",e.cwd]];return e.specId&&g.splice(1,0,["Backlog",`${e.specId}${e.title?` · ${e.title}`:""}`]),e.branch&&g.push(["Branch",e.branch]),a.jsxs(Se,{open:!0,title:e.title??e.specId??e.sessionId,icon:"history",onClose:r,width:1e3,children:[a.jsxs("div",{style:{display:"flex",gap:8,alignItems:"center",marginBottom:10},children:[a.jsx(K,{size:"sm",variant:"ghost",leftIcon:"arrow-left",onClick:r,children:"Kembali"}),a.jsx("div",{style:{flex:1}}),o&&a.jsx(K,{size:"sm",variant:"secondary",leftIcon:"copy",onClick:()=>{var x;return void((x=navigator.clipboard)==null?void 0:x.writeText(o))},children:"Salin transkrip"}),va(e.kind)&&a.jsx(K,{size:"sm",leftIcon:"play",onClick:()=>s(e),children:"Mulai lagi"})]}),R&&a.jsxs(ya,{tone:"warn",title:"Sesi terputus — hasilnya tak diketahui",style:{marginBottom:12},children:["Panenya sudah lenyap saat hanoman menyala lagi (reboot, ",a.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."]}),a.jsx("div",{style:{display:"grid",gridTemplateColumns:"auto 1fr",gap:"4px 12px",marginBottom:12,fontSize:12},children:g.map(([x,b])=>a.jsxs(d.Fragment,{children:[a.jsx("span",{style:{color:"var(--text-subtle)"},children:x}),a.jsx("span",{style:{fontFamily:"var(--font-mono)",color:"var(--text-body)",wordBreak:"break-all"},children:b})]},x))}),I==="loading"&&a.jsx("div",{style:{fontSize:12,color:"var(--text-subtle)"},children:"memuat transkrip…"}),I==="none"&&a.jsx("div",{style:{fontSize:12,color:"var(--text-subtle)"},children:R?"Tanpa transkrip — panenya sudah lenyap sebelum hanoman sempat mengambilnya.":"Tanpa transkrip — sesi ini ditutup sebelum fitur riwayat ada, atau panenya tak menyisakan keluaran."}),I==="error"&&a.jsx("div",{style:{fontSize:12,color:"var(--clay-600)"},children:"Transkrip tak terbaca lagi di server."}),o!==null&&a.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:o})]})}function en({open:e,projectId:i,projectName:r,onClose:s,onCreated:o}){var O;const[c,I]=d.useState("claude"),[h,R]=d.useState("sonnet"),[g,x]=d.useState("medium"),[b,m]=d.useState({claude:{model:"sonnet",effort:"medium"},codex:{...kt}}),[y,T]=d.useState(!1),[C,f]=d.useState(null);d.useEffect(()=>{e&&(P.getSettings().then(w=>{const N={claude:{model:w.model,effort:w.effort},codex:{...kt,...w.codex??{}}},u=w.agent==="codex"?"codex":"claude",v=jt(N,u);m(N),I(u),R(v.model),x(v.effort)}).catch(()=>{}),P.getCodexVersion().then(w=>f(w.version)).catch(()=>{}))},[e]);const z=w=>{I(w);const N=jt(b,w);R(N.model),x(N.effort)},E=w=>{R(w),x(N=>c==="codex"?Ia(w,N):Ca(w,N))};async function D(){T(!0);try{const{id:w}=await P.createTerminal(i,{agent:c,model:h,effort:g});o(w),s()}catch{}finally{T(!1)}}return a.jsxs(Se,{open:e,onClose:s,icon:"plus",eyebrow:r,title:"Sesi baru",footer:a.jsxs(a.Fragment,{children:[a.jsx(K,{variant:"ghost",onClick:s,children:"Batal"}),a.jsx(K,{leftIcon:"play",disabled:y,onClick:()=>void D(),children:"Buka sesi"})]}),children:[a.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 — ",a.jsx("code",{children:"/model"})," di terminal tetap bisa mengubahnya."]}),a.jsx(Ue,{label:"Agen",hint:"Mesin yang menjalankan sesi ini. Perilaku sesi sama; hanya CLI-nya berbeda.",children:a.jsx(Z,{"aria-label":"Agen",value:c,style:{width:"100%"},options:[{value:"claude",label:"Claude Code"},{value:"codex",label:"Codex CLI"}],onChange:w=>z(w.target.value)})}),a.jsx(Ue,{label:"Model",children:a.jsx(Z,{"aria-label":"Model",value:h,style:{width:"100%"},options:ka(c,h),onChange:w=>E(w.target.value)})}),a.jsx(Ue,{label:"Effort",children:a.jsx(Z,{"aria-label":"Effort",value:g,style:{width:"100%"},options:ja(c,h).map(w=>({value:w,label:w})),onChange:w=>x(w.target.value)})}),c==="codex"&&wa(h,C)&&a.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 ",a.jsx("b",{children:C}),", sedangkan ",a.jsx("b",{children:h})," butuh ",a.jsx("b",{children:(O=Sa(h))==null?void 0:O.minClient}),". Sesi tetap boleh dijalankan, tapi modelnya belum tentu dikenali CLI ini."]})]})}const Ht=()=>({rows:1,cols:1,cells:[null]}),Gt=(e,i)=>[...e.slice(0,i),...e.slice(i+1)],Ct=e=>({...e,rows:e.rows+1,cells:[...e.cells,...Array(e.cols).fill(null)],...e.rowSizes?{rowSizes:[...e.rowSizes,1]}:{}});function zt(e){const i=e.cols+1,r=[];for(let s=0;s<e.rows;s++)for(let o=0;o<i;o++)r.push(o<e.cols?e.cells[s*e.cols+o]??null:null);return{...e,cols:i,cells:r,...e.colSizes?{colSizes:[...e.colSizes,1]}:{}}}function Rt(e,i){if(e.rows===1||i<0||i>=e.rows)return e;const r=[...e.cells];return r.splice(i*e.cols,e.cols),{...e,rows:e.rows-1,cells:r,...e.rowSizes?{rowSizes:Gt(e.rowSizes,i)}:{}}}function Tt(e,i){if(e.cols===1||i<0||i>=e.cols)return e;const r=e.cols-1,s=[];for(let o=0;o<e.rows;o++)for(let c=0;c<e.cols;c++)c!==i&&s.push(e.cells[o*e.cols+c]??null);return{...e,cols:r,cells:s,...e.colSizes?{colSizes:Gt(e.colSizes,i)}:{}}}const qt=.3,tn=(e,i,r)=>Math.min(r,Math.max(i,e));function st(e,i,r){if(i<0||i+1>=e.length||r===0)return e;const o=e.reduce((R,g)=>R+g,0)/e.length*qt,c=e[i]+e[i+1],I=tn(e[i]+r,o,c-o);if(I===e[i])return e;const h=[...e];return h[i]=I,h[i+1]=c-I,h}function Ut(e,i,r){const s=e.colSizes??Array(e.cols).fill(1),o=st(s,i,r);return o===s?e:{...e,colSizes:o}}function Yt(e,i,r){const s=e.rowSizes??Array(e.rows).fill(1),o=st(s,i,r);return o===s?e:{...e,rowSizes:o}}const an=.05,nn=.15,Vt=(e,i)=>e.reduce((r,s)=>r+s,0)*(i?nn:an);function rn(e,i,r,s=!1){const o=e.colSizes??Array(e.cols).fill(1);return Ut(e,i,r*Vt(o,s))}function sn(e,i,r,s=!1){const o=e.rowSizes??Array(e.rows).fill(1);return Yt(e,i,r*Vt(o,s))}function Et(e,i){const s=e.reduce((I,h)=>I+h,0)/e.length*qt,o=e[i]+e[i+1],c=Math.round(s/o*100);return{now:Math.round(e[i]/o*100),min:c,max:100-c}}function tt(e,i,r){if(i<0||i>=e.cells.length)return e;const s=e.cells.map(o=>r!==null&&o===r?null:o);return s[i]=r,{...e,cells:s}}const on=(e,i)=>({...e,cells:e.cells.map(r=>r&&i.has(r)?r:null)}),Xt=e=>({id:crypto.randomUUID(),name:e,layout:Ht()});function At(){const e=Xt("Utama");return{groups:[e],active:e.id}}const Ce=e=>e.groups.find(i=>i.id===e.active)??e.groups[0];function ln(e,i){const r=Xt(i);return{groups:[...e.groups,r],active:r.id}}const cn=(e,i,r)=>({...e,groups:e.groups.map(s=>s.id===i?{...s,name:r}:s)});function dn(e,i){if(e.groups.length===1)return e;const r=e.groups.filter(s=>s.id!==i);return r.length===e.groups.length?e:{groups:r,active:e.active===i?r[0].id:e.active}}const un=(e,i)=>e.groups.some(r=>r.id===i)?{...e,active:i}:e;function q(e,i){const r=Ce(e);return{...e,groups:e.groups.map(s=>s.id===r.id?{...s,layout:i(s.layout)}:s)}}function at(e,i,r){const s=Ce(e),o=r===null?e.groups:e.groups.map(c=>c.id===s.id?c:{...c,layout:tt(c.layout,c.layout.cells.indexOf(r),null)});return{...e,groups:o.map(c=>c.id===s.id?{...c,layout:tt(c.layout,i,r)}:c)}}function me(e,i){const r=Ce(e).layout.cells.indexOf(null);return r===-1?e:at(e,r,i)}const pn=(e,i)=>({...e,groups:e.groups.map(r=>({...r,layout:tt(r.layout,r.layout.cells.indexOf(i),null)}))}),Nt=e=>new Set(e.groups.flatMap(i=>i.layout.cells.filter(r=>r!==null))),Dt=(e,i)=>({...e,groups:e.groups.map(r=>({...r,layout:on(r.layout,i)}))}),Jt="hanoman.terminal.workspace",Qt="hanoman.terminal.layout",fe=e=>Ie.parse({version:1,groups:e.groups});function Le(e,i){const r=e.groups,s=i&&r.some(o=>o.id===i)?i:r[0].id;return{groups:r,active:s}}function mn(e){try{const i=JSON.parse(e);if(!i||typeof i!="object")return null;const r=i,s=Ie.parse({version:1,groups:r.groups});return{workspace:s,active:typeof r.active=="string"&&s.groups.some(o=>o.id===r.active)?r.active:s.groups[0].id}}catch{return null}}function fn(){try{const e=localStorage.getItem(Jt);if(e)return mn(e);const i=localStorage.getItem(Qt);if(!i)return null;const r=JSON.parse(i),s={id:crypto.randomUUID(),name:"Utama",layout:r};return{workspace:Ie.parse({version:1,groups:[s]}),active:s.id}}catch{return null}}function Xe(){try{localStorage.removeItem(Jt),localStorage.removeItem(Qt)}catch{}}const Zt=e=>`hanoman.terminal.workspace.v2.${encodeURIComponent(e)}`;function hn(e){try{const i=localStorage.getItem(Zt(e));if(!i)return null;const r=JSON.parse(i),s=Ie.parse(r.workspace);if(!Number.isInteger(r.revision)||(r.revision??-1)<0)return null;const o=typeof r.active=="string"&&s.groups.some(c=>c.id===r.active)?r.active:s.groups[0].id;return{workspace:s,revision:r.revision,active:o}}catch{return null}}function Je(e,i){try{const r=Ie.parse(i.workspace);if(!Number.isInteger(i.revision)||i.revision<0)return;const s=r.groups.some(o=>o.id===i.active)?i.active:r.groups[0].id;localStorage.setItem(Zt(e),JSON.stringify({workspace:r,revision:i.revision,active:s}))}catch{}}function Qe(e){if(!(e instanceof it)||e.status!==409)return null;const i=e.detail;if((i==null?void 0:i.code)!=="revision-conflict")return null;const r=za.safeParse(i.current);return r.success?r.data:null}function gn(e){const i=L.useRef(null);i.current||(i.current=At());const[r,s]=L.useState(i.current),[o,c]=L.useState("loading"),[I,h]=L.useState(null),[R,g]=L.useState(!1),x=L.useRef(r),b=L.useRef(0),m=L.useRef(!1),y=L.useRef(Promise.resolve()),T=L.useRef(0),C=L.useCallback(u=>{x.current=u,s(u)},[]),f=L.useCallback(u=>{m.current=u,g(u)},[]),z=L.useCallback(u=>{const v=y.current.then(u,u);return y.current=v.then(()=>{},()=>{}),v},[]),E=L.useCallback((u,v="ready",j=null,k=x.current.active)=>{const M=u.workspace?Le(u.workspace,k):At();b.current=u.revision,C(M),c(v),h(j),f(!0),u.workspace&&Je(e,{workspace:u.workspace,revision:u.revision,active:M.active})},[C,f,e]),D=L.useCallback(u=>{const v=hn(e);v&&(b.current=v.revision,C(Le(v.workspace,v.active))),f(!1),c("recovering"),h(u instanceof Error?u.message:"Layout server belum tersambung")},[C,f,e]),O=L.useCallback(()=>z(async()=>{try{E(await P.getTerminalWorkspace())}catch(u){D(u)}}),[E,z,D]);L.useEffect(()=>{const u=++T.current;return c("loading"),h(null),f(!1),z(async()=>{try{const v=await P.getTerminalWorkspace();if(u!==T.current)return;if(v.workspace){E(v),Xe();return}const j=fn();if(!j){E(v);return}try{const k=await P.putTerminalWorkspace({baseRevision:v.revision,workspace:j.workspace});if(u!==T.current)return;C(Le(k.workspace,j.active)),b.current=k.revision,Je(e,{workspace:k.workspace,revision:k.revision,active:j.active}),Xe(),c("ready"),h(null),f(!0)}catch(k){const M=Qe(k);M!=null&&M.workspace?(E(M,"conflict","Layout server lebih baru; layout lokal lama tidak diunggah"),Xe()):D(k)}}catch(v){u===T.current&&D(v)}}),()=>{T.current+=1}},[E,z,D,C,f,e]),L.useEffect(()=>{const u=()=>{O()},v=()=>{document.visibilityState==="visible"&&O()};return window.addEventListener("focus",u),document.addEventListener("visibilitychange",v),()=>{window.removeEventListener("focus",u),document.removeEventListener("visibilitychange",v)}},[O]);const w=L.useCallback(u=>z(async()=>{if(!m.current)return!1;const v=u(x.current);let j,k;try{j=fe(v),k=fe(x.current)}catch{return c("conflict"),h("Layout tidak valid dan tidak disimpan"),!1}if(Bt(j,k))return!0;try{return E(await P.putTerminalWorkspace({baseRevision:b.current,workspace:j}),"ready",null,v.active),!0}catch(M){const ee=Qe(M);if(!(ee!=null&&ee.workspace))return D(M),!1;const _=u(Le(ee.workspace,x.current.active));try{const U=await P.putTerminalWorkspace({baseRevision:ee.revision,workspace:fe(_)});return E(U,"conflict","Layout berubah di perangkat lain; perubahan ini diterapkan ulang",_.active),!0}catch(U){if(!Qe(U)&&!(U instanceof it&&U.status===409))return D(U),!1;try{E(await P.getTerminalWorkspace(),"conflict","Layout berubah lagi di perangkat lain; state terbaru dimuat")}catch(te){D(te)}return!1}}}),[E,z,D]),N=L.useCallback(u=>{const v=un(x.current,u);C(v);const j=fe(v);Je(e,{workspace:j,revision:b.current,active:v.active})},[C,e]);return{workspace:r,status:o,message:I,writable:R,mutate:w,setActive:N,refresh:O}}const xn=[];function Nn({userId:e="test-user",projects:i,backlog:r=xn,focusSession:s,startedSession:o,onStartedSessionHandled:c,onStartBacklog:I,onOpenReview:h,onOpenSessionReview:R,titleOf:g,onIntegrate:x,onIntegrateSession:b,specOf:m,sessions:y,setSessions:T}){var yt;const[C,f]=d.useState([]),z=y??C,E=T??f,[D,O]=d.useState([]),w=gn(e),{workspace:N,status:u,message:v,writable:j,mutate:k,setActive:M,refresh:ee}=w,[_,U]=ke("terminal","project",((yt=i[0])==null?void 0:yt.id)??"",Ka),te=Ot(),[le,ce]=ke("terminal","fontSize",te?Wa:_a,Ma),[Y,he]=ke("terminal","keys",te,Ve),[ae,ge]=ke("terminal","predict",!0,Ve),[J,ze]=ke("terminal","diag",!1,Ve),de=t=>ce(n=>Oa(n+t)),[B,Re]=d.useState(!1),[G,xe]=d.useState(null),[Te,ie]=d.useState(!1),[H,W]=d.useState(null),[Fe,be]=d.useState(!1),[Ee,Ae]=d.useState(!1),Be=Aa(),ot=Na(),ta=ot==="mobile",A=Ce(N).layout,Oe=A.rows===1&&A.cols===1&&!A.cells[0]&&z.length===0,Me=d.useRef(null),[aa,na]=d.useState(Number.POSITIVE_INFINITY);d.useEffect(()=>{const t=Me.current;if(!t||typeof ResizeObserver!="function")return;const n=new ResizeObserver(l=>{var S;const p=((S=l[0])==null?void 0:S.contentRect.width)??t.getBoundingClientRect().width;p>0&&na(p)});return n.observe(t),()=>n.disconnect()},[Oe]);const ia=ot==="tablet"&&Da(A.cols,aa,Ba),F=ta||ia,[Q,Ne]=d.useState(0),[ne,re]=d.useState(null),We=d.useRef(null),[ue,ra]=d.useState(!1);d.useEffect(()=>{P.listTerminals().then(t=>{E(t),ra(!0)}).catch(()=>{})},[]),d.useEffect(()=>$a(t=>{t.t==="sessions"&&!y?E(t.sessions):t.t==="cleanups"&&O(t.cleanups)}),[]),d.useEffect(()=>{if(!ue||!j)return;const t=new Set(z.map(l=>l.id)),n=Dt(N,t);Bt(fe(n),fe(N))||k(l=>Dt(l,t))},[k,z,ue,j,N]),d.useEffect(()=>{!o||o.specId==null||!ue||(E(t=>t.some(n=>n.id===o.id)?t:[...t,{...o,cwd:"",exited:!1}]),re(o.id),c==null||c())},[c,ue,o]),d.useEffect(()=>{if(!s){We.current=null;return}!ue||We.current===s||z.some(t=>t.id===s&&!t.exited)&&(We.current=s,re(s))},[s,z,ue]),d.useEffect(()=>{if(!ne)return;const t=N.groups.find(n=>n.layout.cells.includes(ne));if(t){t.id!==N.active&&M(t.id);return}j&&k(n=>{if(Nt(n).has(ne))return n;const l=me(n,ne);return l!==n||!F?l:at(n,Q,ne)})},[Q,F,k,ne,M,j,N]),d.useEffect(()=>{G&&!z.some(t=>t.id===G)&&xe(null)},[G,z]);const _e=D.filter(t=>t.error),De=t=>z.find(n=>n.id===t)??null,ve=d.useCallback(t=>{var n;return((n=i.find(l=>l.id===t))==null?void 0:n.name)??t},[i]);function sa(t){E(n=>n.some(l=>l.id===t)?n:[...n,{id:t,projectId:_,cwd:"",exited:!1}]),k(n=>me(n,t)),re(t)}async function lt(){if(!_)return;const{id:t}=await P.createShell(_);E(n=>[...n,{id:t,projectId:_,cwd:"",exited:!1}]),k(n=>me(n,t)),re(t)}async function ct(t,n){if(I&&!n){ie(!1),W(null),I(t);return}const l=Ga(t.source);try{const{id:p}=await P.startSession({spec:t.id,flow:l,...n?{force:n}:{}});E(S=>S.some($=>$.id===p)?S:[...S,{id:p,projectId:t.projectId,specId:t.id,flow:l,cwd:"",exited:!1}]),k(S=>me(S,p)),re(p),ie(!1),W(null)}catch(p){if(Be.offerRetry(p,t.id,$=>ct(t,$)))return;const S=p instanceof it&&(p.status===400||p.status===422);W(`${t.id} · gagal mulai${S?" · project belum punya repoDir":""}`)}}async function dt(t,n){try{const l=t.specId?await P.startSession({spec:t.specId,flow:t.flow??"feature",agent:t.agent==="codex"?"codex":"claude",...t.model?{model:t.model}:{},...t.effort?{effort:t.effort}:{},...n?{force:n}:{}}):t.kind==="shell"?await P.createShell(t.projectId):t.kind==="terminal"?await P.createTerminal(t.projectId,{agent:t.agent==="codex"?"codex":"claude",...t.model?{model:t.model}:{},...t.effort?{effort:t.effort}:{}}):await(n?P.createTerminalFlow(t.projectId,t.kind,{force:n}):P.createTerminalFlow(t.projectId,t.kind));E(p=>p.some(S=>S.id===l.id)?p:[...p,{id:l.id,projectId:t.projectId,specId:t.specId??void 0,cwd:"",exited:!1}]),k(p=>me(p,l.id)),re(l.id),Ae(!1)}catch(l){if((t.specId||t.kind!=="shell"&&t.kind!=="terminal")&&Be.offerRetry(l,`${t.projectId} · ${t.title??t.specId??t.kind}`,p=>dt(t,p)))return}}const ut=new Set(z.filter(t=>t.specId&&!t.exited).map(t=>t.specId)),oa=r.filter(t=>t.stage!=="done"&&!ut.has(t.id));function pt(t){E(n=>n.filter(l=>l.id!==t)),P.deleteTerminal(t).catch(()=>{})}const la=d.useCallback((t,n)=>{E(l=>l.map(p=>p.id===t?{...p,exited:!0,exitCode:n}:p))},[]),mt={close:pt,detach:t=>{k(n=>pn(n,t))},markExited:la,setFullId:xe,props:{onOpenReview:h,onOpenSessionReview:R,titleOf:g,onIntegrate:x,onIntegrateSession:b,specOf:m}},V=d.useRef(mt);V.current=mt;const ft=d.useRef(new Map),ca=t=>{let n=ft.current.get(t);return n||(n={onClose:()=>void V.current.close(t),onDetach:()=>V.current.detach(t),onExit:l=>V.current.markExited(t,l),onFullscreen:()=>V.current.setFullId(t)},ft.current.set(t,n)),n},pe=d.useRef({onOpenReview:t=>{var n,l;return(l=(n=V.current.props).onOpenReview)==null?void 0:l.call(n,t)},onOpenSessionReview:(t,n)=>{var l,p;return(p=(l=V.current.props).onOpenSessionReview)==null?void 0:p.call(l,t,n)},titleOf:t=>{var n,l;return(l=(n=V.current.props).titleOf)==null?void 0:l.call(n,t)},onIntegrate:(t,n,l)=>{var p,S;return(S=(p=V.current.props).onIntegrate)==null?void 0:S.call(p,t,n,l)},onIntegrateSession:(t,n,l)=>{var p,S;return(S=(p=V.current.props).onIntegrateSession)==null?void 0:S.call(p,t,n,l)},specOf:t=>{var n,l;return(l=(n=V.current.props).specOf)==null?void 0:l.call(n,t)}}).current,da=(t,n)=>{Ne(t),k(l=>at(l,t,n))},ua=t=>{re(t),k(n=>me(n,t))},pa=Nt(N),Ke=z.filter(t=>!pa.has(t.id));d.useEffect(()=>{if(!ne)return;const t=A.cells.indexOf(ne);t<0||(Ne(t),re(null))},[A.cells,ne]),d.useEffect(()=>{Q>=A.cells.length&&Ne(Math.max(0,A.cells.length-1))},[Q,A.cells.length]);const $e=d.useRef(null),[se,He]=d.useState(null),Ge=(se==null?void 0:se.axis)==="col"?se.sizes:A.colSizes??Array(A.cols).fill(1),qe=(se==null?void 0:se.axis)==="row"?se.sizes:A.rowSizes??Array(A.rows).fill(1);function ht(t,n,l){var $,X,ye;if(!j)return;const p=($=Me.current)==null?void 0:$.getBoundingClientRect();if(!p)return;(ye=(X=l.currentTarget).setPointerCapture)==null||ye.call(X,l.pointerId);const S=t==="col"?Ge:qe;$e.current={axis:t,index:n,pointerId:l.pointerId,start:t==="col"?l.clientX:l.clientY,extent:t==="col"?p.width:p.height,startSizes:S,latest:S},He({axis:t,sizes:S})}function gt(t){const n=$e.current;if(!n||n.pointerId!==t.pointerId)return;const l=n.axis==="col"?t.clientX:t.clientY,p=n.startSizes.reduce(($,X)=>$+X,0),S=(l-n.start)/n.extent*p;n.latest=st(n.startSizes,n.index,S),He({axis:n.axis,sizes:n.latest})}function xt(t){var l,p;const n=$e.current;!n||n.pointerId!==t.pointerId||($e.current=null,(p=(l=t.currentTarget).releasePointerCapture)==null||p.call(l,t.pointerId),He(null),n.latest!==n.startSizes&&k(S=>q(S,$=>n.axis==="col"?{...$,colSizes:n.latest}:{...$,rowSizes:n.latest})))}function bt(t,n,l){if(!j)return;const p=t==="col"?"ArrowRight":"ArrowDown",S=t==="col"?"ArrowLeft":"ArrowUp",$=l.key===p?1:l.key===S?-1:0;$!==0&&(l.preventDefault(),k(X=>q(X,ye=>t==="col"?rn(ye,n,$,l.shiftKey):sn(ye,n,$,l.shiftKey))))}function vt(t,n){j&&k(l=>q(l,p=>{const S=t==="col"?p.colSizes??Array(p.cols).fill(1):p.rowSizes??Array(p.rows).fill(1),X=(S[n]+S[n+1])/2-S[n];return t==="col"?Ut(p,n,X):Yt(p,n,X)}))}const ma=a.jsxs("div",{style:{display:"flex",flexDirection:"column",gap:10,marginBottom:10},children:[a.jsxs("div",{className:"hn-dense-row",style:{display:"flex",alignItems:"center",gap:8},children:[a.jsx("span",{style:{flex:1,minWidth:0,fontSize:12,color:"var(--text-muted)"},children:"Ukuran teks terminal"}),a.jsx(Ye,{size:"sm",icon:"minus",label:"Perkecil teks terminal",disabled:le<=Pa,onClick:()=>de(-1)}),a.jsxs("span",{style:{fontFamily:"var(--font-mono)",fontSize:12,minWidth:44,textAlign:"center"},children:[le,"px"]}),a.jsx(Ye,{size:"sm",icon:"plus",label:"Perbesar teks terminal",disabled:le>=La,onClick:()=>de(1)})]}),a.jsxs("div",{className:"hn-dense-row",style:{display:"flex",alignItems:"center",gap:8},children:[a.jsx("span",{style:{flex:1,minWidth:0,fontSize:12,color:"var(--text-muted)"},children:"Papan tombol layar (Esc · panah · Enter)"}),a.jsx(K,{size:"sm",variant:"secondary","aria-pressed":Y,onClick:()=>he(t=>!t),children:Y?"Sembunyikan":"Tampilkan"})]}),a.jsxs("div",{className:"hn-dense-row",style:{display:"flex",alignItems:"center",gap:8},children:[a.jsx("span",{style:{flex:1,minWidth:0,fontSize:12,color:"var(--text-muted)"},children:"Ketik responsif (huruf tampil sebelum echo server)"}),a.jsx(K,{size:"sm",variant:"secondary","aria-pressed":ae,"aria-label":`${ae?"Matikan":"Nyalakan"} ketik responsif`,onClick:()=>ge(t=>!t),children:ae?"Matikan":"Nyalakan"})]}),a.jsxs("div",{className:"hn-dense-row",style:{display:"flex",alignItems:"center",gap:8},children:[a.jsx("span",{style:{flex:1,minWidth:0,fontSize:12,color:"var(--text-muted)"},children:"Rekam jalur ketik (diagnostik — merekam setiap tombol)"}),a.jsx(K,{size:"sm",variant:"secondary","aria-pressed":J,"aria-label":`${J?"Matikan":"Nyalakan"} rekam jalur ketik`,onClick:()=>ze(t=>!t),children:J?"Matikan":"Nyalakan"})]}),a.jsxs("div",{className:"hn-dense-row",style:{display:"flex",alignItems:"center",gap:8},children:[a.jsx("span",{id:"terminal-reset-grid-hint",style:{flex:1,minWidth:0,fontSize:12,color:"var(--text-muted)"},children:'Kembalikan grid ke 1 kolom × 1 baris (sesi lain pindah ke "belum di grid")'}),a.jsx(K,{size:"sm",variant:"secondary","aria-describedby":"terminal-reset-grid-hint",disabled:!j||A.cols===1&&A.rows===1,onClick:()=>void k(t=>q(t,()=>Ht())),children:"Reset grid"})]}),F&&a.jsx(Z,{size:"sm","aria-label":"Project sesi baru",value:_,onChange:t=>U(t.target.value),options:i.map(t=>({value:t.id,label:t.name}))})]}),fa=[{key:"backlog",label:"Ambil backlog",icon:"inbox",onSelect:()=>{W(null),ie(!0)}},{key:"history",label:"Riwayat sesi",icon:"history",onSelect:()=>Ae(!0)},{key:"shell",label:"Terminal biasa",icon:"terminal",onSelect:()=>void lt()},{key:"col+",label:"+ Kolom",icon:"columns-2",disabled:!j,onSelect:()=>void k(t=>q(t,zt))},{key:"row+",label:"+ Baris",icon:"rows-2",disabled:!j,onSelect:()=>void k(t=>q(t,Ct))},{key:"col-",label:"Hapus kolom aktif",icon:"columns-2",disabled:!j||A.cols===1,onSelect:()=>void k(t=>q(t,n=>Tt(n,Q%n.cols)))},{key:"row-",label:"Hapus baris aktif",icon:"rows-2",disabled:!j||A.rows===1,onSelect:()=>void k(t=>q(t,n=>Rt(n,Math.floor(Q/n.cols))))}],ha={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 a.jsxs("div",{"data-testid":"terminal-root",style:ha,children:[a.jsxs("div",{style:{display:"flex",gap:8,flexDirection:B?"row":"column",alignItems:B?"center":"stretch"},children:[a.jsx(vn,{compact:B,ws:N,writable:j,onSelect:M,onAdd:()=>void k(t=>ln(t,`Grup ${t.groups.length+1}`)),onRename:(t,n)=>void k(l=>cn(l,t,n)),onRemove:t=>void k(n=>dn(n,t))}),a.jsxs("div",{style:{display:"flex",alignItems:"center",gap:8,flexWrap:"wrap",...B?{flex:1,minWidth:0}:{}},children:[!F&&a.jsxs(a.Fragment,{children:[a.jsx(K,{size:"sm",variant:"ghost",disabled:!j,onClick:()=>void k(t=>q(t,zt)),children:"+ Kolom"}),a.jsx(K,{size:"sm",variant:"ghost",disabled:!j,onClick:()=>void k(t=>q(t,Ct)),children:"+ Baris"})]}),a.jsx("div",{style:{flex:1,minWidth:0}}),u!=="ready"&&a.jsx("span",{"data-testid":"terminal-workspace-status",title:v??void 0,style:{fontSize:12,color:u==="conflict"?"var(--status-warn)":"var(--text-muted)"},children:u==="loading"?"Memuat layout server…":u==="recovering"?a.jsxs(a.Fragment,{children:[a.jsx("span",{children:"Layout server belum tersambung"})," ",a.jsx("button",{type:"button",onClick:()=>void ee(),children:"Retry"})]}):v??"Layout berubah di perangkat lain"}),D.length>0&&a.jsx("span",{"data-testid":"worktree-cleanups",title:D.map(t=>`${t.sessionId}${t.error?` — ${t.error}`:""}`).join(`
|
|
2
|
+
`),style:{fontSize:12,color:_e.length?"var(--status-err)":"var(--text-muted)"},children:_e.length?`${_e.length} worktree gagal dibersihkan`:`membersihkan ${D.length} worktree…`}),!F&&a.jsxs(a.Fragment,{children:[a.jsx(Z,{size:"sm",value:_,onChange:t=>U(t.target.value),options:i.map(t=>({value:t.id,label:t.name}))}),a.jsx(K,{size:"sm",variant:"secondary",leftIcon:"inbox",onClick:()=>{W(null),ie(!0)},children:"Ambil backlog"}),a.jsx(K,{size:"sm",variant:"secondary",leftIcon:"history",title:"Riwayat sesi yang sudah berlalu — buka kembali atau baca transkripnya",onClick:()=>Ae(!0),children:"Riwayat"}),a.jsx(K,{size:"sm",variant:"secondary",leftIcon:"terminal",title:"Buka shell tmux tanpa Claude di project terpilih — jalankan command di project",onClick:()=>void lt(),children:"Terminal biasa"})]}),a.jsx(K,{size:"sm",leftIcon:"plus",onClick:()=>be(!0),children:"Sesi baru"}),a.jsx(Mt,{label:F?"Aksi terminal lain":"Tampilan terminal",items:F?fa:[],children:ma}),a.jsx(Ye,{size:"sm",icon:B?"minimize-2":"maximize-2",label:B?"Keluar layar penuh":"Layar penuh","aria-pressed":B,onClick:()=>Re(t=>!t)})]})]}),Ke.length>0&&a.jsxs("div",{style:{display:"flex",gap:6,flexWrap:"wrap",alignItems:"center"},children:[a.jsx("span",{style:{fontSize:11,color:"var(--text-subtle)"},children:"Belum di grid:"}),Ke.map(t=>a.jsxs("span",{className:"hn-terminal-unplaced-chip",style:{display:"inline-flex",alignItems:"center",borderRadius:"var(--radius-sm)",background:"var(--bone-200)",border:"1px solid var(--border-hair)",fontFamily:"var(--font-mono)",fontSize:11},children:[a.jsxs("button",{className:"hn-terminal-unplaced-action",disabled:!j,onClick:()=>ua(t.id),title:"Taruh di sel kosong pertama grup ini",style:{all:"unset",cursor:"pointer"},children:[t.specId??ve(t.projectId)," · ",t.id.slice(0,6)]}),a.jsx("button",{type:"button",className:"hn-terminal-action","aria-label":`Tutup sesi ${t.id}`,onClick:()=>void pt(t.id),children:"×"})]},t.id))]}),F&&!Oe&&a.jsx("div",{className:"hn-stack-mobile",style:{display:"flex",alignItems:"center",gap:8},children:a.jsx(Fa,{"aria-label":"Panel terminal",variant:"pill",value:String(Q),onChange:t=>Ne(Number(t)),tabs:A.cells.map((t,n)=>({value:String(n),label:`Panel ${n+1}${t?` · ${t.slice(0,6)}`:" · kosong"}`}))})}),Oe?a.jsx(nt,{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."}):a.jsxs("div",{ref:Me,"data-testid":"terminal-grid",style:{flex:1,minHeight:0,display:"grid",gap:8,gridTemplateColumns:F?"minmax(0, 1fr)":`18px ${Ge.map(t=>`minmax(0, ${t}fr)`).join(" ")}`,gridTemplateRows:F?"minmax(0, 1fr)":`16px ${qe.map(t=>`minmax(0, ${t}fr)`).join(" ")}`},children:[!F&&a.jsx("div",{style:{gridColumn:1,gridRow:1}}),!F&&Array.from({length:A.cols},(t,n)=>a.jsx($t,{axis:"col",label:`Tutup kolom ${n+1}`,disabled:!j||A.cols===1,style:{gridColumn:n+2,gridRow:1},onClick:()=>void k(l=>q(l,p=>Tt(p,n)))},`col-${n}`)),!F&&Array.from({length:A.rows},(t,n)=>a.jsx($t,{axis:"row",label:`Tutup baris ${n+1}`,disabled:!j||A.rows===1,style:{gridColumn:1,gridRow:n+2},onClick:()=>void k(l=>q(l,p=>Rt(p,n)))},`row-${n}`)),!F&&Array.from({length:A.cols-1},(t,n)=>{const l=Et(Ge,n);return a.jsx(Pt,{orientation:"col",label:`Ubah lebar kolom ${n+1}/${n+2}`,now:l.now,min:l.min,max:l.max,disabled:!j,gridColumn:n+3,gridRow:"1 / -1",onPointerDown:p=>ht("col",n,p),onPointerMove:gt,onPointerUp:xt,onKeyDown:p=>bt("col",n,p),onDoubleClick:()=>vt("col",n)},`col-div-${n}`)}),!F&&Array.from({length:A.rows-1},(t,n)=>{const l=Et(qe,n);return a.jsx(Pt,{orientation:"row",label:`Ubah tinggi baris ${n+1}/${n+2}`,now:l.now,min:l.min,max:l.max,disabled:!j,gridColumn:"1 / -1",gridRow:n+3,onPointerDown:p=>ht("row",n,p),onPointerMove:gt,onPointerUp:xt,onKeyDown:p=>bt("row",n,p),onDoubleClick:()=>vt("row",n)},`row-div-${n}`)}),Array.from({length:A.rows},(t,n)=>n).flatMap(t=>Array.from({length:A.cols},(n,l)=>{const p=t*A.cols+l,S=A.cells[p]??null,$=S?De(S):null;return a.jsx("div",{"data-terminal-cell-index":p,"aria-hidden":F&&Q!==p?"true":"false",style:{minHeight:0,minWidth:0,display:F&&Q!==p?"none":"flex",flexDirection:"column",border:"1px solid var(--border-hair)",borderRadius:"var(--radius-sm)",overflow:"hidden",...F?{}:{gridColumn:l+2,gridRow:t+2}},children:$?a.jsx(Sn,{session:$,nameOf:ve,...ca($.id),canArrange:j,onReview:h&&pe.onOpenReview,onSessionReview:R&&pe.onOpenSessionReview,titleOf:g&&pe.titleOf,onIntegrate:x&&pe.onIntegrate,onIntegrateSession:b&&pe.onIntegrateSession,specOf:m&&pe.specOf,backlog:r,fontSize:le,showKeys:Y,predict:ae,diag:J,fullscreen:G===$.id,paneHidden:F&&Q!==p}):a.jsx(zn,{disabled:!j,unplaced:Ke,nameOf:ve,onPick:X=>da(p,X)})},S??`empty-${p}`)}))]}),Te&&a.jsx(bn,{seed:oa,activeIds:ut,error:H,onPick:t=>void ct(t),onClose:()=>ie(!1)}),Fe&&a.jsx(en,{open:!0,projectId:_,projectName:ve(_),onClose:()=>be(!1),onCreated:sa}),Ee&&a.jsx(Qa,{projects:i,onClose:()=>Ae(!1),onRestart:t=>void dt(t)}),Be.dialog,G&&De(G)&&a.jsx(Cn,{session:De(G),label:ea(De(G),ve,g),fontSize:le,showKeys:Y,predict:ae,diag:J,onClose:()=>xe(null)})]})}function ea(e,i,r){const s=i(e.projectId),o=e.specId?r==null?void 0:r(e.specId):void 0;return e.specId?`${s} · ${e.specId}${o?` · ${o}`:""}`:e.id.startsWith("xaudit-")?`${s} · audit lintas`:s}function bn({seed:e,activeIds:i,error:r,onPick:s,onClose:o}){const[c,I]=d.useState(""),[h,R]=d.useState("all"),[g,x]=d.useState("all"),[b,m]=d.useState(e),[y,T]=d.useState("");d.useEffect(()=>{const f=setTimeout(()=>T(c.trim()),250);return()=>clearTimeout(f)},[c]),d.useEffect(()=>{var E,D;let f=!0;const z=(D=(E=P).listSpecs)==null?void 0:D.call(E,{startable:!0,q:y||void 0,stage:h==="all"?void 0:h,priority:g==="all"?void 0:g});return z==null||z.then(O=>{f&&m(O.items)}).catch(()=>{}),()=>{f=!1}},[y,h,g]);const C=b.filter(f=>!i.has(f.id));return a.jsxs(Se,{open:!0,title:"Ambil backlog",icon:"inbox",onClose:o,width:760,children:[r&&a.jsx("div",{style:{marginBottom:10,padding:"8px 10px",borderRadius:"var(--radius-sm)",background:"var(--clay-100)",color:"var(--clay-600)",fontSize:12},children:r}),a.jsxs("div",{style:{display:"flex",alignItems:"center",gap:10,flexWrap:"wrap",marginBottom:10},children:[a.jsx(Lt,{size:"sm",leftIcon:"search",placeholder:"mis. invoice atau SPEC-412","aria-label":"Cari backlog",value:c,onChange:f=>I(f.target.value),style:{flex:"1 1 220px"}}),a.jsx(Z,{size:"sm","aria-label":"Filter stage",value:h,onChange:f=>R(f.target.value),options:[{value:"all",label:"Semua stage"}].concat(Ha.filter(f=>f.key!=="done").map(f=>({value:f.key,label:f.label})))}),a.jsx(Z,{size:"sm","aria-label":"Filter prioritas",value:g,onChange:f=>x(f.target.value),options:[{value:"all",label:"Semua prioritas"},{value:"tinggi",label:"Tinggi"},{value:"sedang",label:"Sedang"},{value:"rendah",label:"Rendah"}]})]}),C.length===0?a.jsx(nt,{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."}):a.jsx("div",{style:{display:"flex",flexDirection:"column",maxHeight:"62vh",overflowY:"auto"},children:C.map(f=>a.jsx("button",{onClick:()=>s(f),style:{cursor:"pointer",display:"block",width:"100%",flex:"0 0 auto",font:"inherit",color:"inherit",textAlign:"left",background:"transparent",padding:"9px 8px",border:"none",borderBottom:"1px solid var(--border-hair)"},children:a.jsxs("span",{className:"hn-dense-row hn-picker-row",style:{display:"flex",alignItems:"center",gap:10,width:"100%"},children:[a.jsx(oe,{name:f.source==="qa"?"bug":f.source==="audit"?"search":"lightbulb",size:14,color:f.source==="qa"?"var(--clay-500)":f.source==="audit"?"var(--wind-600)":"var(--brass-500)"}),a.jsx("span",{style:{fontFamily:"var(--font-mono)",fontSize:12,color:"var(--text-subtle)",flex:"0 0 78px"},children:f.id}),a.jsx("span",{className:"hn-picker-title",style:{flex:1,minWidth:0,fontSize:13,color:"var(--text-strong)",overflow:"hidden",textOverflow:"ellipsis",whiteSpace:"nowrap"},children:f.title}),a.jsx(Ze,{tone:f.priority==="tinggi"?"err":"neutral",size:"sm",children:f.priority}),a.jsx("span",{style:{fontFamily:"var(--font-mono)",fontSize:11,flex:"0 1 auto",minWidth:0,overflow:"hidden",textOverflow:"ellipsis",whiteSpace:"nowrap",color:"var(--text-muted)"},children:f.projectId})]})},f.id))})]})}function vn({ws:e,compact:i=!1,writable:r,onSelect:s,onAdd:o,onRename:c,onRemove:I}){const[h,R]=d.useState(null),g=Ce(e),x=e.groups.length===1;return a.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,m)=>{const y=b.id===g.id;return h===b.id?a.jsx(yn,{initial:b.name,onCommit:T=>{T.trim()&&c(b.id,T.trim()),R(null)},onCancel:()=>R(null)},b.id):a.jsxs("span",{style:{display:"inline-flex",alignItems:"center",gap:4,padding:"3px 6px",borderRadius:"var(--radius-sm)",fontSize:12,background:y?"var(--bone-200)":"transparent",border:`1px solid ${y?"var(--border-hair)":"transparent"}`},children:[a.jsx("button",{className:"hn-terminal-group-control",role:"tab","aria-selected":y,tabIndex:y?0:-1,onClick:()=>s(b.id),onKeyDown:T=>{var f,z;let C=null;T.key==="ArrowRight"?C=(m+1)%e.groups.length:T.key==="ArrowLeft"?C=(m-1+e.groups.length)%e.groups.length:T.key==="Home"?C=0:T.key==="End"&&(C=e.groups.length-1),C!==null&&(T.preventDefault(),s(e.groups[C].id),(z=(f=T.currentTarget.closest('[role="tablist"]'))==null?void 0:f.querySelectorAll('[role="tab"]')[C])==null||z.focus())},style:{border:0,padding:0,background:"transparent",font:"inherit",cursor:"pointer",color:y?"var(--text-strong)":"var(--text-muted)"},children:b.name}),y&&r&&a.jsxs(a.Fragment,{children:[a.jsx("button",{className:"hn-terminal-group-control","aria-label":`Ganti nama grup ${b.name}`,title:"Ganti nama",onClick:()=>R(b.id),style:{border:0,padding:0,background:"transparent",cursor:"pointer",color:"var(--text-subtle)",fontSize:10},children:"✎"}),a.jsx("button",{className:"hn-terminal-group-control","aria-label":`Hapus grup ${b.name}`,title:x?"Grup terakhir tak bisa dihapus":"Hapus grup (sesi tetap hidup)",disabled:x,onClick:()=>I(b.id),style:{border:0,padding:0,background:"transparent",cursor:x?"not-allowed":"pointer",color:"var(--text-subtle)",opacity:x?.35:1},children:"×"})]})]},b.id)}),a.jsx("button",{className:"hn-terminal-group-control","aria-label":"Grup baru",title:"Grup baru",disabled:!r,onClick:o,style:{border:0,background:"transparent",cursor:"pointer",padding:"3px 8px",color:"var(--text-subtle)",fontSize:12},children:"+"})]})}function $t({label:e,disabled:i,onClick:r,axis:s,style:o}){return a.jsx("button",{type:"button","aria-label":e,title:i?"Grid tak boleh menyusut ke nol":e,disabled:i,onClick:r,className:`hn-terminal-gutter hn-terminal-gutter--${s}`,style:{position:"relative",display:"grid",placeItems:"center",fontSize:11,lineHeight:1,opacity:i?.3:1,cursor:i?"not-allowed":"pointer",...o},children:"×"})}function Pt({orientation:e,label:i,now:r,min:s,max:o,disabled:c,gridColumn:I,gridRow:h,onPointerDown:R,onPointerMove:g,onPointerUp:x,onKeyDown:b,onDoubleClick:m}){return a.jsx("div",{role:"separator","aria-label":i,"aria-disabled":c,"aria-orientation":e==="col"?"vertical":"horizontal","aria-valuenow":r,"aria-valuemin":s,"aria-valuemax":o,tabIndex:c?-1:0,className:`hn-terminal-divider hn-terminal-divider--${e}`,title:c?void 0:"Seret untuk ubah ukuran — panah untuk langkah kecil, Shift+panah langkah besar, klik dua kali menyamakan",style:{gridColumn:I,gridRow:h},onPointerDown:c?void 0:R,onPointerMove:c?void 0:g,onPointerUp:c?void 0:x,onPointerCancel:c?void 0:x,onKeyDown:c?void 0:b,onDoubleClick:c?void 0:m})}function yn({initial:e,onCommit:i,onCancel:r}){const[s,o]=d.useState(e);return a.jsx("input",{autoFocus:!0,"aria-label":"Nama grup",value:s,placeholder:"mis. Rilis",onChange:c=>o(c.target.value),onBlur:()=>i(s),onKeyDown:c=>{c.key==="Enter"?i(s):c.key==="Escape"&&r()},style:{width:"min(160px, 60vw)",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 kn={done:"var(--brass)",active:"var(--text-strong)",skipped:"var(--text-subtle)",pending:"var(--text-subtle)"},jn={done:"✓",running:"●",pending:"○",skipped:"–",failed:"✕",abandoned:"⨯"};function wn({phases:e,compact:i=!1,now:r}){const[s,o]=d.useState(null),c=Ra(s!==null,()=>o(null),"dialog"),[,I]=d.useState(0),h=!!(e!=null&&e.some(m=>{var y;return((y=m.agent)==null?void 0:y.status)==="running"}));if(d.useEffect(()=>{if(!(!h||r!==void 0))return Va(()=>I(m=>m+1))},[h,r]),!(e!=null&&e.length))return null;const R=r??Date.now(),g=e.find(m=>m.name===s&&m.agent),x=m=>({color:kn[m.state],fontWeight:m.state==="active"?600:400,textDecoration:m.state==="skipped"?"line-through":"none",opacity:m.state==="pending"?.5:1}),b=m=>{const y=m.agent;return y?typeof y.durationMs=="number"?wt(y.durationMs):y.status==="running"&&y.startedAt?wt(R-Date.parse(y.startedAt)):"":""};return a.jsxs("div",{"data-testid":"phase-strip",style:{flex:"0 0 auto",borderBottom:"1px solid var(--border-hair)"},children:[a.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(m=>{if(!m.agent)return a.jsx("span",{"data-state":m.state,title:m.state,style:x(m),children:m.name},m.name);const y=m.agent,T=Ta(m),C=!i||m.state==="active",f=b(m);return a.jsxs("button",{type:"button","data-tone":T,"aria-expanded":s===m.name,ref:s===m.name?c.triggerRef:void 0,"aria-haspopup":"dialog","aria-controls":s===m.name?c.panelId:void 0,"aria-label":Ea(m,f),onClick:()=>o(s===m.name?null:m.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:[a.jsx("span",{"aria-hidden":!0,children:jn[T]}),a.jsx("span",{"data-state":m.state,title:m.state,style:x(m),children:m.name}),m.state==="skipped"&&a.jsx("span",{children:"dilewati"}),C&&y.model&&a.jsxs("span",{children:["· ",et(y.model)]}),C&&y.effort&&a.jsxs("span",{children:["· ",y.effort]}),C&&f&&a.jsxs("span",{children:["· ",f]}),y.attempts>1&&a.jsxs("span",{children:["↻",y.attempts]}),y.evidence==="missing"&&a.jsx("span",{role:"img","aria-label":"bukti subagent tak diterima",title:"bukti subagent tak diterima",style:{color:"var(--status-warn)"},children:"⚠"})]},m.name)})}),(g==null?void 0:g.agent)&&a.jsxs("div",{ref:c.panelRef,id:c.panelId,role:"dialog","aria-label":`Detail fase ${g.name}`,tabIndex:-1,onKeyDown:c.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:[a.jsx("div",{children:a.jsx("b",{children:g.agent.name})}),a.jsx("div",{children:[et(g.agent.model),g.agent.effort,g.agent.status??"belum mulai"].filter(Boolean).join(" · ")}),a.jsxs("div",{children:["durasi ",b(g)||"—"," · percobaan ",g.agent.attempts]}),a.jsxs("div",{children:["token in ",g.agent.inputTokens??"—"," · out ",g.agent.outputTokens??"—"," · cache ",g.agent.cachedTokens??"—"]}),g.agent.resultExcerpt&&a.jsx("pre",{style:{margin:"6px 0 0",whiteSpace:"pre-wrap",maxHeight:160,overflow:"auto"},children:g.agent.resultExcerpt})]})]})}const Sn=d.memo(In);function In({session:e,nameOf:i,onClose:r,canArrange:s,onDetach:o,onExit:c,onReview:I,onSessionReview:h,titleOf:R,onIntegrate:g,onIntegrateSession:x,specOf:b,fontSize:m,showKeys:y,predict:T,diag:C,fullscreen:f,onFullscreen:z,paneHidden:E}){const[D,O]=d.useState(null),w=d.useRef(null),[N,u]=d.useState(Number.POSITIVE_INFINITY),v=Ot();d.useEffect(()=>{const H=w.current;if(!H||typeof ResizeObserver!="function")return;const W=new ResizeObserver(Fe=>{var Ee;const be=((Ee=Fe[0])==null?void 0:Ee.contentRect.width)??H.getBoundingClientRect().width;be>0&&u(be)});return W.observe(H),()=>W.disconnect()},[]);const[j,k]=d.useState(!1),M=d.useCallback((H,W)=>{O(H),k(W)},[]),[ee,_]=d.useState(!1),[U,te]=d.useState(!1),[le,ce]=d.useState(!1),Y=e.specId?b==null?void 0:b(e.specId):void 0,he=!e.specId&&!!e.branch,ae=ea(e,i,R),ge=!e.exited&&!!e.decision,J=!e.exited&&!!e.deciding,ze=ge||J,de=e.exited&&!!e.exitCode,B=!e.exited&&j,Re=de?null:e.exited||B?"PST-005":ze?"PST-004":"PST-003",G=[...e.specId?[{key:"docs",label:"Lihat dokumen",icon:"file-text",title:"Lihat dokumen (audit/spec/plan)",onSelect:()=>_(!0),render:a.jsx("button",{type:"button",className:"hn-terminal-action",onClick:()=>_(!0),"aria-label":`Lihat dokumen sesi ${e.id}`,title:"Lihat dokumen (audit/spec/plan)",children:a.jsx(oe,{name:"file-text",size:12})},"docs")}]:[],...e.specId&&I?[{key:"review",label:"Review perubahan",icon:"git-compare",title:"Review perubahan (diff worktree)",onSelect:()=>I(e.specId),render:a.jsx("button",{type:"button",className:"hn-terminal-action",onClick:()=>I(e.specId),"aria-label":`Review sesi ${e.id}`,title:"Review perubahan (diff worktree)",children:a.jsx(oe,{name:"git-compare",size:12})},"review")}]:[],...he&&h?[{key:"review-session",label:"Review perubahan",icon:"git-compare",title:"Review perubahan (diff worktree sesi)",onSelect:()=>h(e.id,ae),render:a.jsx("button",{type:"button",className:"hn-terminal-action",onClick:()=>h(e.id,ae),"aria-label":`Review sesi ${e.id}`,title:"Review perubahan (diff worktree sesi)",children:a.jsx(oe,{name:"git-compare",size:12})},"review-session")}]:[],...Y&&g?[{key:"integrate",label:"Rebase / Merge branch",icon:"git-merge",title:"Rebase / Merge branch spec",onSelect:()=>te(!0),render:a.jsx("button",{type:"button",className:"hn-terminal-action",onClick:()=>te(!0),"aria-label":`Integrasikan sesi ${e.id}`,title:"Rebase / Merge branch spec",children:a.jsx(oe,{name:"git-merge",size:12})},"integrate")}]:[],...he&&x?[{key:"integrate-session",label:"Rebase / Merge branch",icon:"git-merge",title:"Rebase / Merge branch sesi",onSelect:()=>ce(!0),render:a.jsx("button",{type:"button",className:"hn-terminal-action",onClick:()=>ce(!0),"aria-label":`Integrasikan sesi ${e.id}`,title:"Rebase / Merge branch sesi",children:a.jsx(oe,{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:o,render:a.jsx("button",{type:"button",className:"hn-terminal-action hn-terminal-action--text",onClick:o,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:z,render:a.jsx("button",{type:"button",className:"hn-terminal-action",onClick:z,title:"Layar penuh — fokus 1 terminal","aria-label":`Layar penuh sesi ${e.id}`,children:a.jsx(oe,{name:"fullscreen",size:12})},"fullscreen")},{key:"close",label:"Tutup",icon:"x",title:"Tutup sesi",onSelect:r,render:a.jsx("button",{type:"button",className:"hn-terminal-action","aria-label":`Tutup sesi ${e.id}`,onClick:r,children:"×"},"close")}],xe=40+(e.orchestrated&&e.model?110:0)+(e.exited||B?110:0)+(J||ge&&!B?130:0),Te=Ya(N,G.length,v?44:28,xe),ie=G.slice(Te);return a.jsxs(a.Fragment,{children:[a.jsxs("div",{ref:w,className:"hn-terminal-cell-header",style:{display:"flex",alignItems:"center",gap:8,padding:"4px 8px",flex:"0 0 auto",background:de?"var(--status-err-tint)":e.exited||B?"var(--status-ok-tint)":ze?"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:[Re&&a.jsx(qa,{id:Re,decorative:!0,style:{width:34,flex:"0 0 auto",borderRadius:"var(--radius-sm)"}}),a.jsxs("span",{style:{flex:1,minWidth:0,overflow:"hidden",textOverflow:"ellipsis",whiteSpace:"nowrap"},children:[ae," · ",e.id.slice(0,6)]}),e.orchestrated&&e.model&&a.jsxs("span",{"data-testid":"orchestrator-chip",title:"Model & effort orchestrator",style:{flex:"0 0 auto",fontSize:10,color:"var(--text-muted)"},children:["orch ",et(e.model),e.effort?` · ${e.effort}`:""]}),e.exited&&(de?a.jsx(je,{status:"failed",size:"sm",children:`Gagal · exit ${e.exitCode}`}):a.jsx(je,{status:"done",size:"sm",children:"Selesai"})),B&&a.jsx(je,{status:"done",size:"sm",children:"Selesai"}),J&&!B&&a.jsx(je,{status:"running",size:"sm",children:"Lead memutuskan"}),ge&&!J&&!B&&a.jsx(je,{status:"awaiting",size:"sm"}),a.jsxs("span",{className:"hn-terminal-actions",children:[G.slice(0,Te).map(H=>H.render),ie.length>0&&a.jsx(Mt,{label:`Aksi lain sesi ${e.id}`,items:ie.map(({render:H,...W})=>W)})]})]}),a.jsxs("div",{style:{display:"flex",flexDirection:"column",flex:1,minHeight:0,position:"relative",opacity:e.exited?.6:1},children:[a.jsx(wn,{phases:D,compact:N<480}),a.jsx("div",{style:{flex:1,minHeight:0},children:f?a.jsx("div",{style:{height:"100%",display:"grid",placeItems:"center",padding:12,color:"var(--text-subtle)",fontSize:12,textAlign:"center"},children:"Terbuka di layar penuh"}):a.jsx(Wt,{sessionId:e.id,onExit:c,onPhases:M,fontSize:m,showKeys:y,predict:T,diag:C,hidden:E},e.id)})]}),ee&&e.specId&&a.jsx(Ua,{specId:e.specId,onClose:()=>_(!1)}),U&&Y&&g&&a.jsx(St,{projectId:Y.projectId,ownBranch:`hanoman/${Y.id.toLowerCase().replace(/[^a-z0-9_-]/g,"_")}`,eyebrow:Y.id,onClose:()=>te(!1),onIntegrate:(H,W)=>{te(!1),g(Y,H,W)}}),le&&he&&x&&a.jsx(St,{projectId:e.projectId,ownBranch:e.branch,eyebrow:e.id.slice(0,16),onClose:()=>ce(!1),onIntegrate:(H,W)=>{ce(!1),x(e,H,W)}})]})}function Cn({session:e,label:i,fontSize:r,showKeys:s,predict:o,diag:c,onClose:I}){return a.jsx(Se,{open:!0,icon:"terminal",title:i,onClose:I,closeOnEscape:!1,width:1600,children:a.jsx("div",{style:{height:"min(72vh, calc(100dvh - 180px))",minHeight:0,display:"flex",flexDirection:"column",opacity:e.exited?.6:1},children:a.jsx(Wt,{sessionId:e.id,onExit:()=>{},fontSize:r,showKeys:s,predict:o,diag:c},e.id)})})}function zn({unplaced:e,nameOf:i,onPick:r,disabled:s}){return a.jsx("div",{style:{flex:1,display:"grid",placeItems:"center",padding:12},children:a.jsx(Z,{size:"sm",value:"","aria-label":"Pilih sesi untuk sel",disabled:s||!e.length,onChange:o=>o.target.value&&r(o.target.value),options:[{value:"",label:e.length?"Pilih sesi…":"tidak ada sesi bebas"}].concat(e.map(o=>({value:o.id,label:`${o.specId??i(o.projectId)} · ${o.id.slice(0,6)}`})))})})}export{wn as PhaseStrip,Nn 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-C0hF6fPX.js";import{R as l}from"./react-DfGhg7ZW.js";import{L as ue}from"./live-DZWDT8yU.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-DYNYB1Nj.js";import{R as l}from"./react-DfGhg7ZW.js";import{L as ue}from"./live-nMnpVkPn.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-C0hF6fPX.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,aE as be,at as ke,c as O,d as T,aa as ye,ao as se,y as ve}from"./index-DYNYB1Nj.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};
|