hanoman 0.9.32 → 0.9.33
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 +240 -130
- package/dist/server.js +21995 -20480
- package/package.json +1 -1
- package/prisma/migrations/20261020120000_lead_session_inbox/migration.sql +42 -0
- package/prisma/schema.prisma +46 -0
- package/web/assets/{DalangHanomanScreen-DdsEmtBl.js → DalangHanomanScreen-DAXIQxrw.js} +1 -1
- package/web/assets/{DocPreviewModal-BbOqdfaH.js → DocPreviewModal-Cu0UFzPH.js} +1 -1
- package/web/assets/{DocsWorkspace-Cr7AXz9z.js → DocsWorkspace-DElNcoar.js} +1 -1
- package/web/assets/{IdeScreen-hdbQW-ui.js → IdeScreen-BBr567gf.js} +1 -1
- package/web/assets/LeadScreen-CYn8RS3H.js +1 -0
- package/web/assets/{ReviewScreen-BIkpEspG.js → ReviewScreen-zAvwSL50.js} +1 -1
- package/web/assets/{SchedulerScreen-3KVE-d_d.js → SchedulerScreen-BptlSAOx.js} +1 -1
- package/web/assets/{SettingsScreen-B0-W2TeR.js → SettingsScreen-a0Cx4M4j.js} +3 -3
- package/web/assets/{TeamScreen-DNdt2P1g.js → TeamScreen-Cm_phItS.js} +1 -1
- package/web/assets/{TerminalScreen-BjQF48XI.js → TerminalScreen-CFuNRq6d.js} +1 -1
- package/web/assets/{TriageScreen-CzM99CrG.js → TriageScreen-ChTidhCT.js} +1 -1
- package/web/assets/{VpsScreen-SGB_BpbS.js → VpsScreen-8vz0QHO-.js} +1 -1
- package/web/assets/{fields-of8G961J.js → fields-Bhl01LnE.js} +1 -1
- package/web/assets/{index-C5P4ykKO.js → index-R2HBkTbR.js} +207 -207
- package/web/assets/{live-DQen7wLm.js → live-V9nWiHoE.js} +1 -1
- package/web/assets/{sched-lead-shared-C34TvLVv.js → sched-lead-shared-Dr48bY7n.js} +1 -1
- package/web/assets/{settings-rebase-DHIWk4mV.js → settings-rebase-DOqNAynI.js} +1 -1
- package/web/index.html +1 -1
- package/web/assets/LeadScreen-BWE4mfJI.js +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{j as e,l as Ie,bd as he,n as O,f as T,B as k,R as Ae,X as Pe,e as J,g as ce,be as ze,bf as Qe,d as Ve,q as Y,r as Xe,h as L,i as M,K as Ye,G as Ze,L as ea,m as aa,x as na,Q as sa,w as ia,bg as Be,aY as ee,C as la,bh as ta,V as ve,D as ra,aJ as De,Z as oe,bi as da,bj as ca,bk as oa,bl as ua,bm as ha,bn as ma,a2 as ga}from"./index-R2HBkTbR.js";import{R as o}from"./react-DfGhg7ZW.js";import{L as ka}from"./live-V9nWiHoE.js";import"./markdown-CWEY34jk.js";import{a as ae,d as pa,c as ue,u as ja,I as we}from"./sched-lead-shared-Dr48bY7n.js";import"./xterm-3VOAfa_q.js";/* empty css */function ba({approvals:n,projectName:c,busyId:l,onDecide:m}){const[g,i]=o.useState(null),[t,d]=o.useState("");return n.length?e.jsx("ul",{className:"hn-lead-waits","aria-label":"Tindakan lead yang menunggu izin",children:n.map(u=>{const b=l===u.id;return e.jsxs("li",{className:"hn-lead-wait",children:[e.jsxs("div",{className:"hn-lead-wait-head",children:[e.jsxs("span",{className:"hn-lead-wait-title",children:[Ie(he,u.action),u.target?` · ${u.target}`:""]}),e.jsx(O,{tone:"warn",size:"sm",children:"minta izin"})]}),e.jsx("p",{className:"hn-lead-wait-question",children:u.reason}),u.evidence.length>0&&e.jsx("div",{className:"hn-lead-refs","aria-label":"Bukti yang diperiksa lead",children:u.evidence.map(x=>e.jsx("span",{className:"hn-lead-ref",children:x},x))}),u.gateReport.length>0&&e.jsxs("p",{className:"hn-lead-note",children:["Gerbang server: ",u.gateReport.join(" · ")]}),e.jsxs("div",{className:"hn-lead-item-meta",children:[e.jsx("span",{children:c(u.projectId)}),e.jsx("span",{children:ae(u.createdAt)})]}),g===u.id?e.jsx("div",{className:"hn-lead-change",children:e.jsxs("div",{className:"hn-lead-change-row",children:[e.jsx(T,{className:"hn-lead-change-input",size:"sm","aria-label":"Catatan untuk lead",placeholder:"Kenapa ditolak? (opsional, dikirim ke lead)",value:t,onChange:x=>d(x.target.value)}),e.jsx(k,{size:"sm",variant:"danger",disabled:b,onClick:()=>{m(u.id,!1,t.trim()||void 0),i(null),d("")},children:"Kirim penolakan"}),e.jsx(k,{size:"sm",variant:"ghost",onClick:()=>{i(null),d("")},children:"Batal"})]})}):e.jsxs("div",{className:"hn-lead-wait-foot",children:[e.jsx(k,{size:"sm",variant:"ghost",leftIcon:"x-circle",disabled:b,onClick:()=>i(u.id),children:"Tolak"}),e.jsx(k,{size:"sm",leftIcon:"check",disabled:b,onClick:()=>m(u.id,!0),children:"Setujui"})]})]},u.id)})}):e.jsx("p",{className:"hn-lead-note",children:"Tidak ada tindakan lead yang menunggu izinmu."})}const xa={ask:"pertanyaan sesi","session-ended":"sesi selesai/gagal",pulse:"pilih backlog",human:"permintaan",rejected:"penolakan manusia","integrate-failed":"integrasi gagal"},fa={open:{label:"menunggu diantar",tone:"neutral"},delivered:{label:"di pane lead",tone:"info"},late:{label:"lewat tenggat · menunggu kamu",tone:"err"},human:{label:"diambil manusia",tone:"neutral"},done:{label:"selesai",tone:"ok"}},Ne=240;function ya({events:n,projectName:c,busyId:l,onTake:m,onGoto:g}){return n.length?e.jsx("ul",{className:"hn-lead-timeline","aria-label":"Inbox sesi lead",children:n.map(i=>{const t=fa[i.status]??{label:i.status,tone:"neutral"},d=i.status==="open"||i.status==="delivered",u=i.question.length>Ne?`${i.question.slice(0,Ne-1)}…`:i.question;return e.jsxs("li",{className:"hn-lead-item",children:[e.jsxs("div",{className:"hn-lead-item-head",children:[e.jsx(O,{tone:"brass",size:"sm",children:xa[i.kind]??i.kind}),e.jsx(O,{tone:t.tone,size:"sm",children:t.label}),e.jsx("span",{className:"hn-lead-item-time",children:ae(i.createdAt)})]}),e.jsx("span",{className:"hn-lead-item-question",children:u}),e.jsxs("div",{className:"hn-lead-item-foot",children:[e.jsxs("span",{className:"hn-lead-item-meta",children:[e.jsx("span",{children:c(i.projectId)}),i.specId&&e.jsx("span",{children:i.specId}),d&&i.deadlineAt&&e.jsxs("span",{children:["tenggat ",pa(i.deadlineAt)]})]}),e.jsxs("span",{className:"hn-lead-chips",children:[i.sessionId&&e.jsx(k,{size:"sm",variant:"ghost",leftIcon:"terminal",onClick:()=>g(i.sessionId),children:"Buka sesi"}),d&&e.jsx(k,{size:"sm",variant:"secondary",disabled:l===i.id,onClick:()=>m(i),children:"Ambil alih"})]})]})]},i.id)})}):e.jsx("p",{className:"hn-lead-note",children:"Inbox lead kosong."})}function va(n){return n.alive?n.humanActive?{label:"kamu sedang mengetik",tone:"warn"}:n.idle?{label:"diam · siap",tone:"ok"}:{label:"sedang bekerja",tone:"info"}:{label:"mati",tone:"neutral"}}function wa({sessions:n,projectName:c,busyId:l,onGoto:m,onOp:g}){return n.length?e.jsx(Ae,{label:"Sesi lead per project",children:n.map(i=>{const t=va(i),d=l===`session:${i.projectId}`;return e.jsxs(Pe,{actions:i.alive?e.jsxs(e.Fragment,{children:[e.jsx(k,{size:"sm",variant:"ghost",leftIcon:"terminal",onClick:()=>m(i.sessionId),children:"Buka terminal"}),e.jsx(k,{size:"sm",variant:"ghost",leftIcon:"refresh-cw",disabled:d,onClick:()=>g(i.projectId,"rotate"),children:"Rotasi"}),e.jsx(k,{size:"sm",variant:"ghost",leftIcon:"ban",disabled:d,onClick:()=>g(i.projectId,"stop"),children:"Hentikan"})]}):e.jsx(k,{size:"sm",leftIcon:"play",disabled:d,onClick:()=>g(i.projectId,"start"),children:"Mulai"}),children:[e.jsx("span",{className:"hn-lead-project-name",children:c(i.projectId)}),e.jsxs("span",{className:"hn-lead-project-meta",children:[i.delivered," event diantar sejak lahir · ",i.restarts," kali lahir"]}),e.jsx(O,{tone:t.tone,size:"sm",children:t.label})]},i.projectId)})}):e.jsx("p",{className:"hn-lead-note",children:"Belum ada project yang diurus lead."})}const Ee=["answer-session","start-session","integrate-main","stop-session","resume-session"],Na=[{value:"auto",label:"jalan sendiri"},{value:"ask",label:"minta izin"},{value:"off",label:"tidak boleh"}],Se=[{key:"quotaStopPct",label:"Berhenti meluncurkan saat kuota (%)",hint:"1–100. Data kuota tak terbaca = berhenti.",min:1,max:100},{key:"rampStep",label:"Sesi baru sekaligus (maks)",hint:"1–16. Sesi berikutnya menunggu yang sebelumnya lolos probe.",min:1,max:16},{key:"rampProbeMin",label:"Probe sesi baru (menit)",hint:"1–240. Lama sesi baru harus bertahan tanpa gagal.",min:1,max:240},{key:"failStreak",label:"Jeda project setelah gagal beruntun",hint:"1–20 sesi lead yang gagal berturut-turut.",min:1,max:20},{key:"answerSlaSec",label:"Tenggat jawaban pertanyaan (detik)",hint:"30–3600. Lewat dari ini, pertanyaan jatuh ke kamu.",min:30,max:3600}],Z=n=>{const c=ze.parse(n??{});return{authority:Object.fromEntries(Ee.map(l=>[l,c.authority[l]??Qe[l]])),targetBranch:c.targetBranch,verifyCommand:c.verifyCommand,quotaStopPct:String(c.quotaStopPct),rampStep:String(c.rampStep),rampProbeMin:String(c.rampProbeMin),failStreak:String(c.failStreak),answerSlaSec:String(c.answerSlaSec)}};function Sa({config:n,projects:c,busy:l,onSave:m}){var z,f;const[g,i]=o.useState(((z=c[0])==null?void 0:z.id)??""),t=(f=n.projects)==null?void 0:f[g],[d,u]=o.useState(()=>Z(t));if(o.useEffect(()=>{var r;u(Z((r=n.projects)==null?void 0:r[g]))},[g,n]),!c.length)return e.jsx("p",{className:"hn-lead-note",children:"Serahkan project ke lead dulu untuk mengatur wewenangnya."});const b=JSON.stringify(d)!==JSON.stringify(Z(t)),x=async()=>{const r=ze.parse(t??{}),I={authority:d.authority,targetBranch:d.targetBranch.trim()||"main",verifyCommand:d.verifyCommand.trim(),...Object.fromEntries(Se.map(A=>[A.key,ue(d[A.key],A.min,A.max,r[A.key])]))};await m({...n,projects:{...n.projects??{},[g]:I}})};return e.jsxs("div",{className:"hn-lead-settings",children:[e.jsx(J,{label:"Project",children:e.jsx(ce,{size:"sm","aria-label":"project untuk wewenang lead",value:g,onChange:r=>i(r.target.value),options:c.map(r=>({value:r.id,label:r.name}))})}),e.jsxs("div",{className:"hn-lead-settings-grid",children:[Ee.map(r=>e.jsx(J,{label:`Wewenang: ${he[r]}`,children:e.jsx(ce,{size:"sm","aria-label":`wewenang ${r}`,value:d.authority[r],onChange:I=>u({...d,authority:{...d.authority,[r]:I.target.value}}),options:Na})},r)),e.jsx(J,{label:"Branch target integrasi",hint:"Lead merge ke branch ini, bukan main terpatok.",children:e.jsx(T,{"aria-label":"branch target integrasi",value:d.targetBranch,placeholder:"main",onChange:r=>u({...d,targetBranch:r.target.value})})}),e.jsx(J,{label:"Perintah verifikasi sebelum merge",hint:"Dijalankan server di worktree sesi dan harus hijau. Kosong = merge selalu minta izin.",children:e.jsx(T,{"aria-label":"perintah verifikasi",value:d.verifyCommand,placeholder:"mis. pnpm test",onChange:r=>u({...d,verifyCommand:r.target.value})})}),Se.map(r=>e.jsx(J,{label:r.label,hint:r.hint,children:e.jsx(T,{type:"number",min:r.min,max:r.max,"aria-label":r.label,value:d[r.key],onChange:I=>u({...d,[r.key]:I.target.value})})},r.key))]}),e.jsxs("div",{className:"hn-lead-footer",children:[e.jsx("span",{role:"status","aria-live":"polite",children:b?"Ada perubahan yang belum disimpan.":""}),e.jsxs("span",{className:"hn-lead-chips",children:[e.jsx(k,{size:"sm",variant:"ghost",disabled:!b||l,onClick:()=>u(Z(t)),children:"Urungkan"}),e.jsx(k,{size:"sm",leftIcon:"check",disabled:!b||l,onClick:()=>void x(),children:"Simpan wewenang"})]})]})]})}const Ca=5e3,G=20,Ce=400,La={aktif:"aktif",jeda:"dijeda",mati:"mati"},Ia=[{key:"semua",label:"Semua"},{key:"keputusan",label:"Keputusan"},{key:"rangkaian",label:"Rangkaian"}],Aa={berlaku:"ok",ditimpa:"warn",dibatalkan:"neutral",gagal:"err"},Pa={menunggu:"warn",sebagian:"info",selesai:"ok",dibatalkan:"neutral"},za=new Set(["menunggu","sebagian"]),H=n=>({everyMin:String(n.everyMin),maxAutoAnswers:String(n.maxAutoAnswers)}),Ba={everyMin:"5",maxAutoAnswers:"3"};function Le({total:n,page:c,onPage:l,unit:m}){const g=oe(n,c,G);return e.jsx(ga,{page:g.page,pageCount:g.pageCount,total:n,from:g.from,to:g.to,onPage:l,unit:m})}function Da({page:n,pageCount:c,onPage:l}){return c<=1?null:e.jsxs("div",{className:"hn-lead-footer",children:[e.jsxs("span",{children:["Halaman ",n," dari ",c," · keputusan dan rangkaian"]}),e.jsxs("span",{className:"hn-lead-chips",children:[e.jsx(k,{size:"sm",variant:"ghost","aria-label":"Sebelumnya",disabled:n<=1,onClick:()=>l(n-1),children:"Sebelumnya"}),e.jsx(k,{size:"sm",variant:"ghost","aria-label":"Berikutnya",disabled:n>=c,onClick:()=>l(n+1),children:"Berikutnya"})]})]})}function Ea({sid:n,title:c,label:l,needsYou:m,onGoto:g,onAnswered:i,onError:t}){const[d,u]=o.useState(null),[b,x]=o.useState("idle"),[z,f]=o.useState([]),[r,I]=o.useState(!1);o.useEffect(()=>{if(!m)return;let p=!0;return x("loading"),Promise.resolve().then(()=>L.sessionDialog(n)).then(w=>{p&&(u(w),x(w&&w.dialog.options.length>0?"ready":"unavailable"))},()=>{p&&x("unavailable")}),()=>{p=!1}},[n,m]);async function A(p,w){if(d){I(!0);try{await L.answerSessionDialog(n,w?{screenHash:d.screenHash,choice:p[0]}:{screenHash:d.screenHash,choices:p}),f([]),i()}catch(E){t(M("menjawab sesi",E))}finally{I(!1)}}}const P=p=>f(w=>w.includes(p)?w.filter(E=>E!==p):[...w,p]),v=d==null?void 0:d.dialog;return e.jsxs("li",{className:"hn-lead-wait",children:[e.jsxs("div",{className:"hn-lead-wait-head",children:[e.jsx("span",{className:"hn-lead-wait-title",children:c}),e.jsx(O,{tone:m?"warn":"ok",size:"sm",children:l})]}),m&&b==="loading"&&e.jsx("p",{className:"hn-lead-note",children:"Membaca pertanyaannya…"}),m&&b==="unavailable"&&e.jsx("p",{className:"hn-lead-note",children:"Pertanyaan ini belum bisa dijawab dari sini. Jawab di Terminal."}),m&&b==="ready"&&v&&e.jsxs(e.Fragment,{children:[v.title&&e.jsx("p",{className:"hn-lead-wait-question",children:v.title}),v.multi?e.jsxs(e.Fragment,{children:[e.jsx("div",{className:"hn-lead-options-multi",role:"group","aria-label":v.title||"Pilihan jawaban",children:v.options.map(p=>e.jsx(De,{checked:z.includes(p.n),label:p.label,disabled:r,onChange:()=>P(p.n)},p.n))}),e.jsx("div",{className:"hn-lead-wait-foot",children:e.jsx(k,{size:"sm",disabled:r||z.length===0,onClick:()=>void A(z,!1),children:"Kirim pilihan"})})]}):e.jsx("div",{className:"hn-lead-options",role:"group","aria-label":v.title||"Pilihan jawaban",children:v.options.map(p=>e.jsx(k,{size:"sm",variant:"secondary",disabled:r,onClick:()=>void A([p.n],!0),children:p.label},p.n))}),(v.freeIndex!=null||v.notes)&&e.jsx("p",{className:"hn-lead-note",children:"Jawaban bebas: jawab di Terminal."})]}),e.jsx("div",{className:"hn-lead-wait-foot",children:e.jsx(k,{size:"sm",variant:"ghost",leftIcon:"terminal",onClick:g,children:"Buka di Terminal"})})]})}function Ma({label:n,options:c,multi:l,value:m,onChange:g}){return l?e.jsx("div",{role:"group","aria-label":n,className:"hn-lead-options-multi",children:c.map(i=>e.jsx(De,{checked:m.includes(i),label:i,onChange:()=>g(m.includes(i)?m.filter(t=>t!==i):[...m,i])},i))}):e.jsx(Be,{"aria-label":n,value:m[0]??"",onChange:i=>g([i]),children:c.map(i=>e.jsx(ee,{value:i,label:i},i))})}function Oa({d:n,projectName:c,onOverride:l,onCancel:m,busyId:g,ask:i}){var F;const[t,d]=o.useState(!1),[u,b]=o.useState(""),[x,z]=o.useState([]),f=(n.choices??[]).length>0?n.choices:n.choiceIndex!=null&&n.choice?[{index:n.choiceIndex,option:n.choice}]:[],r=n.options??[],I=((F=n.select)==null?void 0:F.mode)==="multi",A=[c(n.projectId),n.specId].filter(Boolean).join(" · "),P=n.action!=="none"?he[n.action]:void 0,v=n.question.length>Ce?`${n.question.slice(0,Ce)}…`:n.question,p=g===n.id,w=()=>{d(!1),b(""),z([])},E=f.length?f.map(N=>N.option).join(" · "):n.answer||"tidak ada jawaban",_=u.trim()||x.join("; "),W=async()=>{let N=!1;await i({title:"Ubah jawaban keputusan ini?",eyebrow:"lead · ubah jawaban",impact:[`Jawaban sekarang: ${E}`,`Jadi: ${_}`],confirmLabel:"Ubah jawaban",icon:"edit-3",tone:"default",run:async()=>{N=await l(n.id,_,x)}}),N&&w()};return e.jsxs("li",{className:"hn-lead-item",children:[e.jsxs("div",{className:"hn-lead-item-head",children:[e.jsx(O,{tone:Aa[n.status]??"neutral",size:"sm",children:da[n.status]??n.status}),n.weighty&&e.jsx(O,{tone:"warn",size:"sm",children:"berbobot"}),e.jsx("span",{className:"hn-lead-item-time",children:ae(n.createdAt)})]}),e.jsx("div",{className:"hn-lead-item-question",children:v}),e.jsx("div",{className:"hn-lead-item-answer",children:f.length?f.map(N=>N.option).join(" · "):n.answer||e.jsx("em",{children:"tidak ada jawaban"})}),n.reason&&e.jsx("div",{className:"hn-lead-item-reason",children:n.reason}),e.jsxs("div",{className:"hn-lead-item-meta",children:[e.jsx("span",{children:ca[n.kind]??n.kind}),e.jsx("span",{children:oa[n.gate]??n.gate}),e.jsx("span",{children:ua[n.confidence]??n.confidence}),f.length>0&&r.length>0&&e.jsx("span",{children:f.length>1?`${f.length} dari ${r.length} opsi`:`opsi ${f[0].index} dari ${r.length}`}),(n.missing??[]).length>0&&e.jsx("span",{children:"kurang konteks"}),e.jsxs("span",{children:[A,P?` · ${P}`:""]})]}),(n.missing??[]).length>0&&e.jsxs("div",{className:"hn-lead-item-reason",children:["Yang kurang: ",n.missing.join(" · ")]}),n.refs.length>0&&e.jsx("div",{className:"hn-lead-refs",children:n.refs.map(N=>e.jsx("span",{className:"hn-lead-ref",children:N},N))}),n.status==="berlaku"&&!t&&e.jsx("div",{className:"hn-lead-item-foot",children:e.jsxs("span",{className:"hn-lead-chips",children:[e.jsx(k,{size:"sm",variant:"ghost",leftIcon:"edit-3",onClick:()=>d(!0),children:"Ubah jawaban"}),e.jsx(k,{size:"sm",variant:"ghost",leftIcon:"x-circle",disabled:p,onClick:()=>m(n),children:"Batalkan"})]})}),t&&e.jsxs("div",{className:"hn-lead-change",children:[r.length>0&&e.jsx(Ma,{label:`Pilihan jawaban${n.specId?` untuk ${n.specId}`:""}`,options:r,multi:I,value:x,onChange:z}),e.jsxs("div",{className:"hn-lead-change-row",children:[e.jsx(T,{className:"hn-lead-change-input","aria-label":`Jawaban kamu${n.specId?` untuk ${n.specId}`:""}`,placeholder:"mis. pilih opsi 2, pakai Node 22",value:u,onChange:N=>b(N.target.value)}),e.jsx(k,{size:"sm",variant:"ghost",disabled:p,onClick:w,children:"Batal"}),e.jsx(k,{size:"sm",leftIcon:"check",disabled:!u.trim()&&x.length===0||p,onClick:()=>void W(),children:"Kirim jawaban"})]})]})]})}function Ra({f:n,busyId:c,onClose:l}){return e.jsxs("li",{className:"hn-lead-item",children:[e.jsxs("div",{className:"hn-lead-item-head",children:[e.jsx(O,{tone:Pa[n.status]??"neutral",size:"sm",children:ha[n.status]??n.status}),e.jsx("span",{className:"hn-lead-item-time",children:ae(n.openedAt)})]}),e.jsx("div",{className:"hn-lead-item-answer",children:n.title}),e.jsxs("div",{className:"hn-lead-item-meta",children:[e.jsxs("span",{children:[n.steps," langkah"]}),n.closeReason&&e.jsx("span",{children:Ie(ma,n.closeReason)})]}),za.has(n.status)&&e.jsx("div",{className:"hn-lead-item-foot",children:e.jsxs("span",{className:"hn-lead-chips",children:[e.jsx(k,{size:"sm",leftIcon:"check",disabled:c===n.id,onClick:()=>l(n,"submit"),children:"Kirim rangkaian"}),e.jsx(k,{size:"sm",variant:"ghost",leftIcon:"x-circle",disabled:c===n.id,onClick:()=>l(n,"cancel"),children:"Batalkan rangkaian"})]})})]})}function Ha({projects:n,onProjectChanged:c,onToast:l,onGotoTerminal:m}){var ye;const{confirm:g,dialog:i}=Ve(),[t,d]=o.useState(null),[u,b]=o.useState([]),[x,z]=o.useState([]),[f,r]=o.useState(!1),[I,A]=o.useState(0),[P,v]=Y("lead","decPage",1,ve),[p,w]=o.useState(0),[E,_]=Y("lead","flowPage",1,ve),[W,F]=o.useState("loading"),[N,ne]=o.useState(null),[R,me]=o.useState(!1),[q,S]=o.useState(null),[B,se]=Y("lead","filter","all",ra),[$,Me]=Y("lead","kind","semua",Xe("semua","keputusan","rangkaian")),Q=o.useRef(!1),K=o.useCallback(a=>{var s;return((s=n.find(h=>h.id===a))==null?void 0:s.name)??"Project lain"},[n]),j=o.useCallback((a=!1)=>{!a&&!Q.current&&F("loading"),Promise.all([L.getLeadStatus(),L.getLeadDecisions({projectId:B==="all"?void 0:B,page:P,limit:G}),L.getLeadFlows({projectId:B==="all"?void 0:B,page:E,limit:G}).catch(()=>null)]).then(([s,h,y])=>{Q.current=!0,d(s),b(h.items??[]),A(h.total??0),y?(z(y.items??[]),w(y.total??0),r(!1)):r(!0),ne(null),F("ready")}).catch(s=>{if(!Q.current){F("error");return}a||ne(M("memuat keputusan",s))})},[B,P,E]);o.useEffect(()=>{j()},[j]),Ye(B,()=>{v(1),_(1)}),Ze({topic:"lead",params:{projectId:B==="all"?void 0:B,decPage:P,flowPage:E,limit:G},apply:a=>{Q.current=!0,d(a.status),b(a.decisions.items),A(a.decisions.total),z(a.flows.items),w(a.flows.total),r(!1),ne(null),F("ready")},refetch:()=>j(!0),pollMs:Ca});const C=(t==null?void 0:t.config)??null,D=ja(C?H(C):Ba),ie=D.dirty,U=o.useCallback(async(a,s=!1)=>{me(!0);try{return await L.putLeadConfig(a),s||l("Setelan lead tersimpan","ok","save"),j(!0),!0}catch(h){return l(M("menyimpan setelan lead",h),"err","x-circle"),!1}finally{me(!1)}},[j,l]),Oe=async()=>{if(!C)return;const a={...C,everyMin:ue(D.draft.everyMin,1,1440,C.everyMin),maxAutoAnswers:ue(D.draft.maxAutoAnswers,1,20,C.maxAutoAnswers)};if(JSON.stringify(H(a))===JSON.stringify(H(C))){D.setDraft(H(C));return}D.setDraft(H(a)),await U(a)},ge=o.useCallback(async(a,s)=>{S(a);try{await L.updateProject(a,{leadOptIn:s}),await c(a),j(!0),l(s?"Project diserahkan ke lead":"Project ditarik dari lead","ok")}catch(h){l(M("mengubah lead untuk project",h),"err","x-circle")}finally{S(null)}},[j,c,l]),ke=o.useCallback(async(a,s)=>{if(!t)return;const h=new Set(t.config.pausedProjects);s?h.add(a):h.delete(a),await U({...t.config,pausedProjects:[...h]},!0)},[t,U]),Re=o.useCallback(async(a,s,h=[])=>{S(a);try{const y=await L.overrideLeadDecision(a,s,"",h);return l(y.delivered?"Jawaban kamu dikirim ke sesi":"Keputusan diubah","ok","check"),j(!0),!0}catch(y){return l(M("mengubah keputusan",y),"err","x-circle"),!1}finally{S(null)}},[j,l]),pe=o.useCallback(async(a,s)=>{S(a);try{await(s==="submit"?L.submitLeadFlow(a):L.cancelLeadFlow(a)),l(s==="submit"?"Rangkaian dikirim":"Rangkaian ditutup tanpa dikirim","ok","check"),j(!0)}catch(h){l(M("menutup rangkaian",h),"err","x-circle")}finally{S(null)}},[j,l]),_e=o.useCallback(async(a,s,h)=>{S(a);try{await L.decideLeadApproval(a,s,h),l(s?"Tindakan lead disetujui":"Penolakan dikirim ke lead","ok","check"),j(!0)}catch(y){l(M(s?"menyetujui tindakan lead":"menolak tindakan lead",y),"err","x-circle")}finally{S(null)}},[j,l]),Fe=o.useCallback(async a=>{S(a.id);try{await L.takeLeadEvent(a.id),l("Event diambil alih — lead tak akan menjawabnya","ok","check"),j(!0),a.sessionId&&m(a.sessionId)}catch(s){l(M("mengambil alih event",s),"err","x-circle")}finally{S(null)}},[j,l,m]),le=o.useCallback(async(a,s)=>{S(`session:${a}`);try{await L.leadSession(a,s),l(s==="start"?"Sesi lead dimulai":s==="stop"?"Sesi lead dihentikan":"Sesi lead dirotasi","ok","check"),j(!0)}catch(h){l(M("mengendalikan sesi lead",h),"err","x-circle")}finally{S(null)}},[j,l]),qe=(a,s)=>{if(s==="start"){le(a,s);return}g(s==="stop"?{title:"Hentikan sesi lead?",eyebrow:"lead · sesi",message:"Pertanyaan sesi pekerja jatuh ke kamu sampai sesi lead lahir lagi. Lead melahirkannya kembali saat ada event baru — jeda project untuk benar-benar berhenti.",confirmLabel:"Hentikan sesi lead",icon:"ban",tone:"danger",run:()=>le(a,s)}:{title:"Rotasi sesi lead?",eyebrow:"lead · sesi",message:"Sesi lead dihentikan lalu dilahirkan lagi dengan konteks bersih. Keputusan & inbox tersimpan di server, jadi tak ada yang hilang.",confirmLabel:"Rotasi",icon:"refresh-cw",tone:"default",run:()=>le(a,s)})},$e=o.useCallback(async a=>{S(a);try{await L.cancelLeadDecision(a),l("Keputusan dibatalkan","ok"),j(!0)}catch(s){l(M("membatalkan keputusan",s),"err","x-circle")}finally{S(null)}},[j,l]),Ke=(a,s)=>{g(s==="submit"?{title:"Kirim rangkaian ini?",eyebrow:"lead · rangkaian",message:"Semua jawaban yang sudah terkumpul dikirim ke sesi peminta. Rangkaian lalu ditutup dan tidak bisa ditambah lagi.",confirmLabel:"Kirim rangkaian",icon:"check",tone:"default",run:()=>pe(a.id,"submit")}:{title:"Batalkan rangkaian ini?",eyebrow:"lead · rangkaian",message:"Rangkaian ditutup tanpa dikirim. Jawaban yang sudah terkumpul tidak sampai ke sesi peminta.",confirmLabel:"Tutup tanpa mengirim",icon:"x-circle",tone:"danger",run:()=>pe(a.id,"cancel")})},Je=a=>{g({title:"Batalkan keputusan ini?",eyebrow:"lead · keputusan",message:"Keputusan ini ditandai dibatalkan dan tidak lagi berlaku.",confirmLabel:"Batalkan keputusan",icon:"x-circle",tone:"danger",run:()=>$e(a.id)})},Te=a=>{if(C){if(a==="mati"){g({title:"Matikan lead?",eyebrow:"lead · kendali",message:"Lead berhenti memutuskan untuk semua project. Sesi yang sudah berjalan tidak diubah, dan pertanyaan yang menunggu tetap menunggu kamu.",confirmLabel:"Matikan lead",icon:"ban",tone:"danger",run:()=>U({...C,enabled:!1,paused:!1}).then(()=>{})});return}U({...C,enabled:!0,paused:a==="jeda"})}};if(W==="loading")return e.jsx(ea,{rows:4,label:"Memuat lead…"});if(W==="error"||!t)return e.jsx(aa,{kind:"error",hint:"Gagal memuat status lead.",action:()=>j(),actionLabel:"Coba lagi"});const je=t.config.enabled?t.config.paused?"jeda":"aktif":"mati",te=new Set(t.projects.map(a=>a.projectId)),V=t.waiting,re=t.inbox??[],de=t.approvals??[],Ue=t.sessions??[],be=new Set(t.deciding),xe=new Set(t.queued??[]),X=t.gate??{inFlight:0,queued:0,capacity:1},He=a=>{const s=(t.queue??[]).find(y=>y.sessionId===a);if(s)return[K(s.projectId),s.specId].filter(Boolean).join(" · ");const h=u.find(y=>y.sessionId===a);return h?[K(h.projectId),h.specId].filter(Boolean).join(" · "):"Sesi (rincian ada di riwayat)"},fe=[...$!=="rangkaian"?u.map(a=>({key:`d:${a.id}`,at:a.createdAt,d:a})):[],...$!=="keputusan"&&!f?x.map(a=>({key:`f:${a.id}`,at:a.openedAt,f:a})):[]].sort((a,s)=>Date.parse(s.at)-Date.parse(a.at)),Ge=$==="semua"?e.jsx(Da,{page:P,pageCount:Math.max(oe(I,P,G).pageCount,oe(p,P,G).pageCount),onPage:a=>{v(a),_(a)}}):$==="keputusan"?e.jsx(Le,{total:I,page:P,onPage:v,unit:"keputusan"}):e.jsx(Le,{total:p,page:E,onPage:_,unit:"rangkaian"}),We=B==="all"?[]:[{key:"project",label:`Project: ${K(B)}`,onRemove:()=>se("all")}];return e.jsxs("div",{className:"hn-lead",children:[e.jsxs("p",{className:"hn-lead-summary",children:["Lead ",La[je]," · ",de.length," minta izin · ",V.length," menunggu kamu · ",re.length," di inbox"]}),e.jsxs("div",{className:"hn-lead-layout",children:[e.jsxs("div",{className:"hn-lead-main",children:[e.jsxs("section",{className:"hn-lead-section","aria-labelledby":"lead-izin-h",children:[e.jsxs("h2",{id:"lead-izin-h",className:"hn-lead-h",children:["Menunggu izinmu (",de.length,")"]}),e.jsx(ba,{approvals:de,projectName:K,busyId:q,onDecide:(a,s,h)=>void _e(a,s,h)})]}),e.jsxs("section",{className:"hn-lead-section","aria-labelledby":"lead-menunggu-h",children:[e.jsxs("h2",{id:"lead-menunggu-h",className:"hn-lead-h",children:["Menunggu kamu (",V.length,")"]}),X.queued>0&&e.jsxs("p",{className:"hn-lead-note",children:["Antrean keputusan penuh: ",X.inFlight," dari ",X.capacity," sedang diputuskan, ",X.queued," menunggu giliran."]}),V.length===0?e.jsx("p",{className:"hn-lead-note",children:"Tidak ada sesi yang menunggu keputusanmu. Lead menangani sisanya."}):e.jsx("ul",{className:"hn-lead-waits",children:V.map(a=>{const s=be.has(a)?"Sedang diputuskan":xe.has(a)?"Antre giliran":"Menunggu kamu",h=!be.has(a)&&!xe.has(a);return e.jsx(Ea,{sid:a,title:He(a),label:s,needsYou:h,onGoto:()=>m(a),onAnswered:()=>{l("Jawaban kamu dikirim ke sesi","ok","check"),j(!0)},onError:y=>l(y,"err","x-circle")},a)})})]}),e.jsxs("section",{className:"hn-lead-section","aria-labelledby":"lead-inbox-h",children:[e.jsxs("h2",{id:"lead-inbox-h",className:"hn-lead-h",children:["Inbox sesi lead (",re.length,")"]}),e.jsx("p",{className:"hn-lead-hint",children:"Yang sedang diputuskan sesi lead. Ambil alih bila kamu ingin memutuskannya sendiri."}),e.jsx(ya,{events:re,projectName:K,busyId:q,onTake:a=>void Fe(a),onGoto:m})]}),e.jsxs("section",{className:"hn-lead-section","aria-labelledby":"lead-riwayat-h",children:[e.jsx("h2",{id:"lead-riwayat-h",className:"hn-lead-h",children:"Riwayat"}),e.jsx("div",{className:"hn-lead-chips",role:"group","aria-label":"Jenis riwayat",children:Ia.map(a=>e.jsx("button",{type:"button",className:"hn-lead-chip","aria-pressed":$===a.key,onClick:()=>{a.key==="semua"&&_(P),Me(a.key)},children:a.label},a.key))}),e.jsx(na,{label:"Filter riwayat",chips:We,filters:e.jsx(ia,{gap:3,children:e.jsx(ce,{size:"sm",value:B,"aria-label":"saring project",onChange:a=>se(a.target.value),options:[{value:"all",label:"semua project"},...n.map(a=>({value:a.id,label:a.name}))]})}),filtersLabel:"Project",onReset:()=>se("all"),resetLabel:"Hapus filter",actions:e.jsxs(e.Fragment,{children:[e.jsx(sa,{screen:"lead",active:B==="all"?0:1}),e.jsx(ka,{})]})}),N&&e.jsx(we,{message:N,onRetry:()=>j()}),f&&$!=="keputusan"&&e.jsx(we,{message:"Gagal memuat rangkaian keputusan.",onRetry:()=>j()}),fe.length===0?e.jsx("p",{className:"hn-lead-note",children:$==="rangkaian"?"Belum ada rangkaian. Satu rangkaian adalah satu urusan: beberapa pertanyaan berurutan sampai kamu kirim.":"Belum ada keputusan. Lead menulis satu baris di sini setiap kali ia memutuskan."}):e.jsx("ul",{className:"hn-lead-timeline","aria-label":"Riwayat keputusan dan rangkaian",children:fe.map(a=>a.d?e.jsx(Oa,{d:a.d,projectName:K,onOverride:Re,onCancel:Je,busyId:q,ask:g},a.key):e.jsx(Ra,{f:a.f,busyId:q,onClose:Ke},a.key))}),Ge]})]}),e.jsxs("aside",{className:"hn-lead-side","aria-label":"Kendali lead",children:[e.jsxs("section",{className:"hn-lead-section","aria-labelledby":"lead-kendali-h",children:[e.jsx("h2",{id:"lead-kendali-h",className:"hn-lead-h",children:"Kendali"}),e.jsx("div",{className:"hn-lead-mode",children:e.jsxs(Be,{label:"Mode lead",value:je,onChange:a=>Te(a),children:[e.jsx(ee,{value:"aktif",label:"Aktif",description:"Lead memutuskan untuk project yang diurusnya.",disabled:R}),e.jsx(ee,{value:"jeda",label:"Jeda",description:"Keputusan baru berhenti. Sesi yang berjalan tidak diubah.",disabled:R}),e.jsx(ee,{value:"mati",label:"Mati",description:"Lead berhenti total. Pertanyaan yang menunggu tetap menunggu kamu.",disabled:R})]})}),e.jsx(la,{tone:"info",title:"Dikunci secara teknis",children:"Produksi, VPS, dan penghapusan data tetap terkunci untuk lead, apa pun setelannya."})]}),e.jsxs("section",{className:"hn-lead-section","aria-labelledby":"lead-sesi-h",children:[e.jsx("h2",{id:"lead-sesi-h",className:"hn-lead-h",children:"Sesi lead"}),e.jsx("p",{className:"hn-lead-hint",children:"Satu sesi per project. Buka terminalnya untuk melihat dan mengarahkan lead langsung."}),e.jsx(wa,{sessions:Ue,projectName:K,busyId:q,onGoto:m,onOp:qe})]}),e.jsxs("details",{className:"hn-lead-disclosure",children:[e.jsx("summary",{children:"Wewenang & jatah per project"}),e.jsx(Sa,{config:t.config,busy:R,onSave:a=>U(a),projects:n.filter(a=>te.has(a.id)).map(a=>({id:a.id,name:a.name}))})]}),e.jsxs("details",{className:"hn-lead-disclosure",children:[e.jsxs("summary",{children:["Project yang dipimpin · ",te.size," dari ",n.length," diurus lead"]}),e.jsx("p",{className:"hn-lead-hint",children:"Lead hanya menyentuh project yang diserahkan kepadanya. Default: tidak diserahkan."}),n.length===0?e.jsx("p",{className:"hn-lead-note",children:"Belum ada project."}):e.jsx(Ae,{label:"Project yang dipimpin lead",children:n.map(a=>{const s=t.projects.find(y=>y.projectId===a.id),h=te.has(a.id);return e.jsxs(Pe,{actions:e.jsxs(e.Fragment,{children:[h&&(s!=null&&s.paused?e.jsx(k,{size:"sm",variant:"ghost",leftIcon:"play",disabled:R,onClick:()=>ke(a.id,!1),children:"Lanjutkan"}):e.jsx(k,{size:"sm",variant:"ghost",leftIcon:"pause",disabled:R,onClick:()=>ke(a.id,!0),children:"Jeda"})),h?e.jsx(k,{size:"sm",variant:"ghost",leftIcon:"ban",disabled:q===a.id,onClick:()=>ge(a.id,!1),children:"Tarik dari lead"}):e.jsx(k,{size:"sm",leftIcon:"check",disabled:q===a.id,onClick:()=>ge(a.id,!0),children:"Serahkan ke lead"})]}),children:[e.jsx("span",{className:"hn-lead-project-name",children:a.name}),s&&e.jsxs("span",{className:"hn-lead-project-meta",children:[s.decisions24h," keputusan 24 jam terakhir · ",s.openSessions," sesi terbuka"]}),e.jsx(O,{tone:h?s!=null&&s.paused?"warn":"ok":"neutral",size:"sm",children:h?s!=null&&s.paused?"dijeda":"diurus lead":"tidak diurus"})]},a.id)})})]}),e.jsxs("details",{className:"hn-lead-disclosure",children:[e.jsx("summary",{children:"Pengaturan lead"}),e.jsxs("div",{className:"hn-lead-settings",children:[e.jsxs("div",{className:"hn-lead-settings-grid",children:[e.jsx(J,{label:"Lead memeriksa tiap (menit)",hint:"1–1440. Berlaku setelah Simpan.",children:e.jsx(T,{type:"number",min:1,max:1440,"aria-label":"lead memeriksa tiap (menit)",placeholder:"mis. 5",value:D.draft.everyMin,disabled:!C,onChange:a=>D.setDraft({...D.draft,everyMin:a.target.value})})}),e.jsx(J,{label:"Jawaban berulang per pertanyaan (maks)",hint:"1–20. Bila pertanyaan yang sama terus kembali sesudah dijawab sebanyak ini, pertanyaan itu diserahkan ke kamu. Pertanyaan berbeda tak dihitung.",children:e.jsx(T,{type:"number",min:1,max:20,"aria-label":"maksimum jawaban berulang per pertanyaan",placeholder:"mis. 3",value:D.draft.maxAutoAnswers,disabled:!C,onChange:a=>D.setDraft({...D.draft,maxAutoAnswers:a.target.value})})})]}),e.jsxs("div",{"data-testid":"lead-engine-line",className:"hn-lead-note",children:["Model lead: ",(ye=t.config.engine)!=null&&ye.enabled?e.jsxs(e.Fragment,{children:[ta[t.config.engine.agent]," · ",e.jsx("code",{children:t.config.engine.model})," · ",e.jsx("code",{children:t.config.engine.effort})]}):e.jsx(e.Fragment,{children:"ikut default global · atur di Settings → Model sesi"})]}),e.jsxs("div",{className:"hn-lead-footer",children:[e.jsx("span",{role:"status","aria-live":"polite",children:ie?"Ada perubahan yang belum disimpan.":""}),e.jsxs("span",{className:"hn-lead-chips",children:[e.jsx(k,{size:"sm",variant:"ghost",disabled:!ie||R,onClick:()=>D.setDraft(H(t.config)),children:"Batal"}),e.jsx(k,{size:"sm",leftIcon:"check",disabled:!ie||R||!C,onClick:()=>void Oe(),children:"Simpan pengaturan"})]})]})]})]})]})]}),i]})}export{Ha as LeadScreen};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{d as Ne,aM as Te,aO as Ce,j as e,m as h,bm as De,B as d,U as Re,bn as Fe,aL as Me,aN as Ee,I as Pe,n as $e,aQ as ze,C as Ke,O as Ae,h as b,bo as Le,i as T}from"./index-C5P4ykKO.js";import{R as s}from"./react-DfGhg7ZW.js";import{D as Ue}from"./DocPreviewModal-BbOqdfaH.js";import"./markdown-CWEY34jk.js";import"./xterm-3VOAfa_q.js";const He="(max-width: 399px)";function Ve(){const n=()=>typeof window<"u"&&typeof window.matchMedia=="function"?window.matchMedia(He):null,[C,j]=s.useState(()=>{var t;return((t=n())==null?void 0:t.matches)??!1});return s.useEffect(()=>{var u;const t=n();if(!t)return;const o=()=>j(t.matches);return o(),(u=t.addEventListener)==null||u.call(t,"change",o),()=>{var v;return(v=t.removeEventListener)==null?void 0:v.call(t,"change",o)}},[]),C}function Ze({specId:n,title:C,onBack:j,kind:t="spec",onGoto:o,onIntegrate:u,integrateTarget:v,onRevert:p,onDiscard:L,reviewed:w=!1,onMarkReviewed:x}){const le=t==="session"?b.sessionReview:b.specReview,ce=t==="session"?b.sessionReviewFile:b.specReviewFile,[k,U]=s.useState(null),[D,y]=s.useState("loading"),[oe,Oe]=s.useState(""),[R,H]=s.useState(),[l,V]=s.useState(""),[r,F]=s.useState(null),[de,S]=s.useState("loading"),[ue,me]=s.useState(0),[O,he]=s.useState("diff"),[ke,M]=s.useState(0),[fe,ge]=s.useState("list"),[be,E]=s.useState(!1),[we,_]=s.useState("files"),{confirm:P,dialog:je}=Ne(),[Q,m]=s.useState(""),$=Ve();s.useEffect(()=>{let a=!0;return y("loading"),le(n).then(i=>{var c;if(a){if(i.empty){U(null),H(i.reason),y("empty");return}U(i),H(void 0),y("ready"),V(((c=i.changed[0])==null?void 0:c.path)??i.files[0]??"")}}).catch(i=>{a&&(console.debug("review: gagal memuat",i==null?void 0:i.message),y("error"))}),()=>{a=!1}},[n,ke]),s.useEffect(()=>{if(!l){F(null),S("ready");return}let a=!0;return F(null),E(!1),S("loading"),ce(n,l).then(i=>{a&&(F(i),S("ready"))}).catch(()=>{a&&S("error")}),()=>{a=!1}},[n,l,ue]);const W=s.useMemo(()=>Te((k==null?void 0:k.files)??[]),[k]),f=(k==null?void 0:k.changed)??[],J=f.reduce((a,i)=>a+i.add,0),Y=f.reduce((a,i)=>a+i.del,0),z=f.find(a=>a.path===l),X=!!r&&!r.binary&&r.content!==null&&Ce(l),Z=t==="session"?b.sessionReviewFileDownloadUrl:b.specReviewFileDownloadUrl,I=a=>{V(a),_("viewer")},q=t==="session"?"Kembali ke terminal":"Kembali ke backlog",K=!!(u||p||x),ve=`hanoman/${n.toLowerCase().replace(/[^a-z0-9_-]/g,"_")}`,pe=K?u?"Integrasi menggabungkan branch item ke cabang tujuan. Konflik dibereskan sesi agen di Terminal.":"Tinjau perubahan, lalu putuskan.":t==="session"?"Merge dan konflik dikerjakan di Terminal.":"Merge dan konflik dikerjakan di Backlog. Buka Terminal untuk melanjutkan sesinya.",B={section:"terminal"},G={section:"ide"},A={section:"backlog",specId:n},N=a=>o==null?void 0:o(a),g=(a,i,c,re)=>o?e.jsx(d,{size:"sm",variant:re,leftIcon:c,onClick:()=>N(a),children:i}):e.jsx(d,{size:"sm",variant:re,leftIcon:c,as:"a",href:Le(a),children:i});async function ee(){const a=u;if(a){m("");try{await P({title:`Integrasikan ${n}?`,eyebrow:n,icon:"git-merge",confirmLabel:"Integrasikan",tone:"default",message:"Branch item di-merge ke cabang tujuan. Bila ada konflik, sesi agen membereskannya di Terminal. Rebase tetap di Backlog.",impact:[`Branch: ${ve}`,`${f.length} berkas berubah, +${J} −${Y} baris`,`Cabang tujuan: ${v??"cabang asal item (default project)"}`],run:()=>a(n)})}catch(i){m(T("mengintegrasikan item",i))}}}async function ae(){const a=p;if(a){m("");try{const i=await a(n);if(!i||!("pending"in i))return;const c=i.wouldDelete;await P({title:`Kembalikan ${n} ke Dikerjakan?`,eyebrow:`${n} → Dikerjakan`,icon:"rotate-ccw",tone:c.length?"danger":"default",confirmLabel:c.length?"Hapus dokumen & kembalikan":"Kembalikan",message:c.length?`${c.length} berkas dokumen fase akan dihapus dari disk. Kode dan commit tidak disentuh.`:"Tak ada dokumen fase yang dihapus. Kode dan commit tidak disentuh.",impact:c,run:()=>a(n,!0)})}catch(i){m(T("mengembalikan status",i))}}}async function xe(){const a=L;if(a){m("");try{await P({title:`Hapus worktree ${n}?`,eyebrow:n,icon:"trash-2",tone:"danger",confirmLabel:"Hapus worktree",message:"Direktori worktree dipindah ke tempat sampah repo, lalu dibersihkan. Branch dan commit item tetap ada.",impact:["Sesi yang masih berjalan di worktree ini ditutup.","Perubahan yang belum di-commit di worktree ini ikut dibersihkan."],run:async()=>{await a(n),M(i=>i+1)}})}catch(i){m(T("menghapus worktree",i))}}}async function ie(){const a=x;if(a){m("");try{await a(n,!w)}catch(i){m(T("menandai ditinjau",i))}}}const ye={key:"backlog",label:"Buka di Backlog",icon:"list-checks",onSelect:()=>N(A)},Se={key:"terminal",label:"Buka di Terminal",icon:"terminal",onSelect:()=>N(B)},ne={key:"ide",label:"Buka di IDE",icon:"code",onSelect:()=>N(G)},te=t==="spec"?[ye]:[],Be=o?$?[...te,Se,ne]:K?[...te,ne]:[]:[],se=[...$?[...u?[{key:"integrate",label:"Integrasikan",icon:"git-merge",onSelect:()=>void ee()}]:[],...p?[{key:"revert",label:"Kembalikan ke Dikerjakan",icon:"rotate-ccw",onSelect:()=>void ae()}]:[],...x?[{key:"reviewed",label:w?"Batalkan tanda ditinjau":"Tandai ditinjau",icon:w?"rotate-ccw":"circle-check",onSelect:()=>void ie()}]:[]]:[],...Be,...L?[{key:"discard",label:"Hapus worktree",icon:"trash-2",tone:"danger",onSelect:()=>void xe()}]:[]];return D==="loading"?e.jsx(h,{kind:"loading",title:"Memuat review…",hint:n}):D==="error"?e.jsx(h,{kind:"error",title:"Gagal memuat review",hint:n,action:()=>M(a=>a+1)}):D==="empty"?e.jsxs("div",{className:"hn-review-empty","data-review-state":"empty","data-reason":R??"409","data-status":R?"200":"409","data-detail":oe||void 0,children:[e.jsx(h,{kind:"empty",icon:"git-branch",title:"Belum ada perubahan untuk ditinjau",hint:R==="no-commit"?"Worktree sudah dilepas dan belum ada commit untuk ditinjau. Jalankan sesinya lagi bila perlu.":"Sesi belum membuat worktree. Jalankan atau lanjutkan sesinya dulu, lalu muat ulang."}),e.jsxs(De,{gap:2,justify:"center",children:[t==="spec"&&g(A,"Buka di Backlog","list-checks","primary"),g(B,"Buka di Terminal","terminal",t==="session"?"primary":"secondary"),e.jsx(d,{size:"sm",variant:"ghost",leftIcon:"arrow-left",onClick:j,children:q})]})]}):e.jsxs("div",{className:"hn-review",children:[e.jsxs("header",{className:"hn-review-topbar",children:[e.jsx(d,{size:"sm",variant:"ghost",leftIcon:"arrow-left",onClick:j,children:q}),e.jsx(d,{size:"sm",variant:"ghost",leftIcon:"rotate-ccw",onClick:()=>M(a=>a+1),children:"Muat ulang"})]}),e.jsxs("div",{className:"hn-review-head",children:[e.jsx("span",{className:"hn-eyebrow",children:n}),e.jsx("h2",{className:"hn-review-title",children:C||n}),e.jsxs("p",{className:"hn-review-stat",children:[f.length," berkas berubah · ",e.jsx("span",{className:"hn-review-delta",children:`+${J} −${Y}`})," baris"]})]}),e.jsx(Re,{ariaLabel:"Panel Review",active:we,onActiveChange:a=>_(a),masterWidth:300,panels:[{id:"files",label:"Files",content:e.jsxs("section",{className:"hn-review-pane","aria-label":"Daftar berkas",children:[e.jsxs("div",{className:"hn-review-list",children:[e.jsx(Fe,{label:"Changed",changed:f,selected:l,onSelect:I,view:fe,onView:ge}),e.jsx("div",{className:"hn-eyebrow hn-review-sep",children:"Semua berkas"}),e.jsx(Me,{label:"Pohon berkas",nodes:W,children:W.map(a=>e.jsx(Ee,{node:a,selected:l,onSelect:I},a.path))})]}),e.jsx("p",{className:"hn-review-legend",children:"A = baru · M = diubah · D = dihapus"})]})},{id:"viewer",label:"Viewer",content:e.jsxs("section",{className:"hn-review-viewer","aria-label":"Isi berkas",children:[e.jsxs("div",{className:"hn-review-viewbar",children:[e.jsx(Pe,{name:"file-text",size:15,color:"var(--text-muted)"}),e.jsx("span",{className:"hn-review-path",children:l||"—"}),(r==null?void 0:r.status)&&e.jsx($e,{tone:r.status==="D"?"err":r.status==="A"?"ok":"brass",size:"sm",children:r.status}),z&&e.jsxs("span",{className:"hn-review-filestat",children:["+",z.add," −",z.del]}),X&&e.jsx(d,{size:"sm",variant:"secondary",leftIcon:"book-open",onClick:()=>E(!0),children:"Preview"}),e.jsx("div",{className:"hn-review-seg",children:["diff","source"].map(a=>e.jsx("button",{type:"button","aria-pressed":O===a,onClick:()=>he(a),children:a==="diff"?"Diff":"Sumber"},a))})]}),e.jsx("div",{className:"hn-review-body",children:l?de==="error"?e.jsx(h,{kind:"error",title:"Gagal memuat berkas",hint:l,action:()=>me(a=>a+1)}):r?r.binary?e.jsx(h,{kind:"empty",icon:"file",title:"Berkas biner",hint:"Tak dapat di-review dari dashboard."}):O==="diff"?e.jsxs("div",{className:"hn-review-diff",children:[e.jsx(ze,{diff:r.diff??"",emptyHint:"File ini bagian dari project, tetapi tidak diubah oleh item ini."}),r.truncated&&e.jsxs("div",{className:"hn-review-truncated",children:[e.jsx("span",{children:"… dipotong pada 256 KB."}),e.jsx("a",{href:Z(n,l,"md"),download:!0,children:"Unduh berkas utuh"})]})]}):r.content===null?e.jsx(h,{kind:"empty",icon:"trash-2",title:"File dihapus",hint:"Tak ada isi untuk ditampilkan."}):e.jsx("pre",{className:"hn-review-pre",children:r.content}):e.jsx(h,{kind:"loading",title:"Memuat file…",hint:l}):e.jsx(h,{kind:"empty",icon:"file-text",title:"Pilih file",hint:"Pilih file dari changed atau tree."})})]})}]}),e.jsxs("div",{className:"hn-review-decide",role:"region","aria-label":"Keputusan",children:[Q&&e.jsx(Ke,{tone:"err",className:"hn-review-decide-err",children:Q}),e.jsx("p",{className:"hn-review-decide-hint",children:pe}),e.jsxs("div",{className:"hn-review-decide-actions",children:[!$&&(K?e.jsxs(e.Fragment,{children:[p&&e.jsx(d,{size:"sm",variant:"secondary",leftIcon:"rotate-ccw",onClick:()=>void ae(),children:"Kembalikan ke Dikerjakan"}),x&&e.jsx(d,{size:"sm",variant:"secondary",leftIcon:w?"rotate-ccw":"circle-check",onClick:()=>void ie(),children:w?"Batalkan tanda ditinjau":"Tandai ditinjau"}),u&&e.jsx(d,{size:"sm",variant:"primary",leftIcon:"git-merge",onClick:()=>void ee(),children:"Integrasikan"}),g(B,"Buka di Terminal","terminal","secondary")]}):e.jsxs(e.Fragment,{children:[t==="spec"&&g(A,"Buka di Backlog","list-checks","primary"),g(B,"Buka di Terminal","terminal",t==="session"?"primary":"secondary"),g(G,"Buka di IDE","code","secondary")]})),se.length>0&&e.jsx("div",{className:"hn-review-more",children:e.jsx(Ae,{label:"Aksi lain",items:se})})]})]}),je,be&&X&&e.jsx(Ue,{path:l,text:r.content??"",eyebrow:n,download:a=>Z(n,l,a),onClose:()=>E(!1)})]})}export{Ze as ReviewScreen};
|
|
1
|
+
import{d as Ne,aM as Te,aO as Ce,j as e,m as h,bo as De,B as d,U as Re,bp as Fe,aL as Me,aN as Ee,I as Pe,n as $e,aQ as ze,C as Ke,O as Ae,h as b,bq as Le,i as T}from"./index-R2HBkTbR.js";import{R as s}from"./react-DfGhg7ZW.js";import{D as Ue}from"./DocPreviewModal-Cu0UFzPH.js";import"./markdown-CWEY34jk.js";import"./xterm-3VOAfa_q.js";const He="(max-width: 399px)";function Ve(){const n=()=>typeof window<"u"&&typeof window.matchMedia=="function"?window.matchMedia(He):null,[C,j]=s.useState(()=>{var t;return((t=n())==null?void 0:t.matches)??!1});return s.useEffect(()=>{var u;const t=n();if(!t)return;const o=()=>j(t.matches);return o(),(u=t.addEventListener)==null||u.call(t,"change",o),()=>{var v;return(v=t.removeEventListener)==null?void 0:v.call(t,"change",o)}},[]),C}function Ze({specId:n,title:C,onBack:j,kind:t="spec",onGoto:o,onIntegrate:u,integrateTarget:v,onRevert:p,onDiscard:L,reviewed:w=!1,onMarkReviewed:x}){const le=t==="session"?b.sessionReview:b.specReview,ce=t==="session"?b.sessionReviewFile:b.specReviewFile,[k,U]=s.useState(null),[D,y]=s.useState("loading"),[oe,Oe]=s.useState(""),[R,H]=s.useState(),[l,V]=s.useState(""),[r,F]=s.useState(null),[de,S]=s.useState("loading"),[ue,me]=s.useState(0),[O,he]=s.useState("diff"),[ke,M]=s.useState(0),[fe,ge]=s.useState("list"),[be,E]=s.useState(!1),[we,_]=s.useState("files"),{confirm:P,dialog:je}=Ne(),[Q,m]=s.useState(""),$=Ve();s.useEffect(()=>{let a=!0;return y("loading"),le(n).then(i=>{var c;if(a){if(i.empty){U(null),H(i.reason),y("empty");return}U(i),H(void 0),y("ready"),V(((c=i.changed[0])==null?void 0:c.path)??i.files[0]??"")}}).catch(i=>{a&&(console.debug("review: gagal memuat",i==null?void 0:i.message),y("error"))}),()=>{a=!1}},[n,ke]),s.useEffect(()=>{if(!l){F(null),S("ready");return}let a=!0;return F(null),E(!1),S("loading"),ce(n,l).then(i=>{a&&(F(i),S("ready"))}).catch(()=>{a&&S("error")}),()=>{a=!1}},[n,l,ue]);const W=s.useMemo(()=>Te((k==null?void 0:k.files)??[]),[k]),f=(k==null?void 0:k.changed)??[],J=f.reduce((a,i)=>a+i.add,0),Y=f.reduce((a,i)=>a+i.del,0),z=f.find(a=>a.path===l),X=!!r&&!r.binary&&r.content!==null&&Ce(l),Z=t==="session"?b.sessionReviewFileDownloadUrl:b.specReviewFileDownloadUrl,q=a=>{V(a),_("viewer")},I=t==="session"?"Kembali ke terminal":"Kembali ke backlog",K=!!(u||p||x),ve=`hanoman/${n.toLowerCase().replace(/[^a-z0-9_-]/g,"_")}`,pe=K?u?"Integrasi menggabungkan branch item ke cabang tujuan. Konflik dibereskan sesi agen di Terminal.":"Tinjau perubahan, lalu putuskan.":t==="session"?"Merge dan konflik dikerjakan di Terminal.":"Merge dan konflik dikerjakan di Backlog. Buka Terminal untuk melanjutkan sesinya.",B={section:"terminal"},G={section:"ide"},A={section:"backlog",specId:n},N=a=>o==null?void 0:o(a),g=(a,i,c,re)=>o?e.jsx(d,{size:"sm",variant:re,leftIcon:c,onClick:()=>N(a),children:i}):e.jsx(d,{size:"sm",variant:re,leftIcon:c,as:"a",href:Le(a),children:i});async function ee(){const a=u;if(a){m("");try{await P({title:`Integrasikan ${n}?`,eyebrow:n,icon:"git-merge",confirmLabel:"Integrasikan",tone:"default",message:"Branch item di-merge ke cabang tujuan. Bila ada konflik, sesi agen membereskannya di Terminal. Rebase tetap di Backlog.",impact:[`Branch: ${ve}`,`${f.length} berkas berubah, +${J} −${Y} baris`,`Cabang tujuan: ${v??"cabang asal item (default project)"}`],run:()=>a(n)})}catch(i){m(T("mengintegrasikan item",i))}}}async function ae(){const a=p;if(a){m("");try{const i=await a(n);if(!i||!("pending"in i))return;const c=i.wouldDelete;await P({title:`Kembalikan ${n} ke Dikerjakan?`,eyebrow:`${n} → Dikerjakan`,icon:"rotate-ccw",tone:c.length?"danger":"default",confirmLabel:c.length?"Hapus dokumen & kembalikan":"Kembalikan",message:c.length?`${c.length} berkas dokumen fase akan dihapus dari disk. Kode dan commit tidak disentuh.`:"Tak ada dokumen fase yang dihapus. Kode dan commit tidak disentuh.",impact:c,run:()=>a(n,!0)})}catch(i){m(T("mengembalikan status",i))}}}async function xe(){const a=L;if(a){m("");try{await P({title:`Hapus worktree ${n}?`,eyebrow:n,icon:"trash-2",tone:"danger",confirmLabel:"Hapus worktree",message:"Direktori worktree dipindah ke tempat sampah repo, lalu dibersihkan. Branch dan commit item tetap ada.",impact:["Sesi yang masih berjalan di worktree ini ditutup.","Perubahan yang belum di-commit di worktree ini ikut dibersihkan."],run:async()=>{await a(n),M(i=>i+1)}})}catch(i){m(T("menghapus worktree",i))}}}async function ie(){const a=x;if(a){m("");try{await a(n,!w)}catch(i){m(T("menandai ditinjau",i))}}}const ye={key:"backlog",label:"Buka di Backlog",icon:"list-checks",onSelect:()=>N(A)},Se={key:"terminal",label:"Buka di Terminal",icon:"terminal",onSelect:()=>N(B)},ne={key:"ide",label:"Buka di IDE",icon:"code",onSelect:()=>N(G)},te=t==="spec"?[ye]:[],Be=o?$?[...te,Se,ne]:K?[...te,ne]:[]:[],se=[...$?[...u?[{key:"integrate",label:"Integrasikan",icon:"git-merge",onSelect:()=>void ee()}]:[],...p?[{key:"revert",label:"Kembalikan ke Dikerjakan",icon:"rotate-ccw",onSelect:()=>void ae()}]:[],...x?[{key:"reviewed",label:w?"Batalkan tanda ditinjau":"Tandai ditinjau",icon:w?"rotate-ccw":"circle-check",onSelect:()=>void ie()}]:[]]:[],...Be,...L?[{key:"discard",label:"Hapus worktree",icon:"trash-2",tone:"danger",onSelect:()=>void xe()}]:[]];return D==="loading"?e.jsx(h,{kind:"loading",title:"Memuat review…",hint:n}):D==="error"?e.jsx(h,{kind:"error",title:"Gagal memuat review",hint:n,action:()=>M(a=>a+1)}):D==="empty"?e.jsxs("div",{className:"hn-review-empty","data-review-state":"empty","data-reason":R??"409","data-status":R?"200":"409","data-detail":oe||void 0,children:[e.jsx(h,{kind:"empty",icon:"git-branch",title:"Belum ada perubahan untuk ditinjau",hint:R==="no-commit"?"Worktree sudah dilepas dan belum ada commit untuk ditinjau. Jalankan sesinya lagi bila perlu.":"Sesi belum membuat worktree. Jalankan atau lanjutkan sesinya dulu, lalu muat ulang."}),e.jsxs(De,{gap:2,justify:"center",children:[t==="spec"&&g(A,"Buka di Backlog","list-checks","primary"),g(B,"Buka di Terminal","terminal",t==="session"?"primary":"secondary"),e.jsx(d,{size:"sm",variant:"ghost",leftIcon:"arrow-left",onClick:j,children:I})]})]}):e.jsxs("div",{className:"hn-review",children:[e.jsxs("header",{className:"hn-review-topbar",children:[e.jsx(d,{size:"sm",variant:"ghost",leftIcon:"arrow-left",onClick:j,children:I}),e.jsx(d,{size:"sm",variant:"ghost",leftIcon:"rotate-ccw",onClick:()=>M(a=>a+1),children:"Muat ulang"})]}),e.jsxs("div",{className:"hn-review-head",children:[e.jsx("span",{className:"hn-eyebrow",children:n}),e.jsx("h2",{className:"hn-review-title",children:C||n}),e.jsxs("p",{className:"hn-review-stat",children:[f.length," berkas berubah · ",e.jsx("span",{className:"hn-review-delta",children:`+${J} −${Y}`})," baris"]})]}),e.jsx(Re,{ariaLabel:"Panel Review",active:we,onActiveChange:a=>_(a),masterWidth:300,panels:[{id:"files",label:"Files",content:e.jsxs("section",{className:"hn-review-pane","aria-label":"Daftar berkas",children:[e.jsxs("div",{className:"hn-review-list",children:[e.jsx(Fe,{label:"Changed",changed:f,selected:l,onSelect:q,view:fe,onView:ge}),e.jsx("div",{className:"hn-eyebrow hn-review-sep",children:"Semua berkas"}),e.jsx(Me,{label:"Pohon berkas",nodes:W,children:W.map(a=>e.jsx(Ee,{node:a,selected:l,onSelect:q},a.path))})]}),e.jsx("p",{className:"hn-review-legend",children:"A = baru · M = diubah · D = dihapus"})]})},{id:"viewer",label:"Viewer",content:e.jsxs("section",{className:"hn-review-viewer","aria-label":"Isi berkas",children:[e.jsxs("div",{className:"hn-review-viewbar",children:[e.jsx(Pe,{name:"file-text",size:15,color:"var(--text-muted)"}),e.jsx("span",{className:"hn-review-path",children:l||"—"}),(r==null?void 0:r.status)&&e.jsx($e,{tone:r.status==="D"?"err":r.status==="A"?"ok":"brass",size:"sm",children:r.status}),z&&e.jsxs("span",{className:"hn-review-filestat",children:["+",z.add," −",z.del]}),X&&e.jsx(d,{size:"sm",variant:"secondary",leftIcon:"book-open",onClick:()=>E(!0),children:"Preview"}),e.jsx("div",{className:"hn-review-seg",children:["diff","source"].map(a=>e.jsx("button",{type:"button","aria-pressed":O===a,onClick:()=>he(a),children:a==="diff"?"Diff":"Sumber"},a))})]}),e.jsx("div",{className:"hn-review-body",children:l?de==="error"?e.jsx(h,{kind:"error",title:"Gagal memuat berkas",hint:l,action:()=>me(a=>a+1)}):r?r.binary?e.jsx(h,{kind:"empty",icon:"file",title:"Berkas biner",hint:"Tak dapat di-review dari dashboard."}):O==="diff"?e.jsxs("div",{className:"hn-review-diff",children:[e.jsx(ze,{diff:r.diff??"",emptyHint:"File ini bagian dari project, tetapi tidak diubah oleh item ini."}),r.truncated&&e.jsxs("div",{className:"hn-review-truncated",children:[e.jsx("span",{children:"… dipotong pada 256 KB."}),e.jsx("a",{href:Z(n,l,"md"),download:!0,children:"Unduh berkas utuh"})]})]}):r.content===null?e.jsx(h,{kind:"empty",icon:"trash-2",title:"File dihapus",hint:"Tak ada isi untuk ditampilkan."}):e.jsx("pre",{className:"hn-review-pre",children:r.content}):e.jsx(h,{kind:"loading",title:"Memuat file…",hint:l}):e.jsx(h,{kind:"empty",icon:"file-text",title:"Pilih file",hint:"Pilih file dari changed atau tree."})})]})}]}),e.jsxs("div",{className:"hn-review-decide",role:"region","aria-label":"Keputusan",children:[Q&&e.jsx(Ke,{tone:"err",className:"hn-review-decide-err",children:Q}),e.jsx("p",{className:"hn-review-decide-hint",children:pe}),e.jsxs("div",{className:"hn-review-decide-actions",children:[!$&&(K?e.jsxs(e.Fragment,{children:[p&&e.jsx(d,{size:"sm",variant:"secondary",leftIcon:"rotate-ccw",onClick:()=>void ae(),children:"Kembalikan ke Dikerjakan"}),x&&e.jsx(d,{size:"sm",variant:"secondary",leftIcon:w?"rotate-ccw":"circle-check",onClick:()=>void ie(),children:w?"Batalkan tanda ditinjau":"Tandai ditinjau"}),u&&e.jsx(d,{size:"sm",variant:"primary",leftIcon:"git-merge",onClick:()=>void ee(),children:"Integrasikan"}),g(B,"Buka di Terminal","terminal","secondary")]}):e.jsxs(e.Fragment,{children:[t==="spec"&&g(A,"Buka di Backlog","list-checks","primary"),g(B,"Buka di Terminal","terminal",t==="session"?"primary":"secondary"),g(G,"Buka di IDE","code","secondary")]})),se.length>0&&e.jsx("div",{className:"hn-review-more",children:e.jsx(Ae,{label:"Aksi lain",items:se})})]})]}),je,be&&X&&e.jsx(Ue,{path:l,text:r.content??"",eyebrow:n,download:a=>Z(n,l,a),onClose:()=>E(!1)})]})}export{Ze as ReviewScreen};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{h as N,i as E,j as e,L as G,R as ee,X as H,n as F,B as C,a2 as le,aR as Je,Z as ie,d as Le,q as J,D as Ge,V as ke,W as Ke,a_ as Qe,a$ as Ye,g as O,I as We,aK as Ze,b0 as Ve,O as Xe,M as qe,c as Re,aX as T,e as R,f as $,b1 as ea,H as aa,b2 as xe,b3 as we,ab as na,b4 as sa,b5 as re,l as X,b6 as ta,r as Ee,G as Be,m as ra,Y as la,b7 as ia,b8 as ca,b9 as oa,ba as da,P as ua,bb as q,F as ha,bc as Ae,_ as ma}from"./index-C5P4ykKO.js";import{R as i}from"./react-DfGhg7ZW.js";import{L as pa}from"./live-DQen7wLm.js";import"./markdown-CWEY34jk.js";import{I as W,b as ja,c as _,f as ba,u as xa,a as Me,d as ka}from"./sched-lead-shared-C34TvLVv.js";/* empty css */import{r as ga,O as fa}from"./settings-rebase-DHIWk4mV.js";import"./xterm-3VOAfa_q.js";const Se=10,va=a=>a<1024?`${a} B`:`${(a/1024).toFixed(1)} KiB`;function ya(a){const s=URL.createObjectURL(new Blob([a.body],{type:"text/markdown;charset=utf-8"})),t=document.createElement("a");t.href=s,t.download=a.filename,t.click(),URL.revokeObjectURL(s)}function wa({id:a}){const[s,t]=i.useState(null),[r,x]=i.useState(null),m=i.useCallback(()=>{let p=!0;return N.getCronReport(a).then(c=>{p&&(t(c),x(null))}).catch(c=>{p&&x(E("memuat laporan",c))}),()=>{p=!1}},[a]);return i.useEffect(()=>m(),[m]),r?e.jsx(W,{message:r,onRetry:()=>{m()}}):s?e.jsxs("div",{className:"hn-sched-report-body",children:[e.jsxs("div",{className:"hn-sched-report-actions",children:[e.jsx("span",{className:"hn-sched-row-meta",children:s.filename}),e.jsx(C,{size:"sm",variant:"ghost",leftIcon:"download",onClick:()=>ya(s),children:"Unduh .md"})]}),e.jsx(Je,{text:s.body,name:s.filename})]}):e.jsx(G,{rows:2,label:"Memuat laporan…"})}function Sa({projectId:a,projectName:s}){const[t,r]=i.useState([]),[x,m]=i.useState(0),[p,c]=i.useState(1),[w,g]=i.useState(!1),[h,S]=i.useState(null),[u,l]=i.useState(null),o=i.useCallback(()=>{let b=!0;return N.listCronReports({projectId:a,page:p,limit:Se}).then(P=>{b&&(r(P.items),m(P.total),g(!0),S(null))}).catch(P=>{b&&(S(E("memuat laporan cron",P)),g(!0))}),()=>{b=!1}},[a,p]);if(i.useEffect(()=>{c(1),l(null)},[a]),i.useEffect(()=>(g(!1),o()),[o]),h)return e.jsx(W,{message:h,onRetry:()=>{o()}});if(!w)return e.jsx(G,{rows:2,label:"Memuat laporan cron…"});if(x===0)return e.jsx("p",{className:"hn-sched-empty",children:"Belum ada laporan. Laporan tersimpan otomatis dari pesan akhir tiap run cron."});const k=ie(x,p,Se),B=!a&&s,I=B?[...t].sort((b,P)=>t.findIndex(A=>A.projectId===b.projectId)-t.findIndex(A=>A.projectId===P.projectId)):t;return e.jsxs(e.Fragment,{children:[e.jsx(ee,{label:"Laporan run cron",children:I.map((b,P)=>{var A;return e.jsxs(i.Fragment,{children:[B&&b.projectId!==((A=I[P-1])==null?void 0:A.projectId)&&e.jsx("h4",{className:"hn-sched-group-title hn-sched-group-sub",children:s(b.projectId)}),e.jsx(H,{children:e.jsxs("span",{className:"hn-sched-row-text",children:[e.jsxs("span",{className:"hn-sched-row-head",children:[e.jsx("span",{className:"hn-sched-row-title",children:b.cronName}),e.jsx(F,{tone:"neutral",size:"sm",children:b.runDate}),e.jsx(C,{size:"sm",variant:"ghost","aria-expanded":u===b.id,onClick:()=>l(u===b.id?null:b.id),children:u===b.id?"Sembunyikan":"Baca"})]}),e.jsxs("span",{className:"hn-sched-row-meta",children:[va(b.bytes)," · ",b.filename]}),u===b.id&&e.jsx(wa,{id:b.id})]})})]},b.id)})}),e.jsx(le,{page:k.page,pageCount:k.pageCount,total:x,from:k.from,to:k.to,onPage:c,unit:"laporan"})]})}const Y=10,Ca=500,me=a=>{var s;return(s=a.detail)==null?void 0:s.error},pe=a=>String(a).padStart(2,"0"),Ce=a=>{const s={name:(a==null?void 0:a.name)??"",prompt:(a==null?void 0:a.prompt)??"",enabled:(a==null?void 0:a.enabled)??!1,kind:"lanjutan",time:"07:00",weekday:1,everyHours:"6",expr:(a==null?void 0:a.expr)??"0 7 * * *",agent:(a==null?void 0:a.agent)??"",model:(a==null?void 0:a.model)??"",effort:(a==null?void 0:a.effort)??""},t=a?sa(a.expr):{kind:"harian",hour:7,minute:0};if(!t)return s;if(t.kind==="tiap-n-jam")return{...s,kind:t.kind,everyHours:String(t.everyHours),time:`00:${pe(t.minute)}`};const r=`${pe(t.hour)}:${pe(t.minute)}`;return t.kind==="mingguan"?{...s,kind:t.kind,time:r,weekday:t.weekday}:{...s,kind:t.kind,time:r}},Na=a=>{if(a.kind==="lanjutan")return a.expr.trim();const[s,t]=a.time.split(":").map(Number);switch(a.kind){case"harian":return re({kind:"harian",hour:s,minute:t});case"hari-kerja":return re({kind:"hari-kerja",hour:s,minute:t});case"mingguan":return re({kind:"mingguan",hour:s,minute:t,weekday:a.weekday});case"tiap-n-jam":return re({kind:"tiap-n-jam",everyHours:_(a.everyHours,1,23,6),minute:t})}},Ia={launched:"ok",queued:"neutral",skipped:"warn",failed:"err"};function Pa({cronId:a,at:s}){const[t,r]=i.useState([]),[x,m]=i.useState(0),[p,c]=i.useState(!1),[w,g]=i.useState(null),[h,S]=J("scheduler","cronRunsPage",1,ke),u=i.useCallback(()=>{let o=!0;return N.listCronRuns(a,{page:h,limit:Y}).then(k=>{o&&(r(k.items),m(k.total),c(!0),g(null))}).catch(k=>{o&&(g(E("memuat riwayat",k)),c(!0))}),()=>{o=!1}},[a,h]);if(i.useEffect(()=>u(),[u]),w)return e.jsx(W,{message:w,onRetry:()=>{u()}});if(!p)return e.jsx(G,{rows:2,label:"Memuat riwayat…"});if(x===0)return e.jsx("p",{className:"hn-sched-empty",children:"Belum ada eksekusi."});const l=ie(x,h,Y);return e.jsxs(e.Fragment,{children:[e.jsx(ee,{label:"Riwayat eksekusi",children:t.map(o=>e.jsx(H,{children:e.jsxs("span",{className:"hn-sched-row-text",children:[e.jsx("span",{className:"hn-sched-row-head",children:e.jsx(F,{tone:Ia[o.status]??"neutral",size:"sm",children:X(ta,o.status)})}),e.jsxs("span",{className:"hn-sched-row-meta",children:["jatuh tempo ",s(o.dueAt),o.startedAt?` · mulai ${s(o.startedAt)}`:"",o.manual?" · uji coba":"",o.note?` · ${o.note}`:""]})]})},o.id))}),e.jsx(le,{page:l.page,pageCount:l.pageCount,total:x,from:l.from,to:l.to,onPage:S,unit:"run"})]})}function La({projects:a,onProjectChanged:s,onToast:t,timeZone:r}){const{confirm:x,dialog:m}=Le(),p=r??ja(),c=n=>ba(n,p),[w,g]=J("scheduler","cronProject","",Ge),h=a.some(n=>n.id===w)?w:"",[S,u]=J("scheduler","cronListPage",1,ke),[l,o]=i.useState(""),[k,B]=i.useState([]),[I,b]=i.useState(!1),[P,A]=i.useState(null),[D,U]=i.useState(void 0),[j,L]=i.useState(Ce()),[M,ne]=i.useState("dasar"),[Z,f]=J("scheduler","cronOpenRuns",null,Ke),[y,v]=i.useState(!1),se=a.find(n=>n.id===h),K=i.useCallback(()=>{if(a.length===0){B([]),A(null),b(!0);return}N.listCrons({projectId:h||void 0,page:1,limit:Ca}).then(n=>{B(n.items),A(null),b(!0)}).catch(n=>{A(E("memuat daftar cron",n)),b(!0)})},[h,a.length]);i.useEffect(()=>{B([]),b(!1),K()},[K]);const ce=n=>{var d;return((d=a.find(z=>z.id===n))==null?void 0:d.name)??"Project lain"},V=i.useMemo(()=>{const n=new Map(a.map((d,z)=>[d.id,z]));return[...k].sort((d,z)=>(n.get(d.projectId)??1e9)-(n.get(z.projectId)??1e9))},[k,a]),Q=ie(V.length,S,Y),ge=V.slice((Q.page-1)*Y,Q.page*Y),fe=n=>{var d;U(n??null),L(Ce(n)),ne("dasar"),o(h||((d=a[0])==null?void 0:d.id)||"")},te=Na(j),oe=Qe(te)!==null,de=oe?Ye(te,new Date,p):null,$e=async()=>{if(!oe){t("Ekspresi cron tidak sah","err","x-circle");return}v(!0);try{D?await N.patchCron(D.id,{name:j.name,expr:te,prompt:j.prompt,enabled:j.enabled,agent:j.agent||null,model:j.model||null,effort:j.effort||null}):await N.createCron({project:l,name:j.name,expr:te,prompt:j.prompt,enabled:j.enabled,agent:j.agent||void 0,model:j.model||void 0,effort:j.effort||void 0}),t("Cron tersimpan","ok","save"),U(void 0),K()}catch(n){t(me(n)??E("menyimpan cron",n),"err","x-circle")}finally{v(!1)}},Fe=async n=>{v(!0);try{await N.runCronNow(n),t("Uji coba masuk antrean; sesi dibuka pada siklus berikutnya","ok","play")}catch(d){t(me(d)??E("menjalankan cron",d),"err","x-circle")}finally{v(!1),K()}},He=async n=>{v(!0);try{await N.deleteCron(n),t("Cron dihapus","ok","trash")}catch(d){t(me(d)??E("menghapus cron",d),"err","x-circle")}finally{v(!1),K()}},De=n=>{x({title:"Hapus cron ini?",eyebrow:"scheduler · cronjob",impact:[`Cron "${n.name}" di project ${ce(n.projectId)} dihapus permanen.`,"Jadwalnya berhenti dan tidak akan dijalankan lagi.","Tindakan ini tidak bisa dibatalkan."],confirmLabel:"Hapus cron",icon:"trash-2",tone:"danger",run:()=>He(n.id)})},Ue=async()=>{if(h)try{await N.updateProject(h,{schedulerOptIn:!0}),await s(h),t("Project diizinkan untuk scheduler","ok")}catch(n){t(E("mengizinkan project",n),"err","x-circle")}},Te=n=>[{key:"edit",label:"Ubah",icon:"pencil",onSelect:()=>fe(n)},{key:"run",label:"Jalankan sekarang",icon:"play",disabled:y,onSelect:()=>void Fe(n.id)},{key:"runs",label:Z===n.id?"Sembunyikan riwayat":"Riwayat",icon:"list",onSelect:()=>f(Z===n.id?null:n.id)},{key:"remove",label:"Hapus",icon:"trash",tone:"danger",disabled:y,onSelect:()=>De(n)}],ue=j.agent||"claude",ve=()=>L(n=>({...n,everyHours:String(_(n.everyHours,1,23,6))})),_e=oe?de?`Perkiraan jalan berikutnya: ${c(de.toISOString())}`:`Preview belum bisa dihitung untuk zona ${p}. Jam jalan berikutnya tampil di daftar cron.`:"Jadwal tidak sah, jadi tidak ada jalan berikutnya.";return e.jsxs("div",{className:"hn-sched-panel",children:[e.jsxs("div",{className:"hn-sched-toolbar",children:[e.jsx(O,{value:h,"aria-label":"Project",onChange:n=>{g(n.target.value),u(1)},options:[{value:"",label:"Semua project"},...a.map(n=>({value:n.id,label:n.name}))]}),e.jsx(C,{size:"sm",leftIcon:"plus",disabled:a.length===0,onClick:()=>fe(),children:"Cron baru"})]}),e.jsxs("p",{className:"hn-sched-caption",children:["Jam ditampilkan dalam zona server ",e.jsx("b",{children:p}),r===void 0?" (server belum melaporkan zonanya, jadi zona browser yang dipakai)":"","."]}),se&&!se.schedulerOptIn&&e.jsx("div",{className:"hn-sched-notice",children:e.jsxs("div",{className:"hn-dense-row",role:"note",children:[e.jsx(We,{name:"alert-triangle",size:16,color:"var(--clay-600)"}),e.jsx("span",{className:"hn-grow hn-sched-notice-text",children:"Project ini belum diizinkan untuk scheduler, jadi cron-nya tidak akan pernah dijalankan."}),e.jsx(C,{size:"sm",leftIcon:"check",onClick:()=>void Ue(),children:"Aktifkan scheduler di project ini"})]})}),P?e.jsx(W,{message:P,onRetry:K,busy:y}):I?k.length===0?e.jsx("p",{className:"hn-sched-empty",children:h?"Belum ada cron di project ini.":"Belum ada cron di project mana pun."}):e.jsx(Ze,{children:e.jsxs("table",{className:"hn-sched-table",children:[e.jsx("thead",{children:e.jsxs("tr",{children:[e.jsx("th",{scope:"col",children:"Cron"}),e.jsx("th",{scope:"col",children:"Jadwal"}),e.jsx("th",{scope:"col",children:"Terakhir"}),e.jsx("th",{scope:"col",children:"Berikutnya"}),e.jsx("th",{scope:"col",children:e.jsx("span",{className:"hn-sr-only",children:"Aksi"})})]})}),e.jsx("tbody",{children:ge.map((n,d)=>{var z,ye;return e.jsxs(i.Fragment,{children:[!h&&n.projectId!==((z=ge[d-1])==null?void 0:z.projectId)&&e.jsx("tr",{className:"hn-sched-group-row",children:e.jsx("th",{scope:"colgroup",colSpan:5,children:e.jsxs("span",{className:"hn-sched-row-head",children:[e.jsx("span",{className:"hn-sched-group-title",children:ce(n.projectId)}),e.jsxs(F,{tone:"neutral",size:"sm",children:[V.filter(he=>he.projectId===n.projectId).length," cron"]}),((ye=a.find(he=>he.id===n.projectId))==null?void 0:ye.schedulerOptIn)===!1&&e.jsx(F,{tone:"warn",size:"sm",children:"belum diizinkan"})]})})}),e.jsxs("tr",{children:[e.jsx("td",{"data-label":"Cron",children:e.jsxs("span",{className:"hn-sched-row-head",children:[e.jsx("span",{className:"hn-sched-row-title",children:n.name}),e.jsx(F,{tone:n.enabled?"ok":"neutral",size:"sm",children:n.enabled?"aktif":"nonaktif"})]})}),e.jsx("td",{"data-label":"Jadwal",children:Ve(n.expr)}),e.jsx("td",{"data-label":"Terakhir",children:c(n.lastRunAt)}),e.jsx("td",{"data-label":"Berikutnya",children:c(n.nextRunAt)}),e.jsx("td",{className:"hn-sched-cell-actions",children:e.jsx(Xe,{label:`Aksi untuk cron ${n.name}`,title:n.name,items:Te(n)})})]}),Z===n.id&&e.jsx("tr",{className:"hn-sched-runs",children:e.jsx("td",{colSpan:5,children:e.jsx("div",{id:`cron-runs-${n.id}`,children:e.jsx(Pa,{cronId:n.id,at:c})})})})]},n.id)})})]})}):e.jsx(G,{rows:3,label:"Memuat daftar cron…"}),!P&&I&&V.length>Y&&e.jsx(le,{page:Q.page,pageCount:Q.pageCount,total:V.length,from:Q.from,to:Q.to,onPage:u,unit:"cron"}),a.length>0&&e.jsxs("section",{className:"hn-sched-reports","aria-label":"Laporan run cron",children:[e.jsx("h3",{children:"Laporan run cron"}),e.jsx(Sa,{projectId:h||void 0,projectName:ce})]}),e.jsx(qe,{open:D!==void 0,title:D?"Ubah cron":"Cron baru",eyebrow:"scheduler",onClose:()=>U(void 0),width:640,footer:e.jsxs("div",{className:"hn-sched-savebar",children:[e.jsx(C,{size:"sm",variant:"ghost",onClick:()=>U(void 0),children:"Batal"}),e.jsx(C,{size:"sm",leftIcon:"save",disabled:y,onClick:()=>void $e(),children:"Simpan"})]}),children:e.jsxs(Re,{tabs:[{value:"dasar",label:"Dasar"},{value:"lanjutan",label:"Lanjutan"}],value:M,onChange:n=>ne(n),children:[e.jsxs(T,{value:"dasar",className:"hn-sched-panel",children:[!D&&!h&&e.jsx(R,{label:"Project",children:e.jsx(O,{"aria-label":"Project cron baru",value:l,onChange:n=>o(n.target.value),options:a.map(n=>({value:n.id,label:n.name}))})}),e.jsx(R,{label:"Nama cron",children:e.jsx($,{"aria-label":"Nama cron",placeholder:"mis. Cek error produksi pagi",value:j.name,onChange:n=>L(d=>({...d,name:n.target.value}))})}),e.jsxs("div",{className:"hn-sched-form-grid",children:[e.jsx(R,{label:"Preset jadwal",children:e.jsx(O,{"aria-label":"Preset jadwal",value:j.kind,onChange:n=>L(d=>({...d,kind:n.target.value})),options:[{value:"harian",label:"Setiap hari"},{value:"hari-kerja",label:"Hari kerja"},{value:"mingguan",label:"Mingguan"},{value:"tiap-n-jam",label:"Tiap N jam"},{value:"lanjutan",label:"Ekspresi cron (lanjutan)"}]})}),j.kind!=="lanjutan"&&e.jsx(R,{label:j.kind==="tiap-n-jam"?"Menit pada setiap jam":"Jam",children:e.jsx($,{type:"time","aria-label":"Jam",value:j.time,onChange:n=>L(d=>({...d,time:n.target.value}))})}),j.kind==="mingguan"&&e.jsx(R,{label:"Hari",children:e.jsx(O,{"aria-label":"Hari",value:String(j.weekday),onChange:n=>L(d=>({...d,weekday:Number(n.target.value)})),options:ea.map((n,d)=>({value:String(d),label:n}))})}),j.kind==="tiap-n-jam"&&e.jsx(R,{label:"Tiap berapa jam",children:e.jsx($,{type:"number",min:1,max:23,"aria-label":"Tiap berapa jam",placeholder:"mis. 6",value:j.everyHours,onChange:n=>L(d=>({...d,everyHours:n.target.value})),onBlur:ve,onKeyDown:n=>{n.key==="Enter"&&(n.preventDefault(),ve())}})})]}),j.kind==="lanjutan"&&e.jsx(R,{label:"Ekspresi cron",hint:"Lima bagian: menit, jam, tanggal, bulan, hari dalam minggu.",children:e.jsx($,{"aria-label":"Ekspresi cron",placeholder:"mis. 0 7 * * 1-5",value:j.expr,onChange:n=>L(d=>({...d,expr:n.target.value}))})}),e.jsx("p",{"data-testid":"cron-next-preview",className:`hn-sched-note${de?"":" hn-sched-preview-warn"}`,children:_e}),e.jsxs("p",{className:"hn-sched-note",children:["Jadwal berlaku menurut zona waktu server ",e.jsx("b",{children:p}),"."]}),e.jsx(R,{label:"Prompt",hint:"Instruksi bebas untuk agen. Temuan sebaiknya dicatat sebagai item backlog baru.",children:e.jsx(aa,{"aria-label":"Prompt",rows:6,placeholder:"mis. Periksa error 5xx sejak kemarin, lalu catat temuannya sebagai QA finding.",value:j.prompt,onChange:n=>L(d=>({...d,prompt:n.target.value}))})}),e.jsx(xe,{label:"Aktif",checked:j.enabled,onChange:n=>L(d=>({...d,enabled:n}))})]}),e.jsxs(T,{value:"lanjutan",className:"hn-sched-panel",children:[e.jsx("p",{className:"hn-sched-group-hint",children:"Kosongkan untuk mengikuti default sesi. Model dan effort baru tersedia setelah runtime dipilih."}),e.jsxs("div",{className:"hn-sched-form-grid",children:[e.jsx(R,{label:"Runtime",children:e.jsx(O,{"aria-label":"Runtime",value:j.agent,onChange:n=>L(d=>({...d,agent:n.target.value,model:"",effort:""})),options:[{value:"",label:"Ikuti default sesi"},{value:"claude",label:"Claude Code"},{value:"codex",label:"Codex CLI"}]})}),e.jsx(R,{label:"Model",children:e.jsx(O,{"aria-label":"Model",value:j.model,disabled:!j.agent,onChange:n=>L(d=>({...d,model:n.target.value,effort:""})),options:[{value:"",label:"Ikuti default"},...we(ue).map(n=>({value:n.id,label:n.label}))]})}),e.jsx(R,{label:"Effort",children:e.jsx(O,{"aria-label":"Effort",value:j.effort,disabled:!j.agent,onChange:n=>L(d=>({...d,effort:n.target.value})),options:[{value:"",label:"Ikuti default"},...na(ue,j.model||we(ue)[0].id).map(n=>({value:n,label:n}))]})})]})]})]})}),m]})}const ze=5e3,je=10,Ra=["antre","berjalan","riwayat","cron","setelan"],Ea=["done","failed","canceled"],Ne={done:"Selesai",failed:"Gagal",canceled:"Dibatalkan"},Ba={tinggi:"err",sedang:"warn",rendah:"neutral"},Aa=[{value:"butuh-keputusan",label:"Berhenti dan minta keputusan dulu"},{value:"full-control",label:"Jalan sampai selesai tanpa berhenti"}],Ie=a=>{var s;return(s=a.detail)==null?void 0:s.error};function Ma(a,s){var t;return((t=s.find(r=>r.id===a))==null?void 0:t.title)??a}function ae({specId:a,ctx:s}){return e.jsx("span",{className:"hn-sched-row-title",children:Ma(a,s.backlog)})}function za({q:a,ctx:s,busy:t,onCancel:r}){return e.jsx(H,{actions:e.jsx(C,{size:"sm",variant:"ghost",leftIcon:"ban",disabled:t,onClick:()=>r(a.id),children:"Batalkan"}),children:e.jsxs("span",{className:"hn-sched-row-text",children:[e.jsxs("span",{className:"hn-sched-row-head",children:[e.jsx(ae,{specId:a.specId,ctx:s}),e.jsx(F,{tone:Ba[a.priority]??"neutral",size:"sm",children:X(ua,a.priority)})]}),e.jsxs("span",{className:"hn-sched-row-meta",children:[s.projectName(a.projectId)," · ",X(q,a.source),a.note?` · ${a.note}`:""]})]})})}function Oa({s:a,ctx:s,onGotoTerminal:t}){const r=a.flow?ha[a.flow]??a.flow:"";return e.jsx(H,{actions:e.jsx(C,{size:"sm",variant:"ghost",leftIcon:"terminal",onClick:()=>t(a.id),children:"Buka terminal"}),children:e.jsxs("span",{className:"hn-sched-row-text",children:[e.jsxs("span",{className:"hn-sched-row-head",children:[e.jsx(ae,{specId:a.specId,ctx:s}),a.decision&&e.jsx(F,{tone:"warn",icon:"bell",size:"sm",children:"menunggu kamu"})]}),e.jsxs("span",{className:"hn-sched-row-meta",children:[s.projectName(a.projectId),r?` · ${r}`:""]})]})})}function $a({q:a,ctx:s,onToast:t}){const r=ma(a.specId);return e.jsx(H,{actions:e.jsxs(e.Fragment,{children:[e.jsx(C,{size:"sm",variant:"ghost",leftIcon:"external-link",onClick:()=>window.open(r,"_blank","noreferrer"),children:"Buka review"}),e.jsx(C,{size:"sm",variant:"ghost",leftIcon:"copy",onClick:()=>{var x;(x=navigator.clipboard)==null||x.writeText(r),t("Link review disalin","ok","copy")},children:"Salin"})]}),children:e.jsxs("span",{className:"hn-sched-row-text",children:[e.jsx(ae,{specId:a.specId,ctx:s}),e.jsxs("span",{className:"hn-sched-row-meta",children:[s.projectName(a.projectId)," · ",X(q,a.source)," · ",a.launchedAt?`selesai ${Me(a.launchedAt)}`:a.note??"tidak diluncurkan"]})]})})}function Fa({q:a,ctx:s,onRequeue:t,busy:r}){return e.jsx(H,{actions:e.jsx(C,{size:"sm",variant:"secondary",leftIcon:"rotate-ccw",disabled:r,onClick:()=>t(a.id),children:"Antre ulang"}),children:e.jsxs("span",{className:"hn-sched-row-text",children:[e.jsx(ae,{specId:a.specId,ctx:s}),e.jsxs("span",{className:"hn-sched-row-meta",children:[s.projectName(a.projectId)," · ",a.note??"gagal tanpa alasan tercatat"]})]})})}function Ha({q:a,ctx:s,onRequeue:t,busy:r}){return e.jsx(H,{actions:e.jsx(C,{size:"sm",variant:"ghost",leftIcon:"rotate-ccw",disabled:r,onClick:()=>t(a.id),children:"Antre lagi"}),children:e.jsxs("span",{className:"hn-sched-row-text",children:[e.jsx(ae,{specId:a.specId,ctx:s}),e.jsxs("span",{className:"hn-sched-row-meta",children:[s.projectName(a.projectId)," · ",X(q,a.source)," · ",a.note??"dibatalkan"]})]})})}function Oe({what:a,status:s,count:t,empty:r,render:x}){const[m,p]=i.useState([]),[c,w]=i.useState(0),[g,h]=i.useState(!1),[S,u]=i.useState(null),[l,o]=J("scheduler",`queue-${s}-page`,1,ke),k=i.useCallback(()=>{N.getSchedulerQueue({status:s,page:l,limit:je}).then(I=>{p(I.items),w(I.total),u(null),h(!0)}).catch(I=>{u(E(`memuat ${a}`,I)),h(!0)})},[s,l,a]);if(i.useEffect(()=>{k()},[k]),Be({topic:"schedulerQueue",params:{status:s,page:l,limit:je},apply:I=>{p(I.data.items),w(I.data.total),u(null),h(!0)},refetch:()=>{k()},pollMs:ze}),S)return e.jsx(W,{message:S,onRetry:k});if(t===0)return e.jsx("p",{className:"hn-sched-empty",children:r});if(!g)return e.jsx(G,{rows:3,label:`Memuat ${a}…`});const B=ie(c,l,je);return e.jsxs(e.Fragment,{children:[e.jsx(ee,{label:a,children:m.map(I=>x(I))}),e.jsx(le,{page:B.page,pageCount:B.pageCount,total:c,from:B.from,to:B.to,onPage:o,unit:"item"})]})}function Da({counts:a,ctx:s,busyId:t,onRowAction:r,onToast:x}){const m=Ea.filter(u=>(a[u]??0)>0),p=(a.failed??0)>0?"failed":(a.done??0)>0?"done":"canceled",[c,w]=J("scheduler","riwayatStatus",p,Ee("done","failed","canceled"));if(m.length===0)return e.jsx("p",{className:"hn-sched-empty",children:"Belum ada riwayat."});const g=m.includes(c)?c:m[0],h=u=>void r(u,"requeue"),S=u=>{const l=t===u.id;return g==="done"?e.jsx($a,{q:u,ctx:s,onToast:x},u.id):g==="failed"?e.jsx(Fa,{q:u,ctx:s,onRequeue:h,busy:l},u.id):e.jsx(Ha,{q:u,ctx:s,onRequeue:h,busy:l},u.id)};return e.jsxs(e.Fragment,{children:[e.jsx("div",{role:"group","aria-label":"Filter riwayat",className:"hn-sched-chips",children:m.map(u=>e.jsxs("button",{type:"button",className:"hn-sched-chip hn-touch-target","aria-pressed":u===g,onClick:()=>w(u),children:[Ne[u],e.jsx("span",{className:"hn-sched-chip-count",children:a[u]})]},u))}),e.jsx(Oe,{what:`item ${Ne[g].toLowerCase()}`,status:g,count:a[g]??0,empty:"Belum ada riwayat.",render:S},g)]})}function Ua({cfg:a,cap:s,liveCount:t,onWrite:r,onAsk:x,busy:m}){const p=a.enabled?a.paused?{status:"paused",label:"Dijeda"}:{status:"running",label:"Berjalan"}:{status:"stopped",label:"Berhenti"},c=t>=s;return e.jsxs("section",{"aria-label":"Status scheduler",className:"hn-sched-strip",children:[e.jsx(la,{status:p.status,variant:"dot",children:p.label}),e.jsx("div",{className:"hn-sched-capacity",children:e.jsx(ia,{value:t,max:Math.max(s,1),size:"sm",tone:c?"warn":"brass",label:`${t} dari ${s} sesi`})}),e.jsxs("div",{className:"hn-sched-limits",children:[e.jsx(ca,{}),e.jsx(oa,{}),e.jsx(da,{})]}),e.jsx(pa,{}),e.jsxs("div",{className:"hn-sched-strip-actions",children:[a.enabled?a.paused?e.jsx(C,{size:"sm",leftIcon:"play",disabled:m,onClick:()=>r({...a,paused:!1},"Scheduler dilanjutkan"),children:"Lanjutkan"}):e.jsx(C,{size:"sm",variant:"secondary",leftIcon:"pause",disabled:m,onClick:()=>x({...a,paused:!0},"jeda"),children:"Jeda"}):e.jsx(C,{size:"sm",leftIcon:"play",disabled:m,onClick:()=>r({...a,enabled:!0},"Scheduler diaktifkan"),children:"Aktifkan"}),a.enabled&&e.jsxs(e.Fragment,{children:[e.jsx("span",{className:"hn-sched-strip-divider","aria-hidden":"true"}),e.jsx(C,{size:"sm",variant:"danger",leftIcon:"square",disabled:m,onClick:()=>x({...a,enabled:!1},"hentikan"),children:"Hentikan"})]})]})]})}function Ta({status:a}){return e.jsxs("div",{"aria-label":"Status pemeriksaan peluncuran",className:"hn-sched-guard-status",children:[e.jsxs("div",{children:["Pemeriksaan ",a.enabled?"aktif":"nonaktif"," · ",a.liveCount," dari batas ",a.maxConcurrent," sesi berjalan (",a.liveAgentCount," di antaranya agen)"]}),e.jsxs("div",{children:["Beban CPU per inti: ",a.loadStatus==="available"&&a.loadPerCore!==null?a.loadPerCore.toFixed(2):"tidak tersedia",a.loadStatus==="unsupported"?" (tidak didukung platform)":""," · batas ",a.maxLoadPerCore]}),e.jsxs("div",{children:["Memori bebas: ",a.memStatus==="available"&&a.memAvailablePct!==null?`${a.memAvailablePct.toFixed(0)}%`:"tidak tersedia"," · minimal ",a.minMemAvailablePct,"%"]}),e.jsx("div",{className:"hn-sched-note",children:"Berlaku juga saat scheduler berhenti. Terminal dan shell tetap bisa dibuka, dan keduanya ikut dihitung dalam batas sesi."})]})}const be=a=>{const s=a.launchGuard??Ae.launchGuard;return{maxConcurrent:String(a.maxConcurrent),autonomy:a.autonomy,guardOn:s.enabled,maxLoad:String(s.maxLoadPerCore),minMem:String(s.minMemAvailablePct),sources:{backlog:{enabled:a.sources.backlog.enabled,everyMin:String(a.sources.backlog.everyMin)},triase:{enabled:a.sources.triase.enabled,everyMin:String(a.sources.triase.everyMin)}}}},Pe=(a,s)=>{const t=s.launchGuard??Ae.launchGuard,r=s.sources.backlog,x=s.sources.triase;return{...s,maxConcurrent:_(a.maxConcurrent,1,1/0,s.maxConcurrent),autonomy:a.autonomy,launchGuard:{...t,enabled:a.guardOn,maxLoadPerCore:_(a.maxLoad,.1,1/0,t.maxLoadPerCore,!1),minMemAvailablePct:_(a.minMem,0,100,t.minMemAvailablePct,!1)},sources:{...s.sources,backlog:{...r,enabled:a.sources.backlog.enabled,everyMin:_(a.sources.backlog.everyMin,1,1/0,r.everyMin)},triase:{...x,enabled:a.sources.triase.enabled,everyMin:_(a.sources.triase.everyMin,1,1/0,x.everyMin)}}}},_a=a=>`${a.lastRunAt?`terakhir ${Me(a.lastRunAt)}`:"belum pernah dicek"} · ${a.nextRunAt?`berikutnya ${ka(a.nextRunAt)}`:"belum dijadwalkan"}`;function Ja({cfg:a,sources:s,admission:t,onWrite:r,busy:x}){const{draft:m,setDraft:p,dirty:c}=xa(be(a)),w=l=>be(Pe(l,a)),g=()=>p(l=>w(l)),h=()=>{const l=Pe(m,a);p(be(l)),r(l)},S=l=>{l.key==="Enter"&&(l.preventDefault(),h())},u=(l,o)=>p(k=>({...k,sources:{...k.sources,[l]:{...k.sources[l],...o}}}));return e.jsxs("div",{className:"hn-sched-panel",children:[e.jsxs("section",{className:"hn-sched-group","aria-labelledby":"sched-set-sesi",children:[e.jsx("h3",{id:"sched-set-sesi",className:"hn-sched-group-title",children:"Sesi"}),e.jsxs("div",{className:"hn-sched-grid",children:[e.jsx(R,{label:"Batas sesi bersamaan",hint:"Termasuk terminal dan shell yang kamu buka sendiri.",children:e.jsx($,{type:"number",min:1,value:m.maxConcurrent,"aria-label":"Batas sesi bersamaan",placeholder:"mis. 6",onChange:l=>p(o=>({...o,maxConcurrent:l.target.value})),onBlur:g,onKeyDown:S})}),e.jsx(R,{label:"Saat ada keputusan yang belum jelas",hint:"Keputusan yang ambigu tetap ditanyakan ke lead atau kamu.",children:e.jsx(O,{value:m.autonomy,"aria-label":"Mode otonomi",onChange:l=>p(o=>({...o,autonomy:l.target.value})),options:Aa})})]})]}),e.jsxs("section",{className:"hn-sched-group","aria-labelledby":"sched-set-peluncuran",children:[e.jsx("h3",{id:"sched-set-peluncuran",className:"hn-sched-group-title",children:"Peluncuran"}),e.jsx(xe,{label:"Tahan peluncuran saat server sibuk",checked:m.guardOn,onChange:l=>p(o=>({...o,guardOn:l}))}),e.jsx("p",{className:"hn-sched-group-hint",children:"Mencegah sesi baru diluncurkan saat batas sesi penuh, beban CPU per inti terlalu tinggi, atau memori bebas terlalu sedikit. Berlaku juga untuk peluncuran manual. Mematikannya melewati ketiga pemeriksaan itu. Terpisah dari saklar scheduler dan sumber."}),e.jsxs("div",{className:"hn-sched-grid",children:[e.jsx(R,{label:"Batas beban CPU per inti",hint:"Di atas angka ini, sesi baru tidak diluncurkan.",children:e.jsx($,{type:"number",min:.1,step:"any",value:m.maxLoad,"aria-label":"Batas beban CPU per inti",placeholder:"mis. 2.5",onChange:l=>p(o=>({...o,maxLoad:l.target.value})),onBlur:g,onKeyDown:S})}),e.jsx(R,{label:"Memori bebas minimal (%)",hint:"Di bawah angka ini, sesi baru tidak diluncurkan.",children:e.jsx($,{type:"number",min:0,max:100,step:"any",value:m.minMem,"aria-label":"Memori bebas minimal (%)",placeholder:"mis. 15",onChange:l=>p(o=>({...o,minMem:l.target.value})),onBlur:g,onKeyDown:S})})]}),t&&e.jsx(Ta,{status:t})]}),e.jsxs("section",{className:"hn-sched-group","aria-labelledby":"sched-set-sumber",children:[e.jsx("h3",{id:"sched-set-sumber",className:"hn-sched-group-title",children:"Sumber otomatis"}),["backlog","triase"].map(l=>{const o=s.find(k=>k.id===l);return e.jsxs("div",{className:"hn-sched-source",children:[e.jsx(xe,{label:q[l],checked:m.sources[l].enabled,onChange:k=>u(l,{enabled:k})}),e.jsx("span",{className:"hn-sched-spacer"}),e.jsxs("label",{className:"hn-sched-inline-field",children:["cek tiap",e.jsx($,{type:"number",min:1,"aria-label":`Interval cek ${q[l]}`,placeholder:"mis. 30",value:m.sources[l].everyMin,onChange:k=>u(l,{everyMin:k.target.value}),onBlur:g,onKeyDown:S}),"menit"]}),o&&e.jsx("span",{className:"hn-sched-source-facts",children:_a(o)})]},l)})]}),e.jsxs("div",{className:"hn-sched-savebar",children:[c&&e.jsx("span",{role:"status",className:"hn-sched-note",children:"Ada perubahan yang belum disimpan."}),e.jsx(C,{leftIcon:"save",disabled:x,onClick:h,children:"Simpan setelan"})]})]})}function Ga({projects:a,onToggle:s,busyId:t}){return e.jsxs("section",{className:"hn-sched-group","aria-labelledby":"sched-set-project",children:[e.jsx("h3",{id:"sched-set-project",className:"hn-sched-group-title",children:"Project yang diizinkan"}),e.jsx("p",{className:"hn-sched-group-hint",children:"Scheduler hanya menyentuh project yang diizinkan. Default: tidak diizinkan."}),a.length===0?e.jsx("p",{className:"hn-sched-empty",children:"Belum ada project."}):e.jsx(ee,{label:"Project yang diizinkan",children:a.map(r=>e.jsx(H,{actions:r.schedulerOptIn?e.jsx(C,{size:"sm",variant:"ghost",leftIcon:"ban",disabled:t===r.id,onClick:()=>s(r.id,!1),children:"Cabut izin"}):e.jsx(C,{size:"sm",leftIcon:"check",disabled:t===r.id,onClick:()=>s(r.id,!0),children:"Izinkan"}),children:e.jsx("span",{className:"hn-sched-row-text",children:e.jsxs("span",{className:"hn-sched-row-head",children:[e.jsx("span",{className:"hn-sched-row-title",children:r.name}),e.jsx(F,{tone:r.schedulerOptIn?"ok":"neutral",size:"sm",children:r.schedulerOptIn?"diizinkan":"tidak diizinkan"})]})})},r.id))})]})}function Ka(a){const[s,t]=i.useState(null),[r,x]=i.useState(null),m=i.useCallback(()=>{N.getSettings().then(c=>{t(c),x(null)}).catch(c=>x(E("memuat orkestrasi",c)))},[]);i.useEffect(()=>{m()},[m]);const p=i.useCallback(async(c,w)=>{if(!s)return;const g=s;t({...g,orchestration:c});try{const h=await N.getSettings().catch(()=>{});await N.putSettings(ga(g,{...g,orchestration:c},h)),a(w,"ok","check-circle-2")}catch(h){t(g),a(E("menyimpan orkestrasi",h),"err","alert-triangle")}},[s,a]);return{setting:s,error:r,load:m,writeOrchestration:p}}function Qa({snap:a}){return e.jsxs("section",{className:"hn-sched-group","aria-labelledby":"sched-set-orkestrasi",children:[e.jsx("h3",{id:"sched-set-orkestrasi",className:"hn-sched-group-title",children:"Orkestrasi subagen per fase"}),e.jsx("p",{className:"hn-sched-group-hint",children:"Perubahan tersimpan saat diubah. Buka satu flow untuk mengatur model dan effort per fase."}),a.error?e.jsx(W,{message:a.error,onRetry:a.load}):a.setting?e.jsx(fa,{variant:"accordion",orchestration:a.setting.orchestration,onChange:(s,t)=>void a.writeOrchestration(s,t)}):e.jsx(G,{rows:2,label:"Memuat orkestrasi…"})]})}function nn({projects:a,backlog:s,onProjectChanged:t,onToast:r,onGotoTerminal:x}){const{confirm:m,dialog:p}=Le(),[c,w]=i.useState(null),[g,h]=i.useState("loading"),[S,u]=i.useState(!1),[l,o]=i.useState(null),[k,B]=J("scheduler","tab","antre",Ee(...Ra)),I=Ka(r),b=i.useCallback((f=!1)=>{f||h("loading"),N.getSchedulerState().then(y=>{w(y),h("ready")}).catch(()=>{f||h("error")})},[]);i.useEffect(()=>{b()},[b]),Be({topic:"schedulerState",params:{},apply:f=>{w(f.state),h("ready")},refetch:()=>b(!0),pollMs:ze});const P=i.useCallback(async(f,y="Setelan scheduler tersimpan")=>{u(!0);try{await N.putSchedulerConfig(f),r(y,"ok","save"),b(!0)}catch(v){r(Ie(v)??E("menyimpan setelan",v),"err","x-circle")}finally{u(!1)}},[b,r]),A=i.useCallback((f,y)=>{const v=y==="jeda";m({title:v?"Jeda scheduler?":"Hentikan scheduler?",eyebrow:"scheduler · rem darurat",message:v?"Scheduler berhenti meluncurkan sesi baru dari antrean sampai kamu melanjutkannya. Sesi yang sudah berjalan tidak dihentikan.":void 0,impact:v?void 0:["Sumber backlog dan triase tidak lagi diperiksa sampai diaktifkan lagi.","Antrean tetap tersimpan dan tidak diproses selama berhenti.","Sesi yang sudah berjalan tetap berjalan."],confirmLabel:v?"Jeda scheduler":"Hentikan scheduler",icon:v?"pause":"square",tone:v?"default":"danger",run:()=>P(f,v?"Scheduler dijeda":"Scheduler dihentikan")})},[m,P]),D=i.useCallback(async(f,y)=>{o(f);try{await N.updateProject(f,{schedulerOptIn:y}),await t(f),r(y?"Project diizinkan untuk scheduler":"Izin scheduler dicabut","ok")}catch(v){r(E("mengubah izin project",v),"err","x-circle")}finally{o(null)}},[t,r]),U=i.useCallback(async(f,y)=>{o(f);try{y==="cancel"?(await N.cancelSchedulerQueueItem(f),r("Item antrean dibatalkan","ok","ban")):(await N.requeueSchedulerQueueItem(f),r("Item dikembalikan ke antrean","ok","rotate-ccw"))}catch(v){const se=y==="cancel"?"membatalkan item antrean":"mengembalikan item ke antrean";r(Ie(v)??E(se,v),"err","x-circle")}finally{o(null),b(!0)}},[b,r]);if(g==="loading")return e.jsx(G,{rows:4,label:"Memuat scheduler…"});if(g==="error"||!c)return e.jsx(ra,{kind:"error",hint:"Gagal memuat state scheduler.",action:()=>b(),actionLabel:"Coba lagi"});const L={backlog:s,projectName:f=>{var y;return((y=a.find(v=>v.id===f))==null?void 0:y.name)??"Project lain"}},M=c.queueCounts,ne=(M.done??0)+(M.failed??0)+(M.canceled??0),Z=[{value:"antre",label:"Antre",count:M.queued||void 0},{value:"berjalan",label:"Berjalan",count:c.sessions.length||void 0},{value:"riwayat",label:"Riwayat",count:ne||void 0},{value:"cron",label:"Cron"},{value:"setelan",label:"Setelan"}];return e.jsxs("div",{className:"hn-sched",children:[e.jsx(Ua,{cfg:c.config,cap:c.cap,liveCount:c.liveCount,onWrite:P,onAsk:A,busy:S}),e.jsxs(Re,{tabs:Z,value:k,onChange:f=>B(f),children:[e.jsx(T,{value:"antre",className:"hn-sched-panel",children:e.jsx(Oe,{what:"antrean",status:"queued",count:M.queued,empty:"Antrean kosong.",render:f=>e.jsx(za,{q:f,ctx:L,busy:l===f.id,onCancel:y=>void U(y,"cancel")},f.id)})}),e.jsx(T,{value:"berjalan",className:"hn-sched-panel",children:c.sessions.length===0?e.jsx("p",{className:"hn-sched-empty",children:"Tidak ada sesi dari scheduler yang sedang berjalan."}):e.jsx(ee,{label:"Sesi berjalan",children:c.sessions.map(f=>e.jsx(Oa,{s:f,ctx:L,onGotoTerminal:x},f.id))})}),e.jsx(T,{value:"riwayat",className:"hn-sched-panel",children:k==="riwayat"&&e.jsx(Da,{counts:M,ctx:L,busyId:l,onRowAction:U,onToast:r})}),e.jsx(T,{value:"cron",className:"hn-sched-panel",children:k==="cron"&&e.jsx(La,{projects:a,onProjectChanged:t,onToast:r,timeZone:c.serverTimeZone})}),e.jsxs(T,{value:"setelan",className:"hn-sched-panel",children:[e.jsx(Ja,{cfg:c.config,sources:c.sources,admission:c.admission,onWrite:f=>void P(f),busy:S}),e.jsx(Ga,{projects:a,onToggle:D,busyId:l}),e.jsx(Qa,{snap:I})]})]}),p]})}export{nn as SchedulerScreen};
|
|
1
|
+
import{h as N,i as E,j as e,L as G,R as ee,X as H,n as F,B as C,a2 as le,aR as Je,Z as ie,d as Le,q as J,D as Ge,V as ke,W as Ke,a_ as Qe,a$ as Ye,g as O,I as We,aK as Ze,b0 as Ve,O as Xe,M as qe,c as Re,aX as T,e as R,f as $,b1 as ea,H as aa,b2 as xe,b3 as we,ab as na,b4 as sa,b5 as re,l as X,b6 as ta,r as Ee,G as Be,m as ra,Y as la,b7 as ia,b8 as ca,b9 as oa,ba as da,P as ua,bb as q,F as ha,bc as Ae,_ as ma}from"./index-R2HBkTbR.js";import{R as i}from"./react-DfGhg7ZW.js";import{L as pa}from"./live-V9nWiHoE.js";import"./markdown-CWEY34jk.js";import{I as W,b as ja,c as _,f as ba,u as xa,a as Me,d as ka}from"./sched-lead-shared-Dr48bY7n.js";/* empty css */import{r as ga,O as fa}from"./settings-rebase-DOqNAynI.js";import"./xterm-3VOAfa_q.js";const Se=10,va=a=>a<1024?`${a} B`:`${(a/1024).toFixed(1)} KiB`;function ya(a){const s=URL.createObjectURL(new Blob([a.body],{type:"text/markdown;charset=utf-8"})),t=document.createElement("a");t.href=s,t.download=a.filename,t.click(),URL.revokeObjectURL(s)}function wa({id:a}){const[s,t]=i.useState(null),[r,x]=i.useState(null),m=i.useCallback(()=>{let p=!0;return N.getCronReport(a).then(c=>{p&&(t(c),x(null))}).catch(c=>{p&&x(E("memuat laporan",c))}),()=>{p=!1}},[a]);return i.useEffect(()=>m(),[m]),r?e.jsx(W,{message:r,onRetry:()=>{m()}}):s?e.jsxs("div",{className:"hn-sched-report-body",children:[e.jsxs("div",{className:"hn-sched-report-actions",children:[e.jsx("span",{className:"hn-sched-row-meta",children:s.filename}),e.jsx(C,{size:"sm",variant:"ghost",leftIcon:"download",onClick:()=>ya(s),children:"Unduh .md"})]}),e.jsx(Je,{text:s.body,name:s.filename})]}):e.jsx(G,{rows:2,label:"Memuat laporan…"})}function Sa({projectId:a,projectName:s}){const[t,r]=i.useState([]),[x,m]=i.useState(0),[p,c]=i.useState(1),[w,g]=i.useState(!1),[h,S]=i.useState(null),[u,l]=i.useState(null),o=i.useCallback(()=>{let b=!0;return N.listCronReports({projectId:a,page:p,limit:Se}).then(P=>{b&&(r(P.items),m(P.total),g(!0),S(null))}).catch(P=>{b&&(S(E("memuat laporan cron",P)),g(!0))}),()=>{b=!1}},[a,p]);if(i.useEffect(()=>{c(1),l(null)},[a]),i.useEffect(()=>(g(!1),o()),[o]),h)return e.jsx(W,{message:h,onRetry:()=>{o()}});if(!w)return e.jsx(G,{rows:2,label:"Memuat laporan cron…"});if(x===0)return e.jsx("p",{className:"hn-sched-empty",children:"Belum ada laporan. Laporan tersimpan otomatis dari pesan akhir tiap run cron."});const k=ie(x,p,Se),B=!a&&s,I=B?[...t].sort((b,P)=>t.findIndex(A=>A.projectId===b.projectId)-t.findIndex(A=>A.projectId===P.projectId)):t;return e.jsxs(e.Fragment,{children:[e.jsx(ee,{label:"Laporan run cron",children:I.map((b,P)=>{var A;return e.jsxs(i.Fragment,{children:[B&&b.projectId!==((A=I[P-1])==null?void 0:A.projectId)&&e.jsx("h4",{className:"hn-sched-group-title hn-sched-group-sub",children:s(b.projectId)}),e.jsx(H,{children:e.jsxs("span",{className:"hn-sched-row-text",children:[e.jsxs("span",{className:"hn-sched-row-head",children:[e.jsx("span",{className:"hn-sched-row-title",children:b.cronName}),e.jsx(F,{tone:"neutral",size:"sm",children:b.runDate}),e.jsx(C,{size:"sm",variant:"ghost","aria-expanded":u===b.id,onClick:()=>l(u===b.id?null:b.id),children:u===b.id?"Sembunyikan":"Baca"})]}),e.jsxs("span",{className:"hn-sched-row-meta",children:[va(b.bytes)," · ",b.filename]}),u===b.id&&e.jsx(wa,{id:b.id})]})})]},b.id)})}),e.jsx(le,{page:k.page,pageCount:k.pageCount,total:x,from:k.from,to:k.to,onPage:c,unit:"laporan"})]})}const Y=10,Ca=500,me=a=>{var s;return(s=a.detail)==null?void 0:s.error},pe=a=>String(a).padStart(2,"0"),Ce=a=>{const s={name:(a==null?void 0:a.name)??"",prompt:(a==null?void 0:a.prompt)??"",enabled:(a==null?void 0:a.enabled)??!1,kind:"lanjutan",time:"07:00",weekday:1,everyHours:"6",expr:(a==null?void 0:a.expr)??"0 7 * * *",agent:(a==null?void 0:a.agent)??"",model:(a==null?void 0:a.model)??"",effort:(a==null?void 0:a.effort)??""},t=a?sa(a.expr):{kind:"harian",hour:7,minute:0};if(!t)return s;if(t.kind==="tiap-n-jam")return{...s,kind:t.kind,everyHours:String(t.everyHours),time:`00:${pe(t.minute)}`};const r=`${pe(t.hour)}:${pe(t.minute)}`;return t.kind==="mingguan"?{...s,kind:t.kind,time:r,weekday:t.weekday}:{...s,kind:t.kind,time:r}},Na=a=>{if(a.kind==="lanjutan")return a.expr.trim();const[s,t]=a.time.split(":").map(Number);switch(a.kind){case"harian":return re({kind:"harian",hour:s,minute:t});case"hari-kerja":return re({kind:"hari-kerja",hour:s,minute:t});case"mingguan":return re({kind:"mingguan",hour:s,minute:t,weekday:a.weekday});case"tiap-n-jam":return re({kind:"tiap-n-jam",everyHours:_(a.everyHours,1,23,6),minute:t})}},Ia={launched:"ok",queued:"neutral",skipped:"warn",failed:"err"};function Pa({cronId:a,at:s}){const[t,r]=i.useState([]),[x,m]=i.useState(0),[p,c]=i.useState(!1),[w,g]=i.useState(null),[h,S]=J("scheduler","cronRunsPage",1,ke),u=i.useCallback(()=>{let o=!0;return N.listCronRuns(a,{page:h,limit:Y}).then(k=>{o&&(r(k.items),m(k.total),c(!0),g(null))}).catch(k=>{o&&(g(E("memuat riwayat",k)),c(!0))}),()=>{o=!1}},[a,h]);if(i.useEffect(()=>u(),[u]),w)return e.jsx(W,{message:w,onRetry:()=>{u()}});if(!p)return e.jsx(G,{rows:2,label:"Memuat riwayat…"});if(x===0)return e.jsx("p",{className:"hn-sched-empty",children:"Belum ada eksekusi."});const l=ie(x,h,Y);return e.jsxs(e.Fragment,{children:[e.jsx(ee,{label:"Riwayat eksekusi",children:t.map(o=>e.jsx(H,{children:e.jsxs("span",{className:"hn-sched-row-text",children:[e.jsx("span",{className:"hn-sched-row-head",children:e.jsx(F,{tone:Ia[o.status]??"neutral",size:"sm",children:X(ta,o.status)})}),e.jsxs("span",{className:"hn-sched-row-meta",children:["jatuh tempo ",s(o.dueAt),o.startedAt?` · mulai ${s(o.startedAt)}`:"",o.manual?" · uji coba":"",o.note?` · ${o.note}`:""]})]})},o.id))}),e.jsx(le,{page:l.page,pageCount:l.pageCount,total:x,from:l.from,to:l.to,onPage:S,unit:"run"})]})}function La({projects:a,onProjectChanged:s,onToast:t,timeZone:r}){const{confirm:x,dialog:m}=Le(),p=r??ja(),c=n=>ba(n,p),[w,g]=J("scheduler","cronProject","",Ge),h=a.some(n=>n.id===w)?w:"",[S,u]=J("scheduler","cronListPage",1,ke),[l,o]=i.useState(""),[k,B]=i.useState([]),[I,b]=i.useState(!1),[P,A]=i.useState(null),[D,U]=i.useState(void 0),[j,L]=i.useState(Ce()),[M,ne]=i.useState("dasar"),[Z,f]=J("scheduler","cronOpenRuns",null,Ke),[y,v]=i.useState(!1),se=a.find(n=>n.id===h),K=i.useCallback(()=>{if(a.length===0){B([]),A(null),b(!0);return}N.listCrons({projectId:h||void 0,page:1,limit:Ca}).then(n=>{B(n.items),A(null),b(!0)}).catch(n=>{A(E("memuat daftar cron",n)),b(!0)})},[h,a.length]);i.useEffect(()=>{B([]),b(!1),K()},[K]);const ce=n=>{var d;return((d=a.find(z=>z.id===n))==null?void 0:d.name)??"Project lain"},V=i.useMemo(()=>{const n=new Map(a.map((d,z)=>[d.id,z]));return[...k].sort((d,z)=>(n.get(d.projectId)??1e9)-(n.get(z.projectId)??1e9))},[k,a]),Q=ie(V.length,S,Y),ge=V.slice((Q.page-1)*Y,Q.page*Y),fe=n=>{var d;U(n??null),L(Ce(n)),ne("dasar"),o(h||((d=a[0])==null?void 0:d.id)||"")},te=Na(j),oe=Qe(te)!==null,de=oe?Ye(te,new Date,p):null,$e=async()=>{if(!oe){t("Ekspresi cron tidak sah","err","x-circle");return}v(!0);try{D?await N.patchCron(D.id,{name:j.name,expr:te,prompt:j.prompt,enabled:j.enabled,agent:j.agent||null,model:j.model||null,effort:j.effort||null}):await N.createCron({project:l,name:j.name,expr:te,prompt:j.prompt,enabled:j.enabled,agent:j.agent||void 0,model:j.model||void 0,effort:j.effort||void 0}),t("Cron tersimpan","ok","save"),U(void 0),K()}catch(n){t(me(n)??E("menyimpan cron",n),"err","x-circle")}finally{v(!1)}},Fe=async n=>{v(!0);try{await N.runCronNow(n),t("Uji coba masuk antrean; sesi dibuka pada siklus berikutnya","ok","play")}catch(d){t(me(d)??E("menjalankan cron",d),"err","x-circle")}finally{v(!1),K()}},He=async n=>{v(!0);try{await N.deleteCron(n),t("Cron dihapus","ok","trash")}catch(d){t(me(d)??E("menghapus cron",d),"err","x-circle")}finally{v(!1),K()}},De=n=>{x({title:"Hapus cron ini?",eyebrow:"scheduler · cronjob",impact:[`Cron "${n.name}" di project ${ce(n.projectId)} dihapus permanen.`,"Jadwalnya berhenti dan tidak akan dijalankan lagi.","Tindakan ini tidak bisa dibatalkan."],confirmLabel:"Hapus cron",icon:"trash-2",tone:"danger",run:()=>He(n.id)})},Ue=async()=>{if(h)try{await N.updateProject(h,{schedulerOptIn:!0}),await s(h),t("Project diizinkan untuk scheduler","ok")}catch(n){t(E("mengizinkan project",n),"err","x-circle")}},Te=n=>[{key:"edit",label:"Ubah",icon:"pencil",onSelect:()=>fe(n)},{key:"run",label:"Jalankan sekarang",icon:"play",disabled:y,onSelect:()=>void Fe(n.id)},{key:"runs",label:Z===n.id?"Sembunyikan riwayat":"Riwayat",icon:"list",onSelect:()=>f(Z===n.id?null:n.id)},{key:"remove",label:"Hapus",icon:"trash",tone:"danger",disabled:y,onSelect:()=>De(n)}],ue=j.agent||"claude",ve=()=>L(n=>({...n,everyHours:String(_(n.everyHours,1,23,6))})),_e=oe?de?`Perkiraan jalan berikutnya: ${c(de.toISOString())}`:`Preview belum bisa dihitung untuk zona ${p}. Jam jalan berikutnya tampil di daftar cron.`:"Jadwal tidak sah, jadi tidak ada jalan berikutnya.";return e.jsxs("div",{className:"hn-sched-panel",children:[e.jsxs("div",{className:"hn-sched-toolbar",children:[e.jsx(O,{value:h,"aria-label":"Project",onChange:n=>{g(n.target.value),u(1)},options:[{value:"",label:"Semua project"},...a.map(n=>({value:n.id,label:n.name}))]}),e.jsx(C,{size:"sm",leftIcon:"plus",disabled:a.length===0,onClick:()=>fe(),children:"Cron baru"})]}),e.jsxs("p",{className:"hn-sched-caption",children:["Jam ditampilkan dalam zona server ",e.jsx("b",{children:p}),r===void 0?" (server belum melaporkan zonanya, jadi zona browser yang dipakai)":"","."]}),se&&!se.schedulerOptIn&&e.jsx("div",{className:"hn-sched-notice",children:e.jsxs("div",{className:"hn-dense-row",role:"note",children:[e.jsx(We,{name:"alert-triangle",size:16,color:"var(--clay-600)"}),e.jsx("span",{className:"hn-grow hn-sched-notice-text",children:"Project ini belum diizinkan untuk scheduler, jadi cron-nya tidak akan pernah dijalankan."}),e.jsx(C,{size:"sm",leftIcon:"check",onClick:()=>void Ue(),children:"Aktifkan scheduler di project ini"})]})}),P?e.jsx(W,{message:P,onRetry:K,busy:y}):I?k.length===0?e.jsx("p",{className:"hn-sched-empty",children:h?"Belum ada cron di project ini.":"Belum ada cron di project mana pun."}):e.jsx(Ze,{children:e.jsxs("table",{className:"hn-sched-table",children:[e.jsx("thead",{children:e.jsxs("tr",{children:[e.jsx("th",{scope:"col",children:"Cron"}),e.jsx("th",{scope:"col",children:"Jadwal"}),e.jsx("th",{scope:"col",children:"Terakhir"}),e.jsx("th",{scope:"col",children:"Berikutnya"}),e.jsx("th",{scope:"col",children:e.jsx("span",{className:"hn-sr-only",children:"Aksi"})})]})}),e.jsx("tbody",{children:ge.map((n,d)=>{var z,ye;return e.jsxs(i.Fragment,{children:[!h&&n.projectId!==((z=ge[d-1])==null?void 0:z.projectId)&&e.jsx("tr",{className:"hn-sched-group-row",children:e.jsx("th",{scope:"colgroup",colSpan:5,children:e.jsxs("span",{className:"hn-sched-row-head",children:[e.jsx("span",{className:"hn-sched-group-title",children:ce(n.projectId)}),e.jsxs(F,{tone:"neutral",size:"sm",children:[V.filter(he=>he.projectId===n.projectId).length," cron"]}),((ye=a.find(he=>he.id===n.projectId))==null?void 0:ye.schedulerOptIn)===!1&&e.jsx(F,{tone:"warn",size:"sm",children:"belum diizinkan"})]})})}),e.jsxs("tr",{children:[e.jsx("td",{"data-label":"Cron",children:e.jsxs("span",{className:"hn-sched-row-head",children:[e.jsx("span",{className:"hn-sched-row-title",children:n.name}),e.jsx(F,{tone:n.enabled?"ok":"neutral",size:"sm",children:n.enabled?"aktif":"nonaktif"})]})}),e.jsx("td",{"data-label":"Jadwal",children:Ve(n.expr)}),e.jsx("td",{"data-label":"Terakhir",children:c(n.lastRunAt)}),e.jsx("td",{"data-label":"Berikutnya",children:c(n.nextRunAt)}),e.jsx("td",{className:"hn-sched-cell-actions",children:e.jsx(Xe,{label:`Aksi untuk cron ${n.name}`,title:n.name,items:Te(n)})})]}),Z===n.id&&e.jsx("tr",{className:"hn-sched-runs",children:e.jsx("td",{colSpan:5,children:e.jsx("div",{id:`cron-runs-${n.id}`,children:e.jsx(Pa,{cronId:n.id,at:c})})})})]},n.id)})})]})}):e.jsx(G,{rows:3,label:"Memuat daftar cron…"}),!P&&I&&V.length>Y&&e.jsx(le,{page:Q.page,pageCount:Q.pageCount,total:V.length,from:Q.from,to:Q.to,onPage:u,unit:"cron"}),a.length>0&&e.jsxs("section",{className:"hn-sched-reports","aria-label":"Laporan run cron",children:[e.jsx("h3",{children:"Laporan run cron"}),e.jsx(Sa,{projectId:h||void 0,projectName:ce})]}),e.jsx(qe,{open:D!==void 0,title:D?"Ubah cron":"Cron baru",eyebrow:"scheduler",onClose:()=>U(void 0),width:640,footer:e.jsxs("div",{className:"hn-sched-savebar",children:[e.jsx(C,{size:"sm",variant:"ghost",onClick:()=>U(void 0),children:"Batal"}),e.jsx(C,{size:"sm",leftIcon:"save",disabled:y,onClick:()=>void $e(),children:"Simpan"})]}),children:e.jsxs(Re,{tabs:[{value:"dasar",label:"Dasar"},{value:"lanjutan",label:"Lanjutan"}],value:M,onChange:n=>ne(n),children:[e.jsxs(T,{value:"dasar",className:"hn-sched-panel",children:[!D&&!h&&e.jsx(R,{label:"Project",children:e.jsx(O,{"aria-label":"Project cron baru",value:l,onChange:n=>o(n.target.value),options:a.map(n=>({value:n.id,label:n.name}))})}),e.jsx(R,{label:"Nama cron",children:e.jsx($,{"aria-label":"Nama cron",placeholder:"mis. Cek error produksi pagi",value:j.name,onChange:n=>L(d=>({...d,name:n.target.value}))})}),e.jsxs("div",{className:"hn-sched-form-grid",children:[e.jsx(R,{label:"Preset jadwal",children:e.jsx(O,{"aria-label":"Preset jadwal",value:j.kind,onChange:n=>L(d=>({...d,kind:n.target.value})),options:[{value:"harian",label:"Setiap hari"},{value:"hari-kerja",label:"Hari kerja"},{value:"mingguan",label:"Mingguan"},{value:"tiap-n-jam",label:"Tiap N jam"},{value:"lanjutan",label:"Ekspresi cron (lanjutan)"}]})}),j.kind!=="lanjutan"&&e.jsx(R,{label:j.kind==="tiap-n-jam"?"Menit pada setiap jam":"Jam",children:e.jsx($,{type:"time","aria-label":"Jam",value:j.time,onChange:n=>L(d=>({...d,time:n.target.value}))})}),j.kind==="mingguan"&&e.jsx(R,{label:"Hari",children:e.jsx(O,{"aria-label":"Hari",value:String(j.weekday),onChange:n=>L(d=>({...d,weekday:Number(n.target.value)})),options:ea.map((n,d)=>({value:String(d),label:n}))})}),j.kind==="tiap-n-jam"&&e.jsx(R,{label:"Tiap berapa jam",children:e.jsx($,{type:"number",min:1,max:23,"aria-label":"Tiap berapa jam",placeholder:"mis. 6",value:j.everyHours,onChange:n=>L(d=>({...d,everyHours:n.target.value})),onBlur:ve,onKeyDown:n=>{n.key==="Enter"&&(n.preventDefault(),ve())}})})]}),j.kind==="lanjutan"&&e.jsx(R,{label:"Ekspresi cron",hint:"Lima bagian: menit, jam, tanggal, bulan, hari dalam minggu.",children:e.jsx($,{"aria-label":"Ekspresi cron",placeholder:"mis. 0 7 * * 1-5",value:j.expr,onChange:n=>L(d=>({...d,expr:n.target.value}))})}),e.jsx("p",{"data-testid":"cron-next-preview",className:`hn-sched-note${de?"":" hn-sched-preview-warn"}`,children:_e}),e.jsxs("p",{className:"hn-sched-note",children:["Jadwal berlaku menurut zona waktu server ",e.jsx("b",{children:p}),"."]}),e.jsx(R,{label:"Prompt",hint:"Instruksi bebas untuk agen. Temuan sebaiknya dicatat sebagai item backlog baru.",children:e.jsx(aa,{"aria-label":"Prompt",rows:6,placeholder:"mis. Periksa error 5xx sejak kemarin, lalu catat temuannya sebagai QA finding.",value:j.prompt,onChange:n=>L(d=>({...d,prompt:n.target.value}))})}),e.jsx(xe,{label:"Aktif",checked:j.enabled,onChange:n=>L(d=>({...d,enabled:n}))})]}),e.jsxs(T,{value:"lanjutan",className:"hn-sched-panel",children:[e.jsx("p",{className:"hn-sched-group-hint",children:"Kosongkan untuk mengikuti default sesi. Model dan effort baru tersedia setelah runtime dipilih."}),e.jsxs("div",{className:"hn-sched-form-grid",children:[e.jsx(R,{label:"Runtime",children:e.jsx(O,{"aria-label":"Runtime",value:j.agent,onChange:n=>L(d=>({...d,agent:n.target.value,model:"",effort:""})),options:[{value:"",label:"Ikuti default sesi"},{value:"claude",label:"Claude Code"},{value:"codex",label:"Codex CLI"}]})}),e.jsx(R,{label:"Model",children:e.jsx(O,{"aria-label":"Model",value:j.model,disabled:!j.agent,onChange:n=>L(d=>({...d,model:n.target.value,effort:""})),options:[{value:"",label:"Ikuti default"},...we(ue).map(n=>({value:n.id,label:n.label}))]})}),e.jsx(R,{label:"Effort",children:e.jsx(O,{"aria-label":"Effort",value:j.effort,disabled:!j.agent,onChange:n=>L(d=>({...d,effort:n.target.value})),options:[{value:"",label:"Ikuti default"},...na(ue,j.model||we(ue)[0].id).map(n=>({value:n,label:n}))]})})]})]})]})}),m]})}const ze=5e3,je=10,Ra=["antre","berjalan","riwayat","cron","setelan"],Ea=["done","failed","canceled"],Ne={done:"Selesai",failed:"Gagal",canceled:"Dibatalkan"},Ba={tinggi:"err",sedang:"warn",rendah:"neutral"},Aa=[{value:"butuh-keputusan",label:"Berhenti dan minta keputusan dulu"},{value:"full-control",label:"Jalan sampai selesai tanpa berhenti"}],Ie=a=>{var s;return(s=a.detail)==null?void 0:s.error};function Ma(a,s){var t;return((t=s.find(r=>r.id===a))==null?void 0:t.title)??a}function ae({specId:a,ctx:s}){return e.jsx("span",{className:"hn-sched-row-title",children:Ma(a,s.backlog)})}function za({q:a,ctx:s,busy:t,onCancel:r}){return e.jsx(H,{actions:e.jsx(C,{size:"sm",variant:"ghost",leftIcon:"ban",disabled:t,onClick:()=>r(a.id),children:"Batalkan"}),children:e.jsxs("span",{className:"hn-sched-row-text",children:[e.jsxs("span",{className:"hn-sched-row-head",children:[e.jsx(ae,{specId:a.specId,ctx:s}),e.jsx(F,{tone:Ba[a.priority]??"neutral",size:"sm",children:X(ua,a.priority)})]}),e.jsxs("span",{className:"hn-sched-row-meta",children:[s.projectName(a.projectId)," · ",X(q,a.source),a.note?` · ${a.note}`:""]})]})})}function Oa({s:a,ctx:s,onGotoTerminal:t}){const r=a.flow?ha[a.flow]??a.flow:"";return e.jsx(H,{actions:e.jsx(C,{size:"sm",variant:"ghost",leftIcon:"terminal",onClick:()=>t(a.id),children:"Buka terminal"}),children:e.jsxs("span",{className:"hn-sched-row-text",children:[e.jsxs("span",{className:"hn-sched-row-head",children:[e.jsx(ae,{specId:a.specId,ctx:s}),a.decision&&e.jsx(F,{tone:"warn",icon:"bell",size:"sm",children:"menunggu kamu"})]}),e.jsxs("span",{className:"hn-sched-row-meta",children:[s.projectName(a.projectId),r?` · ${r}`:""]})]})})}function $a({q:a,ctx:s,onToast:t}){const r=ma(a.specId);return e.jsx(H,{actions:e.jsxs(e.Fragment,{children:[e.jsx(C,{size:"sm",variant:"ghost",leftIcon:"external-link",onClick:()=>window.open(r,"_blank","noreferrer"),children:"Buka review"}),e.jsx(C,{size:"sm",variant:"ghost",leftIcon:"copy",onClick:()=>{var x;(x=navigator.clipboard)==null||x.writeText(r),t("Link review disalin","ok","copy")},children:"Salin"})]}),children:e.jsxs("span",{className:"hn-sched-row-text",children:[e.jsx(ae,{specId:a.specId,ctx:s}),e.jsxs("span",{className:"hn-sched-row-meta",children:[s.projectName(a.projectId)," · ",X(q,a.source)," · ",a.launchedAt?`selesai ${Me(a.launchedAt)}`:a.note??"tidak diluncurkan"]})]})})}function Fa({q:a,ctx:s,onRequeue:t,busy:r}){return e.jsx(H,{actions:e.jsx(C,{size:"sm",variant:"secondary",leftIcon:"rotate-ccw",disabled:r,onClick:()=>t(a.id),children:"Antre ulang"}),children:e.jsxs("span",{className:"hn-sched-row-text",children:[e.jsx(ae,{specId:a.specId,ctx:s}),e.jsxs("span",{className:"hn-sched-row-meta",children:[s.projectName(a.projectId)," · ",a.note??"gagal tanpa alasan tercatat"]})]})})}function Ha({q:a,ctx:s,onRequeue:t,busy:r}){return e.jsx(H,{actions:e.jsx(C,{size:"sm",variant:"ghost",leftIcon:"rotate-ccw",disabled:r,onClick:()=>t(a.id),children:"Antre lagi"}),children:e.jsxs("span",{className:"hn-sched-row-text",children:[e.jsx(ae,{specId:a.specId,ctx:s}),e.jsxs("span",{className:"hn-sched-row-meta",children:[s.projectName(a.projectId)," · ",X(q,a.source)," · ",a.note??"dibatalkan"]})]})})}function Oe({what:a,status:s,count:t,empty:r,render:x}){const[m,p]=i.useState([]),[c,w]=i.useState(0),[g,h]=i.useState(!1),[S,u]=i.useState(null),[l,o]=J("scheduler",`queue-${s}-page`,1,ke),k=i.useCallback(()=>{N.getSchedulerQueue({status:s,page:l,limit:je}).then(I=>{p(I.items),w(I.total),u(null),h(!0)}).catch(I=>{u(E(`memuat ${a}`,I)),h(!0)})},[s,l,a]);if(i.useEffect(()=>{k()},[k]),Be({topic:"schedulerQueue",params:{status:s,page:l,limit:je},apply:I=>{p(I.data.items),w(I.data.total),u(null),h(!0)},refetch:()=>{k()},pollMs:ze}),S)return e.jsx(W,{message:S,onRetry:k});if(t===0)return e.jsx("p",{className:"hn-sched-empty",children:r});if(!g)return e.jsx(G,{rows:3,label:`Memuat ${a}…`});const B=ie(c,l,je);return e.jsxs(e.Fragment,{children:[e.jsx(ee,{label:a,children:m.map(I=>x(I))}),e.jsx(le,{page:B.page,pageCount:B.pageCount,total:c,from:B.from,to:B.to,onPage:o,unit:"item"})]})}function Da({counts:a,ctx:s,busyId:t,onRowAction:r,onToast:x}){const m=Ea.filter(u=>(a[u]??0)>0),p=(a.failed??0)>0?"failed":(a.done??0)>0?"done":"canceled",[c,w]=J("scheduler","riwayatStatus",p,Ee("done","failed","canceled"));if(m.length===0)return e.jsx("p",{className:"hn-sched-empty",children:"Belum ada riwayat."});const g=m.includes(c)?c:m[0],h=u=>void r(u,"requeue"),S=u=>{const l=t===u.id;return g==="done"?e.jsx($a,{q:u,ctx:s,onToast:x},u.id):g==="failed"?e.jsx(Fa,{q:u,ctx:s,onRequeue:h,busy:l},u.id):e.jsx(Ha,{q:u,ctx:s,onRequeue:h,busy:l},u.id)};return e.jsxs(e.Fragment,{children:[e.jsx("div",{role:"group","aria-label":"Filter riwayat",className:"hn-sched-chips",children:m.map(u=>e.jsxs("button",{type:"button",className:"hn-sched-chip hn-touch-target","aria-pressed":u===g,onClick:()=>w(u),children:[Ne[u],e.jsx("span",{className:"hn-sched-chip-count",children:a[u]})]},u))}),e.jsx(Oe,{what:`item ${Ne[g].toLowerCase()}`,status:g,count:a[g]??0,empty:"Belum ada riwayat.",render:S},g)]})}function Ua({cfg:a,cap:s,liveCount:t,onWrite:r,onAsk:x,busy:m}){const p=a.enabled?a.paused?{status:"paused",label:"Dijeda"}:{status:"running",label:"Berjalan"}:{status:"stopped",label:"Berhenti"},c=t>=s;return e.jsxs("section",{"aria-label":"Status scheduler",className:"hn-sched-strip",children:[e.jsx(la,{status:p.status,variant:"dot",children:p.label}),e.jsx("div",{className:"hn-sched-capacity",children:e.jsx(ia,{value:t,max:Math.max(s,1),size:"sm",tone:c?"warn":"brass",label:`${t} dari ${s} sesi`})}),e.jsxs("div",{className:"hn-sched-limits",children:[e.jsx(ca,{}),e.jsx(oa,{}),e.jsx(da,{})]}),e.jsx(pa,{}),e.jsxs("div",{className:"hn-sched-strip-actions",children:[a.enabled?a.paused?e.jsx(C,{size:"sm",leftIcon:"play",disabled:m,onClick:()=>r({...a,paused:!1},"Scheduler dilanjutkan"),children:"Lanjutkan"}):e.jsx(C,{size:"sm",variant:"secondary",leftIcon:"pause",disabled:m,onClick:()=>x({...a,paused:!0},"jeda"),children:"Jeda"}):e.jsx(C,{size:"sm",leftIcon:"play",disabled:m,onClick:()=>r({...a,enabled:!0},"Scheduler diaktifkan"),children:"Aktifkan"}),a.enabled&&e.jsxs(e.Fragment,{children:[e.jsx("span",{className:"hn-sched-strip-divider","aria-hidden":"true"}),e.jsx(C,{size:"sm",variant:"danger",leftIcon:"square",disabled:m,onClick:()=>x({...a,enabled:!1},"hentikan"),children:"Hentikan"})]})]})]})}function Ta({status:a}){return e.jsxs("div",{"aria-label":"Status pemeriksaan peluncuran",className:"hn-sched-guard-status",children:[e.jsxs("div",{children:["Pemeriksaan ",a.enabled?"aktif":"nonaktif"," · ",a.liveCount," dari batas ",a.maxConcurrent," sesi berjalan (",a.liveAgentCount," di antaranya agen)"]}),e.jsxs("div",{children:["Beban CPU per inti: ",a.loadStatus==="available"&&a.loadPerCore!==null?a.loadPerCore.toFixed(2):"tidak tersedia",a.loadStatus==="unsupported"?" (tidak didukung platform)":""," · batas ",a.maxLoadPerCore]}),e.jsxs("div",{children:["Memori bebas: ",a.memStatus==="available"&&a.memAvailablePct!==null?`${a.memAvailablePct.toFixed(0)}%`:"tidak tersedia"," · minimal ",a.minMemAvailablePct,"%"]}),e.jsx("div",{className:"hn-sched-note",children:"Berlaku juga saat scheduler berhenti. Terminal dan shell tetap bisa dibuka, dan keduanya ikut dihitung dalam batas sesi."})]})}const be=a=>{const s=a.launchGuard??Ae.launchGuard;return{maxConcurrent:String(a.maxConcurrent),autonomy:a.autonomy,guardOn:s.enabled,maxLoad:String(s.maxLoadPerCore),minMem:String(s.minMemAvailablePct),sources:{backlog:{enabled:a.sources.backlog.enabled,everyMin:String(a.sources.backlog.everyMin)},triase:{enabled:a.sources.triase.enabled,everyMin:String(a.sources.triase.everyMin)}}}},Pe=(a,s)=>{const t=s.launchGuard??Ae.launchGuard,r=s.sources.backlog,x=s.sources.triase;return{...s,maxConcurrent:_(a.maxConcurrent,1,1/0,s.maxConcurrent),autonomy:a.autonomy,launchGuard:{...t,enabled:a.guardOn,maxLoadPerCore:_(a.maxLoad,.1,1/0,t.maxLoadPerCore,!1),minMemAvailablePct:_(a.minMem,0,100,t.minMemAvailablePct,!1)},sources:{...s.sources,backlog:{...r,enabled:a.sources.backlog.enabled,everyMin:_(a.sources.backlog.everyMin,1,1/0,r.everyMin)},triase:{...x,enabled:a.sources.triase.enabled,everyMin:_(a.sources.triase.everyMin,1,1/0,x.everyMin)}}}},_a=a=>`${a.lastRunAt?`terakhir ${Me(a.lastRunAt)}`:"belum pernah dicek"} · ${a.nextRunAt?`berikutnya ${ka(a.nextRunAt)}`:"belum dijadwalkan"}`;function Ja({cfg:a,sources:s,admission:t,onWrite:r,busy:x}){const{draft:m,setDraft:p,dirty:c}=xa(be(a)),w=l=>be(Pe(l,a)),g=()=>p(l=>w(l)),h=()=>{const l=Pe(m,a);p(be(l)),r(l)},S=l=>{l.key==="Enter"&&(l.preventDefault(),h())},u=(l,o)=>p(k=>({...k,sources:{...k.sources,[l]:{...k.sources[l],...o}}}));return e.jsxs("div",{className:"hn-sched-panel",children:[e.jsxs("section",{className:"hn-sched-group","aria-labelledby":"sched-set-sesi",children:[e.jsx("h3",{id:"sched-set-sesi",className:"hn-sched-group-title",children:"Sesi"}),e.jsxs("div",{className:"hn-sched-grid",children:[e.jsx(R,{label:"Batas sesi bersamaan",hint:"Termasuk terminal dan shell yang kamu buka sendiri.",children:e.jsx($,{type:"number",min:1,value:m.maxConcurrent,"aria-label":"Batas sesi bersamaan",placeholder:"mis. 6",onChange:l=>p(o=>({...o,maxConcurrent:l.target.value})),onBlur:g,onKeyDown:S})}),e.jsx(R,{label:"Saat ada keputusan yang belum jelas",hint:"Keputusan yang ambigu tetap ditanyakan ke lead atau kamu.",children:e.jsx(O,{value:m.autonomy,"aria-label":"Mode otonomi",onChange:l=>p(o=>({...o,autonomy:l.target.value})),options:Aa})})]})]}),e.jsxs("section",{className:"hn-sched-group","aria-labelledby":"sched-set-peluncuran",children:[e.jsx("h3",{id:"sched-set-peluncuran",className:"hn-sched-group-title",children:"Peluncuran"}),e.jsx(xe,{label:"Tahan peluncuran saat server sibuk",checked:m.guardOn,onChange:l=>p(o=>({...o,guardOn:l}))}),e.jsx("p",{className:"hn-sched-group-hint",children:"Mencegah sesi baru diluncurkan saat batas sesi penuh, beban CPU per inti terlalu tinggi, atau memori bebas terlalu sedikit. Berlaku juga untuk peluncuran manual. Mematikannya melewati ketiga pemeriksaan itu. Terpisah dari saklar scheduler dan sumber."}),e.jsxs("div",{className:"hn-sched-grid",children:[e.jsx(R,{label:"Batas beban CPU per inti",hint:"Di atas angka ini, sesi baru tidak diluncurkan.",children:e.jsx($,{type:"number",min:.1,step:"any",value:m.maxLoad,"aria-label":"Batas beban CPU per inti",placeholder:"mis. 2.5",onChange:l=>p(o=>({...o,maxLoad:l.target.value})),onBlur:g,onKeyDown:S})}),e.jsx(R,{label:"Memori bebas minimal (%)",hint:"Di bawah angka ini, sesi baru tidak diluncurkan.",children:e.jsx($,{type:"number",min:0,max:100,step:"any",value:m.minMem,"aria-label":"Memori bebas minimal (%)",placeholder:"mis. 15",onChange:l=>p(o=>({...o,minMem:l.target.value})),onBlur:g,onKeyDown:S})})]}),t&&e.jsx(Ta,{status:t})]}),e.jsxs("section",{className:"hn-sched-group","aria-labelledby":"sched-set-sumber",children:[e.jsx("h3",{id:"sched-set-sumber",className:"hn-sched-group-title",children:"Sumber otomatis"}),["backlog","triase"].map(l=>{const o=s.find(k=>k.id===l);return e.jsxs("div",{className:"hn-sched-source",children:[e.jsx(xe,{label:q[l],checked:m.sources[l].enabled,onChange:k=>u(l,{enabled:k})}),e.jsx("span",{className:"hn-sched-spacer"}),e.jsxs("label",{className:"hn-sched-inline-field",children:["cek tiap",e.jsx($,{type:"number",min:1,"aria-label":`Interval cek ${q[l]}`,placeholder:"mis. 30",value:m.sources[l].everyMin,onChange:k=>u(l,{everyMin:k.target.value}),onBlur:g,onKeyDown:S}),"menit"]}),o&&e.jsx("span",{className:"hn-sched-source-facts",children:_a(o)})]},l)})]}),e.jsxs("div",{className:"hn-sched-savebar",children:[c&&e.jsx("span",{role:"status",className:"hn-sched-note",children:"Ada perubahan yang belum disimpan."}),e.jsx(C,{leftIcon:"save",disabled:x,onClick:h,children:"Simpan setelan"})]})]})}function Ga({projects:a,onToggle:s,busyId:t}){return e.jsxs("section",{className:"hn-sched-group","aria-labelledby":"sched-set-project",children:[e.jsx("h3",{id:"sched-set-project",className:"hn-sched-group-title",children:"Project yang diizinkan"}),e.jsx("p",{className:"hn-sched-group-hint",children:"Scheduler hanya menyentuh project yang diizinkan. Default: tidak diizinkan."}),a.length===0?e.jsx("p",{className:"hn-sched-empty",children:"Belum ada project."}):e.jsx(ee,{label:"Project yang diizinkan",children:a.map(r=>e.jsx(H,{actions:r.schedulerOptIn?e.jsx(C,{size:"sm",variant:"ghost",leftIcon:"ban",disabled:t===r.id,onClick:()=>s(r.id,!1),children:"Cabut izin"}):e.jsx(C,{size:"sm",leftIcon:"check",disabled:t===r.id,onClick:()=>s(r.id,!0),children:"Izinkan"}),children:e.jsx("span",{className:"hn-sched-row-text",children:e.jsxs("span",{className:"hn-sched-row-head",children:[e.jsx("span",{className:"hn-sched-row-title",children:r.name}),e.jsx(F,{tone:r.schedulerOptIn?"ok":"neutral",size:"sm",children:r.schedulerOptIn?"diizinkan":"tidak diizinkan"})]})})},r.id))})]})}function Ka(a){const[s,t]=i.useState(null),[r,x]=i.useState(null),m=i.useCallback(()=>{N.getSettings().then(c=>{t(c),x(null)}).catch(c=>x(E("memuat orkestrasi",c)))},[]);i.useEffect(()=>{m()},[m]);const p=i.useCallback(async(c,w)=>{if(!s)return;const g=s;t({...g,orchestration:c});try{const h=await N.getSettings().catch(()=>{});await N.putSettings(ga(g,{...g,orchestration:c},h)),a(w,"ok","check-circle-2")}catch(h){t(g),a(E("menyimpan orkestrasi",h),"err","alert-triangle")}},[s,a]);return{setting:s,error:r,load:m,writeOrchestration:p}}function Qa({snap:a}){return e.jsxs("section",{className:"hn-sched-group","aria-labelledby":"sched-set-orkestrasi",children:[e.jsx("h3",{id:"sched-set-orkestrasi",className:"hn-sched-group-title",children:"Orkestrasi subagen per fase"}),e.jsx("p",{className:"hn-sched-group-hint",children:"Perubahan tersimpan saat diubah. Buka satu flow untuk mengatur model dan effort per fase."}),a.error?e.jsx(W,{message:a.error,onRetry:a.load}):a.setting?e.jsx(fa,{variant:"accordion",orchestration:a.setting.orchestration,onChange:(s,t)=>void a.writeOrchestration(s,t)}):e.jsx(G,{rows:2,label:"Memuat orkestrasi…"})]})}function nn({projects:a,backlog:s,onProjectChanged:t,onToast:r,onGotoTerminal:x}){const{confirm:m,dialog:p}=Le(),[c,w]=i.useState(null),[g,h]=i.useState("loading"),[S,u]=i.useState(!1),[l,o]=i.useState(null),[k,B]=J("scheduler","tab","antre",Ee(...Ra)),I=Ka(r),b=i.useCallback((f=!1)=>{f||h("loading"),N.getSchedulerState().then(y=>{w(y),h("ready")}).catch(()=>{f||h("error")})},[]);i.useEffect(()=>{b()},[b]),Be({topic:"schedulerState",params:{},apply:f=>{w(f.state),h("ready")},refetch:()=>b(!0),pollMs:ze});const P=i.useCallback(async(f,y="Setelan scheduler tersimpan")=>{u(!0);try{await N.putSchedulerConfig(f),r(y,"ok","save"),b(!0)}catch(v){r(Ie(v)??E("menyimpan setelan",v),"err","x-circle")}finally{u(!1)}},[b,r]),A=i.useCallback((f,y)=>{const v=y==="jeda";m({title:v?"Jeda scheduler?":"Hentikan scheduler?",eyebrow:"scheduler · rem darurat",message:v?"Scheduler berhenti meluncurkan sesi baru dari antrean sampai kamu melanjutkannya. Sesi yang sudah berjalan tidak dihentikan.":void 0,impact:v?void 0:["Sumber backlog dan triase tidak lagi diperiksa sampai diaktifkan lagi.","Antrean tetap tersimpan dan tidak diproses selama berhenti.","Sesi yang sudah berjalan tetap berjalan."],confirmLabel:v?"Jeda scheduler":"Hentikan scheduler",icon:v?"pause":"square",tone:v?"default":"danger",run:()=>P(f,v?"Scheduler dijeda":"Scheduler dihentikan")})},[m,P]),D=i.useCallback(async(f,y)=>{o(f);try{await N.updateProject(f,{schedulerOptIn:y}),await t(f),r(y?"Project diizinkan untuk scheduler":"Izin scheduler dicabut","ok")}catch(v){r(E("mengubah izin project",v),"err","x-circle")}finally{o(null)}},[t,r]),U=i.useCallback(async(f,y)=>{o(f);try{y==="cancel"?(await N.cancelSchedulerQueueItem(f),r("Item antrean dibatalkan","ok","ban")):(await N.requeueSchedulerQueueItem(f),r("Item dikembalikan ke antrean","ok","rotate-ccw"))}catch(v){const se=y==="cancel"?"membatalkan item antrean":"mengembalikan item ke antrean";r(Ie(v)??E(se,v),"err","x-circle")}finally{o(null),b(!0)}},[b,r]);if(g==="loading")return e.jsx(G,{rows:4,label:"Memuat scheduler…"});if(g==="error"||!c)return e.jsx(ra,{kind:"error",hint:"Gagal memuat state scheduler.",action:()=>b(),actionLabel:"Coba lagi"});const L={backlog:s,projectName:f=>{var y;return((y=a.find(v=>v.id===f))==null?void 0:y.name)??"Project lain"}},M=c.queueCounts,ne=(M.done??0)+(M.failed??0)+(M.canceled??0),Z=[{value:"antre",label:"Antre",count:M.queued||void 0},{value:"berjalan",label:"Berjalan",count:c.sessions.length||void 0},{value:"riwayat",label:"Riwayat",count:ne||void 0},{value:"cron",label:"Cron"},{value:"setelan",label:"Setelan"}];return e.jsxs("div",{className:"hn-sched",children:[e.jsx(Ua,{cfg:c.config,cap:c.cap,liveCount:c.liveCount,onWrite:P,onAsk:A,busy:S}),e.jsxs(Re,{tabs:Z,value:k,onChange:f=>B(f),children:[e.jsx(T,{value:"antre",className:"hn-sched-panel",children:e.jsx(Oe,{what:"antrean",status:"queued",count:M.queued,empty:"Antrean kosong.",render:f=>e.jsx(za,{q:f,ctx:L,busy:l===f.id,onCancel:y=>void U(y,"cancel")},f.id)})}),e.jsx(T,{value:"berjalan",className:"hn-sched-panel",children:c.sessions.length===0?e.jsx("p",{className:"hn-sched-empty",children:"Tidak ada sesi dari scheduler yang sedang berjalan."}):e.jsx(ee,{label:"Sesi berjalan",children:c.sessions.map(f=>e.jsx(Oa,{s:f,ctx:L,onGotoTerminal:x},f.id))})}),e.jsx(T,{value:"riwayat",className:"hn-sched-panel",children:k==="riwayat"&&e.jsx(Da,{counts:M,ctx:L,busyId:l,onRowAction:U,onToast:r})}),e.jsx(T,{value:"cron",className:"hn-sched-panel",children:k==="cron"&&e.jsx(La,{projects:a,onProjectChanged:t,onToast:r,timeZone:c.serverTimeZone})}),e.jsxs(T,{value:"setelan",className:"hn-sched-panel",children:[e.jsx(Ja,{cfg:c.config,sources:c.sources,admission:c.admission,onWrite:f=>void P(f),busy:S}),e.jsx(Ga,{projects:a,onToggle:D,busyId:l}),e.jsx(Qa,{snap:I})]})]}),p]})}export{nn as SchedulerScreen};
|