bullpane 0.7.0 → 0.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/server.mjs +2 -2
- package/package.json +1 -1
- package/web/assets/FlowsPage-BOHg_j5s.js +26 -0
- package/web/assets/{FlowsPage-C1DrWzZu.css → FlowsPage-BRUBQF1y.css} +1 -1
- package/web/assets/{JobTreePage-CbwbeeRl.js → JobTreePage-DWE60jpd.js} +2 -2
- package/web/assets/{McpConsentPage-CI53cgZX.js → McpConsentPage-YpDqETHG.js} +1 -1
- package/web/assets/{index-Dj9D1-XU.js → index-CIHznD1e.js} +2 -2
- package/web/assets/{style-J6Fkg5PC.js → style-B5JqANGk.js} +3 -3
- package/web/index.html +1 -1
- package/web/assets/FlowsPage-Cp6TR7Wa.js +0 -26
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/FlowsPage-
|
|
1
|
+
const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/FlowsPage-BOHg_j5s.js","assets/style-B5JqANGk.js","assets/style-BnuhLJ6X.css","assets/FlowsPage-BRUBQF1y.css","assets/JobTreePage-DWE60jpd.js"])))=>i.map(i=>d[i]);
|
|
2
2
|
var ob=Object.defineProperty;var pg=e=>{throw TypeError(e)};var cb=(e,n,r)=>n in e?ob(e,n,{enumerable:!0,configurable:!0,writable:!0,value:r}):e[n]=r;var Uh=(e,n,r)=>cb(e,typeof n!="symbol"?n+"":n,r),Qh=(e,n,r)=>n.has(e)||pg("Cannot "+r);var _=(e,n,r)=>(Qh(e,n,"read from private field"),r?r.call(e):n.get(e)),ge=(e,n,r)=>n.has(e)?pg("Cannot add the same private member more than once"):n instanceof WeakSet?n.add(e):n.set(e,r),ne=(e,n,r,i)=>(Qh(e,n,"write to private field"),i?i.call(e,r):n.set(e,r),r),Me=(e,n,r)=>(Qh(e,n,"access private method"),r);var ou=(e,n,r,i)=>({set _(o){ne(e,n,o,r)},get _(){return _(e,n,i)}});function ub(e,n){for(var r=0;r<n.length;r++){const i=n[r];if(typeof i!="string"&&!Array.isArray(i)){for(const o in i)if(o!=="default"&&!(o in e)){const c=Object.getOwnPropertyDescriptor(i,o);c&&Object.defineProperty(e,o,c.get?c:{enumerable:!0,get:()=>i[o]})}}}return Object.freeze(Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}))}(function(){const n=document.createElement("link").relList;if(n&&n.supports&&n.supports("modulepreload"))return;for(const o of document.querySelectorAll('link[rel="modulepreload"]'))i(o);new MutationObserver(o=>{for(const c of o)if(c.type==="childList")for(const d of c.addedNodes)d.tagName==="LINK"&&d.rel==="modulepreload"&&i(d)}).observe(document,{childList:!0,subtree:!0});function r(o){const c={};return o.integrity&&(c.integrity=o.integrity),o.referrerPolicy&&(c.referrerPolicy=o.referrerPolicy),o.crossOrigin==="use-credentials"?c.credentials="include":o.crossOrigin==="anonymous"?c.credentials="omit":c.credentials="same-origin",c}function i(o){if(o.ep)return;o.ep=!0;const c=r(o);fetch(o.href,c)}})();function db(e){return e&&e.__esModule&&Object.prototype.hasOwnProperty.call(e,"default")?e.default:e}var Bh={exports:{}},ro={},Vh={exports:{}},We={};/**
|
|
3
3
|
* @license React
|
|
4
4
|
* react.production.min.js
|
|
@@ -550,4 +550,4 @@ await queue.upsertJobScheduler(
|
|
|
550
550
|
await queue.upsertJobScheduler("heartbeat", { every: 30_000 });`}),t.jsxs("p",{className:"flex items-center gap-1.5 text-[11px] text-fg-subtle",children:[t.jsx(Wy,{className:"size-3","aria-hidden":!0}),"upsertJobScheduler is idempotent: calling it again updates the schedule instead of adding a second one."]})]})}function Wa({feature:e}){const n=bo[e],{pricing:r,checkoutUrl:i}=wt();return t.jsxs("div",{className:"mx-auto flex w-full max-w-5xl flex-col gap-8 px-6 py-10 lg:flex-row lg:items-center lg:gap-12",children:[t.jsxs("div",{className:"flex-1",children:[t.jsxs("div",{className:"mb-3 inline-flex items-center gap-1.5 rounded-full border border-pro/40 bg-pro/10 px-2.5 py-1 text-[11px] font-medium tracking-wider text-pro uppercase",children:[t.jsx(go,{className:"size-3","aria-hidden":!0}),"Pro feature"]}),t.jsx("h1",{className:"text-2xl font-semibold tracking-tight text-fg",children:n.title}),t.jsx("p",{className:"mt-2 max-w-md text-sm leading-relaxed text-fg-muted",children:n.tagline}),t.jsx("ul",{className:"mt-5 space-y-2.5",children:n.bullets.map(o=>t.jsxs("li",{className:"flex items-start gap-2.5 text-[13px] text-fg",children:[t.jsx(Zr,{className:"mt-0.5 size-4 shrink-0 text-success","aria-hidden":!0}),t.jsx("span",{children:o})]},o))}),t.jsxs("div",{className:"mt-7 flex flex-wrap items-center gap-3",children:[t.jsxs("a",{href:i||"#",target:"_blank",rel:"noreferrer noopener","aria-disabled":!i,className:"inline-flex h-9 items-center gap-2 rounded-md bg-accent px-4 text-[13px] font-medium text-accent-fg hover:bg-accent-hover aria-disabled:pointer-events-none aria-disabled:opacity-50",children:["Unlock Pro · $",r.monthlyUsd,"/mo or $",r.yearlyUsd,"/yr",t.jsx(Br,{className:"size-4","aria-hidden":!0})]}),t.jsxs(Ee,{to:"/settings/license",className:"inline-flex h-9 items-center gap-2 rounded-md border border-border-strong px-3 text-[13px] font-medium text-fg hover:bg-surface-2",children:[t.jsx(al,{className:"size-4","aria-hidden":!0}),"I have a key"]})]}),t.jsxs("p",{className:"mt-3 text-xs text-fg-subtle",children:["One key unlocks login with Users & roles, Alerts, Folders, Flows, the Audit log, SSO and MCP for one installation. $",r.monthlyUsd,"/month or $",r.yearlyUsd,"/year, unlimited users, cancel any time."]})]}),t.jsx("div",{className:"flex-1",children:t.jsx(v_,{feature:e})})]})}function v_({feature:e}){return t.jsxs("div",{"aria-hidden":!0,className:"relative overflow-hidden rounded-xl border border-border bg-surface p-3 shadow-[var(--shadow)]",children:[t.jsxs("div",{className:"mb-3 flex items-center gap-1.5",children:[t.jsx("span",{className:"size-2 rounded-full bg-fg-subtle/40"}),t.jsx("span",{className:"size-2 rounded-full bg-fg-subtle/40"}),t.jsx("span",{className:"size-2 rounded-full bg-fg-subtle/40"}),t.jsx("span",{className:"ml-3 h-2 w-24 rounded bg-surface-3"})]}),e==="alerts"&&t.jsx(y_,{}),e==="users"&&t.jsx(j_,{}),e==="folders"&&t.jsx(b_,{}),e==="flows"&&t.jsx(w_,{}),t.jsx("div",{className:"pointer-events-none absolute inset-x-0 bottom-0 h-16 bg-gradient-to-t from-surface to-transparent"})]})}function vu({className:e,children:n}){return t.jsx("div",{className:F("flex items-center gap-2 rounded-md border border-border bg-bg/60 px-2.5 py-2",e),children:n})}function On({w:e,className:n}){return t.jsx("span",{className:F("h-2 rounded bg-surface-3",n),style:{width:e}})}function y_(){return t.jsxs("div",{className:"space-y-2",children:[t.jsxs(vu,{children:[t.jsx("span",{className:"status-dot pulse bg-danger"}),t.jsx(On,{w:"38%",className:"bg-fg-muted/50"}),t.jsx("span",{className:"ml-auto rounded bg-danger/15 px-1.5 py-0.5 text-[9px] font-medium text-danger",children:"FIRING"})]}),t.jsxs(vu,{children:[t.jsx("span",{className:"status-dot bg-success"}),t.jsx(On,{w:"52%"}),t.jsx("span",{className:"ml-auto rounded bg-success/15 px-1.5 py-0.5 text-[9px] font-medium text-success",children:"OK"})]}),t.jsxs(vu,{children:[t.jsx("span",{className:"status-dot bg-success"}),t.jsx(On,{w:"30%"}),t.jsx("span",{className:"ml-auto rounded bg-success/15 px-1.5 py-0.5 text-[9px] font-medium text-success",children:"OK"})]}),t.jsxs("div",{className:"mt-3 rounded-md border border-border bg-surface-2 p-2.5",children:[t.jsxs("div",{className:"mb-2 flex items-center gap-2",children:[t.jsx("span",{className:"size-4 rounded bg-[#4A154B]"}),t.jsx(On,{w:"30%",className:"bg-fg-muted/50"}),t.jsx(On,{w:"12%",className:"ml-auto"})]}),t.jsx(On,{w:"80%",className:"mb-1.5"}),t.jsx(On,{w:"60%"})]})]})}function j_(){const e=[["admin","bg-pro/15 text-pro"],["operator","bg-info/15 text-info"],["operator","bg-info/15 text-info"],["viewer","bg-surface-3 text-fg-muted"]];return t.jsx("div",{className:"space-y-2",children:e.map(([n,r],i)=>t.jsxs(vu,{children:[t.jsx("span",{className:"size-5 rounded-full bg-surface-3"}),t.jsxs("div",{className:"flex flex-col gap-1",children:[t.jsx(On,{w:`${70+i*12}px`,className:"bg-fg-muted/50"}),t.jsx(On,{w:`${100+i*8}px`,className:"h-1.5"})]}),t.jsx("span",{className:F("ml-auto rounded px-1.5 py-0.5 text-[9px] font-medium",r),children:n})]},i))})}function b_(){return t.jsxs("div",{className:"space-y-1.5 text-[11px]",children:[[["Payments","bg-success",0,3],["Checkout","bg-success",1,2],["Refunds","bg-success",1,1],["Notifications","bg-info",0,4],["Data pipeline","bg-violet",0,2]].map(([e,n,r,i],o)=>t.jsxs("div",{className:"flex items-center gap-2 rounded px-2 py-1",style:{paddingLeft:8+r*16},children:[t.jsx("span",{className:F("size-3 rounded-sm",n)}),t.jsx("span",{className:"text-fg-muted",children:e}),t.jsx("span",{className:"ml-auto rounded bg-surface-3 px-1 text-[9px] text-fg-subtle",children:i})]},o)),t.jsxs("div",{className:"ml-6 space-y-1 border-l border-border pl-3",children:[t.jsx(On,{w:"60%"}),t.jsx(On,{w:"45%"}),t.jsx(On,{w:"70%"})]})]})}function w_(){const e=(n,r,i,o="bg-surface-2")=>t.jsxs("div",{className:F("absolute flex h-9 w-28 flex-col justify-center rounded-md border border-border px-2",o),style:{left:n,top:r},children:[t.jsx("span",{className:"text-[10px] font-medium text-fg",children:i}),t.jsx(On,{w:"50%",className:"mt-1 h-1.5"})]});return t.jsxs("div",{className:"relative h-52",children:[t.jsxs("svg",{className:"absolute inset-0 h-full w-full",fill:"none",stroke:"var(--fg-subtle)",strokeWidth:1.5,children:[t.jsx("path",{d:"M120 38 C 160 38, 160 98, 200 98"}),t.jsx("path",{d:"M120 158 C 160 158, 160 98, 200 98",strokeDasharray:"4 3",stroke:"var(--accent)"}),t.jsx("path",{d:"M312 98 C 350 98, 350 60, 380 60"}),t.jsx("path",{d:"M312 98 C 350 98, 350 136, 380 136"})]}),e(8,20,"ingest"),e(8,140,"backfill"),e(200,80,"process","bg-accent/10"),e(380,42,"notify"),e(380,118,"archive"),t.jsx("span",{className:"absolute top-[60px] left-[150px] rounded bg-surface px-1 text-[9px] text-fg-subtle",children:"×214"})]})}function N_(){const{has:e}=wt();return e("alerts")?t.jsx(S_,{}):t.jsx(Wa,{feature:"alerts"})}function fj(e){switch(e.kind){case"waiting_above":return`wait+prioritized > ${K(e.threshold)}`;case"failed_above":return`failed > ${K(e.threshold)} in ${e.windowMinutes}m`;case"failed_rate_above":return`failure rate > ${e.percent}% in ${e.windowMinutes}m (min ${e.minSample})`;case"duration_above":return`p${e.percentile} processing > ${e.seconds}s in ${e.windowMinutes}m (min ${e.minSample})`}}const k_={fired:"danger",resolved:"success",delivery_failed:"warning",no_metrics:"info"};function S_(){var z,O;const{isOperator:e}=mt(),n=bm(),r=xs(),i=Jr(),o=L0(),c=$2(),d=I2(),[h,f]=w.useState(null),[g,p]=w.useState(null),[v,j]=w.useState(""),S=T2({limit:100,alertId:v||void 0}),y=T=>{var M,E;return T?((E=(M=r.data)==null?void 0:M.find(I=>I.id===T))==null?void 0:E.name)??T:"–"},b=T=>{var M,E;return((E=(M=i.data)==null?void 0:M.find(I=>I.id===T))==null?void 0:E.name)??T},k=[...n.data??[]].sort((T,M)=>Number(M.firing)-Number(T.firing)||T.name.localeCompare(M.name)),C=k.filter(T=>T.firing).length;return t.jsxs(bt,{children:[t.jsx(gs,{title:t.jsxs("span",{className:"flex items-center gap-2",children:["Alerts",C>0&&t.jsxs(be,{variant:"danger",dot:!0,children:[C," firing"]})]}),description:"Server-side rules: backlog from live counts, failures from BullMQ metrics counters. Delivered to Slack or any webhook.",actions:e&&t.jsx(V,{variant:"primary",size:"sm",leftIcon:t.jsx(es,{}),onClick:()=>f({alert:null}),children:"New alert"})}),t.jsx("div",{className:"card overflow-hidden",children:t.jsxs(ms,{children:[t.jsx("thead",{children:t.jsxs("tr",{children:[t.jsx(pe,{className:"w-16",children:"State"}),t.jsx(pe,{children:"Name"}),t.jsx(pe,{children:"Scope"}),t.jsx(pe,{children:"Condition"}),t.jsx(pe,{children:"Channels"}),t.jsx(pe,{children:"Last fired"}),t.jsx(pe,{align:"right",children:t.jsx("span",{className:"sr-only",children:"Actions"})})]})}),t.jsxs("tbody",{children:[n.isLoading&&t.jsx(yt,{colSpan:7,children:t.jsx(Kt,{label:"Loading alerts…"})}),n.isError&&t.jsx(yt,{colSpan:7,className:"text-danger",children:ve(n.error)}),n.data&&k.length===0&&t.jsx("tr",{children:t.jsx("td",{colSpan:7,children:t.jsx(cn,{compact:!0,icon:t.jsx(rl,{}),title:"No alerts yet",description:"Start with 'failures above threshold' on your most important queue and a Slack webhook.",action:e&&t.jsx(V,{size:"sm",variant:"primary",leftIcon:t.jsx(es,{}),onClick:()=>f({alert:null}),children:"New alert"})})})}),k.map(T=>{var M;return t.jsxs(cl,{className:F(!T.enabled&&"opacity-60"),children:[t.jsx(xe,{children:T.firing?t.jsxs(be,{variant:"danger",dot:!0,children:[t.jsx(lm,{className:"size-3"})," firing"]}):T.enabled?t.jsx(qC,{measurement:T.measurement}):t.jsx(be,{variant:"neutral",children:"off"})}),t.jsx(xe,{className:"font-medium",children:T.name}),t.jsx(xe,{muted:!0,children:T.scope.type==="queue"?t.jsxs(t.Fragment,{children:[y(T.scope.connectionId),t.jsx("span",{className:"text-fg-subtle",children:" / "}),t.jsx("span",{className:"font-mono text-xs",children:T.scope.queueName})]}):T.scope.type==="folder"?t.jsxs("span",{className:"inline-flex items-center gap-1",children:[t.jsx(be,{variant:"outline",size:"xs",children:"folder"}),b(T.scope.folderId)]}):T.scope.type==="connection"?t.jsxs("span",{className:"inline-flex items-center gap-1",children:[t.jsx(be,{variant:"outline",size:"xs",children:"connection"}),y(T.scope.connectionId)]}):t.jsx(be,{variant:"outline",size:"xs",children:"every queue"})}),t.jsx(xe,{mono:!0,children:fj(T.condition)}),t.jsx(xe,{muted:!0,children:T.channels.length===0?t.jsx("span",{className:"text-[11px] text-fg-subtle",children:"dashboard only"}):t.jsxs(t.Fragment,{children:[T.channels.map((E,I)=>t.jsx(be,{variant:"outline",size:"xs",className:"mr-1",children:E.type},I)),t.jsxs("span",{className:"text-[11px] text-fg-subtle",children:["· cooldown ",T.cooldownMinutes,"m"]})]})}),t.jsx(xe,{muted:!0,children:t.jsx(Yt,{value:T.lastFiredAt,emptyText:"never"})}),t.jsx(xe,{align:"right",children:t.jsxs("div",{className:"flex items-center justify-end gap-1",children:[e&&t.jsx(el,{size:"sm",checked:T.enabled,label:T.enabled?"Disable alert":"Enable alert",disabled:o.isPending&&((M=o.variables)==null?void 0:M.id)===T.id,onChange:E=>o.mutate({id:T.id,input:{enabled:E}},{onError:I=>X.error(ve(I))})}),e&&t.jsx(V,{size:"icon-xs",variant:"ghost",title:"Send test notification","aria-label":"Send test notification",loading:d.isPending&&d.variables===T.id,onClick:()=>d.mutate(T.id,{onSuccess:E=>{var Q,H;const I=((Q=E.results)==null?void 0:Q.filter(q=>!q.ok))??[];E.ok&&I.length===0?X.success("Test notification sent",`${((H=E.results)==null?void 0:H.length)??0} channel(s) delivered`):X.error("Some channels failed",I.map(q=>`${q.channel}: ${q.error??"error"}`).join("; "))},onError:E=>X.error(ve(E))}),children:t.jsx($N,{})}),e&&t.jsx(V,{size:"icon-xs",variant:"ghost",title:"Edit","aria-label":"Edit alert",onClick:()=>f({alert:T}),children:t.jsx(Uo,{})}),e&&t.jsx(V,{size:"icon-xs",variant:"ghost",title:"Delete","aria-label":"Delete alert",className:"hover:text-danger",onClick:()=>p(T),children:t.jsx(Un,{})})]})})]},T.id)})]})]})}),t.jsxs("section",{className:"mt-6",children:[t.jsxs("div",{className:"mb-2 flex items-center justify-between",children:[t.jsx("h2",{className:"text-xs font-semibold tracking-wider text-fg-subtle uppercase",children:"Events"}),t.jsx(dt,{"aria-label":"Filter events by alert",className:"!h-7 !w-auto text-xs",value:v,onChange:T=>j(T.target.value),options:[{value:"",label:"All alerts"},...k.map(T=>({value:T.id,label:T.name}))]})]}),t.jsx("div",{className:"card overflow-hidden",children:t.jsxs(ms,{dense:!0,children:[t.jsx("thead",{children:t.jsxs("tr",{children:[t.jsx(pe,{className:"w-28",children:"When"}),t.jsx(pe,{className:"w-28",children:"Status"}),t.jsx(pe,{children:"Alert"}),t.jsx(pe,{children:"Queue"}),t.jsx(pe,{children:"Message"}),t.jsx(pe,{align:"right",children:"Value"})]})}),t.jsxs("tbody",{children:[S.isLoading&&t.jsx(yt,{colSpan:6,children:t.jsx(Kt,{})}),S.data&&S.data.length===0&&t.jsx(yt,{colSpan:6,children:"No events yet"}),(z=S.data)==null?void 0:z.map(T=>t.jsxs("tr",{children:[t.jsx(xe,{muted:!0,children:t.jsx(Yt,{value:T.createdAt})}),t.jsx(xe,{children:t.jsx(be,{variant:k_[T.status],size:"xs",dot:!0,children:T.status.replace("_"," ")})}),t.jsx(xe,{className:"font-medium",children:T.alertName}),t.jsxs(xe,{muted:!0,children:[y(T.connectionId),T.queueName&&t.jsxs("span",{className:"text-fg-subtle",children:[" / ",T.queueName]})]}),t.jsx(xe,{className:"max-w-lg truncate",title:T.message,children:T.message}),t.jsx(xe,{num:!0,align:"right",muted:!0,children:T.value!=null?K(T.value):"–"})]},T.id))]})]})})]}),h&&t.jsx(od,{open:!0,onClose:()=>f(null),alert:h.alert},((O=h.alert)==null?void 0:O.id)??"new"),t.jsx(Ht,{open:!!g,onClose:()=>p(null),title:`Delete "${g==null?void 0:g.name}"`,description:"The alert and its history of events are removed.",confirmText:"Delete",danger:!0,loading:c.isPending,onConfirm:()=>g&&c.mutate(g.id,{onSuccess:()=>(p(null),X.success("Alert deleted")),onError:T=>X.error(ve(T))})})]})}function C_(e,n){const{has:r}=wt(),i=r("alerts"),o=bm(i),c=Jr(i&&r("folders")),d=w.useMemo(()=>{const h=o.data??[];if(h.length===0)return[];const f=c.data??[],g=new Map;for(const y of f)y.queues.some(b=>b.connectionId===e&&b.queueName===n)&&g.set(y.id,y.name);const p=[];for(const y of h)if(y.scope.type==="queue")y.scope.connectionId===e&&y.scope.queueName===n&&p.push({alert:y,via:{kind:"queue"}});else if(y.scope.type==="folder"){const b=g.get(y.scope.folderId);b!==void 0&&p.push({alert:y,via:{kind:"folder",folderId:y.scope.folderId,folderName:b}})}else y.scope.type==="connection"?y.scope.connectionId===e&&p.push({alert:y,via:{kind:"connection"}}):p.push({alert:y,via:{kind:"global"}});const v=y=>({global:0,connection:1,folder:2,queue:3})[y.via.kind],j=new Map;for(const y of p)y.alert.enabled&&j.set(y.alert.condition.kind,Math.max(j.get(y.alert.condition.kind)??-1,v(y)));const S=p.filter(y=>!y.alert.enabled||v(y)===j.get(y.alert.condition.kind));return p.length=0,p.push(...S),p.sort((y,b)=>Number(b.alert.firing)-Number(y.alert.firing)||Number(b.alert.enabled)-Number(y.alert.enabled)||y.alert.name.localeCompare(b.alert.name))},[o.data,c.data,e,n]);return{matches:d,firing:d.filter(h=>h.alert.firing).length,enabled:i}}function __({matches:e,firing:n}){if(e.length===0)return null;const r=`${e.length} alert${e.length===1?"":"s"}`;return t.jsx(Pe,{content:n>0?`${n} of ${e.length} firing right now`:"Watching this queue",children:t.jsxs(Ee,{to:ue.alerts,className:F("inline-flex items-center gap-1 rounded border px-1.5 py-0.5 text-[11px] font-medium transition-colors",n>0?"border-danger/40 bg-danger/10 text-danger hover:bg-danger/20":"border-border text-fg-muted hover:bg-surface-hover hover:text-fg"),children:[n>0?t.jsx(lm,{className:"size-3"}):t.jsx(rl,{className:"size-3"}),n>0?`${n} firing`:r]})})}function P_({connectionId:e,queueName:n,matches:r,onCreate:i}){const{isOperator:o}=mt(),[c,d]=w.useState(null);return r.length===0?null:t.jsxs("section",{className:"rounded-md border border-border bg-surface","aria-label":"Alerts watching this queue",children:[t.jsxs("div",{className:"flex items-center gap-2 border-b border-border px-3 py-2",children:[t.jsx(rl,{className:"size-3.5 text-fg-muted"}),t.jsx("h2",{className:"text-[11px] font-semibold uppercase tracking-wider text-fg-muted",children:"Alerts on this queue"}),t.jsx("span",{className:"text-[11px] text-fg-subtle",children:r.length}),t.jsxs("div",{className:"ml-auto flex items-center gap-2",children:[t.jsx(Ee,{to:ue.alerts,className:"text-[11px] text-accent hover:underline",children:"Manage all"}),o&&t.jsx(V,{size:"xs",variant:"ghost",leftIcon:t.jsx(es,{}),onClick:i,children:"Add"})]})]}),t.jsx("ul",{className:"divide-y divide-border",children:r.map(({alert:h,via:f})=>t.jsxs("li",{className:"flex flex-wrap items-center gap-x-3 gap-y-1 px-3 py-2 text-[12px]",children:[t.jsx("span",{className:"shrink-0",children:h.firing?t.jsxs(be,{variant:"danger",className:"gap-1",children:[t.jsx(lm,{className:"size-3"})," firing"]}):h.enabled?t.jsx(be,{variant:"success",children:"ok"}):t.jsx(be,{variant:"neutral",children:"off"})}),t.jsx("span",{className:F("font-medium",!h.enabled&&"text-fg-muted"),children:h.name}),t.jsx("span",{className:"font-mono text-[11px] text-fg-muted",children:fj(h.condition)}),(f.kind==="connection"||f.kind==="global")&&t.jsx("span",{className:"rounded border border-border px-1 text-[10px] text-fg-muted",children:f.kind==="global"?"every queue":"whole connection"}),f.kind==="folder"&&t.jsx(Pe,{content:"This alert watches every queue in the folder",children:t.jsxs(Ee,{to:ue.folder(f.folderId),className:"rounded border border-border px-1 text-[10px] text-fg-muted hover:text-fg",children:["via folder ",f.folderName]})}),t.jsxs("span",{className:"ml-auto flex items-center gap-3 text-[11px] text-fg-subtle",children:[t.jsx("span",{children:h.lastFiredAt?t.jsxs(t.Fragment,{children:["last fired ",t.jsx(Yt,{value:h.lastFiredAt})]}):"never fired"}),o&&t.jsx("button",{type:"button",className:"text-fg-muted hover:text-fg",onClick:()=>d(h),title:"Edit alert","aria-label":`Edit ${h.name}`,children:t.jsx(Uo,{className:"size-3.5"})})]})]},h.id))}),c&&t.jsx(od,{open:!0,onClose:()=>d(null),alert:c}),t.jsx("span",{className:"sr-only",children:`Alerts watching ${n} on connection ${e}`})]})}function Bm({open:e,onClose:n,connectionId:r,queue:i,match:o}){const c=v2(r,i),[d,h]=w.useState(null),[f,g]=w.useState(!1),p=w.useRef(!1),v=[o.groupId?`of group ${o.groupId}`:null,o.query?`containing "${o.query}"`:null].filter(Boolean).join(" and "),j=async()=>{p.current=!1,g(!0);let y={promoted:0,failedCount:0,failed:[],scanned:0,total:0,done:!1};h(y);let b;try{do{const k=await c.mutateAsync({...o,cursor:b});y={promoted:y.promoted+k.promoted,failedCount:y.failedCount+k.failedCount,failed:[...y.failed,...k.failed].slice(0,20),scanned:y.scanned+k.scanned,total:k.total,done:k.nextCursor===null},h(y),b=k.nextCursor??void 0}while(b!==void 0&&!p.current);y.failedCount===0?X.success(`${K(y.promoted)} delayed jobs promoted`):X.error(`${K(y.promoted)} promoted · ${K(y.failedCount)} failed`)}catch(k){X.error(ve(k))}finally{g(!1)}},S=()=>{p.current=!0,f||h(null),n()};return t.jsx(bn,{open:e,onClose:S,size:"sm",title:"Promote every matching delayed job",description:`Every delayed job ${v} in ${i}, not only the ones on screen, runs now. On a BullMQ Pro queue grouped jobs go back into their group and keep its rate limit.`,footer:f?t.jsx(V,{variant:"ghost",size:"sm",onClick:()=>p.current=!0,children:"Stop after this batch"}):d!=null&&d.done||d&&p.current?t.jsx(V,{size:"sm",onClick:S,children:"Close"}):t.jsxs(t.Fragment,{children:[t.jsx(V,{variant:"ghost",size:"sm",onClick:S,children:"Cancel"}),t.jsx(V,{size:"sm",onClick:j,children:"Promote all"})]}),children:d&&t.jsxs("div",{className:"space-y-2 text-xs",role:"status",children:[t.jsxs("p",{children:[t.jsx("span",{className:"num font-semibold text-fg",children:K(d.promoted)})," promoted",d.failedCount>0&&t.jsxs(t.Fragment,{children:[" ","· ",t.jsx("span",{className:"num font-semibold text-danger",children:K(d.failedCount)})," failed"]})," ","· scanned ",t.jsx("span",{className:"num",children:K(Math.min(d.scanned,Math.max(d.total,d.scanned)))})," delayed jobs",d.done?" · done":f?"…":" · stopped"]}),d.failed.length>0&&t.jsx("ul",{className:"max-h-32 overflow-auto rounded border border-border p-2 font-mono text-[11px] text-fg-muted",children:d.failed.map(y=>t.jsxs("li",{className:"truncate",children:[y.jobId,": ",y.reason]},y.jobId))})]})})}function E_({connectionId:e,queue:n,groupId:r}){var S;const{isOperator:i,isAdmin:o}=mt(),c=((S=td(e,n,{page:1,pageSize:1}).data)==null?void 0:S.bullmqProApi)??!1,d=q0(e,n),[h,f]=w.useState(!1),[g,p]=w.useState(!1),v=c?void 0:"Needs BullMQ Pro's package installed next to Bullpane",j=y=>d.mutate({groupId:r,action:y},{onSuccess:()=>X.success(`Group ${r} ${y==="pause"?"paused":y==="resume"?"resumed":"drained"}`),onError:b=>X.error(ve(b)),onSettled:()=>f(!1)});return t.jsxs("div",{className:"mb-3 flex flex-wrap items-center gap-2 rounded-md border border-border bg-surface-2/40 px-3 py-2 text-xs",children:[t.jsx(Do,{className:"size-3.5 text-pro","aria-hidden":!0}),t.jsxs("span",{className:"text-fg-muted",children:["Group ",t.jsx("span",{className:"font-mono text-fg",children:r})]}),t.jsx(Ee,{to:ue.group(e,n,r),className:"text-accent hover:underline",children:"open group page"}),i&&t.jsxs("div",{className:"ml-auto flex flex-wrap items-center gap-2",children:[t.jsx(V,{size:"xs",variant:"secondary",leftIcon:t.jsx(Gr,{}),disabled:!c||d.isPending,title:v,onClick:()=>j("pause"),children:"Pause group"}),t.jsx(V,{size:"xs",variant:"secondary",leftIcon:t.jsx(Qo,{}),disabled:!c||d.isPending,title:v,onClick:()=>j("resume"),children:"Resume group"}),t.jsx(V,{size:"xs",variant:"secondary",leftIcon:t.jsx(um,{}),disabled:!c,title:v,onClick:()=>p(!0),children:"Promote all delayed"}),o&&t.jsx(V,{size:"xs",variant:"danger",leftIcon:t.jsx(Un,{}),disabled:!c||d.isPending,title:v,onClick:()=>f(!0),children:"Drain group"})]}),t.jsx(Ht,{open:h,onClose:()=>f(!1),title:"Drain group",description:`Remove every waiting job of group ${r} in ${n} (BullMQ Pro's deleteGroup)? Its delayed jobs stay in the queue's delayed state. This cannot be undone.`,confirmText:"Drain group",danger:!0,loading:d.isPending,onConfirm:()=>j("drain")}),t.jsx(Bm,{open:g,onClose:()=>p(!1),connectionId:e,queue:n,match:{groupId:r}})]})}function R_({connectionId:e,queue:n,value:r,onChange:i,disabled:o,className:c,showWaiting:d=!0,pageGroups:h=[]}){var M;const f=td(e,n,{page:1,pageSize:200}),[g,p]=w.useState(!1),[v,j]=w.useState(""),[S,y]=w.useState(0),b=w.useRef(null),k=w.useRef(null),C=w.useId(),z=((M=f.data)==null?void 0:M.groups)??[],O=w.useMemo(()=>{const E=v.trim().toLowerCase(),I=z.filter(ce=>!E||ce.id.toLowerCase().includes(E)).slice(0,100),Q=E&&z.some(ce=>ce.id.toLowerCase()===E),H=h.filter(ce=>!E||ce.toLowerCase().includes(E)).slice(0,50),q=new Set(H),B=[];E||B.push({id:"",label:"All groups"}),B.push(...H.map(ce=>({id:ce,label:ce,onPage:!0}))),B.push(...I.filter(ce=>!q.has(ce.id)).map(ce=>({id:ce.id,label:ce.id,waiting:d?ce.waiting:void 0})));const de=Q||H.some(ce=>ce.toLowerCase()===E);return E&&!de&&B.push({id:v.trim(),label:`Use "${v.trim()}"`,custom:!0}),B},[z,v,h,d]);w.useEffect(()=>y(0),[v,g]),w.useEffect(()=>{if(!g)return;const E=I=>{var Q;(Q=k.current)!=null&&Q.contains(I.target)||p(!1)};return document.addEventListener("mousedown",E),()=>document.removeEventListener("mousedown",E)},[g]);const T=E=>{i(E),p(!1),j("")};return t.jsxs("div",{ref:k,className:F("relative",c),children:[t.jsxs("div",{className:F("control flex !h-7 !w-auto min-w-44 items-center gap-1.5 !px-2 text-xs",o&&"cursor-not-allowed opacity-50",r&&"border-pro/60"),children:[t.jsx(Do,{className:"size-3.5 shrink-0 text-pro","aria-hidden":!0}),g?t.jsx("input",{ref:b,autoFocus:!0,role:"combobox","aria-expanded":g,"aria-controls":C,"aria-autocomplete":"list","aria-label":"Filter by group",className:"min-w-0 flex-1 bg-transparent font-mono outline-none placeholder:font-sans placeholder:text-fg-subtle",placeholder:"Type a group id…",value:v,onChange:E=>j(E.target.value),onKeyDown:E=>{E.key==="ArrowDown"?(E.preventDefault(),y(I=>Math.min(O.length-1,I+1))):E.key==="ArrowUp"?(E.preventDefault(),y(I=>Math.max(0,I-1))):E.key==="Enter"?(E.preventDefault(),O[S]&&T(O[S].id)):E.key==="Escape"&&(E.preventDefault(),p(!1),j(""))}}):t.jsx("button",{type:"button",disabled:o,className:"flex min-w-0 flex-1 items-center gap-1 text-left",onClick:()=>p(!0),"aria-haspopup":"listbox","aria-expanded":g,title:r?`Showing group ${r}`:"Filter jobs by group",children:r?t.jsx("span",{className:"truncate font-mono text-fg",children:r}):t.jsxs("span",{className:"truncate text-fg-muted",children:["All groups",f.data?t.jsxs("span",{className:"num text-fg-subtle",children:[" · ",ft(f.data.total)]}):null]})}),r&&!o?t.jsx("button",{type:"button",className:"rounded p-0.5 text-fg-subtle hover:text-fg","aria-label":"Clear group filter",onClick:()=>T(""),children:t.jsx(vn,{className:"size-3"})}):t.jsx(ps,{className:"size-3.5 shrink-0 text-fg-subtle","aria-hidden":!0})]}),g&&t.jsxs("ul",{id:C,role:"listbox",className:"absolute left-0 z-40 mt-1 max-h-64 w-72 overflow-auto rounded-md border border-border bg-surface p-1 text-xs shadow-[var(--shadow)]",children:[f.isLoading&&t.jsx("li",{className:"px-2 py-1.5 text-fg-subtle",children:"Loading groups…"}),!f.isLoading&&O.length===0&&t.jsx("li",{className:"px-2 py-1.5 text-fg-subtle",children:"No groups"}),O.map((E,I)=>{const Q=E.id===r;return t.jsxs("li",{role:"option","aria-selected":Q,className:F("flex cursor-pointer items-center gap-2 rounded px-2 py-1",I===S?"bg-surface-3 text-fg":"text-fg-muted hover:bg-surface-2 hover:text-fg"),onMouseEnter:()=>y(I),onMouseDown:H=>H.preventDefault(),onClick:()=>T(E.id),children:[t.jsx("span",{className:F("min-w-0 flex-1 truncate",E.id&&!E.custom&&"font-mono"),children:E.label}),E.waiting!=null&&t.jsxs("span",{className:"num text-[10px] text-fg-subtle",children:[ft(E.waiting)," waiting"]}),E.onPage&&t.jsx("span",{className:"text-[10px] text-fg-subtle",children:"on this page"}),Q&&t.jsx(Zr,{className:"size-3.5 text-accent","aria-hidden":!0})]},E.custom?`custom:${E.id}`:E.id||"__all__")}),f.data&&f.data.total>z.length&&t.jsxs("li",{className:"border-t border-border px-2 py-1 text-[10px] text-fg-subtle",children:["Showing the first ",z.length," of ",ft(f.data.total)," groups — type an id to filter or use it directly."]})]})]})}const M_={retry:"retried",promote:"promoted",remove:"removed",discard:"discarded"};function mj(e,n,r){return n==="promote"&&(r==null?void 0:r.mode)==="ran_copy"?`Job ${e} belongs to scheduler "${r.schedulerId}": ran a copy (${r.jobId}) now, the next scheduled run is unchanged`:n==="promote"&&(r==null?void 0:r.mode)==="skipped_next"?`Job ${e} promoted: scheduler "${r.schedulerId}" skips the run it was scheduled for`:`Job ${e} ${M_[n]}`}const T_=[{mode:"run_copy",title:"Run a copy now",detail:e=>`A one-off copy runs now. The scheduled run at ${e} still happens.`},{mode:"skip_next",title:"Promote and skip the next run",detail:e=>`The run scheduled for ${e} runs now instead. Nothing runs at ${e}; the scheduler continues with the run after it.`}];function pj({job:e,onClose:n,onPick:r,pending:i}){const o=e!=null&&e.delayedUntil?gn(e.delayedUntil):"its scheduled time";return t.jsx(bn,{open:e!==null,onClose:n,size:"md",title:"Promote a scheduled job",description:e?t.jsxs(t.Fragment,{children:["Job ",t.jsx("span",{className:"font-mono",children:e.id})," is the next run of scheduler"," ",t.jsx("span",{className:"font-mono",children:e.repeatJobKey}),"."]}):void 0,footer:t.jsx(V,{variant:"ghost",size:"sm",onClick:n,disabled:!!i,children:"Cancel"}),children:t.jsx("div",{className:"flex flex-col gap-2",children:T_.map(c=>t.jsxs("button",{type:"button",disabled:!!i,onClick:()=>r(c.mode),className:"rounded-md border border-border bg-surface-2 px-3 py-2.5 text-left transition-colors hover:border-border-strong hover:bg-surface-3 disabled:opacity-60",children:[t.jsxs("span",{className:"block text-sm font-medium text-fg",children:[c.title,i===c.mode&&"…"]}),t.jsx("span",{className:"mt-0.5 block text-xs text-fg-muted",children:c.detail(o)})]},c.mode))})})}const q_=10;function $_(e){return!!e&&yo.includes(e)}function sf({view:e="jobs"}={}){var ml,pl,xl,si,gl,cr,ri,ur,Jo,dr,aa,ia,ai,Xo,Yo,ec,ys,vl,yl,tc,jl,bl,wl,Nl,nc,sc,gt;const{connectionId:n="",queue:r=""}=Fn(),[i,o]=sl(),c=un(),{isOperator:d,isAdmin:h}=mt(),f=$_(i.get("state"))?i.get("state"):"waiting",g=Math.max(1,Number(i.get("page")??1)||1),p=[25,50,100,200].includes(Number(i.get("pageSize")))?Number(i.get("pageSize")):25,v=i.get("order")==="asc"?"asc":"desc",j=i.get("q")??"",S=i.get("group")??"",[y,b]=w.useState(j),k=w.useCallback(le=>{o(nt=>{const et=new URLSearchParams(nt);for(const[Tt,kl]of Object.entries(le))kl==null||kl===""?et.delete(Tt):et.set(Tt,kl);return et},{replace:!0})},[o]),C=R0(n,r),z=C_(n,r),O=_m(n),T=!!C.data&&(C.data.isPro||C.data.groupsCount>0),M=j.trim().length>0,E=!M&&!!S&&f!=="waiting"&&f!=="prioritized",I=!M&&!!S&&!E,Q=M||E,H=e==="metrics",q=e==="schedulers",B=H||q,de=M0(n,r,{state:f,page:g,pageSize:p,order:v,groupId:I?S:void 0},{enabled:!Q&&!B}),ce=h2(n,r,{state:f,q:j.trim(),groupId:E?S:void 0,limit:50},{enabled:Q&&!B}),Ne=jm(n,r),Ie=T0(n,r),ot=p2(n,r),De=((ml=ce.data)==null?void 0:ml.pages)??[],W=De.flatMap(le=>le.jobs),me=De.reduce((le,nt)=>le+(nt.scanned??0),0),re=De.reduce((le,nt)=>le+(nt.skippedLargePayloads??0),0),A=De.length?De[De.length-1].total:((xl=(pl=C.data)==null?void 0:pl.counts)==null?void 0:xl[f])??0,[Z,Fe]=w.useState(0);w.useEffect(()=>Fe(0),[S,f]),w.useEffect(()=>{!E||!ce.hasNextPage||ce.isFetching||W.length>=50||De.length-Z>=q_||ce.fetchNextPage()},[E,ce,W.length,De.length,Z]);const Ue=()=>{Fe(De.length),ce.fetchNextPage()},Se=Q?W:((si=de.data)==null?void 0:si.jobs)??[],Qe=w.useMemo(()=>Se.map(le=>le.id),[Se]),rt=w.useMemo(()=>[...new Set(Se.map(le=>le.groupId).filter(le=>!!le))],[Se]),He=kC(Qe),[at,Zt]=w.useState(null),[lr,ul]=w.useState(null),[Za,Yr]=w.useState(null),[ea,Ga]=w.useState(null),[ta,Ja]=w.useState(null),[dl,or]=w.useState(!1),[Rn,Ut]=w.useState(null),[Ko,Xa]=w.useState(!1),Qn=i.get("confirm");w.useEffect(()=>{if(Qn!=="drain"&&Qn!=="clean"&&Qn!=="obliterate")return;(Qn==="clean"?d:h)?Ut(Qn):X.error(`${Qn==="clean"?"Cleaning":Qn==="drain"?"Draining":"Obliterating"} a queue needs the ${Qn==="clean"?"operator":"admin"} role`),o(nt=>{const et=new URLSearchParams(nt);return et.delete("confirm"),et},{replace:!0})},[Qn,h,d,o]);const{has:Wo,gate:Ya}=wt(),[na,vs]=w.useState(!1),zs=w.useRef(null),Os=w.useCallback(()=>{var le,nt;(le=zs.current)==null||le.focus(),(nt=zs.current)==null||nt.select()},[]);S0("/",le=>{le.preventDefault(),Os()}),w.useEffect(()=>{if(i.get("search")!=="1")return;const le=window.setTimeout(Os,0);return k({search:null}),()=>window.clearTimeout(le)},[i,k,Os]),w.useEffect(()=>b(j),[j]);const Nt=(gl=C.data)==null?void 0:gl.counts,hl=(cr=$0(n,r,S||void 0,{page:1,pageSize:1}).data)==null?void 0:cr.total,Ot=(ri=C.data)==null?void 0:ri.groupWaiting,Zo=w.useMemo(()=>{if(S)return{count:hl??null,title:`Jobs waiting in group ${S} (its list and its prioritized jobs)`};if(!Ot||Ot.jobs===0)return{count:(Nt==null?void 0:Nt.waiting)??null};const le=(Nt==null?void 0:Nt.waiting)??0;return{count:le+Ot.jobs,countSuffix:Ot.complete?void 0:"+",title:`${K(le)} in the queue's wait list + ${K(Ot.jobs)} waiting inside BullMQ Pro groups`+(Ot.complete?"":` (the first ${K(Sk)} groups)`)+". Pick a group to list its jobs."}},[S,hl,Ot,Nt==null?void 0:Nt.waiting]),fl=w.useMemo(()=>{var nt,et;const le=[{value:"metrics",label:"Metrics",icon:t.jsx(om,{className:"size-3.5"})},{value:"schedulers",label:"Schedulers",count:((nt=C.data)==null?void 0:nt.schedulersCount)??null,icon:t.jsx(Lo,{className:"size-3.5"})},...yo.map(Tt=>({value:Tt,label:lt[Tt].label,count:(Nt==null?void 0:Nt[Tt])??null,tone:lt[Tt].dotClass,...Tt==="waiting"?Zo:{}}))];return(et=C.data)!=null&&et.isPro&&le.push({value:"groups",label:"Groups",count:C.data.groupsCount,icon:t.jsx(Do,{className:"size-3.5 text-pro"})}),le},[Nt,Zo,(ur=C.data)==null?void 0:ur.isPro,(Jo=C.data)==null?void 0:Jo.groupsCount,(dr=C.data)==null?void 0:dr.schedulersCount]),sa=(le,nt,et)=>{Ne.mutate({jobId:le,action:nt,scheduler:et},{onSuccess:Tt=>{X.success(mj(le,nt,Tt)),Ja(null)},onError:Tt=>X.error(ve(Tt))})},ei=(le,nt,et)=>{if(nt==="remove"){Ga(le);return}if(nt==="promote"&&(et!=null&&et.repeatJobKey)){Ja({id:et.id,repeatJobKey:et.repeatJobKey,delayedUntil:et.delayedUntil});return}sa(le,nt)},ti=w.useMemo(()=>aj(M?"mixed":f),[M,f]),ni=le=>{const nt=He.selectedIds;if(nt.length!==0){if(nt.length>Au){X.error(`Select at most ${K(Au)} jobs per action (${K(nt.length)} selected).`);return}ul(le),ot.mutate({action:le,jobIds:nt},{onSuccess:et=>{Zt(et),He.deselect(et.ok);const Tt=le==="retry"?"retried":le==="promote"?"promoted":"removed";et.failed.length===0?X.success(`${K(et.ok.length)} ${Tt}`):X.error(`${K(et.ok.length)} ${Tt} · ${K(et.failed.length)} failed`)},onError:et=>X.error(ve(et)),onSettled:()=>{ul(null),Yr(null)}})}},As=le=>{le==="remove"?Yr("remove"):ni(le)},Bn=(le,nt)=>Ie.mutate(le,{onSuccess:()=>{X.success(nt),Ut(null),le.action==="obliterate"&&c(ue.connection(n))},onError:et=>X.error(ve(et))}),Go=()=>k({q:y.trim()||null,page:null}),ra=()=>{b(""),k({q:null,page:null})};return t.jsxs(bt,{wide:!0,children:[t.jsxs("div",{className:"mb-3 flex flex-wrap items-start justify-between gap-3",children:[t.jsxs("div",{className:"min-w-0",children:[t.jsxs("div",{className:"flex items-center gap-2",children:[t.jsx("h1",{className:"truncate font-mono text-lg font-semibold tracking-tight",children:r}),((aa=C.data)==null?void 0:aa.isPaused)&&t.jsx(be,{variant:"warning",dot:!0,className:"tracking-wider",children:"PAUSED"}),((ia=C.data)==null?void 0:ia.isPro)&&t.jsx(be,{variant:"pro",title:"BullMQ Pro groups detected",className:"tracking-wider",children:"PRO"}),C.isError&&t.jsx(be,{variant:"danger",children:"unreachable"})]}),t.jsxs("p",{className:"mt-0.5 flex items-center gap-3 text-xs text-fg-muted",children:[t.jsxs("span",{className:"font-mono",children:[((ai=C.data)==null?void 0:ai.prefix)??"bull",":",r]}),((Xo=C.data)==null?void 0:Xo.metrics)&&C.data.metrics.completed.length>1&&t.jsxs("span",{className:"flex items-center gap-1.5",children:[t.jsx("span",{style:{color:lt.completed.fg},children:t.jsx(tl,{values:C.data.metrics.completed,width:72,height:16,title:"Completed per minute"})}),t.jsx("span",{style:{color:lt.failed.fg},children:t.jsx(tl,{values:C.data.metrics.failed,width:72,height:16,title:"Failed per minute"})})]}),t.jsx(__,{matches:z.matches,firing:z.firing})]})]}),d&&t.jsxs("div",{className:"flex flex-wrap items-center gap-2",children:[t.jsx(V,{size:"sm",variant:"primary",leftIcon:t.jsx(es,{}),onClick:()=>Ut("add"),children:"Add job"}),t.jsx(V,{size:"sm",leftIcon:t.jsx(rl,{}),onClick:()=>Ya("alerts",()=>Xa(!0)),title:"Alert on this queue",children:"Create alert"}),t.jsx(V,{size:"sm",leftIcon:(Yo=C.data)!=null&&Yo.isPaused?t.jsx(Qo,{}):t.jsx(Gr,{}),loading:Ie.isPending&&(((ec=Ie.variables)==null?void 0:ec.action)==="pause"||((ys=Ie.variables)==null?void 0:ys.action)==="resume"),onClick:()=>{var le;return(le=C.data)!=null&&le.isPaused?Bn({action:"resume"},"Queue resumed"):Ut("pause")},children:(vl=C.data)!=null&&vl.isPaused?"Resume":"Pause"}),t.jsx(V,{size:"sm",leftIcon:t.jsx(Zu,{}),onClick:()=>Ut("retryAll"),disabled:!Nt||Nt.failed===0,children:"Retry all failed"}),t.jsxs("div",{className:"relative",children:[t.jsx(V,{size:"sm",variant:"secondary",rightIcon:t.jsx(ps,{}),"aria-haspopup":"menu","aria-expanded":na,onClick:()=>vs(le=>!le),children:"More"}),na&&t.jsxs(t.Fragment,{children:[t.jsx("div",{className:"fixed inset-0 z-30",onClick:()=>vs(!1),"aria-hidden":!0}),t.jsxs("div",{role:"menu",className:"absolute right-0 z-40 mt-1 w-56 rounded-lg border border-border bg-surface p-1 shadow-[var(--shadow)]",children:[t.jsx(hu,{icon:t.jsx(bN,{}),label:"Clean…",hint:"remove by state and age",onClick:()=>(vs(!1),Ut("clean"))}),h&&t.jsxs(Ee,{role:"menuitem",to:ue.audit({connectionId:n,queueName:r}),onClick:()=>vs(!1),className:"nav-item w-full text-left",children:[t.jsx(Bo,{className:"size-3.5 shrink-0","aria-hidden":!0}),t.jsxs("span",{className:"flex-1",children:["Audit this queue",t.jsx("span",{className:"block text-[10px] text-fg-subtle",children:"who paused, cleaned or drained it"})]})]}),d&&t.jsx(hu,{icon:t.jsx(Fo,{}),label:"Hide from the lists",hint:kS,onClick:()=>(vs(!1),O.hide(r))}),h&&t.jsx(hu,{icon:t.jsx(Un,{}),label:"Drain",hint:"remove all waiting jobs",onClick:()=>(vs(!1),Ut("drain"))}),h&&t.jsx(hu,{icon:t.jsx(wN,{}),label:"Obliterate…",hint:"deletes the queue and every job · permanent",danger:!0,onClick:()=>(vs(!1),Ut("obliterate"))})]})]})]})]})]}),t.jsx(u_,{connectionId:n,queue:r,className:"mb-3"}),t.jsx("div",{className:"mb-3",children:t.jsx(P_,{connectionId:n,queueName:r,matches:z.matches,onCreate:()=>Ya("alerts",()=>Xa(!0))})}),!B&&t.jsxs("form",{className:"mb-3 flex flex-wrap items-center gap-2",role:"search",onSubmit:le=>{le.preventDefault(),Go()},children:[t.jsxs("div",{className:"relative min-w-72 flex-1",children:[t.jsx(Te,{ref:zs,leftIcon:t.jsx(Yn,{}),placeholder:`Search job data, name, id or error in ${f}…`,"aria-label":"Search jobs",value:y,onChange:le=>b(le.target.value),onKeyDown:le=>{le.key==="Escape"&&(le.preventDefault(),ra(),le.target.blur())},className:"!h-9 pr-16 text-[13px]"}),t.jsx("span",{className:"absolute top-1/2 right-2 flex -translate-y-1/2 items-center gap-1",children:y||M?t.jsx("button",{type:"button",className:"rounded p-0.5 text-fg-subtle hover:text-fg","aria-label":"Clear search",onClick:ra,children:t.jsx(vn,{className:"size-3.5"})}):t.jsx("span",{className:"hidden items-center gap-1 sm:flex",children:t.jsx(Xi,{children:"/"})})})]}),t.jsx(dt,{"aria-label":"State to search",className:"!h-9 !w-auto",value:f,onChange:le=>k({state:le.target.value,page:null,group:null}),options:yo.map(le=>({value:le,label:`in ${lt[le].label}`}))}),t.jsx(V,{type:"submit",size:"md",variant:M?"secondary":"primary",leftIcon:t.jsx(Yn,{}),disabled:!y.trim()&&!M,children:"Search"}),t.jsx("span",{className:"hidden text-[11px] text-fg-subtle lg:inline",children:"Enter to search · Esc to clear · substring match, server-side"})]}),t.jsxs("div",{className:"mb-3 flex flex-wrap items-end gap-3 border-b border-border",children:[t.jsx("div",{className:F("min-w-0 flex-1 transition-opacity",!B&&M&&"opacity-50"),children:t.jsx(Um,{"aria-label":"Job state",items:fl,value:H?"metrics":q?"schedulers":f,onChange:le=>{le==="groups"?c(ue.groups(n,r)):le==="metrics"?c(ue.queueMetrics(n,r)):le==="schedulers"?c(`/c/${encodeURIComponent(n)}/q/${encodeURIComponent(r)}/schedulers`):B?c(ue.queue(n,r,le)):k({state:le,page:null})},className:"!border-b-0",size:"sm"})}),T&&!M&&!B&&t.jsxs("div",{className:"flex items-center gap-2 pb-1.5",children:[(I||E)&&t.jsxs("span",{className:"text-[11px] text-fg-muted",children:["showing group ",t.jsx("span",{className:"font-mono text-fg",children:S}),"'s ",E?f:"waiting"," jobs"]}),t.jsx(R_,{connectionId:n,queue:r,value:S,onChange:le=>k({group:le||null,page:null}),showWaiting:f==="waiting"||f==="prioritized",pageGroups:rt})]}),!Q&&!B&&t.jsx(V,{size:"sm",variant:"ghost",className:"mb-1",leftIcon:t.jsx(lN,{}),onClick:()=>k({order:v==="desc"?"asc":"desc"}),title:"Toggle order",children:v==="desc"?"Newest first":"Oldest first"})]}),T&&S&&!M&&!B&&t.jsx(E_,{connectionId:n,queue:r,groupId:S}),q?t.jsx(m_,{connectionId:n,queue:r}):H?t.jsx(YC,{connectionId:n,queue:r,summary:C.data,onOpenState:le=>c(ue.queue(n,r,le))}):t.jsx("div",{className:"card overflow-hidden",children:Q?t.jsxs(t.Fragment,{children:[t.jsxs("div",{className:"flex flex-wrap items-center justify-between gap-2 border-b border-border bg-surface-2/50 px-3 py-2 text-xs",role:"status",children:[t.jsxs("span",{className:"flex items-center gap-2 text-fg-muted",children:[t.jsx(Yn,{className:"size-3.5 text-fg-subtle","aria-hidden":!0}),ce.isFetching&&!ce.isFetchingNextPage?t.jsx(Kt,{label:M?`Scanning ${f} jobs for "${j}"…`:`Scanning ${f} jobs for group ${S}…`}):t.jsxs(t.Fragment,{children:[t.jsx("span",{className:"num font-semibold text-fg",children:K(W.length)})," ",M?W.length===1?"match":"matches":`${W.length===1?"job":"jobs"} of group ${S}`," · scanned ",t.jsx("span",{className:"num text-fg",children:K(Math.min(me,A))})," of"," ",t.jsx("span",{className:"num text-fg",children:K(A)})," jobs in ",t.jsx("span",{className:lt[f].textClass,children:f}),!ce.hasNextPage&&ce.data&&t.jsx("span",{className:"text-fg-subtle",children:" · whole state scanned"}),re>0&&t.jsxs("span",{className:"text-fg-subtle",title:"Payloads above the search size cap are not read into Lua; those jobs still match on id, name and error.",children:[" ","· ",K(re)," ",re===1?"payload":"payloads"," too large to search inside"]})]})]}),t.jsxs("span",{className:"flex items-center gap-2",children:[M&&f==="delayed"&&d&&t.jsx(V,{size:"sm",variant:"secondary",leftIcon:t.jsx(um,{}),onClick:()=>or(!0),title:"Promote every delayed job that contains the search, not only the loaded ones",children:"Promote all matches"}),ce.hasNextPage&&t.jsx(V,{size:"sm",onClick:Ue,loading:ce.isFetchingNextPage,children:"Scan more"}),t.jsx(V,{size:"sm",variant:"ghost",leftIcon:t.jsx(vn,{}),onClick:M?ra:()=>k({group:null,page:null}),children:"Clear"})]})]}),at&&t.jsx(wv,{result:at,onDismiss:()=>Zt(null)}),d&&t.jsx(bv,{selection:He,state:M?"mixed":f,queue:r,actions:ti,onRun:As,pending:lr,searching:!0}),t.jsx(Kf,{connectionId:n,queue:r,jobs:ce.data?W:void 0,loading:ce.isLoading,error:ce.error,emptyText:ce.hasNextPage?"No matches yet — scan more to keep looking":M?`No ${f} job contains "${j}"`:`No ${f} jobs in group ${S}`,canOperate:d,onAction:ei,pendingId:Ne.isPending?(yl=Ne.variables)==null?void 0:yl.jobId:null,showState:!1,showGroup:T,onGroupClick:le=>{ra(),k({group:le,page:null})},highlight:M?j:void 0,selection:d?He:void 0}),t.jsxs("div",{className:"flex items-center justify-between border-t border-border px-3 py-2 text-xs text-fg-subtle",children:[t.jsx("span",{children:"Each scan reads a bounded slice of the state to keep the database happy."}),ce.hasNextPage&&t.jsx(V,{size:"sm",onClick:Ue,loading:ce.isFetchingNextPage,children:"Scan more"})]})]}):t.jsxs(t.Fragment,{children:[f==="active"&&(((tc=C.data)==null?void 0:tc.stalledCount)??0)>0&&t.jsxs("div",{className:"flex items-start gap-2 border-b border-border bg-warning/10 px-3 py-2 text-xs",role:"status",children:[t.jsx(fm,{className:"mt-0.5 size-3.5 shrink-0 text-warning","aria-hidden":!0}),t.jsxs("span",{children:[t.jsx("span",{className:"num font-semibold text-fg",children:K(((jl=C.data)==null?void 0:jl.stalledCount)??0)})," of these are stalled (worker lost the lock).",t.jsx("span",{className:"text-fg-muted",children:" BullMQ still reports them as active; the next stalled check moves them back to waiting and bumps their stall counter."})]})]}),at&&t.jsx(wv,{result:at,onDismiss:()=>Zt(null)}),d&&t.jsx(bv,{selection:He,state:f,queue:r,actions:ti,onRun:As,pending:lr}),t.jsx(Kf,{connectionId:n,queue:r,jobs:(bl=de.data)==null?void 0:bl.jobs,loading:de.isLoading,error:de.error,emptyText:I?`No waiting jobs in group ${S}`:f==="waiting"&&((Ot==null?void 0:Ot.jobs)??0)>0?`The queue's wait list is empty: BullMQ Pro keeps ${K((Ot==null?void 0:Ot.jobs)??0)}${Ot!=null&&Ot.complete?"":"+"} waiting jobs inside groups. Pick a group above to list them.`:"No jobs in this state",canOperate:d,onAction:ei,pendingId:Ne.isPending?(wl=Ne.variables)==null?void 0:wl.jobId:null,showState:!1,showGroup:T,onGroupClick:le=>k({group:le,page:null}),selection:d?He:void 0}),t.jsx("div",{className:F("border-t border-border px-3 py-2",de.isFetching&&"opacity-80"),children:t.jsx(ld,{page:g,pageSize:p,total:((Nl=de.data)==null?void 0:Nl.total)??(I?0:(Nt==null?void 0:Nt[f])??0),count:(nc=de.data)==null?void 0:nc.jobs.length,onPage:le=>k({page:String(le)}),onPageSize:le=>k({pageSize:String(le),page:null})})})]})}),d&&t.jsx(i_,{open:Rn==="add",onClose:()=>Ut(null),connectionId:n,queue:r}),d&&Wo("alerts")&&Ko&&t.jsx(od,{open:!0,onClose:()=>Xa(!1),alert:null,initialScope:{type:"queue",connectionId:n,queueName:r}}),d&&t.jsx(c_,{open:Rn==="clean",onClose:()=>Ut(null),connectionId:n,queue:r,defaultState:f==="waiting"?"wait":f==="waiting-children"?"completed":f}),t.jsx(Ht,{open:Za==="remove",onClose:()=>Yr(null),title:"Remove selected jobs",description:`Remove ${K(He.selectedIds.length)} ${He.selectedIds.length===1?"job":"jobs"} from ${r}? This cannot be undone.`,confirmText:`Remove ${K(He.selectedIds.length)}`,danger:!0,loading:lr==="remove",onConfirm:()=>ni("remove")}),t.jsx(Ht,{open:ea!==null,onClose:()=>Ga(null),title:"Remove job",description:`Remove job ${ea??""} from ${r}? This cannot be undone.`,confirmText:"Remove",danger:!0,loading:Ne.isPending,onConfirm:()=>{ea&&sa(ea,"remove"),Ga(null)}}),t.jsx(pj,{job:ta,onClose:()=>Ja(null),onPick:le=>ta&&sa(ta.id,"promote",le),pending:Ne.isPending&&((sc=Ne.variables)==null?void 0:sc.action)==="promote"?Ne.variables.scheduler??null:null}),t.jsx(tj,{queue:Rn==="pause"?r:null,onClose:()=>Ut(null),loading:Ie.isPending&&((gt=Ie.variables)==null?void 0:gt.action)==="pause",onConfirm:le=>Bn({action:"pause",body:le?{reason:le}:{}},"Queue paused")}),t.jsx(Ht,{open:Rn==="retryAll",onClose:()=>Ut(null),title:"Retry all failed jobs",description:`Moves ${K((Nt==null?void 0:Nt.failed)??0)} failed jobs in ${r} back to waiting.`,confirmText:"Retry all",loading:Ie.isPending,onConfirm:()=>Bn({action:"retry-all",body:{state:"failed"}},"Retrying all failed jobs")}),t.jsx(Ht,{open:Rn==="drain",onClose:()=>Ut(null),title:"Drain queue",description:`Removes every waiting and prioritized job in ${r}. Active, completed and failed jobs are kept.`,confirmText:"Drain",danger:!0,loading:Ie.isPending,onConfirm:()=>Bn({action:"drain",body:{includeDelayed:!1}},"Queue drained")}),t.jsx(Ht,{open:Rn==="obliterate",onClose:()=>Ut(null),title:"Obliterate queue",description:"Deletes every key of this queue from Redis, including completed and failed history. This cannot be undone.",confirmText:"Obliterate",danger:!0,typeToConfirm:r,loading:Ie.isPending,onConfirm:()=>Bn({action:"obliterate"},`${r} obliterated`)}),M&&t.jsx(Bm,{open:dl,onClose:()=>or(!1),connectionId:n,queue:r,match:{query:j.trim()}})]})}function hu({icon:e,label:n,hint:r,danger:i,onClick:o}){return t.jsxs("button",{role:"menuitem",type:"button",onClick:o,className:F("nav-item h-auto w-full py-1.5 text-left [&_svg]:size-3.5",i&&"text-danger hover:text-danger"),children:[e,t.jsxs("span",{className:"flex flex-col",children:[t.jsx("span",{className:F(!i&&"text-fg"),children:n}),r&&t.jsx("span",{className:"text-[11px] text-fg-subtle",children:r})]})]})}function xj({value:e,defaultExpandDepth:n=2,className:r,name:i}){return t.jsx("div",{className:F("font-mono text-xs leading-[1.6] text-fg",r),children:t.jsx(vj,{name:i,value:e,depth:0,expandDepth:n,last:!0})})}function gj(e){if(e===null)return"null";if(e===void 0)return"undefined";if(Array.isArray(e))return"array";const n=typeof e;return n==="object"?"object":n==="string"?"string":n==="number"||n==="bigint"?"number":n==="boolean"?"boolean":"other"}const fu=200;function I_({value:e}){const[n,r]=w.useState(!1);switch(gj(e)){case"string":{const o=e,d=!n&&o.length>fu?`${o.slice(0,fu)}…`:o;return t.jsxs("span",{className:"text-success break-all",children:['"',d,'"',o.length>fu&&t.jsx("button",{type:"button",className:"ml-1 rounded bg-surface-3 px-1 text-[10px] text-fg-muted hover:text-fg",onClick:()=>r(h=>!h),children:n?"less":`+${o.length-fu} chars`})]})}case"number":return t.jsx("span",{className:"text-info",children:String(e)});case"boolean":return t.jsx("span",{className:"text-violet",children:String(e)});case"null":return t.jsx("span",{className:"text-fg-subtle",children:"null"});case"undefined":return t.jsx("span",{className:"text-fg-subtle",children:"undefined"});default:return t.jsx("span",{className:"text-fg-muted",children:String(e)})}}function vj({name:e,value:n,depth:r,expandDepth:i,last:o}){const c=gj(n),d=c==="object"||c==="array",[h,f]=w.useState(r<i),g=e!==void 0?t.jsxs(t.Fragment,{children:[t.jsx("span",{className:"text-fg",children:z_(e)?e:JSON.stringify(e)}),t.jsx("span",{className:"text-fg-subtle",children:": "})]}):null;if(!d)return t.jsxs("div",{className:"flex",style:{paddingLeft:r?16:0},children:[t.jsx("span",{className:"w-4 shrink-0"}),t.jsxs("span",{className:"min-w-0",children:[g,t.jsx(I_,{value:n}),!o&&t.jsx("span",{className:"text-fg-subtle",children:","})]})]});const p=c==="array"?n.map((y,b)=>[String(b),y]):Object.entries(n),[v,j]=c==="array"?["[","]"]:["{","}"],S=c==="array"?`${p.length} item${p.length===1?"":"s"}`:`${p.length} key${p.length===1?"":"s"}`;return p.length===0?t.jsxs("div",{className:"flex",style:{paddingLeft:r?16:0},children:[t.jsx("span",{className:"w-4 shrink-0"}),t.jsxs("span",{children:[g,t.jsxs("span",{className:"text-fg-muted",children:[v,j]}),!o&&t.jsx("span",{className:"text-fg-subtle",children:","})]})]}):t.jsxs("div",{style:{paddingLeft:r?16:0},children:[t.jsxs("div",{className:"flex",children:[t.jsx("button",{type:"button","aria-expanded":h,"aria-label":h?"Collapse":"Expand",onClick:()=>f(y=>!y),className:"flex w-4 shrink-0 items-start justify-center pt-[3px] text-fg-subtle hover:text-fg",children:h?t.jsx(ps,{className:"size-3"}):t.jsx(Dn,{className:"size-3"})}),t.jsxs("span",{className:"min-w-0 cursor-default",onClick:()=>!h&&f(!0),children:[g,t.jsx("span",{className:"text-fg-muted",children:v}),!h&&t.jsxs(t.Fragment,{children:[t.jsx("span",{className:"mx-1 rounded bg-surface-3 px-1 text-[10px] text-fg-subtle",children:S}),t.jsx("span",{className:"text-fg-muted",children:j}),!o&&t.jsx("span",{className:"text-fg-subtle",children:","})]})]})]}),h&&t.jsxs(t.Fragment,{children:[t.jsx("div",{className:"border-l border-border/70",style:{marginLeft:7},children:p.map(([y,b],k)=>t.jsx(vj,{name:c==="array"?void 0:y,value:b,depth:r+1,expandDepth:i,last:k===p.length-1},y))}),t.jsxs("div",{className:"flex",children:[t.jsx("span",{className:"w-4 shrink-0"}),t.jsxs("span",{className:"text-fg-muted",children:[j,!o&&t.jsx("span",{className:"text-fg-subtle",children:","})]})]})]})]})}function z_(e){return/^[A-Za-z_$][\w$]*$/.test(e)}function O_(){var T,M,E,I,Q;const{connectionId:e="",queue:n="",jobId:r=""}=Fn(),i=un(),{has:o}=wt(),{isOperator:c,isAdmin:d}=mt(),h=f2(e,n,r),f=jm(e,n),[g,p]=w.useState("data"),[v,j]=w.useState(null),[S,y]=w.useState(!1),b=(H,q)=>f.mutate({jobId:r,action:H,scheduler:q},{onSuccess:B=>{X.success(mj(r,H,B)),j(null),y(!1),H==="remove"&&i(ue.queue(e,n))},onError:B=>X.error(ve(B))});if(h.isLoading)return t.jsx(bt,{children:t.jsx(il,{label:"Loading job…"})});if(h.isError||!h.data){const H=Ts(h.error)&&h.error.status===404;return t.jsx(bt,{children:t.jsx(cn,{title:H?"Job not found":"Could not load job",description:H?"It may have been removed or cleaned since you opened it.":ve(h.error),action:t.jsxs(V,{variant:"secondary",leftIcon:t.jsx(Su,{}),onClick:()=>i(ue.queue(e,n)),children:["Back to ",n]})})})}const k=h.data,C=k.state==="failed"||k.state==="completed",z=k.state==="delayed",O=!!k.failedReason||(((T=k.stacktrace)==null?void 0:T.length)??0)>0;return t.jsxs(bt,{children:[t.jsxs("div",{className:"mb-4 flex flex-wrap items-start justify-between gap-3",children:[t.jsxs("div",{className:"min-w-0",children:[t.jsxs(Ee,{to:ue.queue(e,n,k.state!=="unknown"?k.state:void 0),className:"mb-1 inline-flex items-center gap-1 text-xs text-fg-muted hover:text-fg",children:[t.jsx(Su,{className:"size-3.5"})," ",n]}),t.jsxs("div",{className:"flex flex-wrap items-center gap-2",children:[t.jsx("h1",{className:"truncate text-lg font-semibold tracking-tight",children:k.name}),t.jsx(G0,{state:k.state}),k.groupId&&t.jsx(Ee,{to:ue.group(e,n,k.groupId),children:t.jsxs(be,{variant:"pro",mono:!0,title:"BullMQ Pro group",children:["group ",k.groupId]})}),k.priority>0&&t.jsxs(be,{variant:"violet",children:["priority ",k.priority]})]}),t.jsxs("p",{className:"mt-1 flex items-center gap-1 font-mono text-xs text-fg-muted",children:[t.jsx("span",{className:"select-all",children:k.id}),t.jsx(_o,{value:k.id,label:"Copy id",size:"icon-xs"}),t.jsx(_o,{value:()=>Du(k),label:"Copy JSON",copiedLabel:"Copied JSON",showLabel:!0,size:"xs",icon:t.jsx(Ly,{}),className:"ml-1 font-sans"})]})]}),c&&t.jsxs("div",{className:"flex flex-wrap items-center gap-2",children:[C&&t.jsx(V,{size:"sm",leftIcon:t.jsx(Zu,{}),onClick:()=>b("retry"),loading:f.isPending&&((M=f.variables)==null?void 0:M.action)==="retry",children:"Retry"}),z&&t.jsx(V,{size:"sm",leftIcon:t.jsx(im,{}),onClick:()=>k.repeatJobKey?y(!0):b("promote"),loading:f.isPending&&((E=f.variables)==null?void 0:E.action)==="promote",children:"Promote"}),t.jsx(V,{size:"sm",variant:"ghost",leftIcon:t.jsx(hN,{}),onClick:()=>j("discard"),title:"Mark as not retryable",children:"Discard"}),t.jsx(V,{size:"sm",variant:"ghost",className:"hover:text-danger",leftIcon:t.jsx(Un,{}),onClick:()=>j("remove"),children:"Remove"})]})]}),t.jsxs("div",{className:"mb-4 grid gap-3 lg:grid-cols-3",children:[t.jsx("div",{className:"card p-4 lg:col-span-2",children:t.jsx(F_,{job:k})}),t.jsxs("dl",{className:"card grid grid-cols-2 gap-x-4 gap-y-3 p-4 text-xs",children:[t.jsx(ja,{label:"Attempts",children:t.jsxs("span",{className:F(k.attemptsMade>1&&"text-warning"),children:[k.attemptsMade,k.attempts!=null&&t.jsxs("span",{className:"text-fg-subtle",children:[" / ",k.attempts]})]})}),k.state==="delayed"?t.jsx(ja,{label:"Runs at",children:t.jsx(A_,{at:k.delayedUntil})}):t.jsx(ja,{label:"Delay",children:k.delay?An(k.delay):"–"}),t.jsx(ja,{label:"Priority",children:k.priority||"–"}),t.jsx(ja,{label:"Progress",children:t.jsx(L_,{value:k.progress})}),t.jsx(ja,{label:"Parent",children:k.parent?t.jsxs(Ee,{to:ue.job(e,lv(k.parent.queueKey),k.parent.id),className:"inline-flex items-center gap-1 font-mono text-accent hover:underline",children:[t.jsx(kN,{className:"size-3"}),k.parent.queue||lv(k.parent.queueKey),"/",k.parent.id]}):"–"}),t.jsx(ja,{label:"Children",children:k.dependencies?t.jsxs("span",{children:[t.jsx("span",{className:"text-success",children:K(k.dependencies.processed)})," done ·"," ",t.jsx("span",{className:F(k.dependencies.unprocessed>0&&"text-teal"),children:K(k.dependencies.unprocessed)})," pending"]}):"–"})]}),(k.parent||k.dependencies)&&t.jsx("div",{className:"mt-3 border-t border-border pt-3",children:t.jsxs(Ee,{to:ue.jobTree(e,n,k.id),className:"inline-flex items-center gap-1.5 text-[13px] text-accent hover:underline",children:[t.jsx(TN,{className:"size-3.5","aria-hidden":!0}),"View flow tree"]})})]}),t.jsx(Um,{"aria-label":"Job details",size:"sm",className:"mb-3",value:g,onChange:p,items:[{value:"data",label:"Data"},{value:"opts",label:"Options",count:Object.keys(k.opts??{}).length},{value:"returnvalue",label:"Return value"},{value:"error",label:"Error",tone:O?"bg-danger":void 0},{value:"logs",label:"Logs",count:k.logsCount??((I=k.logs)==null?void 0:I.length)??0},...d&&o("audit")?[{value:"audit",label:"Audit"}]:[]]}),g==="data"&&t.jsx(rf,{value:k.data,empty:"No data"}),g==="opts"&&t.jsx(rf,{value:k.opts,empty:"No options"}),g==="returnvalue"&&t.jsx(rf,{value:k.returnvalue,empty:"No return value (job has not completed)"}),g==="error"&&t.jsx(D_,{job:k}),g==="logs"&&t.jsx(U_,{connectionId:e,queue:n,jobId:r,initial:k.logs,total:k.logsCount}),g==="audit"&&t.jsx(Q_,{connectionId:e,queue:n,jobId:r}),t.jsx(pj,{job:S&&k.repeatJobKey?{id:k.id,repeatJobKey:k.repeatJobKey,delayedUntil:k.delayedUntil}:null,onClose:()=>y(!1),onPick:H=>b("promote",H),pending:f.isPending&&((Q=f.variables)==null?void 0:Q.action)==="promote"?f.variables.scheduler??null:null}),t.jsx(Ht,{open:v==="remove",onClose:()=>j(null),title:"Remove job",description:`Job ${r} will be deleted from ${n}. Active jobs cannot be removed while locked.`,confirmText:"Remove",danger:!0,loading:f.isPending,onConfirm:()=>b("remove")}),t.jsx(Ht,{open:v==="discard",onClose:()=>j(null),title:"Discard job",description:"Marks the job as not retryable: attemptsMade is set to the max so backoff retries stop. The job itself is kept.",confirmText:"Discard",loading:f.isPending,onConfirm:()=>b("discard")})]})}function ja({label:e,children:n}){return t.jsxs("div",{className:"min-w-0",children:[t.jsx("dt",{className:"text-[10px] tracking-wide text-fg-subtle uppercase",children:e}),t.jsx("dd",{className:"num truncate text-[13px] text-fg",children:n})]})}function A_({at:e}){return e?t.jsxs("span",{className:"flex flex-col leading-tight",children:[t.jsx(Yt,{value:e}),t.jsx("span",{className:"font-mono text-[10px] text-fg-subtle",children:Uf(e)})]}):t.jsx(t.Fragment,{children:"–"})}function L_({value:e}){if(e==null)return t.jsx(t.Fragment,{children:"–"});if(typeof e=="number"){const n=Math.max(0,Math.min(100,e));return t.jsxs("span",{className:"flex items-center gap-2",children:[t.jsx("span",{className:"h-1.5 w-16 overflow-hidden rounded bg-surface-3",children:t.jsx("span",{className:"block h-full bg-accent",style:{width:`${n}%`}})}),t.jsxs("span",{children:[n,"%"]})]})}return t.jsx("span",{className:"font-mono text-[11px]",title:Du(e),children:Du(e,0).slice(0,40)})}function F_({job:e}){var g;const n=ol(1e3),r=e.timestamp,i=e.processedOn,o=e.finishedOn,c=i?i-r:e.state==="waiting"||e.state==="delayed"||e.state==="prioritized"?n-r:null,d=i?o??(e.state==="active"?n:null):null,h=i&&d?d-i:null,f=[{label:"Created",ts:r,tone:"bg-info"},{label:"Processed",ts:i,tone:"bg-accent"},{label:o&&e.state==="failed"?"Failed":"Finished",ts:o,tone:e.state==="failed"?"bg-danger":"bg-success"}];return t.jsxs("div",{children:[t.jsx("h2",{className:"mb-3 text-[10px] font-semibold tracking-wider text-fg-subtle uppercase",children:"Timeline"}),t.jsxs("ol",{className:"relative flex items-start justify-between gap-2",children:[t.jsx("span",{className:"absolute top-[7px] right-4 left-4 -z-0 h-px bg-border","aria-hidden":!0}),f.map((p,v)=>t.jsxs("li",{className:F("relative z-[1] flex flex-1 flex-col",v===1?"items-center text-center":v===2?"items-end text-right":"items-start"),children:[t.jsx("span",{className:F("status-dot size-3.5 ring-4 ring-surface",p.ts?p.tone:"bg-surface-3",!p.ts&&e.state==="active"&&v===2&&"pulse bg-accent/50")}),t.jsx("span",{className:"mt-1.5 text-xs font-medium text-fg",children:p.label}),t.jsx("span",{className:"text-[11px] text-fg-muted",children:p.ts?t.jsx(Yt,{value:p.ts}):e.state==="active"&&v===2?"running…":e.state==="delayed"&&v===1&&e.delayedUntil?t.jsxs(t.Fragment,{children:["runs ",t.jsx(Yt,{value:e.delayedUntil})]}):"–"}),p.ts&&t.jsx("span",{className:"font-mono text-[10px] text-fg-subtle",children:Uf(p.ts)}),!p.ts&&e.state==="delayed"&&v===1&&e.delayedUntil&&t.jsx("span",{className:"font-mono text-[10px] text-fg-subtle",children:Uf(e.delayedUntil)})]},p.label))]}),t.jsxs("div",{className:"mt-4 flex flex-wrap gap-4 border-t border-border pt-3 text-xs",children:[t.jsxs("span",{children:[t.jsx("span",{className:"text-fg-subtle",children:"Wait "}),t.jsx("span",{className:"num text-fg",children:c!=null?An(c):"–"})]}),t.jsxs("span",{children:[t.jsx("span",{className:"text-fg-subtle",children:"Run "}),t.jsx("span",{className:F("num text-fg",e.state==="active"&&"text-accent"),children:h!=null?An(h):"–"})]}),t.jsxs("span",{children:[t.jsx("span",{className:"text-fg-subtle",children:"Total "}),t.jsx("span",{className:"num text-fg",children:o?An(o-r):"–"})]}),t.jsxs("span",{className:"ml-auto flex items-center gap-1.5 text-fg-subtle",children:[t.jsx("span",{className:F("status-dot",((g=QS[e.state])==null?void 0:g.dot)??"bg-fg-subtle")})," ",e.state]})]})]})}function rf({value:e,empty:n}){const[r,i]=w.useState(!1),o=w.useMemo(()=>Du(e),[e]),c=e==null||typeof e=="object"&&Object.keys(e).length===0;return t.jsxs("div",{className:"card",children:[t.jsxs("div",{className:"flex h-8 items-center justify-between border-b border-border bg-surface-2/60 pr-1 pl-3",children:[t.jsxs("div",{className:"flex items-center gap-1 text-[11px]",children:[t.jsx("button",{type:"button",className:F("rounded px-1.5 py-0.5",r?"text-fg-subtle hover:text-fg":"bg-surface-3 text-fg"),onClick:()=>i(!1),children:"Tree"}),t.jsx("button",{type:"button",className:F("rounded px-1.5 py-0.5",r?"bg-surface-3 text-fg":"text-fg-subtle hover:text-fg"),onClick:()=>i(!0),children:"Raw"})]}),t.jsx(_o,{value:o,size:"icon-xs"})]}),t.jsx("div",{className:"max-h-[60vh] overflow-auto p-3",children:c?t.jsx("p",{className:"text-xs text-fg-subtle",children:n}):r?t.jsx("pre",{className:"font-mono text-xs leading-relaxed whitespace-pre-wrap break-all",children:o}):t.jsx(xj,{value:e,defaultExpandDepth:3})})]})}function D_({job:e}){var n;return!e.failedReason&&(!e.stacktrace||e.stacktrace.length===0)?t.jsx("div",{className:"card p-6 text-center text-xs text-fg-subtle",children:"No error recorded for this job"}):t.jsxs("div",{className:"space-y-3",children:[e.failedReason&&t.jsx("div",{className:"rounded-md border border-danger/40 bg-danger/10 px-3 py-2 text-[13px] break-words text-danger",children:e.failedReason}),(n=e.stacktrace)==null?void 0:n.map((r,i)=>t.jsx(Qm,{code:r,header:`Stacktrace · attempt ${i+1} of ${e.stacktrace.length}`,wrap:!0,maxHeight:360},i))]})}function U_({connectionId:e,queue:n,jobId:r,initial:i,total:o}){var p,v;const[c,d]=w.useState(!1),h=m2(e,n,r,c?{}:{start:0,end:199},!0),f=((p=h.data)==null?void 0:p.logs)??i??[],g=((v=h.data)==null?void 0:v.count)??o??f.length;return f.length===0?t.jsx("div",{className:"card p-6 text-center text-xs text-fg-subtle",children:"No logs. Use job.log() in your processor to emit lines here."}):t.jsxs("div",{className:"card",children:[t.jsxs("div",{className:"flex h-8 items-center justify-between border-b border-border bg-surface-2/60 pr-1 pl-3 text-[11px] text-fg-subtle",children:[t.jsxs("span",{children:[K(f.length)," of ",K(g)," lines"]}),t.jsxs("div",{className:"flex items-center gap-1",children:[!c&&f.length<g&&t.jsx(V,{size:"xs",variant:"ghost",onClick:()=>d(!0),children:"Load all"}),t.jsx(_o,{value:f.join(`
|
|
551
551
|
`),size:"icon-xs"})]})]}),t.jsx("ol",{className:"max-h-[60vh] overflow-auto p-2 font-mono text-xs leading-relaxed",children:f.map((j,S)=>t.jsxs("li",{className:"flex gap-3 hover:bg-surface-2/50",children:[t.jsx("span",{className:"num w-10 shrink-0 select-none text-right text-fg-subtle",children:S+1}),t.jsx("span",{className:"whitespace-pre-wrap break-all",children:j})]},S))})]})}function Q_({connectionId:e,queue:n,jobId:r}){var c;const i=U2(e,n,r),o=((c=i.data)==null?void 0:c.entries)??[];return i.isLoading?t.jsx("div",{className:"card p-6 text-center text-xs text-fg-subtle",children:"Loading history…"}):i.isError?t.jsx("div",{className:"card p-6 text-center text-xs text-fg-subtle",children:"Could not read the audit log."}):o.length===0?t.jsx("div",{className:"card p-6 text-center text-xs text-fg-subtle",children:"Nobody has acted on this job through the dashboard. Worker activity is not audited — only what people do here."}):t.jsxs("div",{className:"card divide-y divide-border",children:[o.map(d=>t.jsxs("div",{className:"flex flex-wrap items-center gap-2 px-4 py-2.5 text-xs",children:[t.jsx(Yt,{value:d.createdAt,className:"w-24 shrink-0 text-fg-muted"}),t.jsx("span",{className:"font-medium text-fg",children:d.actorName??d.actorEmail??"anonymous"}),t.jsx("span",{className:"text-fg-muted",children:vm[d.action]}),d.result==="error"&&t.jsx(be,{variant:"danger",size:"xs",title:d.errorMessage??void 0,children:"refused"}),d.ip&&t.jsx("span",{className:"num ml-auto text-[11px] text-fg-subtle",children:d.ip})]},d.id)),t.jsx("div",{className:"px-4 py-2",children:t.jsxs(Ee,{to:ue.audit({connectionId:e,queueName:n}),className:"inline-flex items-center gap-1.5 text-xs text-accent hover:underline",children:[t.jsx(Bo,{className:"size-3.5","aria-hidden":!0})," Full audit log for this queue"]})})]})}const yj={waiting:"info",limited:"violet",maxed:"danger",paused:"warning"},jj={waiting:"In rotation: the next worker fetch may take a job from this group.",limited:"Hit its rate limit. Pro parks the group until the window resets.",maxed:"Every concurrency slot of the group is busy. Frees up when one of its jobs finishes.",paused:"Paused with queue.pauseGroup(). Jobs keep arriving, none are processed."},qv="No per-group override in Redis. The worker's own group option applies (a worker option, not stored in Redis).";function B_(){var v,j,S;const{connectionId:e="",queue:n=""}=Fn(),r=un(),[i,o]=w.useState(1),[c,d]=w.useState(50),h=R0(e,n),f=td(e,n,{page:i,pageSize:c}),g=ol(1e3),p=6;return t.jsxs(bt,{wide:!0,children:[t.jsx(gs,{title:t.jsxs("span",{className:"flex items-center gap-2",children:[t.jsx(Ee,{to:ue.queue(e,n),className:"text-fg-muted hover:text-fg",children:n}),t.jsx("span",{className:"text-fg-subtle",children:"/"}),"Groups",t.jsx(be,{variant:"pro",children:"BullMQ Pro"})]}),description:`Groups partition a queue for fairness, with their own concurrency and rate limit. ${h.data?`${K(h.data.groupsCount)} groups with jobs waiting or running.`:""} A group whose jobs are all delayed is not listed until one becomes due: Pro keeps delayed jobs in the queue's delayed state, not under the group. Filter the queue's Delayed tab by group to see them.`}),f.data&&t.jsx(H_,{byStatus:f.data.byStatus,total:f.data.total}),f.data&&!f.data.bullmqProApi&&t.jsx(bj,{}),t.jsxs("div",{className:"card overflow-hidden",children:[t.jsxs(ms,{children:[t.jsx("thead",{children:t.jsxs("tr",{children:[t.jsx(pe,{children:"Group"}),t.jsx(pe,{children:"Status"}),t.jsx(pe,{align:"right",children:"Waiting"}),t.jsx(pe,{align:"right",children:"Active / concurrency"}),t.jsx(pe,{align:"right",children:"Rate limit"}),t.jsx(pe,{align:"right",children:"Next"})]})}),t.jsxs("tbody",{children:[f.isLoading&&t.jsx(yt,{colSpan:p,children:t.jsx(Kt,{label:"Loading groups…"})}),f.isError&&!f.data&&t.jsx(yt,{colSpan:p,className:"text-danger",children:ve(f.error)}),f.data&&f.data.groups.length===0&&t.jsx(yt,{colSpan:p,children:"No groups with jobs right now. Add jobs with opts.group.id to see them here."}),(v=f.data)==null?void 0:v.groups.map(y=>t.jsx(K_,{g:y,now:g,onOpen:()=>r(ue.group(e,n,y.id)),href:ue.group(e,n,y.id)},y.id))]})]}),t.jsx("div",{className:"border-t border-border px-3 py-2",children:t.jsx(ld,{page:i,pageSize:c,total:((j=f.data)==null?void 0:j.total)??0,count:(S=f.data)==null?void 0:S.groups.length,onPage:o,onPageSize:y=>(d(y),o(1))})})]})]})}const V_="https://github.com/madmorett/bullpane/blob/main/docs/BULLMQ-PRO.md";function bj(){return t.jsxs("div",{className:"flex items-start gap-2 rounded-md border border-border bg-surface-2/50 px-3 py-2 text-xs text-fg-muted",role:"note",children:[t.jsx(Ha,{className:"mt-0.5 size-3.5 shrink-0 text-pro","aria-hidden":!0}),t.jsxs("span",{children:["Pausing, resuming and draining a group, and promoting, retrying or removing a grouped job, need BullMQ Pro's own package installed next to Bullpane: core bullmq would run those jobs outside their group."," ",t.jsx("a",{href:V_,target:"_blank",rel:"noreferrer",className:"text-accent hover:underline",children:"How to install it"})]})]})}function H_({byStatus:e,total:n}){return t.jsxs("div",{className:"flex flex-wrap items-center gap-2 text-xs",children:[Ck.map(r=>t.jsx(Pe,{content:jj[r],side:"bottom",children:t.jsxs("span",{className:F("inline-flex cursor-help items-center gap-1.5 rounded-md border border-border px-2 py-1",e[r]===0&&"opacity-60"),children:[t.jsx(be,{variant:yj[r],dot:!0,size:"xs",children:r}),t.jsx("span",{className:"num font-medium",children:K(e[r])})]})},r)),t.jsxs("span",{className:"text-fg-subtle",children:[K(n)," ",n===1?"group":"groups"," with jobs"]})]})}function K_({g:e,now:n,onOpen:r,href:i}){const o=e.concurrency!==null,c=o?Math.min(100,Math.round(e.active/Math.max(1,e.concurrency??1)*100)):0;return t.jsxs(cl,{onActivate:r,children:[t.jsx(xe,{mono:!0,children:t.jsx(Ee,{to:i,className:"text-accent hover:underline",children:e.id})}),t.jsx(xe,{className:"whitespace-nowrap",children:t.jsx(be,{variant:yj[e.status],dot:!0,size:"xs",title:jj[e.status],children:e.status})}),t.jsxs(xe,{num:!0,align:"right",children:[K(e.waiting),e.prioritized>0&&t.jsx(Pe,{content:"Jobs added with opts.priority. Pro serves the group's plain list first, then these.",side:"bottom",children:t.jsxs("span",{className:"ml-1.5 cursor-help text-[10px] text-fg-subtle",children:["+",K(e.prioritized)," prioritized"]})})]}),t.jsx(xe,{num:!0,align:"right",children:t.jsxs("span",{className:"inline-flex items-center justify-end gap-2",children:[o&&t.jsx("span",{className:"h-1.5 w-14 overflow-hidden rounded-full bg-surface-2","aria-hidden":!0,children:t.jsx("span",{className:F("block h-full rounded-full",c>=100?"bg-danger":"bg-accent"),style:{width:`${c}%`}})}),t.jsxs("span",{children:[K(e.active),t.jsx("span",{className:"text-fg-subtle",children:" / "}),o?t.jsx(Pe,{content:"Per-group override set with queue.setGroupConcurrency().",side:"bottom",children:t.jsx("span",{className:"cursor-help",children:K(e.concurrency)})}):t.jsx(Pe,{content:qv,side:"bottom",children:t.jsx("span",{className:"cursor-help text-fg-subtle",children:"worker default"})})]})]})}),t.jsx(xe,{num:!0,align:"right",children:e.rateLimit?t.jsx(Pe,{content:"Per-group override set with queue.setGroupRateLimit(): max jobs per window.",side:"bottom",children:t.jsxs("span",{className:"cursor-help",children:[K(e.rateLimit.max),t.jsx("span",{className:"text-fg-subtle",children:" / "}),An(e.rateLimit.durationMs)]})}):t.jsx(Pe,{content:qv,side:"bottom",children:t.jsx("span",{className:"cursor-help text-fg-subtle",children:"worker default"})})}),t.jsx(xe,{num:!0,align:"right",muted:!0,children:t.jsx(W_,{g:e,now:n})})]})}function W_({g:e,now:n}){if(e.status==="limited"&&e.limitedUntil!==null){const r=e.limitedUntil-n;return t.jsx("span",{title:new Date(e.limitedUntil).toLocaleTimeString(),children:r>0?`resumes in ${An(r)}`:"resuming…"})}return e.status==="maxed"&&e.since!==null?t.jsxs("span",{title:new Date(e.since).toLocaleTimeString(),children:["at cap for ",An(n-e.since)]}):e.status==="paused"&&e.since!==null?t.jsxs("span",{title:new Date(e.since).toLocaleTimeString(),children:["paused for ",An(n-e.since)]}):e.status==="waiting"?t.jsx("span",{children:"in rotation"}):t.jsx("span",{children:"–"})}function Z_(){var H,q,B,de,ce;const{connectionId:e="",queue:n="",groupId:r=""}=Fn(),{isOperator:i}=mt(),[o,c]=w.useState(1),[d,h]=w.useState(25),f=$0(e,n,r,{page:o,pageSize:d}),g=jm(e,n),{isAdmin:p}=mt(),v=((H=td(e,n,{page:1,pageSize:1}).data)==null?void 0:H.bullmqProApi)??!1,j=q0(e,n),[S,y]=sl(),[b,k]=w.useState(S.get("confirm")==="drain"),C=Ne=>j.mutate({groupId:r,action:Ne},{onSuccess:()=>X.success(`Group ${r} ${Ne==="pause"?"paused":Ne==="resume"?"resumed":"drained"}`),onError:Ie=>X.error(ve(Ie)),onSettled:()=>{Ne==="drain"&&(k(!1),S.has("confirm")&&y(Ie=>(Ie.delete("confirm"),Ie),{replace:!0}))}}),z=v?void 0:"Needs BullMQ Pro's package installed next to Bullpane",[O,T]=w.useState(!1),[M,E]=w.useState(null),I=(Ne,Ie)=>g.mutate({jobId:Ne,action:Ie},{onSuccess:()=>X.success(`Job ${Ne} ${Ie==="remove"?"removed":Ie}`),onError:ot=>X.error(ve(ot))}),Q=(Ne,Ie)=>Ie==="remove"?E(Ne):I(Ne,Ie);return t.jsxs(bt,{wide:!0,children:[t.jsx(gs,{title:t.jsxs("span",{className:"flex items-center gap-2",children:[t.jsxs(Ee,{to:ue.groups(e,n),className:"inline-flex items-center gap-1 text-fg-muted hover:text-fg",children:[t.jsx(Su,{className:"size-4"})," Groups"]}),t.jsx("span",{className:"text-fg-subtle",children:"/"}),t.jsx(Do,{className:"size-4 text-pro","aria-hidden":!0}),t.jsx("span",{className:"font-mono",children:r})]}),description:`Jobs waiting in group ${r} of ${n}, in the order Pro will serve them: the group's list first, then its prioritized jobs.`,actions:i&&t.jsxs("div",{className:"flex items-center gap-2",children:[t.jsx(V,{size:"sm",variant:"secondary",leftIcon:t.jsx(Gr,{}),disabled:!v||j.isPending,title:z,onClick:()=>C("pause"),children:"Pause group"}),t.jsx(V,{size:"sm",variant:"secondary",leftIcon:t.jsx(Qo,{}),disabled:!v||j.isPending,title:z,onClick:()=>C("resume"),children:"Resume group"}),t.jsx(V,{size:"sm",variant:"secondary",leftIcon:t.jsx(um,{}),disabled:!v,title:z,onClick:()=>T(!0),children:"Promote all delayed"}),p&&t.jsx(V,{size:"sm",variant:"danger",leftIcon:t.jsx(Un,{}),disabled:!v||j.isPending,title:z,onClick:()=>k(!0),children:"Drain group"})]})}),t.jsxs("p",{className:"mb-3 text-xs text-fg-muted",children:["Pro keeps the group's delayed, failed and completed jobs in the queue's own states, not here:"," ",["delayed","failed","completed"].map((Ne,Ie)=>t.jsxs("span",{children:[Ie>0&&" · ",t.jsx(Ee,{to:ue.queueGroup(e,n,r,Ne),className:"text-accent hover:underline",children:Ne})]},Ne))]}),f.data&&!v&&t.jsx(bj,{}),t.jsxs("div",{className:"card overflow-hidden",children:[t.jsx(Kf,{connectionId:e,queue:n,jobs:(q=f.data)==null?void 0:q.jobs,loading:f.isLoading,error:f.error,canOperate:i,onAction:Q,pendingId:g.isPending?(B=g.variables)==null?void 0:B.jobId:null,emptyText:"No jobs waiting in this group"}),t.jsx("div",{className:"border-t border-border px-3 py-2",children:t.jsx(ld,{page:o,pageSize:d,total:((de=f.data)==null?void 0:de.total)??0,count:(ce=f.data)==null?void 0:ce.jobs.length,onPage:c,onPageSize:Ne=>(h(Ne),c(1))})})]}),t.jsx(Bm,{open:O,onClose:()=>T(!1),connectionId:e,queue:n,match:{groupId:r}}),t.jsx(Ht,{open:b&&v&&p,onClose:()=>k(!1),title:"Drain group",description:`Remove every waiting job of group ${r} in ${n} (BullMQ Pro's deleteGroup)? Its delayed jobs stay in the queue's delayed state. This cannot be undone.`,confirmText:"Drain group",danger:!0,loading:j.isPending,onConfirm:()=>C("drain")}),t.jsx(Ht,{open:M!==null,onClose:()=>E(null),title:"Remove job",description:`Remove job ${M??""} from ${n}? This cannot be undone.`,confirmText:"Remove",danger:!0,loading:g.isPending,onConfirm:()=>{M&&I(M,"remove"),E(null)}})]})}function wj({open:e,onClose:n,initial:r,onSave:i,saving:o,title:c="Assign queues",description:d="Pick queues from any connection. A queue can live in several folders."}){const{byConnection:h,isLoading:f}=ll(),[g,p]=w.useState(""),[v,j]=w.useState(new Set),S=k=>`${k.connectionId} ${k.queueName}`;w.useEffect(()=>{e&&j(new Set(r.map(S)))},[e,r]);const y=k=>j(C=>{const z=new Set(C),O=S(k);return z.has(O)?z.delete(O):z.add(O),z}),b=g.trim().toLowerCase();return t.jsxs(bn,{open:e,onClose:n,size:"md",title:c,description:d,footer:t.jsxs(t.Fragment,{children:[t.jsxs("span",{className:"mr-auto text-xs text-fg-muted",children:[v.size," selected"]}),t.jsx(V,{variant:"ghost",size:"sm",onClick:n,children:"Cancel"}),t.jsx(V,{variant:"primary",size:"sm",loading:o,onClick:()=>i([...v].map(k=>{const[C,z]=k.split(" ");return{connectionId:C,queueName:z}})),children:"Save"})]}),children:[t.jsx(Te,{leftIcon:t.jsx(Yn,{}),placeholder:"Filter queues…",value:g,onChange:k=>p(k.target.value),autoFocus:!0,"aria-label":"Filter queues"}),t.jsxs("div",{className:"mt-3 max-h-[50vh] space-y-3 overflow-y-auto",children:[f&&t.jsx(il,{}),h.map(({connection:k,queues:C})=>{const z=C.filter(O=>!b||O.name.toLowerCase().includes(b)).sort((O,T)=>O.name.localeCompare(T.name));return z.length===0?null:t.jsxs("div",{children:[t.jsxs("div",{className:"mb-1 flex items-center justify-between text-[11px] font-semibold tracking-wider text-fg-subtle uppercase",children:[k.name,t.jsx("button",{type:"button",className:"font-normal tracking-normal normal-case hover:text-fg",onClick:()=>j(O=>{const T=new Set(O),M=z.every(E=>T.has(S({connectionId:k.id,queueName:E.name})));return z.forEach(E=>M?T.delete(S({connectionId:k.id,queueName:E.name})):T.add(S({connectionId:k.id,queueName:E.name}))),T}),children:"toggle all"})]}),t.jsx("div",{className:"grid gap-1 sm:grid-cols-2",children:z.map(O=>{const T={connectionId:k.id,queueName:O.name};return t.jsx(Pm,{label:O.name,checked:v.has(S(T)),onChange:()=>y(T),className:"rounded px-1.5 py-1 hover:bg-surface-2"},O.name)})})]},k.id)})]})]})}const Qu=["#5b8def","#3fb950","#d29922","#f85149","#a371f7","#39c5bb","#f778ba","#9aa3ad"];function G_(){const{has:e}=wt();return e("folders")?t.jsx(J_,{}):t.jsx(Wa,{feature:"folders"})}function J_(){const{isOperator:e}=mt(),n=Jr(),[r,i]=w.useState(null),[o,c]=w.useState(null),d=n.data??[],h=w.useMemo(()=>d.filter(p=>!p.parentId).sort((p,v)=>p.position-v.position||p.name.localeCompare(v.name)),[d]),f=p=>d.filter(v=>v.parentId===p).sort((v,j)=>v.position-j.position||v.name.localeCompare(j.name)),g=d.find(p=>p.id===r)??null;return w.useEffect(()=>{!r&&h[0]&&i(h[0].id)},[h,r]),n.isLoading?t.jsx(bt,{children:t.jsx(il,{})}):t.jsxs(bt,{children:[t.jsx(gs,{title:"Folders",description:"Group queues from any connection into folders. Nested one level. The sidebar mirrors this tree.",actions:e&&t.jsx(V,{variant:"primary",size:"sm",leftIcon:t.jsx(Bg,{}),onClick:()=>c({parentId:null}),children:"New folder"})}),d.length===0?t.jsx(cn,{icon:t.jsx(sr,{}),title:"No folders yet",description:"Without folders the sidebar shows one implicit folder per connection. Create a folder to organise queues by team, product or environment.",action:e&&t.jsx(V,{variant:"primary",leftIcon:t.jsx(Bg,{}),onClick:()=>c({parentId:null}),children:"Create the first folder"})}):t.jsxs("div",{className:"grid gap-4 lg:grid-cols-[280px_1fr]",children:[t.jsx("div",{className:"card p-1.5",children:h.map(p=>t.jsxs("div",{children:[t.jsx($v,{folder:p,selected:r===p.id,onSelect:()=>i(p.id),onAddChild:e?()=>c({parentId:p.id}):void 0}),f(p.id).map(v=>t.jsx($v,{folder:v,depth:1,selected:r===v.id,onSelect:()=>i(v.id)},v.id))]},p.id))}),t.jsx("div",{children:g?t.jsx(X_,{folder:g,allFolders:d,canEdit:e,onDeleted:()=>i(null)},g.id):t.jsx(cn,{compact:!0,title:"Select a folder"})})]}),t.jsx(Y_,{open:!!o,parentId:(o==null?void 0:o.parentId)??null,roots:h,onClose:()=>c(null),onCreated:p=>i(p.id)})]})}function $v({folder:e,depth:n=0,selected:r,onSelect:i,onAddChild:o}){return t.jsxs("div",{className:F("group flex h-8 items-center gap-2 rounded-md pr-1 text-[13px]",r?"bg-surface-3 text-fg":"text-fg-muted hover:bg-surface-2 hover:text-fg"),style:{paddingLeft:8+n*16},children:[t.jsxs("button",{type:"button",onClick:i,className:"flex min-w-0 flex-1 items-center gap-2 text-left","aria-current":r||void 0,children:[t.jsx(sr,{className:"size-4 shrink-0",style:{color:e.color??"var(--fg-subtle)"},"aria-hidden":!0}),t.jsx("span",{className:"truncate",children:e.name}),t.jsx("span",{className:"num ml-auto text-[10px] text-fg-subtle",children:e.queues.length})]}),o&&t.jsx(V,{size:"icon-xs",variant:"ghost",className:"opacity-0 group-hover:opacity-100 focus-visible:opacity-100",title:"Add subfolder","aria-label":"Add subfolder",onClick:o,children:t.jsx(es,{})})]})}function X_({folder:e,allFolders:n,canEdit:r,onDeleted:i}){var T;const o=O0(),c=R2(),d=A0(),{byConnection:h}=ll(),[f,g]=w.useState(!1),[p,v]=w.useState(e.name),[j,S]=w.useState(!1),[y,b]=w.useState(!1),k=n.filter(M=>M.parentId===e.id),C=()=>{const M=p.trim();if(!M||M===e.name){g(!1),v(e.name);return}o.mutate({id:e.id,input:{name:M}},{onSuccess:()=>g(!1),onError:E=>X.error(ve(E))})},z=M=>d.mutate({id:e.id,input:{queues:e.queues.filter(E=>!(E.connectionId===M.connectionId&&E.queueName===M.queueName))}},{onError:E=>X.error(ve(E))}),O=M=>{var E;return((E=h.find(I=>I.connection.id===M))==null?void 0:E.connection.name)??M};return t.jsxs("div",{className:"space-y-4",children:[t.jsxs("div",{className:"card p-4",children:[t.jsxs("div",{className:"flex flex-wrap items-start gap-3",children:[t.jsx(sr,{className:"mt-1 size-6",style:{color:e.color??"var(--fg-subtle)"},"aria-hidden":!0}),t.jsxs("div",{className:"min-w-0 flex-1",children:[f?t.jsxs("form",{className:"flex items-center gap-2",onSubmit:M=>{M.preventDefault(),C()},children:[t.jsx(Te,{autoFocus:!0,value:p,onChange:M=>v(M.target.value),className:"!h-8 max-w-xs","aria-label":"Folder name",onKeyDown:M=>M.key==="Escape"&&(g(!1),v(e.name))}),t.jsx(V,{size:"icon-sm",type:"submit",variant:"primary","aria-label":"Save",loading:o.isPending,children:t.jsx(Zr,{})}),t.jsx(V,{size:"icon-sm",variant:"ghost","aria-label":"Cancel",onClick:()=>(g(!1),v(e.name)),children:t.jsx(vn,{})})]}):t.jsxs("h2",{className:"flex items-center gap-2 text-base font-semibold",children:[e.name,r&&t.jsx(V,{size:"icon-xs",variant:"ghost","aria-label":"Rename",onClick:()=>g(!0),children:t.jsx(Uo,{})})]}),t.jsxs("p",{className:"text-xs text-fg-muted",children:[e.parentId?`Subfolder of ${((T=n.find(M=>M.id===e.parentId))==null?void 0:T.name)??"?"}`:"Top-level folder"," · ",e.queues.length," queues",k.length>0&&` · ${k.length} subfolders`]})]}),t.jsxs(Ee,{to:ue.folder(e.id),className:"inline-flex h-7 items-center gap-1.5 rounded-md border border-border px-2.5 text-xs font-medium text-fg hover:bg-surface-2",title:"Open this folder's dashboard",children:["Open folder",t.jsx(uN,{className:"size-3.5","aria-hidden":!0})]}),r&&t.jsx(V,{size:"sm",variant:"ghost",className:"hover:text-danger",leftIcon:t.jsx(Un,{}),onClick:()=>b(!0),children:"Delete"})]}),r&&t.jsxs("div",{className:"mt-4 flex flex-wrap items-center gap-4",children:[t.jsxs("div",{children:[t.jsx("span",{className:"mb-1 block text-[10px] tracking-wide text-fg-subtle uppercase",children:"Colour"}),t.jsxs("div",{className:"flex gap-1.5",role:"radiogroup","aria-label":"Folder colour",children:[Qu.map(M=>t.jsx("button",{type:"button",role:"radio","aria-checked":e.color===M,"aria-label":M,className:F("size-5 rounded-full ring-offset-2 ring-offset-surface transition-shadow",e.color===M&&"ring-2 ring-fg"),style:{background:M},onClick:()=>o.mutate({id:e.id,input:{color:M}},{onError:E=>X.error(ve(E))})},M)),t.jsx("button",{type:"button",role:"radio","aria-checked":!e.color,"aria-label":"No colour",className:F("size-5 rounded-full border border-dashed border-border-strong ring-offset-2 ring-offset-surface",!e.color&&"ring-2 ring-fg"),onClick:()=>o.mutate({id:e.id,input:{color:null}},{onError:M=>X.error(ve(M))})})]})]}),!k.length&&t.jsx(dt,{label:"Parent",className:"!h-8 w-56",value:e.parentId??"",onChange:M=>o.mutate({id:e.id,input:{parentId:M.target.value||null}},{onError:E=>X.error(ve(E))}),options:[{value:"",label:"None (top level)"},...n.filter(M=>!M.parentId&&M.id!==e.id).map(M=>({value:M.id,label:M.name}))]})]})]}),t.jsxs("div",{className:"card",children:[t.jsxs("div",{className:"flex items-center justify-between border-b border-border px-4 py-2.5",children:[t.jsx("h3",{className:"text-xs font-semibold tracking-wider text-fg-subtle uppercase",children:"Queues"}),r&&t.jsx(V,{size:"sm",leftIcon:t.jsx(es,{}),onClick:()=>S(!0),children:"Assign queues"})]}),e.queues.length===0?t.jsx("p",{className:"px-4 py-8 text-center text-xs text-fg-subtle",children:"No queues assigned yet."}):t.jsx("ul",{className:"divide-y divide-border",children:e.queues.map(M=>t.jsxs("li",{className:"flex items-center gap-3 px-4 py-2 text-[13px]",children:[t.jsx(Ee,{to:ue.queue(M.connectionId,M.queueName),className:"font-medium hover:underline",children:M.queueName}),t.jsx(be,{variant:"outline",size:"xs",children:O(M.connectionId)}),r&&t.jsx(V,{size:"icon-xs",variant:"ghost",className:"ml-auto hover:text-danger","aria-label":"Remove from folder",onClick:()=>z(M),children:t.jsx(vn,{})})]},`${M.connectionId}/${M.queueName}`))})]}),t.jsx(wj,{open:j,onClose:()=>S(!1),initial:e.queues,onSave:M=>d.mutate({id:e.id,input:{queues:M}},{onSuccess:()=>(S(!1),X.success("Folder updated")),onError:E=>X.error(ve(E))}),saving:d.isPending}),t.jsx(Ht,{open:y,onClose:()=>b(!1),title:`Delete "${e.name}"`,description:k.length>0?"Subfolders move up to the top level. Queues themselves are untouched.":"Queues themselves are untouched.",confirmText:"Delete folder",danger:!0,loading:c.isPending,onConfirm:()=>c.mutate(e.id,{onSuccess:()=>(b(!1),i(),X.success("Folder deleted")),onError:M=>X.error(ve(M))})})]})}function Y_({open:e,parentId:n,roots:r,onClose:i,onCreated:o}){const c=E2(),[d,h]=w.useState(""),[f,g]=w.useState(Qu[0]),[p,v]=w.useState(n??""),[j,S]=w.useState(null);w.useEffect(()=>v(n??""),[n,e]);const y=()=>{var k;const b=v0.safeParse({name:d.trim(),color:f,parentId:p||null});if(!b.success){S(((k=b.error.issues[0])==null?void 0:k.message)??"Invalid");return}c.mutate(b.data,{onSuccess:C=>{X.success(`Folder "${C.name}" created`),o(C),i()},onError:C=>X.error(ve(C))})};return t.jsx(bn,{open:e,onClose:i,size:"sm",title:"New folder",footer:t.jsxs(t.Fragment,{children:[t.jsx(V,{variant:"ghost",size:"sm",onClick:i,children:"Cancel"}),t.jsx(V,{variant:"primary",size:"sm",onClick:y,loading:c.isPending,children:"Create"})]}),children:t.jsxs("form",{className:"space-y-3",onSubmit:b=>{b.preventDefault(),y()},children:[t.jsx(Te,{label:"Name",autoFocus:!0,value:d,onChange:b=>h(b.target.value),error:j}),t.jsxs("div",{children:[t.jsx("span",{className:"mb-1 block text-xs font-medium text-fg-muted",children:"Colour"}),t.jsx("div",{className:"flex gap-1.5",role:"radiogroup","aria-label":"Folder colour",children:Qu.map(b=>t.jsx("button",{type:"button",role:"radio","aria-checked":f===b,"aria-label":b,className:F("size-5 rounded-full ring-offset-2 ring-offset-surface",f===b&&"ring-2 ring-fg"),style:{background:b},onClick:()=>g(b)},b))})]}),t.jsx(dt,{label:"Parent folder",value:p,onChange:b=>v(b.target.value),options:[{value:"",label:"None (top level)"},...r.map(b=>({value:b.id,label:b.name}))],hint:"Folders nest one level deep."})]})})}const e3=["waiting","active","completed","failed","delayed"];function t3(e){var f,g,p,v;const n={waiting:0,active:0,completed:0,failed:0,delayed:0,prioritized:0,paused:0,"waiting-children":0};let r=0,i=0,o=0,c=null;const d=[];for(const{queue:j}of e){for(const S of Object.keys(n))n[S]+=j.counts[S]??0;r+=((f=j.rates)==null?void 0:f.completed)??0,i+=((g=j.rates)==null?void 0:g.failed)??0,(p=j.rates)!=null&&p.windowMinutes&&(c=j.rates.windowMinutes),j.metrics&&j.metrics.completed.length>0&&(o+=1),(v=j.rates)!=null&&v.retentionSkewed&&d.push(j.name)}const h=r+i;return{counts:n,completed:r,failed:i,successPct:h>0?r/h*100:null,completedSeries:Nv(e.map(j=>{var S;return(S=j.queue.metrics)==null?void 0:S.completed})),failedSeries:Nv(e.map(j=>{var S;return(S=j.queue.metrics)==null?void 0:S.failed})),withMetrics:o,windowMinutes:c,skewedQueues:d}}function n3({entries:e,className:n}){const r=w.useMemo(()=>t3(e),[e]),i=r.windowMinutes?r.windowMinutes%60===0?`${r.windowMinutes/60}h`:`${r.windowMinutes}m`:"1h",o=r.completedSeries.length>1,c=r.skewedQueues.length>0,d=c?`${r.skewedQueues.length===1?`Queue "${r.skewedQueues[0]}"`:`${r.skewedQueues.length} queues (${r.skewedQueues.slice(0,3).join(", ")}${r.skewedQueues.length>3?", …":""})`} feed this total. ${Tm}`:"";return t.jsxs("div",{className:F("grid gap-2 sm:grid-cols-3 xl:grid-cols-7",n),children:[e3.map(h=>{const f=lt[h],g=r.counts[h];return t.jsxs("div",{className:"card px-3 py-2.5",children:[t.jsxs("div",{className:"flex items-center gap-1.5 text-[10px] font-medium tracking-wider text-fg-subtle uppercase",children:[t.jsx("span",{className:F("status-dot size-1.5",f.dotClass),"aria-hidden":!0}),f.label]}),t.jsx("div",{className:F("num text-2xl leading-tight font-semibold",g>0?f.textClass:"text-fg-muted"),children:ft(g)})]},h)}),t.jsxs("div",{className:"card px-3 py-2.5",children:[t.jsxs("div",{className:"flex items-center gap-1 text-[10px] font-medium tracking-wider text-fg-subtle uppercase",children:["Success · ",i,c&&t.jsx(Pe,{content:d,className:"ml-auto",children:t.jsx(ts,{className:"size-3 text-warning","aria-label":"This total is unreliable: some queues prune completed jobs"})})]}),t.jsx(Pe,{content:`${K(r.completed)} completed · ${K(r.failed)} failed across ${e.length} ${e.length===1?"queue":"queues"}${c?`
|
|
552
552
|
|
|
553
|
-
${d}`:""}`,children:t.jsx("div",{className:F("num text-2xl leading-tight font-semibold",c&&"opacity-50",r.successPct==null?"text-fg-subtle":r.successPct<90?"text-state-failed":"text-state-completed"),children:r.successPct==null?"—":En(r.successPct)})}),t.jsx("div",{className:F("mt-1 flex h-1.5 w-full overflow-hidden rounded-full bg-surface-3",c&&"opacity-50"),role:"img","aria-label":r.successPct==null?"No finished jobs":`${En(r.successPct)} success${c?", unreliable: some queues prune completed jobs":""}`,children:r.successPct!=null&&t.jsxs(t.Fragment,{children:[t.jsx("span",{className:"h-full",style:{width:`${r.successPct}%`,background:lt.completed.fg}}),t.jsx("span",{className:"h-full flex-1",style:{background:lt.failed.fg,opacity:r.successPct>=100?0:1}})]})})]}),t.jsxs("div",{className:"card flex flex-col px-3 py-2.5",children:[t.jsx("div",{className:"text-[10px] font-medium tracking-wider text-fg-subtle uppercase",children:"Completed / min"}),o?t.jsxs(t.Fragment,{children:[t.jsx("span",{className:"mt-1 block",style:{color:lt.completed.fg},children:t.jsx(tl,{values:r.completedSeries,width:140,height:30,title:"Combined completed per minute",className:"w-full"})}),t.jsxs("span",{className:"mt-auto text-[10px] text-fg-subtle",children:[K(r.withMetrics)," of ",K(e.length)," queues report metrics"]})]}):t.jsx("span",{className:"mt-2 text-[11px] leading-relaxed text-fg-subtle",children:"No queue in this folder collects metrics."})]})]})}function s3(e){let n="";for(const r of e)r==="*"?n+=".*":r==="?"?n+=".":n+=r.replace(/[.*+?^${}()|[\]\\]/g,"\\$&");return new RegExp(`^${n}$`,"i")}function r3(e,n){const r=e.trim();if(!r)return!1;try{return s3(r).test(n)}catch{return!1}}const mu="__any__";function a3({open:e,onClose:n,existing:r,onImport:i,saving:o}){const{byConnection:c}=ll(),[d,h]=w.useState(""),[f,g]=w.useState(mu),p=w.useMemo(()=>new Set(r.map(y=>`${y.connectionId} ${y.queueName}`)),[r]),v=w.useMemo(()=>{const y=d.trim();if(!y)return[];const b=[];for(const{connection:k,queues:C}of c)if(!(f!==mu&&k.id!==f))for(const z of C){if(!r3(y,z.name))continue;const O={connectionId:k.id,queueName:z.name};b.push({ref:O,connectionName:k.name,already:p.has(`${k.id} ${z.name}`)})}return b.sort((k,C)=>k.ref.queueName.localeCompare(C.ref.queueName))},[d,f,c,p]),j=v.filter(y=>!y.already),S=()=>{i([...r,...j.map(y=>y.ref)])};return t.jsx(bn,{open:e,onClose:n,size:"md",title:"Import matching queues",description:"Add every queue whose name matches a pattern, in one go.",footer:t.jsxs(t.Fragment,{children:[t.jsx("span",{className:"mr-auto text-xs text-fg-muted",children:d.trim()===""?"Type a pattern to preview":`${K(j.length)} to add · ${K(v.length-j.length)} already in folder`}),t.jsx(V,{variant:"ghost",size:"sm",onClick:n,children:"Cancel"}),t.jsxs(V,{variant:"primary",size:"sm",leftIcon:t.jsx(Rf,{}),loading:o,disabled:j.length===0,onClick:S,children:["Import ",j.length>0?K(j.length):""]})]}),children:t.jsxs("div",{className:"space-y-3",children:[t.jsxs("div",{className:"grid gap-3 sm:grid-cols-[1fr_200px]",children:[t.jsx(Te,{label:"Pattern",mono:!0,autoFocus:!0,placeholder:"channels*",value:d,onChange:y=>h(y.target.value),hint:"* matches any run of characters, ? matches exactly one. Case-insensitive."}),t.jsx(dt,{label:"Connection",value:f,onChange:y=>g(y.target.value),options:[{value:mu,label:"Any connection"},...c.map(y=>({value:y.connection.id,label:y.connection.name}))]})]}),t.jsxs("div",{className:"flex flex-wrap gap-1.5 text-[11px] text-fg-subtle",children:[t.jsx("span",{children:"Examples:"}),["channels*","*-retry","email-?"].map(y=>t.jsx("button",{type:"button",onClick:()=>h(y),className:"rounded border border-border bg-surface-2 px-1.5 py-0.5 font-mono text-fg-muted hover:text-fg",children:y},y))]}),t.jsxs("div",{className:"rounded-md border border-border",children:[t.jsxs("div",{className:"flex items-center justify-between border-b border-border bg-surface-2/50 px-3 py-1.5 text-[11px] font-semibold tracking-wider text-fg-subtle uppercase",children:["Preview",t.jsxs("span",{className:"num font-normal tracking-normal normal-case",children:[K(v.length)," matching"]})]}),t.jsx("div",{className:"max-h-64 overflow-y-auto",children:d.trim()===""?t.jsx("p",{className:"px-3 py-6 text-center text-xs text-fg-subtle",children:"Nothing to preview yet."}):v.length===0?t.jsxs("p",{className:"px-3 py-6 text-center text-xs text-fg-subtle",children:["No queue matches ",t.jsx("span",{className:"font-mono text-fg-muted",children:d.trim()}),f!==mu&&" on this connection","."]}):t.jsx("ul",{className:"divide-y divide-border",children:v.map(y=>t.jsxs("li",{className:"flex items-center gap-2 px-3 py-1.5 text-xs",children:[t.jsx("span",{className:"truncate font-mono text-fg",children:y.ref.queueName}),t.jsx(be,{variant:"outline",size:"xs",children:y.connectionName}),y.already&&t.jsx("span",{className:"ml-auto shrink-0 text-[10px] text-fg-subtle",children:"already in folder"})]},`${y.ref.connectionId}/${y.ref.queueName}`))})})]}),t.jsxs("p",{className:"flex items-start gap-2 rounded-md border border-border bg-surface-2/50 px-3 py-2 text-[11px] leading-relaxed text-fg-muted",children:[t.jsx(Ha,{className:"mt-0.5 size-3.5 shrink-0 text-fg-subtle","aria-hidden":!0}),t.jsxs("span",{children:["Imports the queues matching this pattern ",t.jsx("strong",{className:"text-fg",children:"now"}),". New queues that appear later are"," ",t.jsx("strong",{className:"text-fg",children:"not"})," added automatically — run the import again when they show up."]})]})]})})}function i3({open:e,onClose:n,folder:r,allFolders:i}){const o=O0(),[c,d]=w.useState(r.name),[h,f]=w.useState(r.color),[g,p]=w.useState(r.parentId??""),[v,j]=w.useState(null),S=i.some(k=>k.parentId===r.id),y=i.filter(k=>!k.parentId&&k.id!==r.id),b=()=>{var C;const k=Ek.safeParse({name:c.trim(),color:h,parentId:g||null});if(!k.success){j(((C=k.error.issues[0])==null?void 0:C.message)??"Invalid");return}o.mutate({id:r.id,input:k.data},{onSuccess:()=>{X.success("Folder updated"),n()},onError:z=>X.error(ve(z))})};return t.jsx(bn,{open:e,onClose:n,size:"sm",title:"Edit folder",footer:t.jsxs(t.Fragment,{children:[t.jsx(V,{variant:"ghost",size:"sm",onClick:n,children:"Cancel"}),t.jsx(V,{variant:"primary",size:"sm",onClick:b,loading:o.isPending,children:"Save changes"})]}),children:t.jsxs("form",{className:"space-y-3",onSubmit:k=>{k.preventDefault(),b()},children:[t.jsx(Te,{label:"Name",autoFocus:!0,value:c,onChange:k=>d(k.target.value),error:v}),t.jsxs("div",{children:[t.jsx("span",{className:"mb-1 block text-xs font-medium text-fg-muted",children:"Colour"}),t.jsxs("div",{className:"flex flex-wrap gap-1.5",role:"radiogroup","aria-label":"Folder colour",children:[Qu.map(k=>t.jsx("button",{type:"button",role:"radio","aria-checked":h===k,"aria-label":k,className:F("size-5 rounded-full ring-offset-2 ring-offset-surface transition-shadow",h===k&&"ring-2 ring-fg"),style:{background:k},onClick:()=>f(k)},k)),t.jsx("button",{type:"button",role:"radio","aria-checked":!h,"aria-label":"No colour",className:F("size-5 rounded-full border border-dashed border-border-strong ring-offset-2 ring-offset-surface",!h&&"ring-2 ring-fg"),onClick:()=>f(null)})]})]}),t.jsx(dt,{label:"Parent folder",value:g,disabled:S,onChange:k=>p(k.target.value),options:[{value:"",label:"None (top level)"},...y.map(k=>({value:k.id,label:k.name}))],hint:S?"This folder has subfolders, so it must stay top-level.":"Folders nest one level deep."})]})})}function l3(){const{has:e}=wt();return e("folders")?t.jsx(o3,{}):t.jsx(Wa,{feature:"folders"})}function o3(){const{folderId:e=""}=Fn(),{isOperator:n}=mt(),{has:r,gate:i}=wt(),o=Jr(),{byConnection:c,isLoading:d}=ll(),h=A0(),[f,g]=w.useState(null),{sort:p,setSort:v,filter:j,setFilter:S}=Mm(`folder.${e}`,Lm,Am),y=o.data??[],b=y.find(I=>I.id===e)??null,{entries:k,missing:C}=w.useMemo(()=>{const I=[],Q=[];for(const H of(b==null?void 0:b.queues)??[]){const q=c.find(de=>de.connection.id===H.connectionId),B=q==null?void 0:q.queues.find(de=>de.name===H.queueName);q&&B?I.push({connection:q.connection,queue:B}):Q.push(H)}return{entries:I,missing:Q}},[b,c]),z=w.useMemo(()=>k.filter(I=>Rm(I,j)),[k,j]),O=(I,Q,H=!0)=>{b&&h.mutate({id:b.id,input:{queues:I}},{onSuccess:()=>{X.success(Q),H&&g(null)},onError:q=>X.error(ve(q))})},T=I=>O(((b==null?void 0:b.queues)??[]).filter(Q=>!(Q.connectionId===I.connectionId&&Q.queueName===I.queueName)),`${I.queueName} removed from ${(b==null?void 0:b.name)??"folder"}`,!1);if(o.isLoading)return t.jsx(bt,{wide:!0,children:t.jsx(il,{})});if(!b)return t.jsx(bt,{wide:!0,children:t.jsx(cn,{icon:t.jsx(sr,{}),title:"Folder not found",description:"It may have been deleted.",action:t.jsx(Ee,{to:ue.folders,className:"text-accent hover:underline",children:"Back to folders"})})});const M=b.parentId?y.find(I=>I.id===b.parentId):null,E=b.queues.length===0;return t.jsxs(bt,{wide:!0,children:[t.jsxs("div",{className:"mb-4 flex flex-wrap items-start justify-between gap-3",children:[t.jsxs("div",{className:"min-w-0",children:[t.jsxs("div",{className:"flex items-center gap-2.5",children:[t.jsx("span",{className:"size-3 shrink-0 rounded-full ring-2 ring-inset ring-white/10",style:{background:b.color??"var(--fg-subtle)"},"aria-hidden":!0}),t.jsx("h1",{className:"truncate text-lg font-semibold tracking-tight",children:b.name})]}),t.jsxs("p",{className:"mt-0.5 flex flex-wrap items-center gap-x-2 text-xs text-fg-muted",children:[M&&t.jsxs(t.Fragment,{children:[t.jsx(Ee,{to:`/folders/${encodeURIComponent(M.id)}`,className:"hover:underline",children:M.name}),t.jsx("span",{className:"text-fg-subtle",children:"/"})]}),t.jsxs("span",{className:"num",children:[K(b.queues.length)," ",b.queues.length===1?"queue":"queues"]}),C.length>0&&t.jsxs("span",{className:"text-state-waiting",title:C.map(I=>I.queueName).join(", "),children:["· ",K(C.length)," not found"]}),t.jsx("span",{className:"text-fg-subtle",children:"·"}),t.jsx(Ee,{to:ue.folders,className:"hover:underline",children:"Manage folders"})]})]}),t.jsxs("div",{className:"flex flex-wrap items-center gap-2",children:[n&&t.jsx(V,{size:"sm",variant:"secondary",leftIcon:t.jsx(Uo,{}),onClick:()=>g("edit"),children:"Edit"}),n&&t.jsx(V,{size:"sm",variant:"secondary",leftIcon:t.jsx(Rf,{}),onClick:()=>g("import"),title:"Import queues matching a pattern",children:"Import matching"}),n&&t.jsx(V,{size:"sm",variant:"primary",leftIcon:t.jsx(es,{}),onClick:()=>g("add"),children:"Add queue"}),t.jsx(V,{size:"sm",leftIcon:t.jsx(rl,{}),onClick:()=>i("alerts",()=>g("alert")),title:"Alert on every queue in this folder",children:"Create alert"})]})]}),t.jsx(n3,{entries:k,className:"mb-4"}),E?t.jsx("div",{className:"card",children:t.jsx(cn,{icon:t.jsx(sr,{}),title:"This folder is empty",description:"Add queues by hand, or import every queue whose name matches a pattern like channels* or *-retry.",action:n&&t.jsxs(t.Fragment,{children:[t.jsx(V,{variant:"primary",leftIcon:t.jsx(es,{}),onClick:()=>g("add"),children:"Add queue"}),t.jsx(V,{leftIcon:t.jsx(Rf,{}),onClick:()=>g("import"),children:"Import matching queues"})]})})}):t.jsxs("section",{className:"space-y-3","aria-label":"Queues in this folder",children:[t.jsxs("div",{className:"flex flex-wrap items-center justify-between gap-2",children:[t.jsx("h2",{className:"text-xs font-semibold tracking-wider text-fg-subtle uppercase",children:"Queues"}),t.jsxs("div",{className:"flex items-center gap-2",children:[t.jsx(Om,{value:j,onChange:S,"aria-label":"Filter queues in this folder"}),t.jsxs("span",{className:"num whitespace-nowrap text-xs text-fg-subtle",children:[z.length," of ",k.length]})]})]}),d&&k.length===0?t.jsx(zm,{}):z.length>0?t.jsx("div",{className:"grid gap-2",style:{gridTemplateColumns:"repeat(auto-fill, minmax(230px, 1fr))"},children:z.map(I=>t.jsx(c3,{entry:I,onRemove:n?()=>T({connectionId:I.connection.id,queueName:I.queue.name}):void 0,removing:h.isPending},Ia(I)))}):null,t.jsx("div",{className:"card overflow-hidden",children:t.jsx(Fm,{rows:z,showConnection:!0,sort:p,onSort:v,message:d&&k.length===0?"Loading queues…":j?"No queue matches the filter":"None of this folder's queues could be resolved on their connections."})}),C.length>0&&t.jsxs("div",{className:"card px-4 py-3",children:[t.jsx("h3",{className:"mb-1.5 text-[11px] font-semibold tracking-wider text-fg-subtle uppercase",children:"Not found on their connection"}),t.jsx("ul",{className:"flex flex-wrap gap-2",children:C.map(I=>{var Q;return t.jsxs("li",{className:"flex items-center gap-1.5 rounded border border-border bg-surface-2 px-2 py-1 text-xs",children:[t.jsx("span",{className:"font-mono text-fg-muted line-through",children:I.queueName}),t.jsx(be,{variant:"outline",size:"xs",children:((Q=c.find(H=>H.connection.id===I.connectionId))==null?void 0:Q.connection.name)??I.connectionId}),n&&t.jsx(V,{size:"icon-xs",variant:"ghost",className:"hover:text-danger","aria-label":`Remove ${I.queueName}`,onClick:()=>T(I),children:t.jsx(vn,{})})]},`${I.connectionId}/${I.queueName}`)})}),t.jsx("p",{className:"mt-2 text-[11px] text-fg-subtle",children:"These queues are referenced by the folder but were not discovered on their connection — renamed, obliterated, or the connection is down."})]})]}),n&&f==="edit"&&t.jsx(i3,{open:!0,onClose:()=>g(null),folder:b,allFolders:y}),n&&t.jsx(wj,{open:f==="add",onClose:()=>g(null),initial:b.queues,saving:h.isPending,onSave:I=>O(I,"Folder updated"),title:`Add queues to ${b.name}`}),n&&t.jsx(a3,{open:f==="import",onClose:()=>g(null),existing:b.queues,saving:h.isPending,onImport:I=>O(I,`Imported into ${b.name}`)}),f==="alert"&&r("alerts")&&t.jsx(od,{open:!0,onClose:()=>g(null),alert:null,initialScope:{type:"folder",folderId:b.id}})]})}function c3({entry:e,onRemove:n,removing:r}){return t.jsxs("div",{className:"group/card relative",children:[t.jsx(id,{entry:e,showConnection:!0}),n&&t.jsx(V,{size:"icon-xs",variant:"ghost",disabled:r,onClick:n,"aria-label":`Remove ${e.queue.name} from this folder`,title:"Remove from folder",className:"absolute top-2 right-8 z-10 bg-surface/90 opacity-0 backdrop-blur-sm transition-opacity group-hover/card:opacity-100 focus-visible:opacity-100 hover:text-danger",children:t.jsx(vn,{})})]})}const Wf={admin:"Everything, including connections, users, license, drain and obliterate.",operator:"Manage jobs and queues, alerts, folders and flow edges. No settings.",viewer:"Read-only access to queues, jobs, alerts and flows."};function u3(){const{has:e}=wt();return e("users")?t.jsx(N0,{role:"admin",children:t.jsx(d3,{})}):t.jsx(Wa,{feature:"users"})}function d3(){const{user:e}=mt(),n=z2(),r=A2(),[i,o]=w.useState(!1),[c,d]=w.useState(null),h=[...n.data??[]].sort((p,v)=>+!!p.disabledAt-+!!v.disabledAt||p.name.localeCompare(v.name)),f=h.filter(p=>p.role==="admin"&&!p.disabledAt).length,g=(p,v)=>r.mutate({id:p.id,input:{disabled:v}},{onSuccess:()=>{d(null),X.success(v?`${p.name} disabled`:`${p.name} re-enabled`,v?"Their sessions are revoked; the account keeps its history.":"They can sign in again.")},onError:j=>X.error(ve(j))});return t.jsxs(bt,{children:[t.jsx(gs,{title:"Users",description:"Roles are enforced on every API call, not only in the UI.",actions:t.jsx(V,{variant:"primary",size:"sm",leftIcon:t.jsx(LN,{}),onClick:()=>o(!0),children:"Invite user"})}),t.jsx("div",{className:"card overflow-hidden",children:t.jsxs(ms,{children:[t.jsx("thead",{children:t.jsxs("tr",{children:[t.jsx(pe,{children:"Name"}),t.jsx(pe,{children:"Email"}),t.jsx(pe,{className:"w-40",children:"Role"}),t.jsx(pe,{children:"Created"}),t.jsx(pe,{children:"Last login"}),t.jsx(pe,{align:"right",children:t.jsx("span",{className:"sr-only",children:"Actions"})})]})}),t.jsxs("tbody",{children:[n.isLoading&&t.jsx(yt,{colSpan:6,children:t.jsx(Kt,{label:"Loading users…"})}),n.isError&&t.jsx(yt,{colSpan:6,className:"text-danger",children:ve(n.error)}),h.map(p=>{var k;const v=p.id===(e==null?void 0:e.id),j=!!p.disabledAt,S=p.role==="admin"&&!j&&f<=1,y=v?"You cannot disable your own account":S?"Cannot disable the last admin":null,b=r.isPending&&((k=r.variables)==null?void 0:k.id)===p.id;return t.jsxs("tr",{className:F(j&&"text-fg-muted"),children:[t.jsxs(xe,{className:"font-medium",children:[t.jsx("span",{className:F(j&&"line-through decoration-fg-subtle"),children:p.name}),v&&t.jsx(be,{variant:"outline",size:"xs",className:"ml-1.5",children:"you"}),j&&t.jsx(Pe,{content:t.jsxs(t.Fragment,{children:["Disabled ",t.jsx(Yt,{value:p.disabledAt,withAbsolute:!0}),". Cannot sign in; sessions revoked."]}),side:"bottom",children:t.jsx(be,{variant:"neutral",size:"xs",className:"ml-1.5",children:"disabled"})})]}),t.jsx(xe,{muted:!0,children:p.email}),t.jsx(xe,{children:t.jsx(Pe,{content:v?"Ask another admin to change your role":S?"Promote someone else to admin first":Wf[p.role],block:!0,children:t.jsx(dt,{"aria-label":`Role of ${p.name}`,className:"!h-7 text-xs",value:p.role,disabled:v||S||j||b,onChange:C=>r.mutate({id:p.id,input:{role:C.target.value}},{onSuccess:()=>X.success(`${p.name} is now ${C.target.value}`),onError:z=>X.error(ve(z))}),options:Ou.map(C=>({value:C,label:C}))})})}),t.jsx(xe,{muted:!0,children:t.jsx(Yt,{value:p.createdAt})}),t.jsx(xe,{muted:!0,children:t.jsx(Yt,{value:p.lastLoginAt,emptyText:"never"})}),t.jsx(xe,{align:"right",children:j?t.jsx(Pe,{content:"Re-enable: they can sign in again with the same account",side:"left",children:t.jsx(V,{size:"xs",variant:"ghost",leftIcon:t.jsx(AN,{}),"aria-label":`Re-enable ${p.name}`,loading:b,onClick:()=>g(p,!1),children:"Enable"})}):t.jsx(Pe,{content:y??"Disable: revokes access, keeps the account and its history",side:"left",children:t.jsx(V,{size:"icon-xs",variant:"ghost",className:"hover:text-danger","aria-label":`Disable ${p.name}`,disabled:!!y||b,onClick:()=>d(p),children:t.jsx(FN,{})})})})]},p.id)})]})]})}),t.jsx("div",{className:"mt-4 grid gap-2 text-xs text-fg-muted sm:grid-cols-3",children:Ou.map(p=>t.jsxs("div",{className:"card p-3",children:[t.jsx(be,{variant:p==="admin"?"pro":p==="operator"?"info":"neutral",className:"mb-1.5",children:p}),t.jsx("p",{children:Wf[p]})]},p))}),t.jsx(h3,{open:i,onClose:()=>o(!1)}),t.jsx(Ht,{open:!!c,onClose:()=>d(null),title:`Disable ${c==null?void 0:c.name}`,description:`${c==null?void 0:c.email} loses access immediately: active sessions are revoked and password or SSO sign-in is refused. The account and its audit history stay, and you can re-enable it any time.`,confirmText:"Disable user",danger:!0,loading:r.isPending,onConfirm:()=>c&&g(c,!0)})]})}function Iv(){const e="ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz23456789",n=new Uint8Array(16);return crypto.getRandomValues(n),Array.from(n,r=>e[r%e.length]).join("")}function h3({open:e,onClose:n}){const r=O2(),{has:i}=wt(),o=i("sso"),[c,d]=w.useState({name:"",email:"",role:"viewer",password:Iv()}),[h,f]=w.useState(!1),[g,p]=w.useState({}),v=S=>y=>d(b=>({...b,[S]:y.target.value})),j=()=>{const S={name:c.name.trim(),email:c.email.trim(),role:c.role,...h?{}:{password:c.password}},y=bk.safeParse(S);if(!y.success){const b={};for(const k of y.error.issues)b[String(k.path[0])]=k.message;p(b);return}r.mutate(y.data,{onSuccess:b=>{X.success(`${b.name} invited`,h?"They can now sign in with SSO using that email.":"Share the temporary password with them over a secure channel."),n()},onError:b=>X.error(ve(b))})};return t.jsx(bn,{open:e,onClose:n,size:"sm",title:"Invite user",description:h?"The account is created without a password; they sign in through your identity provider.":"There is no email delivery: copy the temporary password and share it yourself.",footer:t.jsxs(t.Fragment,{children:[t.jsx(V,{variant:"ghost",size:"sm",onClick:n,children:"Cancel"}),t.jsx(V,{variant:"primary",size:"sm",onClick:j,loading:r.isPending,children:"Create user"})]}),children:t.jsxs("form",{className:"space-y-3",onSubmit:S=>{S.preventDefault(),j()},children:[t.jsx(Te,{label:"Name",autoFocus:!0,value:c.name,onChange:v("name"),error:g.name}),t.jsx(Te,{label:"Email",type:"email",value:c.email,onChange:v("email"),error:g.email}),t.jsx(dt,{label:"Role",value:c.role,onChange:v("role"),options:Ou.map(S=>({value:S,label:S})),hint:Wf[c.role]}),o&&t.jsxs("div",{className:"flex items-center gap-2.5",children:[t.jsx(el,{checked:h,onChange:f,label:"SSO only (no password)"}),t.jsx("button",{type:"button",className:"text-xs font-medium text-fg",onClick:()=>f(!h),children:"SSO only (no password)"})]}),h?t.jsx("p",{className:"rounded-md border border-border bg-surface-2 px-3 py-2 text-xs text-fg-muted",children:"This account will have no password and can only sign in through an identity provider. Make sure the email matches the one your IdP sends."}):t.jsxs("div",{className:"flex items-end gap-2",children:[t.jsx(Te,{label:"Temporary password",mono:!0,value:c.password,onChange:v("password"),error:g.password,wrapperClassName:"flex-1",autoComplete:"off",spellCheck:!1}),t.jsx(V,{size:"icon",variant:"ghost","aria-label":"Generate password",title:"Generate",onClick:()=>d(S=>({...S,password:Iv()})),children:t.jsx(dm,{})})]})]})})}const f3=50,m3=new Set(Ak);function p3(){const{has:e}=wt();return e("audit")?t.jsx(N0,{role:"admin",children:t.jsx(g3,{})}):t.jsx(Wa,{feature:"audit"})}function x3(){const[e,n]=sl();return[w.useMemo(()=>{const c=e.get("action"),d=e.get("result");return{actorId:e.get("actorId")||void 0,action:c&&gm.includes(c)?c:void 0,connectionId:e.get("connectionId")||void 0,queueName:e.get("queueName")||void 0,jobId:e.get("jobId")||void 0,result:d==="ok"||d==="error"?d:void 0,from:e.get("from")||void 0,to:e.get("to")||void 0}},[e]),c=>{n(d=>{const h=new URLSearchParams(d);for(const[f,g]of Object.entries(c))g?h.set(f,g):h.delete(f);return h},{replace:!0})},()=>n(new URLSearchParams,{replace:!0})]}const zv=(e,n)=>e?new Date(`${e}T${n?"23:59:59.999":"00:00:00.000"}Z`).toISOString():void 0,Ov=e=>e?e.slice(0,10):"";function g3(){var v;const[e,n,r]=x3(),i=xs(),o=F2(),c=L2(e,f3),[d,h]=w.useState(null),f=((v=c.data)==null?void 0:v.pages.flatMap(j=>j.entries))??[],g=Object.values(e).filter(Boolean).length,p=j=>{var S,y;return((y=(S=i.data)==null?void 0:S.find(b=>b.id===j))==null?void 0:y.name)??null};return t.jsxs(bt,{wide:!0,children:[t.jsx(gs,{title:"Audit log",description:"Every mutating action, who did it and whether it worked. Append-only: nothing here can be edited or deleted from the UI.",actions:t.jsxs(t.Fragment,{children:[g>0&&t.jsx(V,{size:"sm",variant:"ghost",leftIcon:t.jsx(vn,{}),onClick:r,children:"Clear filters"}),t.jsxs("a",{href:D2(e),className:"inline-flex h-7 shrink-0 items-center gap-1.5 rounded-md border border-border bg-surface-2 px-2.5 text-xs font-medium text-fg hover:border-border-strong hover:bg-surface-3 [&_svg]:size-3.5",children:[t.jsx(jN,{"aria-hidden":!0}),"Export CSV"]})]})}),t.jsxs("div",{className:"card mb-3 flex flex-wrap items-end gap-2 p-3",children:[t.jsx(dt,{label:"Who",className:"!h-7 w-44 text-xs",value:e.actorId??"",onChange:j=>n({actorId:j.target.value}),options:[{value:"",label:"Anyone"},...(o.data??[]).filter(j=>j.id).map(j=>({value:j.id,label:j.name??j.email??j.id}))]}),t.jsx(dt,{label:"Action",className:"!h-7 w-52 text-xs",value:e.action??"",onChange:j=>n({action:j.target.value}),options:[{value:"",label:"Any action"},...gm.map(j=>({value:j,label:`${vm[j]} (${j})`}))]}),t.jsx(dt,{label:"Connection",className:"!h-7 w-40 text-xs",value:e.connectionId??"",onChange:j=>n({connectionId:j.target.value}),options:[{value:"",label:"Any connection"},...(i.data??[]).map(j=>({value:j.id,label:j.name}))]}),t.jsx(Te,{label:"Queue",className:"!h-7 w-40 text-xs",placeholder:"exact name",value:e.queueName??"",onChange:j=>n({queueName:j.target.value})}),t.jsx(dt,{label:"Result",className:"!h-7 w-32 text-xs",value:e.result??"",onChange:j=>n({result:j.target.value}),options:[{value:"",label:"Any result"},{value:"ok",label:"ok"},{value:"error",label:"refused / failed"}]}),t.jsx(Te,{label:"From",type:"date",className:"!h-7 w-36 text-xs",value:Ov(e.from),onChange:j=>n({from:zv(j.target.value,!1)})}),t.jsx(Te,{label:"To",type:"date",className:"!h-7 w-36 text-xs",value:Ov(e.to),onChange:j=>n({to:zv(j.target.value,!0)})}),e.jobId&&t.jsxs(be,{variant:"outline",mono:!0,className:"mb-1",children:["job ",e.jobId,t.jsx("button",{type:"button","aria-label":"Clear job filter",onClick:()=>n({jobId:void 0}),children:t.jsx(vn,{className:"size-3"})})]})]}),t.jsx("div",{className:"card overflow-hidden",children:t.jsxs(ms,{dense:!0,children:[t.jsx("thead",{children:t.jsxs("tr",{children:[t.jsx(pe,{className:"w-8"}),t.jsx(pe,{className:"w-32",children:"When"}),t.jsx(pe,{className:"w-56",children:"Who"}),t.jsx(pe,{className:"w-56",children:"Action"}),t.jsx(pe,{children:"Target"}),t.jsx(pe,{className:"w-28",children:"Result"}),t.jsx(pe,{className:"w-32",children:"IP"})]})}),t.jsxs("tbody",{children:[c.isLoading&&t.jsx(yt,{colSpan:7,children:t.jsx(Kt,{label:"Loading the audit log…"})}),c.isError&&t.jsx(yt,{colSpan:7,className:"text-danger",children:ve(c.error)}),!c.isLoading&&!c.isError&&f.length===0&&t.jsx(yt,{colSpan:7,children:t.jsx(cn,{compact:!0,icon:t.jsx(Bo,{}),title:g>0?"Nothing matches these filters":"Nothing recorded yet",description:g>0?"Widen the date range or clear a filter.":"The log fills as people act: pausing a queue, retrying a job, inviting a user. Reads are never recorded."})}),f.map(j=>t.jsx(v3,{entry:j,open:d===j.id,onToggle:()=>h(d===j.id?null:j.id),connectionStillExists:!!p(j.connectionId)},j.id))]})]})}),t.jsxs("div",{className:"mt-3 flex items-center justify-between gap-3 text-xs text-fg-muted",children:[t.jsxs("span",{className:"num",children:[f.length," ",f.length===1?"entry":"entries"," loaded"]}),c.hasNextPage&&t.jsx(V,{size:"sm",variant:"secondary",loading:c.isFetchingNextPage,onClick:()=>void c.fetchNextPage(),children:"Load 50 more"})]}),t.jsxs("p",{className:"mt-4 text-xs text-fg-subtle",children:["Retention is ",t.jsx("code",{className:"font-mono",children:"BULLPANE_AUDIT_RETENTION_DAYS"})," (default 365). Rows leave only by age — there is no delete endpoint, on purpose. The job payload is never recorded: ",t.jsx("code",{className:"font-mono",children:"detail"})," ","holds the parameters of an action and, where it helps, the payload size in bytes."]})]})}function v3({entry:e,open:n,onToggle:r,connectionStillExists:i}){var h;const o=m3.has(e.action),c=e.result==="error",d=!!e.detail||!!e.userAgent||!!e.errorMessage;return t.jsxs(t.Fragment,{children:[t.jsxs("tr",{className:F(c&&"bg-danger/5"),children:[t.jsx(xe,{children:d?t.jsx("button",{type:"button","aria-label":n?"Hide detail":"Show detail","aria-expanded":n,onClick:r,className:"rounded p-0.5 text-fg-subtle hover:text-fg",children:n?t.jsx(ps,{className:"size-3.5"}):t.jsx(Dn,{className:"size-3.5"})}):null}),t.jsx(xe,{muted:!0,children:t.jsx(Yt,{value:e.createdAt})}),t.jsx(xe,{children:e.actorName||e.actorEmail?t.jsxs("div",{className:"flex min-w-0 items-center gap-1.5",children:[t.jsx("span",{className:"truncate font-medium",children:e.actorName??"—"}),e.actorRole&&t.jsx(be,{size:"xs",variant:e.actorRole==="admin"?"pro":e.actorRole==="operator"?"info":"neutral",children:e.actorRole}),e.actorEmail&&t.jsx("span",{className:"truncate text-[11px] text-fg-subtle",children:e.actorEmail})]}):t.jsx(Pe,{content:"No session — an anonymous request, e.g. a failed login on an unknown email",children:t.jsx("span",{className:"cursor-help text-fg-subtle",children:"anonymous"})})}),t.jsxs(xe,{children:[t.jsxs("div",{className:"flex items-center gap-1.5",children:[o&&t.jsx(hm,{className:"size-3.5 shrink-0 text-warning","aria-label":"High-risk action"}),t.jsx("span",{className:F(o&&"font-medium"),children:vm[e.action]}),t.jsx(Pe,{content:e.action,children:t.jsx("code",{className:"cursor-help font-mono text-[10px] text-fg-subtle",children:e.action})})]}),typeof((h=e.detail)==null?void 0:h.reason)=="string"&&e.detail.reason&&t.jsxs("p",{className:"mt-0.5 max-w-md truncate text-[11px] text-fg-muted italic",title:e.detail.reason,children:["“",e.detail.reason,"”"]})]}),t.jsx(xe,{children:t.jsx(y3,{entry:e,connectionStillExists:i})}),t.jsx(xe,{children:c?t.jsx(Pe,{content:e.errorMessage??"The action was refused or failed",children:t.jsx(be,{variant:"danger",size:"xs",className:"cursor-help",children:"refused"})}):t.jsx(be,{variant:"success",size:"xs",children:"ok"})}),t.jsx(xe,{muted:!0,mono:!0,children:e.ip??"–"})]}),n&&t.jsx("tr",{children:t.jsx("td",{colSpan:7,className:"bg-surface-2 !px-4 !py-3",children:t.jsxs("dl",{className:"grid gap-3 text-xs sm:grid-cols-[10rem_1fr]",children:[t.jsx("dt",{className:"text-fg-subtle",children:"Exact time"}),t.jsx("dd",{className:"num",children:gn(e.createdAt)}),e.errorMessage&&t.jsxs(t.Fragment,{children:[t.jsx("dt",{className:"text-fg-subtle",children:"Why it failed"}),t.jsx("dd",{className:"text-danger",children:e.errorMessage})]}),e.userAgent&&t.jsxs(t.Fragment,{children:[t.jsx("dt",{className:"text-fg-subtle",children:"User agent"}),t.jsx("dd",{className:"font-mono text-[11px] break-all text-fg-muted",children:e.userAgent})]}),t.jsxs("dt",{className:"text-fg-subtle",children:["Detail",t.jsx("span",{className:"mt-0.5 block text-[10px] text-fg-subtle",children:"parameters only — never the job payload"})]}),t.jsx("dd",{children:e.detail?t.jsx(xj,{value:e.detail,defaultExpandDepth:3}):t.jsx("span",{className:"text-fg-subtle",children:"no parameters recorded"})})]})})})]})}function y3({entry:e,connectionStillExists:n}){if(!e.connectionId&&!e.queueName)return t.jsx("span",{className:"text-fg-subtle",children:"–"});const r=e.connectionName??e.connectionId;return t.jsxs("div",{className:"flex min-w-0 flex-wrap items-center gap-1 text-xs",children:[r&&t.jsx(t.Fragment,{children:n&&e.connectionId?t.jsx(Ee,{to:ue.connection(e.connectionId),className:"text-accent hover:underline",children:r}):t.jsx(Pe,{content:"This connection no longer exists — the name is the one it had at the time",children:t.jsx("span",{className:"cursor-help text-fg-muted line-through",children:r})})}),e.queueName&&t.jsxs(t.Fragment,{children:[t.jsx("span",{className:"text-fg-subtle",children:"/"}),n&&e.connectionId?t.jsx(Ee,{to:ue.queue(e.connectionId,e.queueName),className:"font-mono text-accent hover:underline",children:e.queueName}):t.jsx("span",{className:"font-mono text-fg-muted line-through",children:e.queueName})]}),e.jobId&&t.jsxs(t.Fragment,{children:[t.jsx("span",{className:"text-fg-subtle",children:"/"}),n&&e.connectionId&&e.queueName?t.jsxs(Ee,{to:ue.job(e.connectionId,e.queueName,e.jobId),className:"font-mono text-accent hover:underline",title:"The job may have been removed since",children:["#",e.jobId]}):t.jsxs("span",{className:"font-mono text-fg-muted",children:["#",e.jobId]})]})]})}function j3(){const{has:e}=wt();return e("alerts")?t.jsx(b3,{}):t.jsx(w3,{})}function b3(){const r=(bm().data??[]).filter(o=>o.enabled),i=o=>r.filter(c=>c.scope.type===o).length;return t.jsxs("div",{className:"max-w-xl space-y-4",children:[t.jsxs("p",{className:"text-xs text-fg-muted",children:[t.jsx("strong",{className:"font-medium text-fg",children:"Needs attention"})," is driven by your alert rules. Every queue that breaks an enabled rule gets a card at the top of the Overview, with the value, the window and the threshold. Paused queues and queues with a backlog but no worker are always flagged."]}),t.jsxs("ul",{className:"space-y-1 text-xs text-fg-muted",children:[t.jsxs("li",{children:["Scope each rule to ",t.jsx("span",{className:"text-fg",children:"every queue"}),", a ",t.jsx("span",{className:"text-fg",children:"connection"}),", a"," ",t.jsx("span",{className:"text-fg",children:"folder"})," or ",t.jsx("span",{className:"text-fg",children:"one queue"}),". The most specific rule of each kind wins, so a queue rule overrides the global one for that queue."]}),t.jsx("li",{children:"Failure count and failure rate come from BullMQ metrics over the window, so removeOnComplete cannot skew them."}),t.jsx("li",{children:"Processing time is the p50 or p95 of the jobs completed in the window."}),t.jsx("li",{children:"A rule without channels is dashboard only; add Slack or a webhook to be notified as well."})]}),t.jsx("p",{className:"text-xs text-fg-subtle",children:r.length===0?"No enabled rule yet.":`${r.length} enabled: ${i("global")} on every queue, ${i("connection")} per connection, ${i("folder")} per folder, ${i("queue")} per queue.`}),t.jsx(Ee,{to:ue.alerts,className:"inline-flex text-xs text-accent hover:underline",children:"Manage rules →"})]})}function w3(){const{isAdmin:e}=mt(),n=z0(),r=P2(),[i,o]=w.useState(""),[c,d]=w.useState(""),h=n.data;if(w.useEffect(()=>{h&&(o(String(h.waitingAbove)),d(String(h.failedAbove)))},[h]),n.isLoading)return t.jsx(Kt,{});const f=Rk.safeParse({waitingAbove:Number(i===""?0:i),failedAbove:Number(c===""?0:c)}),g=!!h&&f.success&&(f.data.waitingAbove!==h.waitingAbove||f.data.failedAbove!==h.failedAbove),p=()=>{f.success&&r.mutate(f.data,{onSuccess:()=>X.success("Attention thresholds saved"),onError:v=>X.error(ve(v))})};return t.jsxs("div",{className:"max-w-xl space-y-5",children:[t.jsxs("p",{className:"text-xs text-fg-muted",children:["When a queue shows up in ",t.jsx("strong",{className:"font-medium text-fg",children:"Needs attention"})," at the top of the Overview. Failing, paused and stuck-with-no-worker queues are always flagged — these two add the cases only you can define.",t.jsx("span",{className:"text-fg-subtle",children:" Set 0 to turn a rule off."})]}),t.jsxs("p",{className:"rounded-md border border-border bg-surface-2/50 px-3 py-2 text-xs text-fg-muted",children:[t.jsx("span",{className:"font-medium text-fg",children:"Pro:"})," rules per queue, folder, connection or everywhere, on failure rate and processing time over a window, measured from BullMQ metrics — the same rules can notify Slack or a webhook."," ",t.jsx(Ee,{to:ue.alerts,className:"text-accent hover:underline",children:"See Alerts"})]}),t.jsx(Te,{label:"Waiting above",hint:"Flag a queue whose waiting backlog passes this, even when a worker is draining it. Leave at 0 if your queues run deep on purpose.",inputMode:"numeric",value:i,disabled:!e,onChange:v=>o(v.target.value.replace(/[^0-9]/g,""))}),t.jsx(Te,{label:"Failed above",hint:"Flag a queue whose failed list passes this. At 0 any failed job at all is flagged, which is the previous behaviour.",inputMode:"numeric",value:c,disabled:!e,onChange:v=>d(v.target.value.replace(/[^0-9]/g,""))}),e?t.jsxs("div",{className:"flex items-center gap-2",children:[t.jsx(V,{variant:"primary",disabled:!g||r.isPending,onClick:p,children:r.isPending?"Saving…":"Save"}),g&&t.jsx(V,{variant:"ghost",onClick:()=>{o(String((h==null?void 0:h.waitingAbove)??Lu.waitingAbove)),d(String((h==null?void 0:h.failedAbove)??Lu.failedAbove))},children:"Cancel"})]}):t.jsx("p",{className:"text-xs text-fg-subtle",children:"Only an administrator can change these."})]})}const yu={host:"localhost",port:"6379",username:"",password:"",db:"0",tls:!1};function N3(e){try{const n=new URL(e);if(n.protocol!=="redis:"&&n.protocol!=="rediss:")return{...yu};const r=Lv(n.password);return{host:n.hostname||yu.host,port:n.port||(n.protocol==="rediss:"?"6380":"6379"),username:Lv(n.username),password:r==="****"?"":r,db:n.pathname.replace(/^\//,"")||"0",tls:n.protocol==="rediss:"}}catch{return{...yu}}}function Av(e){const n=e.username||e.password?`${encodeURIComponent(e.username)}:${encodeURIComponent(e.password)}@`:"",r=e.host.includes(":")&&!e.host.startsWith("[")?`[${e.host}]`:e.host,i=e.db.trim()&&e.db.trim()!=="0"?`/${e.db.trim()}`:"";return`${e.tls?"rediss":"redis"}://${n}${r.trim()}:${e.port.trim()||"6379"}${i}`}function k3(e,n){return e.host!==n.host||e.port!==n.port||e.username!==n.username||e.db!==n.db||e.tls!==n.tls}function Lv(e){try{return decodeURIComponent(e)}catch{return e}}function S3(){var v;const{isAdmin:e}=mt(),{demo:n}=wt(),r=xs(),i=k2(),[o,c]=sl(),[d,h]=w.useState(null),[f,g]=w.useState(null);w.useEffect(()=>{if(e){if(o.get("new"))h({connection:null}),c({},{replace:!0});else if(o.get("edit")&&r.data){const j=r.data.find(S=>S.id===o.get("edit"));j&&h({connection:j}),c({},{replace:!0})}}},[o,c,r.data,e]);const p=r.data??[];return t.jsxs("div",{children:[t.jsxs("div",{className:"mb-3 flex items-center justify-between",children:[t.jsxs("p",{className:"text-xs text-fg-muted",children:["Each connection points at one Redis (or cluster) with a BullMQ key prefix, or at the Postgres schema of BullMQ 6's Postgres backend. On Redis, queues are discovered with ",t.jsx("span",{className:"font-mono",children:"SCAN"}),", never ",t.jsx("span",{className:"font-mono",children:"KEYS"}),"."]}),e&&t.jsx(V,{variant:"primary",size:"sm",leftIcon:t.jsx(es,{}),onClick:()=>h({connection:null}),disabled:n,title:n?"Locked in the demo":void 0,children:"Add connection"})]}),n&&t.jsx("p",{className:"mb-3 rounded-md border border-warning/40 bg-warning/10 px-3 py-2 text-xs text-warning",children:"Demo mode: connections are read-only."}),t.jsx("div",{className:"card overflow-hidden",children:t.jsxs(ms,{children:[t.jsx("thead",{children:t.jsxs("tr",{children:[t.jsx(pe,{children:"Name"}),t.jsx(pe,{children:"URL"}),t.jsx(pe,{children:"Prefix / schema"}),t.jsx(pe,{children:"Filter"}),t.jsx(pe,{children:"Status"}),t.jsx(pe,{children:"Added"}),t.jsx(pe,{align:"right",children:t.jsx("span",{className:"sr-only",children:"Actions"})})]})}),t.jsxs("tbody",{children:[r.isLoading&&t.jsx(yt,{colSpan:7,children:t.jsx(Kt,{})}),r.data&&p.length===0&&t.jsx("tr",{children:t.jsx("td",{colSpan:7,children:t.jsx(cn,{compact:!0,icon:t.jsx(Va,{}),title:"No connections",description:e?"Add your first Redis or Postgres connection.":"Ask an admin to add one."})})}),p.map(j=>{var S;return t.jsxs("tr",{children:[t.jsxs(xe,{className:"font-medium",children:[t.jsx(Ee,{to:ue.connection(j.id),className:"hover:underline",children:j.name}),j.kind==="postgres"&&t.jsx(be,{variant:"outline",size:"xs",className:"ml-1.5",children:"postgres"}),j.cluster&&t.jsx(be,{variant:"outline",size:"xs",className:"ml-1.5",children:"cluster"})]}),t.jsx(xe,{mono:!0,muted:!0,className:"max-w-xs truncate",title:j.url,children:j.url}),t.jsx(xe,{mono:!0,children:j.prefix}),t.jsx(xe,{mono:!0,muted:!0,children:j.queueFilter??"–"}),t.jsxs(xe,{children:[t.jsxs("span",{className:"flex items-center gap-2",children:[t.jsx(nd,{status:j.status,withLabel:!0,pulse:!0}),((S=j.status)==null?void 0:S.ok)&&j.status.redisVersion&&t.jsxs("span",{className:"text-[11px] text-fg-subtle",children:["v",j.status.redisVersion]})]}),j.status&&!j.status.ok&&j.status.error&&t.jsx("p",{className:"mt-0.5 max-w-xs truncate text-[11px] text-danger",title:j.status.error,children:j.status.error})]}),t.jsx(xe,{muted:!0,children:t.jsx(Yt,{value:j.createdAt})}),t.jsx(xe,{align:"right",children:e&&t.jsxs("div",{className:"flex items-center justify-end gap-1",children:[t.jsx(V,{size:"icon-xs",variant:"ghost","aria-label":"Edit connection",title:"Edit",onClick:()=>h({connection:j}),disabled:n,children:t.jsx(Uo,{})}),t.jsx(V,{size:"icon-xs",variant:"ghost","aria-label":"Delete connection",title:"Delete",className:"hover:text-danger",onClick:()=>g(j),disabled:n,children:t.jsx(Un,{})})]})})]},j.id)})]})]})}),d&&t.jsx(C3,{open:!0,onClose:()=>h(null),connection:d.connection},((v=d.connection)==null?void 0:v.id)??"new"),t.jsx(Ht,{open:!!f,onClose:()=>g(null),title:`Remove "${f==null?void 0:f.name}"`,description:"Only the dashboard entry is removed. Nothing in Redis or Postgres is touched. Folders and alerts pointing at this connection stop working.",confirmText:"Remove connection",danger:!0,typeToConfirm:f==null?void 0:f.name,loading:i.isPending,onConfirm:()=>f&&i.mutate(f.id,{onSuccess:()=>(g(null),X.success("Connection removed")),onError:j=>X.error(ve(j))})})]})}function C3({open:e,onClose:n,connection:r}){const i=w2(),o=N2(),c=S2(),[d,h]=w.useState({name:(r==null?void 0:r.name)??"",kind:(r==null?void 0:r.kind)??"redis",url:r?"":"redis://localhost:6379",prefix:(r==null?void 0:r.prefix)??"bull",cluster:(r==null?void 0:r.cluster)??!1,queueFilter:(r==null?void 0:r.queueFilter)??""}),[f,g]=w.useState({}),[p,v]=w.useState(null),[j,S]=w.useState("fields"),y=r?N3(r.url):yu,[b,k]=w.useState(y),C=(q,B)=>{h(de=>({...de,[q]:B})),v(null)},z=d.kind==="postgres",O=q=>{h(B=>({...B,kind:q,url:q==="postgres"?B.url.startsWith("redis")?"":B.url:B.url||"redis://localhost:6379",prefix:B.prefix===xu[B.kind]||!B.prefix?xu[q]:B.prefix,cluster:q==="postgres"?!1:B.cluster})),g({}),v(null)},T=(q,B)=>{k(de=>({...de,[q]:B})),v(null)},M=()=>j==="url"||z?d.url.trim():r&&!b.password&&!k3(b,y)?"":Av(b),E=()=>{const q=M(),B={name:d.name.trim(),kind:d.kind,url:q,prefix:d.prefix.trim()||xu[d.kind],cluster:d.cluster,queueFilter:d.queueFilter.trim()||null};r&&!B.url&&(B.url=r.url);const de=kk.safeParse(B);if(!de.success){const ce={};for(const Ne of de.error.issues)ce[String(Ne.path[0])]=Ne.message;return g(ce),null}return g({}),de.data},I=()=>{const q=E();if(!q)return;const B=de=>{X.success(`Connection "${de.name}" saved`),n()};if(r){const de={name:q.name,prefix:q.prefix,cluster:q.cluster,queueFilter:q.queueFilter};M()&&(de.url=q.url),o.mutate({id:r.id,input:de},{onSuccess:B,onError:ce=>X.error(ve(ce))})}else i.mutate(q,{onSuccess:B,onError:de=>X.error(ve(de))})},Q=()=>{const q=M();if(!q){g({url:r?j==="url"||z?"Enter the URL (with password) to test it":"Enter the password to test the stored connection":"URL is required"});return}c.mutate({kind:d.kind,url:q,prefix:d.prefix.trim()||void 0,cluster:d.cluster},{onSuccess:v,onError:B=>v({ok:!1,error:ve(B)})})},H=i.isPending||o.isPending;return t.jsx(bn,{open:e,onClose:n,size:"md",title:r?`Edit ${r.name}`:"Add connection",description:"Credentials are stored server-side and never sent back to the browser.",footer:t.jsxs(t.Fragment,{children:[t.jsx(V,{variant:"ghost",size:"sm",onClick:n,children:"Cancel"}),t.jsx(V,{variant:"secondary",size:"sm",leftIcon:t.jsx(Ky,{}),onClick:Q,loading:c.isPending,children:"Test connection"}),t.jsx(V,{variant:"primary",size:"sm",onClick:I,loading:H,children:r?"Save":"Add connection"})]}),children:t.jsxs("form",{className:"space-y-3",onSubmit:q=>{q.preventDefault(),I()},children:[t.jsx(Te,{label:"Name",autoFocus:!0,value:d.name,onChange:q=>C("name",q.target.value),error:f.name,placeholder:"production"}),t.jsxs("div",{className:"flex items-center justify-between",children:[t.jsx("span",{className:"text-xs font-medium text-fg-muted",children:"Backend"}),r?t.jsx("span",{className:"text-xs text-fg",children:z?"Postgres (BullMQ 6)":"Redis"}):t.jsx("div",{className:"inline-flex rounded-md border border-border p-0.5 text-xs",role:"tablist","aria-label":"Where the queues live",children:["redis","postgres"].map(q=>t.jsx("button",{type:"button",role:"tab","aria-selected":d.kind===q,className:`rounded px-2 py-0.5 ${d.kind===q?"bg-surface-3 text-fg":"text-fg-muted hover:text-fg"}`,onClick:()=>O(q),children:q==="redis"?"Redis":"Postgres (BullMQ 6)"},q))})]}),z?t.jsx(Te,{label:"Postgres URL",mono:!0,value:d.url,onChange:q=>C("url",q.target.value),error:f.url,placeholder:r?`${r.url} (leave empty to keep)`:"postgres://user:password@host:5432/app",hint:"The database your BullMQ workers use. Add ?sslmode=require for TLS. A read-only role is enough to browse; actions need write access.",autoComplete:"off",spellCheck:!1}):t.jsxs(t.Fragment,{children:[t.jsxs("div",{className:"flex items-center justify-between",children:[t.jsx("span",{className:"text-xs font-medium text-fg-muted",children:"Redis"}),t.jsx("div",{className:"inline-flex rounded-md border border-border p-0.5 text-xs",role:"tablist","aria-label":"How to enter the Redis address",children:["fields","url"].map(q=>t.jsx("button",{type:"button",role:"tab","aria-selected":j===q,className:`rounded px-2 py-0.5 ${j===q?"bg-surface-3 text-fg":"text-fg-muted hover:text-fg"}`,onClick:()=>(S(q),v(null)),children:q==="fields"?"Host & password":"Connection URL"},q))})]}),j==="url"?t.jsx(Te,{label:"Redis URL",mono:!0,value:d.url,onChange:q=>C("url",q.target.value),error:f.url,placeholder:r?`${r.url} (leave empty to keep)`:"redis://:password@host:6379/0",hint:"redis:// or rediss:// (TLS). Include the password; it is redacted everywhere in the UI.",autoComplete:"off",spellCheck:!1}):t.jsxs("div",{className:"space-y-3",children:[t.jsxs("div",{className:"grid gap-3 sm:grid-cols-[1fr_120px]",children:[t.jsx(Te,{label:"Host",mono:!0,value:b.host,onChange:q=>T("host",q.target.value),placeholder:"cache.internal",autoComplete:"off",spellCheck:!1}),t.jsx(Te,{label:"Port",mono:!0,inputMode:"numeric",value:b.port,onChange:q=>T("port",q.target.value)})]}),t.jsxs("div",{className:"grid gap-3 sm:grid-cols-2",children:[t.jsx(Te,{label:"Username (optional)",mono:!0,value:b.username,onChange:q=>T("username",q.target.value),placeholder:"default",autoComplete:"off",spellCheck:!1}),t.jsx(Te,{label:"Password",type:"password",mono:!0,value:b.password,onChange:q=>T("password",q.target.value),placeholder:r?"leave empty to keep the stored one":"optional",hint:r?"Stored server-side and never shown again. Changing the host or TLS needs it typed again.":"Stored server-side, redacted everywhere in the UI.",autoComplete:"new-password"})]}),t.jsxs("div",{className:"grid items-end gap-3 sm:grid-cols-[120px_1fr]",children:[t.jsx(Te,{label:"Database",mono:!0,inputMode:"numeric",value:b.db,onChange:q=>T("db",q.target.value)}),t.jsxs("div",{className:"flex items-start gap-2.5 pb-1",children:[t.jsx(el,{checked:b.tls,onChange:q=>T("tls",q),label:"TLS",className:"mt-0.5"}),t.jsxs("button",{type:"button",className:"text-left text-xs",onClick:()=>T("tls",!b.tls),children:[t.jsx("span",{className:"font-medium text-fg",children:"TLS"}),t.jsx("span",{className:"text-fg-muted",children:" (rediss://) — required by ElastiCache with in-transit encryption, Redis Cloud, Upstash and most managed Redis."})]})]})]}),f.url&&t.jsx("p",{className:"text-xs text-danger",children:f.url}),t.jsx("p",{className:"font-mono text-[11px] text-fg-subtle",children:M()?Av({...b,password:b.password?"****":""}):`${(r==null?void 0:r.url)??""} (unchanged)`})]})]}),t.jsxs("div",{className:"grid gap-3 sm:grid-cols-2",children:[z?t.jsx(Te,{label:"Schema",mono:!0,value:d.prefix,onChange:q=>C("prefix",q.target.value),error:f.prefix,hint:"BullMQ default is bullmq"}):t.jsx(Te,{label:"Key prefix",mono:!0,value:d.prefix,onChange:q=>C("prefix",q.target.value),error:f.prefix,hint:"BullMQ default is bull"}),t.jsx(Te,{label:"Queue filter (optional)",mono:!0,value:d.queueFilter,onChange:q=>C("queueFilter",q.target.value),error:f.queueFilter,placeholder:"payments-*",hint:"Glob over queue names; limits discovery."})]}),!z&&t.jsx(Pm,{label:"Redis Cluster",description:"Use cluster-aware client. Each queue lives in one hash slot, so all reads stay single-node.",checked:d.cluster,onChange:q=>C("cluster",q.target.checked)}),p&&t.jsxs("div",{className:`flex items-start gap-2 rounded-md border px-3 py-2 text-xs ${p.ok?"border-success/40 bg-success/10 text-success":"border-danger/40 bg-danger/10 text-danger"}`,role:"status",children:[p.ok?t.jsx(cm,{className:"mt-px size-4 shrink-0"}):t.jsx(Fy,{className:"mt-px size-4 shrink-0"}),t.jsx("div",{children:p.ok?t.jsxs(t.Fragment,{children:["Connected",p.latencyMs!=null&&` in ${p.latencyMs} ms`,p.redisVersion&&` · ${z?"Postgres":"Redis"} ${p.redisVersion}`,p.queuesFound!=null&&` · ${p.queuesFound} queues found`]}):t.jsxs(t.Fragment,{children:["Failed: ",p.error??"unknown error"]})})]})]})})}const Fv={active:{label:"active",variant:"success"},grace:{label:"grace period",variant:"warning"},expired:{label:"expired",variant:"danger"},invalid:{label:"invalid",variant:"danger"}};function _3(e){if(e.source==="offline")return e.status==="expired"?"This offline key has expired. Ask for a renewed key or activate a subscription key.":e.status==="invalid"?"This key does not verify against this build. Paste it again or ask for a new one.":null;switch(e.status){case"grace":return`bullpane.com could not be reached (${e.lastCheckError??"unknown error"}). Pro keeps working until ${gn(e.leaseExpiresAt)}; the server retries once a day, or check now.`;case"expired":return e.lastCheckError?`${e.lastCheckError} Renew the subscription on bullpane.com, then check again.`:"The lease ran out without reaching bullpane.com. Restore the connection and check now.";case"invalid":return e.lastCheckError??"The store rejected this key.";default:return null}}function P3(){const{isAdmin:e,setEdition:n}=mt(),{edition:r,isPro:i,demo:o,pricing:c,checkoutUrl:d,has:h}=wt(),f=Q2(),g=V2(),p=B2(),[v,j]=w.useState(""),[S,y]=w.useState(null),[b,k]=w.useState(!1),C=()=>{const E=v.trim();if(!E){y("Paste the license key");return}y(null),f.mutate(E,{onSuccess:I=>{n(I),j(""),X.success("Pro unlocked",I.license?`Licensed to ${I.license.licensee}`:void 0)},onError:I=>{Ts(I)&&(I.body.error==="invalid_license"||I.body.error==="license_already_activated"||I.body.error==="license_server_unavailable")?y(I.body.message||"This key is not valid"):y(ve(I))}})},z=()=>p.mutate(void 0,{onSuccess:E=>{var Q,H,q,B;n(E);const I=(Q=E.license)==null?void 0:Q.status;I==="active"?X.success("License verified",`Lease renewed until ${gn((H=E.license)==null?void 0:H.leaseExpiresAt)}`):I==="grace"?X.error("Could not reach bullpane.com",((q=E.license)==null?void 0:q.lastCheckError)??void 0):X.error("License not valid",((B=E.license)==null?void 0:B.lastCheckError)??void 0)},onError:E=>X.error(ve(E))}),O=r.license,T=O?_3(O):null,M=(O==null?void 0:O.source)==="online";return t.jsxs("div",{className:"grid gap-4 lg:grid-cols-[1fr_360px]",children:[t.jsxs("div",{className:"space-y-4",children:[t.jsxs("div",{className:"card p-4",children:[t.jsxs("div",{className:"flex items-center gap-3",children:[t.jsx("div",{className:"flex size-10 items-center justify-center rounded-lg bg-surface-2",children:i?t.jsx(Gu,{className:"size-5 text-pro"}):t.jsx(go,{className:"size-5 text-fg-subtle"})}),t.jsxs("div",{className:"min-w-0 flex-1",children:[t.jsxs("div",{className:"flex items-center gap-2",children:[t.jsx("h2",{className:"text-sm font-semibold",children:o?"Demo mode":i?"Pro edition":"Free edition"}),t.jsx(Nm,{})]}),t.jsx("p",{className:"text-xs text-fg-muted",children:o?"Every Pro feature is unlocked for the playground. Settings that could break the demo are read-only.":i?"All features unlocked for this installation.":"Everything bull-board does, plus search. Team features need a Pro key."})]}),M&&e&&!o&&t.jsx(V,{variant:"outline",size:"sm",leftIcon:t.jsx(dm,{}),onClick:z,loading:p.isPending,children:"Check now"})]}),O&&t.jsxs("dl",{className:"mt-4 grid grid-cols-2 gap-3 border-t border-border pt-4 text-xs sm:grid-cols-4",children:[t.jsxs("div",{children:[t.jsx("dt",{className:"text-[10px] tracking-wide text-fg-subtle uppercase",children:"Licensee"}),t.jsx("dd",{className:"truncate text-fg",children:O.licensee})]}),t.jsxs("div",{children:[t.jsx("dt",{className:"text-[10px] tracking-wide text-fg-subtle uppercase",children:"Email"}),t.jsx("dd",{className:"truncate text-fg",children:O.email})]}),t.jsxs("div",{children:[t.jsx("dt",{className:"text-[10px] tracking-wide text-fg-subtle uppercase",children:M?"Plan":"Issued"}),t.jsx("dd",{className:"text-fg",children:M?"Subscription":Fu(O.issuedAt)})]}),t.jsxs("div",{children:[t.jsx("dt",{className:"text-[10px] tracking-wide text-fg-subtle uppercase",children:M?"Paid until":"Expires"}),t.jsxs("dd",{className:"text-fg",children:[O.expiresAt?Fu(O.expiresAt):M?"Renews automatically":"Never"," ",t.jsx(be,{variant:Fv[O.status].variant,size:"xs",className:"ml-1",children:Fv[O.status].label})]})]}),M&&t.jsxs(t.Fragment,{children:[t.jsxs("div",{children:[t.jsx("dt",{className:"text-[10px] tracking-wide text-fg-subtle uppercase",children:"Last verified"}),t.jsx("dd",{className:"text-fg",title:O.lastCheckedAt?gn(O.lastCheckedAt):void 0,children:O.lastCheckedAt?Kr(O.lastCheckedAt):"never"})]}),t.jsxs("div",{children:[t.jsx("dt",{className:"text-[10px] tracking-wide text-fg-subtle uppercase",children:"Works offline until"}),t.jsx("dd",{className:"text-fg",children:gn(O.leaseExpiresAt)})]}),t.jsxs("div",{className:"col-span-2",children:[t.jsx("dt",{className:"text-[10px] tracking-wide text-fg-subtle uppercase",children:"Activation"}),t.jsx("dd",{className:"truncate font-mono text-fg",children:O.activationId})]})]})]}),T&&t.jsx("p",{className:`mt-3 rounded-md border px-3 py-2 text-xs ${(O==null?void 0:O.status)==="grace"?"border-warning/40 bg-warning/10 text-warning":"border-danger/40 bg-danger/10 text-danger"}`,children:T}),o&&t.jsx("p",{className:"mt-3 rounded-md border border-warning/40 bg-warning/10 px-3 py-2 text-xs text-warning",children:"Demo mode notice: license changes are blocked here. Run your own instance to activate a key."})]}),t.jsxs("div",{className:"card p-4",children:[t.jsx("h3",{className:"mb-3 text-xs font-semibold tracking-wider text-fg-subtle uppercase",children:"Features"}),t.jsx("ul",{className:"grid gap-2 sm:grid-cols-2",children:xm.map(E=>t.jsxs("li",{className:"flex items-start gap-2 rounded-md border border-border p-2.5 text-xs",children:[h(E)?t.jsx(Zr,{className:"mt-px size-4 shrink-0 text-success"}):t.jsx(go,{className:"mt-px size-4 shrink-0 text-fg-subtle"}),t.jsxs("div",{children:[t.jsx("p",{className:"font-medium text-fg",children:bo[E].title}),t.jsx("p",{className:"text-fg-muted",children:bo[E].tagline})]})]},E))})]})]}),t.jsxs("div",{className:"space-y-4",children:[e?t.jsxs("div",{className:"card p-4",children:[t.jsxs("h3",{className:"mb-1 flex items-center gap-2 text-sm font-semibold",children:[t.jsx(al,{className:"size-4"})," ",i&&!o?"Replace license key":"Activate a license key"]}),t.jsx("p",{className:"mb-3 text-xs text-fg-muted",children:"Paste the key from your bullpane.com receipt. One key runs one installation: it is activated once against bullpane.com, re-checked daily, and keeps working for 7 days without internet. Nothing about your queues or jobs is sent."}),t.jsx(Yi,{mono:!0,rows:3,value:v,onChange:E=>j(E.target.value),placeholder:"BULLPANE-XXXX-XXXX-XXXX",error:S,spellCheck:!1,disabled:o,"aria-label":"License key"}),t.jsxs("div",{className:"mt-3 flex items-center gap-2",children:[t.jsx(V,{variant:"primary",size:"sm",onClick:C,loading:f.isPending,disabled:o,children:"Activate"}),O&&!o&&t.jsx(V,{variant:"ghost",size:"sm",className:"hover:text-danger",leftIcon:t.jsx(Un,{}),onClick:()=>k(!0),children:"Remove license"})]})]}):t.jsx("div",{className:"card p-4 text-xs text-fg-muted",children:"Only admins can change the license."}),!i&&t.jsxs("div",{className:"card border-pro/30 p-4",children:[t.jsxs("p",{className:"text-sm font-semibold",children:["Unlock Pro · $",c.monthlyUsd,"/month or $",c.yearlyUsd,"/year"]}),t.jsx("p",{className:"mt-1 text-xs text-fg-muted",children:"One installation, unlimited connections, queues and users. Cancel any time; your data stays."}),t.jsxs("a",{href:d||"#",target:"_blank",rel:"noreferrer noopener","aria-disabled":!d,className:"mt-3 inline-flex h-8 items-center gap-2 rounded-md bg-accent px-3 text-xs font-medium text-accent-fg hover:bg-accent-hover aria-disabled:pointer-events-none aria-disabled:opacity-50",children:["Get a key ",t.jsx(Br,{className:"size-3.5"})]})]})]}),t.jsx(Ht,{open:b,onClose:()=>k(!1),title:"Remove license",description:M?"The installation goes back to the free edition, which has NO LOGIN: anyone who can reach this URL will be able to retry, promote and delete jobs. The key is released so it can be activated on another server. Alerts, folders, flow edges and your user accounts are kept in the database but become inaccessible until a key is activated again.":"The installation goes back to the free edition, which has NO LOGIN: anyone who can reach this URL will be able to retry, promote and delete jobs. Alerts, folders, flow edges and your user accounts are kept in the database but become inaccessible until a key is activated again.",confirmText:"Remove license",danger:!0,loading:g.isPending,onConfirm:()=>g.mutate(void 0,{onSuccess:E=>{n(E),k(!1),X.success("License removed")},onError:E=>X.error(ve(E))})})]})}function E3(){const e=l2(),{edition:n,checkoutUrl:r}=wt();return t.jsxs("div",{className:"grid gap-4 lg:grid-cols-2",children:[t.jsxs("div",{className:"card p-4",children:[t.jsxs("div",{className:"flex items-center gap-3",children:[t.jsx(km,{className:"size-9"}),t.jsxs("div",{children:[t.jsx("h2",{className:"text-sm font-semibold",children:"Bullpane"}),t.jsx("p",{className:"text-xs text-fg-muted",children:"Self-hosted dashboard for BullMQ and BullMQ Pro."})]})]}),t.jsxs("dl",{className:"mt-4 grid grid-cols-2 gap-3 border-t border-border pt-4 text-xs",children:[t.jsxs("div",{children:[t.jsx("dt",{className:"text-[10px] tracking-wide text-fg-subtle uppercase",children:"Server version"}),t.jsx("dd",{className:"font-mono text-fg",children:e.data?e.data.version:e.isError?"unknown":t.jsx(Cu,{})})]}),t.jsxs("div",{children:[t.jsx("dt",{className:"text-[10px] tracking-wide text-fg-subtle uppercase",children:"Server uptime"}),t.jsx("dd",{className:"text-fg",children:e.data?No(e.data.uptime):e.isError?"unknown":t.jsx(Cu,{})})]}),t.jsxs("div",{children:[t.jsx("dt",{className:"text-[10px] tracking-wide text-fg-subtle uppercase",children:"Edition"}),t.jsxs("dd",{className:"text-fg",children:[n.tier,n.demo&&" (demo)"]})]}),t.jsxs("div",{children:[t.jsx("dt",{className:"text-[10px] tracking-wide text-fg-subtle uppercase",children:"UI build"}),t.jsx("dd",{className:"font-mono text-fg",children:"production"})]})]})]}),t.jsxs("div",{className:"card p-4",children:[t.jsx("h3",{className:"mb-2 text-xs font-semibold tracking-wider text-fg-subtle uppercase",children:"Links"}),t.jsxs("ul",{className:"space-y-1.5 text-[13px]",children:[t.jsx("li",{children:t.jsxs("a",{href:"https://docs.bullmq.io",target:"_blank",rel:"noreferrer noopener",className:"inline-flex items-center gap-1.5 text-accent hover:underline",children:["BullMQ documentation ",t.jsx(Br,{className:"size-3.5"})]})}),r&&t.jsx("li",{children:t.jsxs("a",{href:r,target:"_blank",rel:"noreferrer noopener",className:"inline-flex items-center gap-1.5 text-accent hover:underline",children:["Buy a Pro license (from $",n.pricing.monthlyUsd,"/mo) ",t.jsx(Br,{className:"size-3.5"})]})}),t.jsx("li",{children:t.jsxs("a",{href:"/api/health",target:"_blank",rel:"noreferrer noopener",className:"inline-flex items-center gap-1.5 text-accent hover:underline",children:["API health ",t.jsx(Br,{className:"size-3.5"})]})})]}),t.jsx("h3",{className:"mt-5 mb-2 text-xs font-semibold tracking-wider text-fg-subtle uppercase",children:"How it reads Redis"}),t.jsxs("ul",{className:"list-disc space-y-1 pl-4 text-xs text-fg-muted",children:[t.jsxs("li",{children:["Discovery via ",t.jsx("span",{className:"font-mono",children:"SCAN"}),", never ",t.jsx("span",{className:"font-mono",children:"KEYS"}),"; cached 30 s."]}),t.jsx("li",{children:"Counts, pages and details are single Lua round trips per queue."}),t.jsx("li",{children:"Payloads are truncated inside Redis for list views."}),t.jsx("li",{children:"Writes go through the official bullmq library."})]})]})]})}const R3={oidc:"OIDC",saml:"SAML 2.0"};function M3(){const{has:e}=wt();return e("sso")?t.jsx(T3,{}):t.jsx(Wa,{feature:"sso"})}function ju({label:e,value:n}){const[r,i]=w.useState(!1);return t.jsxs("div",{className:"flex items-center gap-2",children:[t.jsx("span",{className:"w-24 shrink-0 text-[11px] uppercase tracking-wide text-fg-subtle",children:e}),t.jsx("code",{className:"min-w-0 flex-1 truncate rounded bg-surface-2 px-2 py-1 text-[11px] text-fg-muted",children:n}),t.jsx(V,{size:"icon-xs",variant:"ghost","aria-label":`Copy ${e}`,onClick:()=>{var o;(o=navigator.clipboard)==null||o.writeText(n).then(()=>{i(!0),setTimeout(()=>i(!1),1500)},()=>X.error("Could not copy to the clipboard"))},children:r?t.jsx(Zr,{className:"size-3 text-success"}):t.jsx(Uy,{className:"size-3"})})]})}function T3(){var k;const e=K2(),n=F0(),r=D0(),i=Z2(),o=G2(),c=J2(),[d,h]=w.useState(!1),[f,g]=w.useState(null),[p,v]=w.useState({}),j=e.data??[],S=j.filter(C=>C.enabled).length,y=((k=n.data)==null?void 0:k.requireSso)??!1,b=async C=>{try{const z=await c.mutateAsync(C.id);v(O=>({...O,[C.id]:z}))}catch(z){v(O=>({...O,[C.id]:{ok:!1,message:ve(z)}}))}};return t.jsxs("div",{className:"space-y-5",children:[t.jsxs("div",{className:"flex items-start justify-between gap-4",children:[t.jsxs("div",{children:[t.jsx("h2",{className:"text-sm font-semibold text-fg",children:"Single sign-on"}),t.jsxs("p",{className:"mt-1 max-w-2xl text-xs text-fg-muted",children:["Let your team sign in with your identity provider. By default accounts are not created automatically: add the person under ",t.jsx("span",{className:"text-fg",children:"Users & roles"})," first, then they can sign in with SSO using that same email. Or turn on ",t.jsx("span",{className:"text-fg",children:"auto-provisioning"})," below for your company's email domains."]})]}),t.jsx(V,{variant:"primary",leftIcon:t.jsx(es,{className:"size-4"}),onClick:()=>h(!0),children:"Add provider"})]}),e.isLoading?t.jsx("div",{className:"flex justify-center py-8",children:t.jsx(Kt,{})}):j.length===0?t.jsxs("div",{className:"card p-6 text-center",children:[t.jsx(Gu,{className:"mx-auto size-6 text-fg-subtle"}),t.jsx("p",{className:"mt-2 text-sm text-fg",children:"No identity provider yet"}),t.jsx("p",{className:"mx-auto mt-1 max-w-md text-xs text-fg-muted",children:"Add an OIDC provider (Google Workspace, Microsoft Entra ID, Okta, Keycloak, Authentik) or a SAML 2.0 provider."})]}):t.jsx("div",{className:"space-y-3",children:j.map(C=>{const z=p[C.id];return t.jsxs("div",{className:"card p-4",children:[t.jsxs("div",{className:"flex items-start justify-between gap-3",children:[t.jsxs("div",{className:"min-w-0",children:[t.jsxs("div",{className:"flex items-center gap-2",children:[t.jsx("span",{className:"truncate text-sm font-medium text-fg",children:C.name}),t.jsx(be,{variant:"neutral",children:R3[C.kind]}),!C.enabled&&t.jsx(be,{variant:"warning",children:"disabled"}),C.kind==="oidc"&&!C.hasSecret&&t.jsx(be,{variant:"danger",children:"no client secret"})]}),t.jsx("p",{className:"mt-1 truncate text-xs text-fg-muted",children:C.kind==="oidc"?String(C.config.issuer??""):String(C.config.entryPoint??"")})]}),t.jsxs("div",{className:"flex shrink-0 items-center gap-2",children:[t.jsx(el,{checked:C.enabled,label:"Enabled",onChange:O=>{i.mutate({id:C.id,input:{enabled:O}},{onError:T=>X.error(ve(T))})}}),t.jsx(V,{size:"sm",variant:"secondary",leftIcon:t.jsx(Ky,{className:"size-3.5"}),loading:c.isPending&&c.variables===C.id,onClick:()=>void b(C),children:"Test"}),t.jsx(V,{size:"icon-sm",variant:"ghost","aria-label":"Delete provider",onClick:()=>g(C),children:t.jsx(Un,{className:"size-3.5"})})]})]}),t.jsx("div",{className:"mt-3 space-y-1.5 border-t border-border pt-3",children:C.kind==="oidc"?t.jsx(ju,{label:"Redirect URI",value:C.callbackUrl}):t.jsxs(t.Fragment,{children:[t.jsx(ju,{label:"ACS URL",value:C.callbackUrl}),C.entityId&&t.jsx(ju,{label:"Entity ID",value:C.entityId})]})}),z&&t.jsxs("div",{className:`mt-3 rounded-md border px-3 py-2 text-xs ${z.ok?"border-success/40 bg-success/10 text-success":"border-danger/40 bg-danger/10 text-danger"}`,children:[t.jsxs("p",{className:"flex items-center gap-1.5 font-medium",children:[z.ok?t.jsx(Zr,{className:"size-3.5"}):t.jsx(vn,{className:"size-3.5"}),z.message]}),z.details&&t.jsx("dl",{className:"mt-2 space-y-0.5 text-fg-muted",children:Object.entries(z.details).map(([O,T])=>t.jsxs("div",{className:"flex gap-2",children:[t.jsx("dt",{className:"w-44 shrink-0 font-mono text-[10px] uppercase",children:O}),t.jsx("dd",{className:"min-w-0 truncate font-mono text-[10px]",children:T})]},O))})]})]},C.id)})}),t.jsxs("div",{className:"card p-4",children:[t.jsxs("div",{className:"flex items-start justify-between gap-4",children:[t.jsxs("div",{children:[t.jsx("p",{className:"text-sm font-medium text-fg",children:"Require SSO"}),t.jsxs("p",{className:"mt-1 max-w-2xl text-xs text-fg-muted",children:["Hide the password form and send everyone through your identity provider."," ",t.jsx("span",{className:"text-fg",children:"Admin accounts keep password sign-in"})," so a misconfigured provider cannot lock you out of your own installation. Set ",t.jsx("code",{className:"text-[11px]",children:"BULLPANE_ALLOW_PASSWORD_LOGIN=true"})," to allow it for everyone."]})]}),t.jsx(el,{checked:y,disabled:n.isLoading||r.isPending,onChange:C=>{r.mutate({requireSso:C},{onSuccess:()=>X.success(C?"SSO is now required":"Password sign-in is available again"),onError:z=>X.error(ve(z))})}})]}),y&&S===0&&t.jsxs("p",{className:"mt-3 flex items-center gap-1.5 rounded-md border border-warning/40 bg-warning/10 px-3 py-2 text-xs text-warning",children:[t.jsx(ts,{className:"size-3.5 shrink-0"}),"SSO is required but no provider is enabled. Only admins can sign in right now."]})]}),t.jsx(q3,{}),d&&t.jsx($3,{onClose:()=>h(!1)}),t.jsx(Ht,{open:f!==null,title:"Delete this provider?",confirmText:"Delete",danger:!0,description:f?`Anyone who signs in through "${f.name}" will have to use another method. The Bullpane accounts themselves are not touched.`:"",loading:o.isPending,onClose:()=>g(null),onConfirm:()=>{f&&o.mutate(f.id,{onSuccess:()=>{X.success(`Deleted ${f.name}`),g(null)},onError:C=>{X.error(ve(C)),g(null)}})}})]})}function q3(){var p,v;const e=F0(),n=D0(),r=((p=e.data)==null?void 0:p.autoProvisionDomains)??[],i=((v=e.data)==null?void 0:v.autoProvision)??!1,[o,c]=w.useState(null),[d,h]=w.useState(null),f=o??r.join(", "),g=()=>{h(null);const j=f.split(/[\s,]+/).map(y=>y.trim()).filter(y=>y!==""),S=[];for(const y of j){const b=h0.safeParse(y);if(!b.success){h(`"${y}" is not a domain. Use something like example.com.`);return}S.push(b.data)}n.mutate({autoProvisionDomains:S},{onSuccess:()=>{c(null),X.success("Domains saved")},onError:y=>h(ve(y))})};return t.jsxs("div",{className:"card p-4",children:[t.jsxs("div",{className:"flex items-start justify-between gap-4",children:[t.jsxs("div",{children:[t.jsx("p",{className:"text-sm font-medium text-fg",children:"Let anyone from your domains sign in"}),t.jsxs("p",{className:"mt-1 max-w-2xl text-xs text-fg-muted",children:["When someone your identity provider authenticates has no Bullpane account yet and their email ends in one of the domains below, create one for them as a ",t.jsx("span",{className:"text-fg",children:"viewer"})," instead of refusing. They can look at every queue but change nothing; promote them under Users & roles if they need more. Disabled accounts stay disabled."]})]}),t.jsx(el,{checked:i,label:"Auto-provision SSO accounts",disabled:e.isLoading||n.isPending,onChange:j=>{if(j&&r.length===0){h("Save at least one domain first.");return}n.mutate({autoProvision:j},{onSuccess:()=>X.success(j?"New SSO users from your domains now get a viewer account":"SSO accounts must be invited again"),onError:S=>X.error(ve(S))})}})]}),t.jsxs("div",{className:"mt-3 flex items-start gap-2",children:[t.jsx(Te,{label:"Allowed email domains",hint:"Comma separated. Exact match: example.com does not include sub.example.com.",placeholder:"example.com",mono:!0,wrapperClassName:"flex-1",value:f,onChange:j=>c(j.target.value),error:d??void 0}),t.jsx(V,{className:"mt-5",variant:"secondary",disabled:o===null,loading:n.isPending,onClick:g,children:"Save"})]})]})}function $3({onClose:e}){const n=W2(),[r,i]=w.useState("oidc"),[o,c]=w.useState(""),[d,h]=w.useState(""),[f,g]=w.useState(""),[p,v]=w.useState(""),[j,S]=w.useState(""),[y,b]=w.useState(""),[k,C]=w.useState(""),[z,O]=w.useState(""),[T,M]=w.useState(""),[E,I]=w.useState(null),Q=()=>{var B;I(null);const H=r==="oidc"?{kind:"oidc",name:o.trim(),config:{issuer:d.trim(),clientId:f.trim(),clientSecret:p,...j.trim()?{emailClaim:j.trim()}:{}}}:{kind:"saml",name:o.trim(),config:{entryPoint:y.trim(),issuer:k.trim(),idpCert:z.trim(),...T.trim()?{emailAttribute:T.trim()}:{}}},q=wk.safeParse(H);if(!q.success){I(((B=q.error.issues[0])==null?void 0:B.message)??"Check the fields above");return}n.mutate(q.data,{onSuccess:de=>{X.success(`Added ${de.name}. Enter the redirect URI at your IdP, then use Test.`),e()},onError:de=>I(ve(de))})};return t.jsx(bn,{open:!0,onClose:e,title:"Add an identity provider",description:"Unless auto-provisioning is on, invite people under Users & roles first.",size:"md",footer:t.jsxs(t.Fragment,{children:[t.jsx(V,{variant:"ghost",onClick:e,children:"Cancel"}),t.jsx(V,{variant:"primary",loading:n.isPending,onClick:Q,children:"Add provider"})]}),children:t.jsxs("div",{className:"space-y-3",children:[t.jsxs(dt,{label:"Protocol",value:r,onChange:H=>i(H.target.value),children:[t.jsx("option",{value:"oidc",children:"OIDC / OpenID Connect"}),t.jsx("option",{value:"saml",children:"SAML 2.0"})]}),t.jsx(Te,{label:"Display name",placeholder:r==="oidc"?"Google Workspace":"Corporate SSO",hint:"Shown on the sign-in button.",value:o,onChange:H=>c(H.target.value),required:!0}),r==="oidc"?t.jsxs(t.Fragment,{children:[t.jsx(Te,{label:"Issuer URL",placeholder:"https://accounts.google.com",hint:"Endpoints are discovered from /.well-known/openid-configuration, so this is the only URL you need.",value:d,onChange:H=>h(H.target.value),required:!0}),t.jsx(Te,{label:"Client ID",value:f,onChange:H=>g(H.target.value),required:!0}),t.jsx(Te,{label:"Client secret",type:"password",hint:"Stored encrypted and never shown again.",value:p,onChange:H=>v(H.target.value),required:!0}),t.jsx(Te,{label:"Email claim (optional)",placeholder:"email",hint:"Override only if your provider puts the email somewhere else, e.g. upn.",value:j,onChange:H=>S(H.target.value)})]}):t.jsxs(t.Fragment,{children:[t.jsx(Te,{label:"Sign-in URL (SSO endpoint)",placeholder:"https://idp.example.com/sso/saml",value:y,onChange:H=>b(H.target.value),required:!0}),t.jsx(Te,{label:"IdP entity ID",placeholder:"https://idp.example.com/metadata",value:k,onChange:H=>C(H.target.value),required:!0}),t.jsx(Yi,{label:"IdP signing certificate",rows:5,placeholder:"-----BEGIN CERTIFICATE-----",hint:"PEM or base64. Assertions must be signed; there is no way to disable that.",value:z,onChange:H=>O(H.target.value),required:!0}),t.jsx(Te,{label:"Email attribute (optional)",placeholder:"http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress",value:T,onChange:H=>M(H.target.value)})]}),E&&t.jsx("p",{role:"alert",className:"rounded-md border border-danger/40 bg-danger/10 px-3 py-2 text-xs text-danger",children:E})]})})}const Dv=[{value:"off",label:"Off",hint:"No MCP client can connect or call anything."},{value:"read",label:"Read only",hint:"Clients can list queues, read jobs, logs and schedulers. Nothing changes."},{value:"write",label:"Read & write",hint:"Operators and admins may also let a client retry, promote, remove and add jobs and pause queues. Viewers still only read."}];function I3(){const{has:e}=wt();return e("mcp")?t.jsx(z3,{}):t.jsx(Wa,{feature:"mcp"})}function z3(){var S;const{isAdmin:e}=mt(),n=X2(),r=Y2(),[i,o]=w.useState(!1),c=eS(e&&i),d=tS(),[h,f]=w.useState(null);if(n.isLoading||!n.data)return t.jsx("div",{className:"flex justify-center py-8",children:t.jsx(Kt,{})});const{maxAccess:g,endpoint:p,reachableFromCloud:v}=n.data,j=c.data??[];return t.jsxs("div",{className:"space-y-5",children:[t.jsxs("div",{children:[t.jsx("h2",{className:"text-sm font-semibold text-fg",children:"MCP"}),t.jsx("p",{className:"mt-1 max-w-2xl text-xs text-fg-muted",children:"Connect your AI to this Bullpane: Claude, or any MCP client that supports OAuth. Each person signs in with their own Bullpane login (or SSO) and picks read or read & write. A client acts as that person, with their role: what they cannot do in the dashboard, the client cannot do either. Every change is in the audit log, and draining, cleaning or obliterating a queue always comes back here for a human to confirm."})]}),t.jsxs("div",{className:"card space-y-3 p-4",children:[t.jsx("h3",{className:"text-xs font-semibold uppercase tracking-wide text-fg-subtle",children:"Access for MCP clients"}),t.jsx(dt,{label:"Most a client can do on this install",value:g,disabled:!e||r.isPending,onChange:y=>r.mutate({maxAccess:y.target.value},{onSuccess:()=>X.success("MCP access updated. It applies to connected clients on their next call."),onError:b=>X.error(ve(b))}),options:Dv.map(y=>({value:y.value,label:y.label})),hint:e?(S=Dv.find(y=>y.value===g))==null?void 0:S.hint:"Only an admin can change this.",wrapperClassName:"max-w-md"})]}),t.jsxs("div",{className:"card space-y-3 p-4",children:[t.jsx("h3",{className:"text-xs font-semibold uppercase tracking-wide text-fg-subtle",children:"Connect a client"}),t.jsx(ju,{label:"Server URL",value:p}),!v&&t.jsxs("div",{className:"flex gap-2 rounded-md border border-warning/40 bg-warning/10 px-3 py-2 text-xs text-fg",children:[t.jsx(ts,{className:"mt-0.5 size-3.5 shrink-0 text-warning"}),t.jsxs("span",{children:["Cloud-hosted clients such as claude.ai and Claude Desktop connect from their provider's servers, so they need this URL to be public HTTPS. It looks private (check ",t.jsx("span",{className:"font-mono",children:"PUBLIC_URL"}),"). Clients that run on your machine, such as Claude Code, work on a private network."]})]}),t.jsxs("dl",{className:"space-y-2 text-xs text-fg-muted",children:[t.jsxs("div",{children:[t.jsx("dt",{className:"font-medium text-fg",children:"claude.ai and Claude Desktop"}),t.jsx("dd",{children:"Settings → Connectors → Add custom connector, paste the server URL, then Connect and sign in."})]}),t.jsxs("div",{children:[t.jsx("dt",{className:"font-medium text-fg",children:"Claude Code"}),t.jsxs("dd",{children:[t.jsxs("code",{className:"rounded bg-surface-2 px-1.5 py-0.5 font-mono text-[11px]",children:["claude mcp add --transport http bullpane ",p]}),", then run ",t.jsx("code",{className:"font-mono",children:"/mcp"})," to sign in."]})]}),t.jsxs("div",{children:[t.jsx("dt",{className:"font-medium text-fg",children:"Any other MCP client"}),t.jsx("dd",{children:"Add the server URL as a remote (HTTP) MCP server. The client registers itself and opens this Bullpane to sign in."})]})]})]}),t.jsxs("div",{className:"space-y-2",children:[t.jsxs("div",{className:"flex items-center justify-between gap-3",children:[t.jsx("h3",{className:"text-xs font-semibold uppercase tracking-wide text-fg-subtle",children:i?"All connected clients":"Your connected clients"}),e&&t.jsx(V,{size:"sm",variant:"ghost",onClick:()=>o(y=>!y),children:i?"Show only mine":"Show everyone's"})]}),c.isLoading?t.jsx("div",{className:"flex justify-center py-6",children:t.jsx(Kt,{})}):j.length===0?t.jsxs("div",{className:"card p-6 text-center",children:[t.jsx(Ay,{className:"mx-auto size-6 text-fg-subtle"}),t.jsx("p",{className:"mt-2 text-sm text-fg",children:"No client connected"}),t.jsx("p",{className:"mx-auto mt-1 max-w-md text-xs text-fg-muted",children:"Add the server URL to Claude and sign in; the connection shows up here."})]}):t.jsx("div",{className:"card divide-y divide-border",children:j.map(y=>t.jsxs("div",{className:"flex items-center justify-between gap-3 px-4 py-3",children:[t.jsxs("div",{className:"min-w-0",children:[t.jsxs("div",{className:"flex items-center gap-2",children:[t.jsx("span",{className:"truncate text-sm font-medium text-fg",children:y.clientName}),t.jsx(be,{variant:y.access==="write"?"warning":"neutral",children:y.access==="write"?"read & write":"read"})]}),t.jsxs("p",{className:"mt-0.5 truncate text-xs text-fg-muted",children:[i&&t.jsxs(t.Fragment,{children:[y.userEmail," · "]}),y.redirectHost," · connected ",Kr(y.createdAt)," · ",y.lastUsedAt?`last used ${Kr(y.lastUsedAt)}`:"not used yet"]})]}),t.jsx(V,{size:"sm",variant:"ghost",leftIcon:t.jsx(fm,{className:"size-3.5"}),onClick:()=>f(y),children:"Disconnect"})]},y.id))})]}),t.jsx(Ht,{open:h!==null,onClose:()=>f(null),title:"Disconnect client",description:h?`${h.clientName} (${h.userEmail}) loses access on its next call. Connecting again needs a new sign-in.`:void 0,confirmText:"Disconnect",danger:!0,loading:d.isPending,onConfirm:()=>h&&d.mutate(h.id,{onSuccess:()=>{X.success(`${h.clientName} disconnected`),f(null)},onError:y=>X.error(ve(y))})})]})}const O3=["connections","attention","sso","mcp","license","about"];function A3(){const{tab:e}=Fn(),n=un();if(!e||!O3.includes(e))return t.jsx(Vr,{to:"/settings/connections",replace:!0});const r=e;return t.jsxs(bt,{children:[t.jsx(gs,{title:"Settings"}),t.jsx(Um,{"aria-label":"Settings sections",className:"mb-5",value:r,onChange:i=>n(`/settings/${i}`),items:[{value:"connections",label:"Connections",icon:t.jsx(Va,{className:"size-3.5"})},{value:"attention",label:"Attention",icon:t.jsx(ts,{className:"size-3.5"})},{value:"sso",label:"SSO",icon:t.jsx(Gu,{className:"size-3.5"})},{value:"mcp",label:"MCP",icon:t.jsx(Ay,{className:"size-3.5"})},{value:"license",label:"License",icon:t.jsx(al,{className:"size-3.5"})},{value:"about",label:"About",icon:t.jsx(Ha,{className:"size-3.5"})}]}),r==="connections"&&t.jsx(S3,{}),r==="attention"&&t.jsx(j3,{}),r==="sso"&&t.jsx(M3,{}),r==="mcp"&&t.jsx(I3,{}),r==="license"&&t.jsx(P3,{}),r==="about"&&t.jsx(E3,{})]})}const L3=[{label:"Any time",ms:0},{label:"Next hour",ms:36e5},{label:"Next 24 hours",ms:864e5},{label:"Next 7 days",ms:6048e5}];function F3(){var r;const e=xs();if(e.isLoading)return t.jsx(bt,{children:t.jsx(Kt,{label:"Loading…"})});const n=(r=e.data)==null?void 0:r[0];return n?t.jsx(Vr,{to:ue.schedulers(n.id),replace:!0}):t.jsx(bt,{children:t.jsx(cn,{icon:t.jsx(Lo,{}),title:"No connections",description:"Add a Redis connection first; schedulers are listed per connection."})})}function D3(){var p;const{connectionId:e}=Fn(),n=xs(),r=un(),[i,o]=w.useState(""),[c,d]=w.useState(0),h=j2(e,{...i.trim()?{q:i.trim()}:{},...c>0?{withinMs:c}:{}}),f=((p=h.data)==null?void 0:p.schedulers)??[],g=h.data;return t.jsxs(bt,{children:[t.jsx(gs,{title:"Schedulers",description:g?`${K(g.total)} across ${K(g.queuesWithSchedulers)} of ${K(g.queuesScanned)} queues`:void 0,actions:n.data&&n.data.length>1?t.jsx(dt,{"aria-label":"Connection",value:e??"",onChange:v=>r(ue.schedulers(v.target.value)),children:n.data.map(v=>t.jsx("option",{value:v.id,children:v.name},v.id))}):void 0}),t.jsxs("div",{className:"mb-3 flex flex-wrap items-center gap-2",children:[t.jsx(Te,{value:i,onChange:v=>o(v.target.value),placeholder:"Filter by scheduler id, job name or queue…","aria-label":"Filter schedulers",leftIcon:t.jsx(Yn,{className:"size-3.5"}),className:"w-full sm:w-80"}),t.jsx(dt,{"aria-label":"Next run within",value:String(c),onChange:v=>d(Number(v.target.value)),children:L3.map(v=>t.jsx("option",{value:v.ms,children:v.label},v.ms))}),h.isFetching&&t.jsx(Kt,{className:"size-3.5"})]}),g&&g.failed.length>0&&t.jsxs("div",{className:"mb-3 flex items-start gap-2 rounded-md border border-warning/40 bg-warning/10 px-3 py-2 text-xs text-fg-muted",children:[t.jsx(ts,{className:"mt-0.5 size-3.5 shrink-0 text-warning","aria-hidden":!0}),t.jsxs("span",{children:["Could not read schedulers from ",g.failed.length," queue",g.failed.length===1?"":"s",":"," ",t.jsx("span",{className:"font-mono",children:g.failed.map(v=>v.queueName).join(", ")}),". The rest of the list is complete."]})]}),t.jsx("div",{className:"card overflow-hidden",children:t.jsxs(ms,{children:[t.jsx("thead",{children:t.jsxs("tr",{children:[t.jsx(pe,{children:"Queue"}),t.jsx(pe,{children:"Scheduler"}),t.jsx(pe,{children:"Job name"}),t.jsx(pe,{children:"Repeats"}),t.jsx(pe,{align:"right",children:"Next run"})]})}),t.jsxs("tbody",{children:[h.isLoading&&t.jsx(yt,{colSpan:5,children:t.jsx(Kt,{label:"Reading schedulers…"})}),h.isError&&!g&&t.jsx(yt,{colSpan:5,className:"text-danger",children:ve(h.error)}),g&&f.length===0&&t.jsx(yt,{colSpan:5,children:t.jsx(Q3,{filtered:!!i.trim()||c>0,total:g.total})}),f.map(v=>t.jsx(U3,{s:v,connectionId:e},`${v.queueName}:${v.key}`))]})]})}),g&&f.length>0&&f.length<g.total&&t.jsxs("p",{className:"mt-2 text-[11px] text-fg-subtle",children:["Showing ",K(f.length)," of ",K(g.total),". Narrow the filter to see the rest."]})]})}function U3({s:e,connectionId:n}){const r=e.next!=null&&e.next<=Date.now();return t.jsxs(cl,{children:[t.jsx(xe,{children:t.jsx(Ee,{to:ue.queueSchedulers(n,e.queueName),className:"text-accent hover:underline",children:e.queueName})}),t.jsx(xe,{mono:!0,children:t.jsx("span",{className:"text-fg",title:e.key,children:e.key})}),t.jsx(xe,{mono:!0,muted:!0,children:e.name}),t.jsx(xe,{children:t.jsxs("span",{className:"flex flex-wrap items-center gap-1.5",children:[t.jsx(be,{variant:"outline",size:"xs",className:"font-mono",children:hj(e)}),e.tz&&t.jsx("span",{className:"text-[11px] text-fg-subtle",children:e.tz}),e.iterationCount===0&&t.jsx("span",{className:"text-[11px] text-warning",title:"This scheduler has never produced a job",children:"never ran"})]})}),t.jsx(xe,{align:"right",num:!0,children:e.next==null?t.jsx("span",{className:"text-fg-subtle",title:"No next run: the scheduler ended or hit its limit",children:"–"}):t.jsxs("span",{className:F("inline-flex items-center gap-1",r&&"text-warning"),title:gn(e.next),children:[r&&t.jsx(Dy,{className:"size-3","aria-hidden":!0}),Kr(e.next)]})})]})}function Q3({filtered:e,total:n}){return e&&n>0?t.jsxs("div",{className:"py-6 text-center text-sm text-fg-muted",children:["No scheduler matches this filter. This connection has ",K(n)," in total."]}):t.jsxs("div",{className:"mx-auto flex max-w-xl flex-col items-center gap-2 py-6 text-center",children:[t.jsx(Lo,{className:"size-6 text-fg-subtle","aria-hidden":!0}),t.jsx("p",{className:"text-sm font-medium text-fg",children:"No job schedulers on this connection"}),t.jsx("p",{className:"text-xs text-fg-muted",children:"A job scheduler (BullMQ calls it a repeatable job) stamps out the same job on a cron pattern or a fixed interval. It lives outside the job states, so it never shows up under Waiting or Delayed — only the single job it has queued next does."}),t.jsxs("p",{className:"flex items-center gap-1.5 text-[11px] text-fg-subtle",children:[t.jsx(Wy,{className:"size-3","aria-hidden":!0}),"Create one with ",t.jsx("span",{className:"font-mono",children:"queue.upsertJobScheduler()"}),"."]})]})}function B3(){return t.jsx(bt,{children:t.jsx(cn,{icon:t.jsx(gN,{}),title:"Page not found",description:"The link may be stale, or the queue or connection was removed.",action:t.jsx(Ee,{to:"/",className:"text-accent hover:underline",children:"Back to overview"})})})}const V3=w.lazy(()=>Bu(()=>import("./FlowsPage-Cp6TR7Wa.js"),__vite__mapDeps([0,1,2,3])).then(e=>({default:e.FlowsPage}))),H3=w.lazy(()=>Bu(()=>import("./FlowsPage-Cp6TR7Wa.js"),__vite__mapDeps([0,1,2,3])).then(e=>({default:e.FlowsIndexPage}))),K3=w.lazy(()=>Bu(()=>import("./McpConsentPage-CI53cgZX.js"),[]).then(e=>({default:e.McpConsentPage}))),W3=w.lazy(()=>Bu(()=>import("./JobTreePage-CbwbeeRl.js"),__vite__mapDeps([4,1,2])).then(e=>({default:e.JobTreePage})));function pu({children:e}){return t.jsx(w.Suspense,{fallback:t.jsx(il,{}),children:e})}const Z3=new tN({defaultOptions:{queries:{retry:(e,n)=>Ts(n)&&n.status>0&&n.status<500?!1:e<2,retryDelay:e=>Math.min(1e3*2**e,8e3),staleTime:1e3,refetchOnWindowFocus:!0,refetchIntervalInBackground:!1},mutations:{retry:!1}}});function G3(){return t.jsx(_w,{client:Z3,children:t.jsx(bw,{children:t.jsxs(Wk,{children:[t.jsxs(hw,{children:[t.jsx(ct,{path:"/login",element:t.jsx(iv,{children:t.jsx(PS,{})})}),t.jsx(ct,{path:"/setup",element:t.jsx(iv,{children:t.jsx(ES,{})})}),t.jsx(ct,{path:"/oauth/consent",element:t.jsx(pu,{children:t.jsx(K3,{})})}),t.jsx(ct,{element:t.jsx(Zk,{}),children:t.jsxs(ct,{element:t.jsx(_S,{}),children:[t.jsx(ct,{index:!0,element:t.jsx(oC,{})}),t.jsx(ct,{path:"c/:connectionId",element:t.jsx(uC,{})}),t.jsx(ct,{path:"c/:connectionId/q/:queue",element:t.jsx(sf,{})}),t.jsx(ct,{path:"c/:connectionId/q/:queue/metrics",element:t.jsx(sf,{view:"metrics"})}),t.jsx(ct,{path:"c/:connectionId/q/:queue/schedulers",element:t.jsx(sf,{view:"schedulers"})}),t.jsx(ct,{path:"c/:connectionId/q/:queue/groups",element:t.jsx(B_,{})}),t.jsx(ct,{path:"c/:connectionId/q/:queue/groups/:groupId",element:t.jsx(Z_,{})}),t.jsx(ct,{path:"c/:connectionId/q/:queue/j/:jobId",element:t.jsx(O_,{})}),t.jsx(ct,{path:"c/:connectionId/q/:queue/j/:jobId/tree",element:t.jsx(pu,{children:t.jsx(W3,{})})}),t.jsx(ct,{path:"health",element:t.jsx(yC,{})}),t.jsx(ct,{path:"schedulers",element:t.jsx(F3,{})}),t.jsx(ct,{path:"schedulers/:connectionId",element:t.jsx(D3,{})}),t.jsx(ct,{path:"folders",element:t.jsx(G_,{})}),t.jsx(ct,{path:"folders/:folderId",element:t.jsx(l3,{})}),t.jsx(ct,{path:"alerts",element:t.jsx(N_,{})}),t.jsx(ct,{path:"users",element:t.jsx(u3,{})}),t.jsx(ct,{path:"audit",element:t.jsx(p3,{})}),t.jsxs(t.Fragment,{children:[t.jsx(ct,{path:"flows",element:t.jsx(pu,{children:t.jsx(H3,{})})}),t.jsx(ct,{path:"flows/:connectionId",element:t.jsx(pu,{children:t.jsx(V3,{})})})]}),t.jsx(ct,{path:"settings",element:t.jsx(Vr,{to:"/settings/connections",replace:!0})}),t.jsx(ct,{path:"settings/:tab",element:t.jsx(A3,{})}),t.jsx(ct,{path:"*",element:t.jsx(B3,{})})]})})]}),t.jsx(e2,{}),t.jsx(Kk,{})]})})})}bb.createRoot(document.getElementById("root")).render(t.jsx(w.StrictMode,{children:t.jsx(G3,{})}));export{mt as $,h5 as A,V as B,Dn as C,Va as D,Br as E,f5 as F,p5 as G,x5 as H,Te as I,g5 as J,m5 as K,Ee as L,d5 as M,Ts as N,cn as O,es as P,Uy as Q,ON as R,Cu as S,Pe as T,u5 as U,Uo as V,DN as W,vn as X,Un as Y,Ht as Z,un as _,Yu as a,s5 as a0,r5 as a1,a5 as a2,dm as a3,Ha as a4,wt as a5,Wa as a6,Fn as a7,sl as a8,i5 as a9,Ay as aa,Ln as ab,Z0 as ac,ts as ad,Vr as ae,v5 as af,y5 as ag,n5 as ah,bt as ai,gs as aj,kN as ak,ad as al,Vy as am,FS as an,Kr as ao,Gf as ap,db as aq,pb as ar,X3 as as,F as b,ie as c,Kt as d,K as e,ft as f,lt as g,be as h,ue as i,t as j,Yn as k,Zr as l,e5 as m,o5 as n,bn as o,Yi as p,dt as q,w as r,t5 as s,X as t,ll as u,ve as v,So as w,c5 as x,l5 as y,xs as z};
|
|
553
|
+
${d}`:""}`,children:t.jsx("div",{className:F("num text-2xl leading-tight font-semibold",c&&"opacity-50",r.successPct==null?"text-fg-subtle":r.successPct<90?"text-state-failed":"text-state-completed"),children:r.successPct==null?"—":En(r.successPct)})}),t.jsx("div",{className:F("mt-1 flex h-1.5 w-full overflow-hidden rounded-full bg-surface-3",c&&"opacity-50"),role:"img","aria-label":r.successPct==null?"No finished jobs":`${En(r.successPct)} success${c?", unreliable: some queues prune completed jobs":""}`,children:r.successPct!=null&&t.jsxs(t.Fragment,{children:[t.jsx("span",{className:"h-full",style:{width:`${r.successPct}%`,background:lt.completed.fg}}),t.jsx("span",{className:"h-full flex-1",style:{background:lt.failed.fg,opacity:r.successPct>=100?0:1}})]})})]}),t.jsxs("div",{className:"card flex flex-col px-3 py-2.5",children:[t.jsx("div",{className:"text-[10px] font-medium tracking-wider text-fg-subtle uppercase",children:"Completed / min"}),o?t.jsxs(t.Fragment,{children:[t.jsx("span",{className:"mt-1 block",style:{color:lt.completed.fg},children:t.jsx(tl,{values:r.completedSeries,width:140,height:30,title:"Combined completed per minute",className:"w-full"})}),t.jsxs("span",{className:"mt-auto text-[10px] text-fg-subtle",children:[K(r.withMetrics)," of ",K(e.length)," queues report metrics"]})]}):t.jsx("span",{className:"mt-2 text-[11px] leading-relaxed text-fg-subtle",children:"No queue in this folder collects metrics."})]})]})}function s3(e){let n="";for(const r of e)r==="*"?n+=".*":r==="?"?n+=".":n+=r.replace(/[.*+?^${}()|[\]\\]/g,"\\$&");return new RegExp(`^${n}$`,"i")}function r3(e,n){const r=e.trim();if(!r)return!1;try{return s3(r).test(n)}catch{return!1}}const mu="__any__";function a3({open:e,onClose:n,existing:r,onImport:i,saving:o}){const{byConnection:c}=ll(),[d,h]=w.useState(""),[f,g]=w.useState(mu),p=w.useMemo(()=>new Set(r.map(y=>`${y.connectionId} ${y.queueName}`)),[r]),v=w.useMemo(()=>{const y=d.trim();if(!y)return[];const b=[];for(const{connection:k,queues:C}of c)if(!(f!==mu&&k.id!==f))for(const z of C){if(!r3(y,z.name))continue;const O={connectionId:k.id,queueName:z.name};b.push({ref:O,connectionName:k.name,already:p.has(`${k.id} ${z.name}`)})}return b.sort((k,C)=>k.ref.queueName.localeCompare(C.ref.queueName))},[d,f,c,p]),j=v.filter(y=>!y.already),S=()=>{i([...r,...j.map(y=>y.ref)])};return t.jsx(bn,{open:e,onClose:n,size:"md",title:"Import matching queues",description:"Add every queue whose name matches a pattern, in one go.",footer:t.jsxs(t.Fragment,{children:[t.jsx("span",{className:"mr-auto text-xs text-fg-muted",children:d.trim()===""?"Type a pattern to preview":`${K(j.length)} to add · ${K(v.length-j.length)} already in folder`}),t.jsx(V,{variant:"ghost",size:"sm",onClick:n,children:"Cancel"}),t.jsxs(V,{variant:"primary",size:"sm",leftIcon:t.jsx(Rf,{}),loading:o,disabled:j.length===0,onClick:S,children:["Import ",j.length>0?K(j.length):""]})]}),children:t.jsxs("div",{className:"space-y-3",children:[t.jsxs("div",{className:"grid gap-3 sm:grid-cols-[1fr_200px]",children:[t.jsx(Te,{label:"Pattern",mono:!0,autoFocus:!0,placeholder:"channels*",value:d,onChange:y=>h(y.target.value),hint:"* matches any run of characters, ? matches exactly one. Case-insensitive."}),t.jsx(dt,{label:"Connection",value:f,onChange:y=>g(y.target.value),options:[{value:mu,label:"Any connection"},...c.map(y=>({value:y.connection.id,label:y.connection.name}))]})]}),t.jsxs("div",{className:"flex flex-wrap gap-1.5 text-[11px] text-fg-subtle",children:[t.jsx("span",{children:"Examples:"}),["channels*","*-retry","email-?"].map(y=>t.jsx("button",{type:"button",onClick:()=>h(y),className:"rounded border border-border bg-surface-2 px-1.5 py-0.5 font-mono text-fg-muted hover:text-fg",children:y},y))]}),t.jsxs("div",{className:"rounded-md border border-border",children:[t.jsxs("div",{className:"flex items-center justify-between border-b border-border bg-surface-2/50 px-3 py-1.5 text-[11px] font-semibold tracking-wider text-fg-subtle uppercase",children:["Preview",t.jsxs("span",{className:"num font-normal tracking-normal normal-case",children:[K(v.length)," matching"]})]}),t.jsx("div",{className:"max-h-64 overflow-y-auto",children:d.trim()===""?t.jsx("p",{className:"px-3 py-6 text-center text-xs text-fg-subtle",children:"Nothing to preview yet."}):v.length===0?t.jsxs("p",{className:"px-3 py-6 text-center text-xs text-fg-subtle",children:["No queue matches ",t.jsx("span",{className:"font-mono text-fg-muted",children:d.trim()}),f!==mu&&" on this connection","."]}):t.jsx("ul",{className:"divide-y divide-border",children:v.map(y=>t.jsxs("li",{className:"flex items-center gap-2 px-3 py-1.5 text-xs",children:[t.jsx("span",{className:"truncate font-mono text-fg",children:y.ref.queueName}),t.jsx(be,{variant:"outline",size:"xs",children:y.connectionName}),y.already&&t.jsx("span",{className:"ml-auto shrink-0 text-[10px] text-fg-subtle",children:"already in folder"})]},`${y.ref.connectionId}/${y.ref.queueName}`))})})]}),t.jsxs("p",{className:"flex items-start gap-2 rounded-md border border-border bg-surface-2/50 px-3 py-2 text-[11px] leading-relaxed text-fg-muted",children:[t.jsx(Ha,{className:"mt-0.5 size-3.5 shrink-0 text-fg-subtle","aria-hidden":!0}),t.jsxs("span",{children:["Imports the queues matching this pattern ",t.jsx("strong",{className:"text-fg",children:"now"}),". New queues that appear later are"," ",t.jsx("strong",{className:"text-fg",children:"not"})," added automatically — run the import again when they show up."]})]})]})})}function i3({open:e,onClose:n,folder:r,allFolders:i}){const o=O0(),[c,d]=w.useState(r.name),[h,f]=w.useState(r.color),[g,p]=w.useState(r.parentId??""),[v,j]=w.useState(null),S=i.some(k=>k.parentId===r.id),y=i.filter(k=>!k.parentId&&k.id!==r.id),b=()=>{var C;const k=Ek.safeParse({name:c.trim(),color:h,parentId:g||null});if(!k.success){j(((C=k.error.issues[0])==null?void 0:C.message)??"Invalid");return}o.mutate({id:r.id,input:k.data},{onSuccess:()=>{X.success("Folder updated"),n()},onError:z=>X.error(ve(z))})};return t.jsx(bn,{open:e,onClose:n,size:"sm",title:"Edit folder",footer:t.jsxs(t.Fragment,{children:[t.jsx(V,{variant:"ghost",size:"sm",onClick:n,children:"Cancel"}),t.jsx(V,{variant:"primary",size:"sm",onClick:b,loading:o.isPending,children:"Save changes"})]}),children:t.jsxs("form",{className:"space-y-3",onSubmit:k=>{k.preventDefault(),b()},children:[t.jsx(Te,{label:"Name",autoFocus:!0,value:c,onChange:k=>d(k.target.value),error:v}),t.jsxs("div",{children:[t.jsx("span",{className:"mb-1 block text-xs font-medium text-fg-muted",children:"Colour"}),t.jsxs("div",{className:"flex flex-wrap gap-1.5",role:"radiogroup","aria-label":"Folder colour",children:[Qu.map(k=>t.jsx("button",{type:"button",role:"radio","aria-checked":h===k,"aria-label":k,className:F("size-5 rounded-full ring-offset-2 ring-offset-surface transition-shadow",h===k&&"ring-2 ring-fg"),style:{background:k},onClick:()=>f(k)},k)),t.jsx("button",{type:"button",role:"radio","aria-checked":!h,"aria-label":"No colour",className:F("size-5 rounded-full border border-dashed border-border-strong ring-offset-2 ring-offset-surface",!h&&"ring-2 ring-fg"),onClick:()=>f(null)})]})]}),t.jsx(dt,{label:"Parent folder",value:g,disabled:S,onChange:k=>p(k.target.value),options:[{value:"",label:"None (top level)"},...y.map(k=>({value:k.id,label:k.name}))],hint:S?"This folder has subfolders, so it must stay top-level.":"Folders nest one level deep."})]})})}function l3(){const{has:e}=wt();return e("folders")?t.jsx(o3,{}):t.jsx(Wa,{feature:"folders"})}function o3(){const{folderId:e=""}=Fn(),{isOperator:n}=mt(),{has:r,gate:i}=wt(),o=Jr(),{byConnection:c,isLoading:d}=ll(),h=A0(),[f,g]=w.useState(null),{sort:p,setSort:v,filter:j,setFilter:S}=Mm(`folder.${e}`,Lm,Am),y=o.data??[],b=y.find(I=>I.id===e)??null,{entries:k,missing:C}=w.useMemo(()=>{const I=[],Q=[];for(const H of(b==null?void 0:b.queues)??[]){const q=c.find(de=>de.connection.id===H.connectionId),B=q==null?void 0:q.queues.find(de=>de.name===H.queueName);q&&B?I.push({connection:q.connection,queue:B}):Q.push(H)}return{entries:I,missing:Q}},[b,c]),z=w.useMemo(()=>k.filter(I=>Rm(I,j)),[k,j]),O=(I,Q,H=!0)=>{b&&h.mutate({id:b.id,input:{queues:I}},{onSuccess:()=>{X.success(Q),H&&g(null)},onError:q=>X.error(ve(q))})},T=I=>O(((b==null?void 0:b.queues)??[]).filter(Q=>!(Q.connectionId===I.connectionId&&Q.queueName===I.queueName)),`${I.queueName} removed from ${(b==null?void 0:b.name)??"folder"}`,!1);if(o.isLoading)return t.jsx(bt,{wide:!0,children:t.jsx(il,{})});if(!b)return t.jsx(bt,{wide:!0,children:t.jsx(cn,{icon:t.jsx(sr,{}),title:"Folder not found",description:"It may have been deleted.",action:t.jsx(Ee,{to:ue.folders,className:"text-accent hover:underline",children:"Back to folders"})})});const M=b.parentId?y.find(I=>I.id===b.parentId):null,E=b.queues.length===0;return t.jsxs(bt,{wide:!0,children:[t.jsxs("div",{className:"mb-4 flex flex-wrap items-start justify-between gap-3",children:[t.jsxs("div",{className:"min-w-0",children:[t.jsxs("div",{className:"flex items-center gap-2.5",children:[t.jsx("span",{className:"size-3 shrink-0 rounded-full ring-2 ring-inset ring-white/10",style:{background:b.color??"var(--fg-subtle)"},"aria-hidden":!0}),t.jsx("h1",{className:"truncate text-lg font-semibold tracking-tight",children:b.name})]}),t.jsxs("p",{className:"mt-0.5 flex flex-wrap items-center gap-x-2 text-xs text-fg-muted",children:[M&&t.jsxs(t.Fragment,{children:[t.jsx(Ee,{to:`/folders/${encodeURIComponent(M.id)}`,className:"hover:underline",children:M.name}),t.jsx("span",{className:"text-fg-subtle",children:"/"})]}),t.jsxs("span",{className:"num",children:[K(b.queues.length)," ",b.queues.length===1?"queue":"queues"]}),C.length>0&&t.jsxs("span",{className:"text-state-waiting",title:C.map(I=>I.queueName).join(", "),children:["· ",K(C.length)," not found"]}),t.jsx("span",{className:"text-fg-subtle",children:"·"}),t.jsx(Ee,{to:ue.folders,className:"hover:underline",children:"Manage folders"})]})]}),t.jsxs("div",{className:"flex flex-wrap items-center gap-2",children:[n&&t.jsx(V,{size:"sm",variant:"secondary",leftIcon:t.jsx(Uo,{}),onClick:()=>g("edit"),children:"Edit"}),n&&t.jsx(V,{size:"sm",variant:"secondary",leftIcon:t.jsx(Rf,{}),onClick:()=>g("import"),title:"Import queues matching a pattern",children:"Import matching"}),n&&t.jsx(V,{size:"sm",variant:"primary",leftIcon:t.jsx(es,{}),onClick:()=>g("add"),children:"Add queue"}),t.jsx(V,{size:"sm",leftIcon:t.jsx(rl,{}),onClick:()=>i("alerts",()=>g("alert")),title:"Alert on every queue in this folder",children:"Create alert"})]})]}),t.jsx(n3,{entries:k,className:"mb-4"}),E?t.jsx("div",{className:"card",children:t.jsx(cn,{icon:t.jsx(sr,{}),title:"This folder is empty",description:"Add queues by hand, or import every queue whose name matches a pattern like channels* or *-retry.",action:n&&t.jsxs(t.Fragment,{children:[t.jsx(V,{variant:"primary",leftIcon:t.jsx(es,{}),onClick:()=>g("add"),children:"Add queue"}),t.jsx(V,{leftIcon:t.jsx(Rf,{}),onClick:()=>g("import"),children:"Import matching queues"})]})})}):t.jsxs("section",{className:"space-y-3","aria-label":"Queues in this folder",children:[t.jsxs("div",{className:"flex flex-wrap items-center justify-between gap-2",children:[t.jsx("h2",{className:"text-xs font-semibold tracking-wider text-fg-subtle uppercase",children:"Queues"}),t.jsxs("div",{className:"flex items-center gap-2",children:[t.jsx(Om,{value:j,onChange:S,"aria-label":"Filter queues in this folder"}),t.jsxs("span",{className:"num whitespace-nowrap text-xs text-fg-subtle",children:[z.length," of ",k.length]})]})]}),d&&k.length===0?t.jsx(zm,{}):z.length>0?t.jsx("div",{className:"grid gap-2",style:{gridTemplateColumns:"repeat(auto-fill, minmax(230px, 1fr))"},children:z.map(I=>t.jsx(c3,{entry:I,onRemove:n?()=>T({connectionId:I.connection.id,queueName:I.queue.name}):void 0,removing:h.isPending},Ia(I)))}):null,t.jsx("div",{className:"card overflow-hidden",children:t.jsx(Fm,{rows:z,showConnection:!0,sort:p,onSort:v,message:d&&k.length===0?"Loading queues…":j?"No queue matches the filter":"None of this folder's queues could be resolved on their connections."})}),C.length>0&&t.jsxs("div",{className:"card px-4 py-3",children:[t.jsx("h3",{className:"mb-1.5 text-[11px] font-semibold tracking-wider text-fg-subtle uppercase",children:"Not found on their connection"}),t.jsx("ul",{className:"flex flex-wrap gap-2",children:C.map(I=>{var Q;return t.jsxs("li",{className:"flex items-center gap-1.5 rounded border border-border bg-surface-2 px-2 py-1 text-xs",children:[t.jsx("span",{className:"font-mono text-fg-muted line-through",children:I.queueName}),t.jsx(be,{variant:"outline",size:"xs",children:((Q=c.find(H=>H.connection.id===I.connectionId))==null?void 0:Q.connection.name)??I.connectionId}),n&&t.jsx(V,{size:"icon-xs",variant:"ghost",className:"hover:text-danger","aria-label":`Remove ${I.queueName}`,onClick:()=>T(I),children:t.jsx(vn,{})})]},`${I.connectionId}/${I.queueName}`)})}),t.jsx("p",{className:"mt-2 text-[11px] text-fg-subtle",children:"These queues are referenced by the folder but were not discovered on their connection — renamed, obliterated, or the connection is down."})]})]}),n&&f==="edit"&&t.jsx(i3,{open:!0,onClose:()=>g(null),folder:b,allFolders:y}),n&&t.jsx(wj,{open:f==="add",onClose:()=>g(null),initial:b.queues,saving:h.isPending,onSave:I=>O(I,"Folder updated"),title:`Add queues to ${b.name}`}),n&&t.jsx(a3,{open:f==="import",onClose:()=>g(null),existing:b.queues,saving:h.isPending,onImport:I=>O(I,`Imported into ${b.name}`)}),f==="alert"&&r("alerts")&&t.jsx(od,{open:!0,onClose:()=>g(null),alert:null,initialScope:{type:"folder",folderId:b.id}})]})}function c3({entry:e,onRemove:n,removing:r}){return t.jsxs("div",{className:"group/card relative",children:[t.jsx(id,{entry:e,showConnection:!0}),n&&t.jsx(V,{size:"icon-xs",variant:"ghost",disabled:r,onClick:n,"aria-label":`Remove ${e.queue.name} from this folder`,title:"Remove from folder",className:"absolute top-2 right-8 z-10 bg-surface/90 opacity-0 backdrop-blur-sm transition-opacity group-hover/card:opacity-100 focus-visible:opacity-100 hover:text-danger",children:t.jsx(vn,{})})]})}const Wf={admin:"Everything, including connections, users, license, drain and obliterate.",operator:"Manage jobs and queues, alerts, folders and flow edges. No settings.",viewer:"Read-only access to queues, jobs, alerts and flows."};function u3(){const{has:e}=wt();return e("users")?t.jsx(N0,{role:"admin",children:t.jsx(d3,{})}):t.jsx(Wa,{feature:"users"})}function d3(){const{user:e}=mt(),n=z2(),r=A2(),[i,o]=w.useState(!1),[c,d]=w.useState(null),h=[...n.data??[]].sort((p,v)=>+!!p.disabledAt-+!!v.disabledAt||p.name.localeCompare(v.name)),f=h.filter(p=>p.role==="admin"&&!p.disabledAt).length,g=(p,v)=>r.mutate({id:p.id,input:{disabled:v}},{onSuccess:()=>{d(null),X.success(v?`${p.name} disabled`:`${p.name} re-enabled`,v?"Their sessions are revoked; the account keeps its history.":"They can sign in again.")},onError:j=>X.error(ve(j))});return t.jsxs(bt,{children:[t.jsx(gs,{title:"Users",description:"Roles are enforced on every API call, not only in the UI.",actions:t.jsx(V,{variant:"primary",size:"sm",leftIcon:t.jsx(LN,{}),onClick:()=>o(!0),children:"Invite user"})}),t.jsx("div",{className:"card overflow-hidden",children:t.jsxs(ms,{children:[t.jsx("thead",{children:t.jsxs("tr",{children:[t.jsx(pe,{children:"Name"}),t.jsx(pe,{children:"Email"}),t.jsx(pe,{className:"w-40",children:"Role"}),t.jsx(pe,{children:"Created"}),t.jsx(pe,{children:"Last login"}),t.jsx(pe,{align:"right",children:t.jsx("span",{className:"sr-only",children:"Actions"})})]})}),t.jsxs("tbody",{children:[n.isLoading&&t.jsx(yt,{colSpan:6,children:t.jsx(Kt,{label:"Loading users…"})}),n.isError&&t.jsx(yt,{colSpan:6,className:"text-danger",children:ve(n.error)}),h.map(p=>{var k;const v=p.id===(e==null?void 0:e.id),j=!!p.disabledAt,S=p.role==="admin"&&!j&&f<=1,y=v?"You cannot disable your own account":S?"Cannot disable the last admin":null,b=r.isPending&&((k=r.variables)==null?void 0:k.id)===p.id;return t.jsxs("tr",{className:F(j&&"text-fg-muted"),children:[t.jsxs(xe,{className:"font-medium",children:[t.jsx("span",{className:F(j&&"line-through decoration-fg-subtle"),children:p.name}),v&&t.jsx(be,{variant:"outline",size:"xs",className:"ml-1.5",children:"you"}),j&&t.jsx(Pe,{content:t.jsxs(t.Fragment,{children:["Disabled ",t.jsx(Yt,{value:p.disabledAt,withAbsolute:!0}),". Cannot sign in; sessions revoked."]}),side:"bottom",children:t.jsx(be,{variant:"neutral",size:"xs",className:"ml-1.5",children:"disabled"})})]}),t.jsx(xe,{muted:!0,children:p.email}),t.jsx(xe,{children:t.jsx(Pe,{content:v?"Ask another admin to change your role":S?"Promote someone else to admin first":Wf[p.role],block:!0,children:t.jsx(dt,{"aria-label":`Role of ${p.name}`,className:"!h-7 text-xs",value:p.role,disabled:v||S||j||b,onChange:C=>r.mutate({id:p.id,input:{role:C.target.value}},{onSuccess:()=>X.success(`${p.name} is now ${C.target.value}`),onError:z=>X.error(ve(z))}),options:Ou.map(C=>({value:C,label:C}))})})}),t.jsx(xe,{muted:!0,children:t.jsx(Yt,{value:p.createdAt})}),t.jsx(xe,{muted:!0,children:t.jsx(Yt,{value:p.lastLoginAt,emptyText:"never"})}),t.jsx(xe,{align:"right",children:j?t.jsx(Pe,{content:"Re-enable: they can sign in again with the same account",side:"left",children:t.jsx(V,{size:"xs",variant:"ghost",leftIcon:t.jsx(AN,{}),"aria-label":`Re-enable ${p.name}`,loading:b,onClick:()=>g(p,!1),children:"Enable"})}):t.jsx(Pe,{content:y??"Disable: revokes access, keeps the account and its history",side:"left",children:t.jsx(V,{size:"icon-xs",variant:"ghost",className:"hover:text-danger","aria-label":`Disable ${p.name}`,disabled:!!y||b,onClick:()=>d(p),children:t.jsx(FN,{})})})})]},p.id)})]})]})}),t.jsx("div",{className:"mt-4 grid gap-2 text-xs text-fg-muted sm:grid-cols-3",children:Ou.map(p=>t.jsxs("div",{className:"card p-3",children:[t.jsx(be,{variant:p==="admin"?"pro":p==="operator"?"info":"neutral",className:"mb-1.5",children:p}),t.jsx("p",{children:Wf[p]})]},p))}),t.jsx(h3,{open:i,onClose:()=>o(!1)}),t.jsx(Ht,{open:!!c,onClose:()=>d(null),title:`Disable ${c==null?void 0:c.name}`,description:`${c==null?void 0:c.email} loses access immediately: active sessions are revoked and password or SSO sign-in is refused. The account and its audit history stay, and you can re-enable it any time.`,confirmText:"Disable user",danger:!0,loading:r.isPending,onConfirm:()=>c&&g(c,!0)})]})}function Iv(){const e="ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz23456789",n=new Uint8Array(16);return crypto.getRandomValues(n),Array.from(n,r=>e[r%e.length]).join("")}function h3({open:e,onClose:n}){const r=O2(),{has:i}=wt(),o=i("sso"),[c,d]=w.useState({name:"",email:"",role:"viewer",password:Iv()}),[h,f]=w.useState(!1),[g,p]=w.useState({}),v=S=>y=>d(b=>({...b,[S]:y.target.value})),j=()=>{const S={name:c.name.trim(),email:c.email.trim(),role:c.role,...h?{}:{password:c.password}},y=bk.safeParse(S);if(!y.success){const b={};for(const k of y.error.issues)b[String(k.path[0])]=k.message;p(b);return}r.mutate(y.data,{onSuccess:b=>{X.success(`${b.name} invited`,h?"They can now sign in with SSO using that email.":"Share the temporary password with them over a secure channel."),n()},onError:b=>X.error(ve(b))})};return t.jsx(bn,{open:e,onClose:n,size:"sm",title:"Invite user",description:h?"The account is created without a password; they sign in through your identity provider.":"There is no email delivery: copy the temporary password and share it yourself.",footer:t.jsxs(t.Fragment,{children:[t.jsx(V,{variant:"ghost",size:"sm",onClick:n,children:"Cancel"}),t.jsx(V,{variant:"primary",size:"sm",onClick:j,loading:r.isPending,children:"Create user"})]}),children:t.jsxs("form",{className:"space-y-3",onSubmit:S=>{S.preventDefault(),j()},children:[t.jsx(Te,{label:"Name",autoFocus:!0,value:c.name,onChange:v("name"),error:g.name}),t.jsx(Te,{label:"Email",type:"email",value:c.email,onChange:v("email"),error:g.email}),t.jsx(dt,{label:"Role",value:c.role,onChange:v("role"),options:Ou.map(S=>({value:S,label:S})),hint:Wf[c.role]}),o&&t.jsxs("div",{className:"flex items-center gap-2.5",children:[t.jsx(el,{checked:h,onChange:f,label:"SSO only (no password)"}),t.jsx("button",{type:"button",className:"text-xs font-medium text-fg",onClick:()=>f(!h),children:"SSO only (no password)"})]}),h?t.jsx("p",{className:"rounded-md border border-border bg-surface-2 px-3 py-2 text-xs text-fg-muted",children:"This account will have no password and can only sign in through an identity provider. Make sure the email matches the one your IdP sends."}):t.jsxs("div",{className:"flex items-end gap-2",children:[t.jsx(Te,{label:"Temporary password",mono:!0,value:c.password,onChange:v("password"),error:g.password,wrapperClassName:"flex-1",autoComplete:"off",spellCheck:!1}),t.jsx(V,{size:"icon",variant:"ghost","aria-label":"Generate password",title:"Generate",onClick:()=>d(S=>({...S,password:Iv()})),children:t.jsx(dm,{})})]})]})})}const f3=50,m3=new Set(Ak);function p3(){const{has:e}=wt();return e("audit")?t.jsx(N0,{role:"admin",children:t.jsx(g3,{})}):t.jsx(Wa,{feature:"audit"})}function x3(){const[e,n]=sl();return[w.useMemo(()=>{const c=e.get("action"),d=e.get("result");return{actorId:e.get("actorId")||void 0,action:c&&gm.includes(c)?c:void 0,connectionId:e.get("connectionId")||void 0,queueName:e.get("queueName")||void 0,jobId:e.get("jobId")||void 0,result:d==="ok"||d==="error"?d:void 0,from:e.get("from")||void 0,to:e.get("to")||void 0}},[e]),c=>{n(d=>{const h=new URLSearchParams(d);for(const[f,g]of Object.entries(c))g?h.set(f,g):h.delete(f);return h},{replace:!0})},()=>n(new URLSearchParams,{replace:!0})]}const zv=(e,n)=>e?new Date(`${e}T${n?"23:59:59.999":"00:00:00.000"}Z`).toISOString():void 0,Ov=e=>e?e.slice(0,10):"";function g3(){var v;const[e,n,r]=x3(),i=xs(),o=F2(),c=L2(e,f3),[d,h]=w.useState(null),f=((v=c.data)==null?void 0:v.pages.flatMap(j=>j.entries))??[],g=Object.values(e).filter(Boolean).length,p=j=>{var S,y;return((y=(S=i.data)==null?void 0:S.find(b=>b.id===j))==null?void 0:y.name)??null};return t.jsxs(bt,{wide:!0,children:[t.jsx(gs,{title:"Audit log",description:"Every mutating action, who did it and whether it worked. Append-only: nothing here can be edited or deleted from the UI.",actions:t.jsxs(t.Fragment,{children:[g>0&&t.jsx(V,{size:"sm",variant:"ghost",leftIcon:t.jsx(vn,{}),onClick:r,children:"Clear filters"}),t.jsxs("a",{href:D2(e),className:"inline-flex h-7 shrink-0 items-center gap-1.5 rounded-md border border-border bg-surface-2 px-2.5 text-xs font-medium text-fg hover:border-border-strong hover:bg-surface-3 [&_svg]:size-3.5",children:[t.jsx(jN,{"aria-hidden":!0}),"Export CSV"]})]})}),t.jsxs("div",{className:"card mb-3 flex flex-wrap items-end gap-2 p-3",children:[t.jsx(dt,{label:"Who",className:"!h-7 w-44 text-xs",value:e.actorId??"",onChange:j=>n({actorId:j.target.value}),options:[{value:"",label:"Anyone"},...(o.data??[]).filter(j=>j.id).map(j=>({value:j.id,label:j.name??j.email??j.id}))]}),t.jsx(dt,{label:"Action",className:"!h-7 w-52 text-xs",value:e.action??"",onChange:j=>n({action:j.target.value}),options:[{value:"",label:"Any action"},...gm.map(j=>({value:j,label:`${vm[j]} (${j})`}))]}),t.jsx(dt,{label:"Connection",className:"!h-7 w-40 text-xs",value:e.connectionId??"",onChange:j=>n({connectionId:j.target.value}),options:[{value:"",label:"Any connection"},...(i.data??[]).map(j=>({value:j.id,label:j.name}))]}),t.jsx(Te,{label:"Queue",className:"!h-7 w-40 text-xs",placeholder:"exact name",value:e.queueName??"",onChange:j=>n({queueName:j.target.value})}),t.jsx(dt,{label:"Result",className:"!h-7 w-32 text-xs",value:e.result??"",onChange:j=>n({result:j.target.value}),options:[{value:"",label:"Any result"},{value:"ok",label:"ok"},{value:"error",label:"refused / failed"}]}),t.jsx(Te,{label:"From",type:"date",className:"!h-7 w-36 text-xs",value:Ov(e.from),onChange:j=>n({from:zv(j.target.value,!1)})}),t.jsx(Te,{label:"To",type:"date",className:"!h-7 w-36 text-xs",value:Ov(e.to),onChange:j=>n({to:zv(j.target.value,!0)})}),e.jobId&&t.jsxs(be,{variant:"outline",mono:!0,className:"mb-1",children:["job ",e.jobId,t.jsx("button",{type:"button","aria-label":"Clear job filter",onClick:()=>n({jobId:void 0}),children:t.jsx(vn,{className:"size-3"})})]})]}),t.jsx("div",{className:"card overflow-hidden",children:t.jsxs(ms,{dense:!0,children:[t.jsx("thead",{children:t.jsxs("tr",{children:[t.jsx(pe,{className:"w-8"}),t.jsx(pe,{className:"w-32",children:"When"}),t.jsx(pe,{className:"w-56",children:"Who"}),t.jsx(pe,{className:"w-56",children:"Action"}),t.jsx(pe,{children:"Target"}),t.jsx(pe,{className:"w-28",children:"Result"}),t.jsx(pe,{className:"w-32",children:"IP"})]})}),t.jsxs("tbody",{children:[c.isLoading&&t.jsx(yt,{colSpan:7,children:t.jsx(Kt,{label:"Loading the audit log…"})}),c.isError&&t.jsx(yt,{colSpan:7,className:"text-danger",children:ve(c.error)}),!c.isLoading&&!c.isError&&f.length===0&&t.jsx(yt,{colSpan:7,children:t.jsx(cn,{compact:!0,icon:t.jsx(Bo,{}),title:g>0?"Nothing matches these filters":"Nothing recorded yet",description:g>0?"Widen the date range or clear a filter.":"The log fills as people act: pausing a queue, retrying a job, inviting a user. Reads are never recorded."})}),f.map(j=>t.jsx(v3,{entry:j,open:d===j.id,onToggle:()=>h(d===j.id?null:j.id),connectionStillExists:!!p(j.connectionId)},j.id))]})]})}),t.jsxs("div",{className:"mt-3 flex items-center justify-between gap-3 text-xs text-fg-muted",children:[t.jsxs("span",{className:"num",children:[f.length," ",f.length===1?"entry":"entries"," loaded"]}),c.hasNextPage&&t.jsx(V,{size:"sm",variant:"secondary",loading:c.isFetchingNextPage,onClick:()=>void c.fetchNextPage(),children:"Load 50 more"})]}),t.jsxs("p",{className:"mt-4 text-xs text-fg-subtle",children:["Retention is ",t.jsx("code",{className:"font-mono",children:"BULLPANE_AUDIT_RETENTION_DAYS"})," (default 365). Rows leave only by age — there is no delete endpoint, on purpose. The job payload is never recorded: ",t.jsx("code",{className:"font-mono",children:"detail"})," ","holds the parameters of an action and, where it helps, the payload size in bytes."]})]})}function v3({entry:e,open:n,onToggle:r,connectionStillExists:i}){var h;const o=m3.has(e.action),c=e.result==="error",d=!!e.detail||!!e.userAgent||!!e.errorMessage;return t.jsxs(t.Fragment,{children:[t.jsxs("tr",{className:F(c&&"bg-danger/5"),children:[t.jsx(xe,{children:d?t.jsx("button",{type:"button","aria-label":n?"Hide detail":"Show detail","aria-expanded":n,onClick:r,className:"rounded p-0.5 text-fg-subtle hover:text-fg",children:n?t.jsx(ps,{className:"size-3.5"}):t.jsx(Dn,{className:"size-3.5"})}):null}),t.jsx(xe,{muted:!0,children:t.jsx(Yt,{value:e.createdAt})}),t.jsx(xe,{children:e.actorName||e.actorEmail?t.jsxs("div",{className:"flex min-w-0 items-center gap-1.5",children:[t.jsx("span",{className:"truncate font-medium",children:e.actorName??"—"}),e.actorRole&&t.jsx(be,{size:"xs",variant:e.actorRole==="admin"?"pro":e.actorRole==="operator"?"info":"neutral",children:e.actorRole}),e.actorEmail&&t.jsx("span",{className:"truncate text-[11px] text-fg-subtle",children:e.actorEmail})]}):t.jsx(Pe,{content:"No session — an anonymous request, e.g. a failed login on an unknown email",children:t.jsx("span",{className:"cursor-help text-fg-subtle",children:"anonymous"})})}),t.jsxs(xe,{children:[t.jsxs("div",{className:"flex items-center gap-1.5",children:[o&&t.jsx(hm,{className:"size-3.5 shrink-0 text-warning","aria-label":"High-risk action"}),t.jsx("span",{className:F(o&&"font-medium"),children:vm[e.action]}),t.jsx(Pe,{content:e.action,children:t.jsx("code",{className:"cursor-help font-mono text-[10px] text-fg-subtle",children:e.action})})]}),typeof((h=e.detail)==null?void 0:h.reason)=="string"&&e.detail.reason&&t.jsxs("p",{className:"mt-0.5 max-w-md truncate text-[11px] text-fg-muted italic",title:e.detail.reason,children:["“",e.detail.reason,"”"]})]}),t.jsx(xe,{children:t.jsx(y3,{entry:e,connectionStillExists:i})}),t.jsx(xe,{children:c?t.jsx(Pe,{content:e.errorMessage??"The action was refused or failed",children:t.jsx(be,{variant:"danger",size:"xs",className:"cursor-help",children:"refused"})}):t.jsx(be,{variant:"success",size:"xs",children:"ok"})}),t.jsx(xe,{muted:!0,mono:!0,children:e.ip??"–"})]}),n&&t.jsx("tr",{children:t.jsx("td",{colSpan:7,className:"bg-surface-2 !px-4 !py-3",children:t.jsxs("dl",{className:"grid gap-3 text-xs sm:grid-cols-[10rem_1fr]",children:[t.jsx("dt",{className:"text-fg-subtle",children:"Exact time"}),t.jsx("dd",{className:"num",children:gn(e.createdAt)}),e.errorMessage&&t.jsxs(t.Fragment,{children:[t.jsx("dt",{className:"text-fg-subtle",children:"Why it failed"}),t.jsx("dd",{className:"text-danger",children:e.errorMessage})]}),e.userAgent&&t.jsxs(t.Fragment,{children:[t.jsx("dt",{className:"text-fg-subtle",children:"User agent"}),t.jsx("dd",{className:"font-mono text-[11px] break-all text-fg-muted",children:e.userAgent})]}),t.jsxs("dt",{className:"text-fg-subtle",children:["Detail",t.jsx("span",{className:"mt-0.5 block text-[10px] text-fg-subtle",children:"parameters only — never the job payload"})]}),t.jsx("dd",{children:e.detail?t.jsx(xj,{value:e.detail,defaultExpandDepth:3}):t.jsx("span",{className:"text-fg-subtle",children:"no parameters recorded"})})]})})})]})}function y3({entry:e,connectionStillExists:n}){if(!e.connectionId&&!e.queueName)return t.jsx("span",{className:"text-fg-subtle",children:"–"});const r=e.connectionName??e.connectionId;return t.jsxs("div",{className:"flex min-w-0 flex-wrap items-center gap-1 text-xs",children:[r&&t.jsx(t.Fragment,{children:n&&e.connectionId?t.jsx(Ee,{to:ue.connection(e.connectionId),className:"text-accent hover:underline",children:r}):t.jsx(Pe,{content:"This connection no longer exists — the name is the one it had at the time",children:t.jsx("span",{className:"cursor-help text-fg-muted line-through",children:r})})}),e.queueName&&t.jsxs(t.Fragment,{children:[t.jsx("span",{className:"text-fg-subtle",children:"/"}),n&&e.connectionId?t.jsx(Ee,{to:ue.queue(e.connectionId,e.queueName),className:"font-mono text-accent hover:underline",children:e.queueName}):t.jsx("span",{className:"font-mono text-fg-muted line-through",children:e.queueName})]}),e.jobId&&t.jsxs(t.Fragment,{children:[t.jsx("span",{className:"text-fg-subtle",children:"/"}),n&&e.connectionId&&e.queueName?t.jsxs(Ee,{to:ue.job(e.connectionId,e.queueName,e.jobId),className:"font-mono text-accent hover:underline",title:"The job may have been removed since",children:["#",e.jobId]}):t.jsxs("span",{className:"font-mono text-fg-muted",children:["#",e.jobId]})]})]})}function j3(){const{has:e}=wt();return e("alerts")?t.jsx(b3,{}):t.jsx(w3,{})}function b3(){const r=(bm().data??[]).filter(o=>o.enabled),i=o=>r.filter(c=>c.scope.type===o).length;return t.jsxs("div",{className:"max-w-xl space-y-4",children:[t.jsxs("p",{className:"text-xs text-fg-muted",children:[t.jsx("strong",{className:"font-medium text-fg",children:"Needs attention"})," is driven by your alert rules. Every queue that breaks an enabled rule gets a card at the top of the Overview, with the value, the window and the threshold. Paused queues and queues with a backlog but no worker are always flagged."]}),t.jsxs("ul",{className:"space-y-1 text-xs text-fg-muted",children:[t.jsxs("li",{children:["Scope each rule to ",t.jsx("span",{className:"text-fg",children:"every queue"}),", a ",t.jsx("span",{className:"text-fg",children:"connection"}),", a"," ",t.jsx("span",{className:"text-fg",children:"folder"})," or ",t.jsx("span",{className:"text-fg",children:"one queue"}),". The most specific rule of each kind wins, so a queue rule overrides the global one for that queue."]}),t.jsx("li",{children:"Failure count and failure rate come from BullMQ metrics over the window, so removeOnComplete cannot skew them."}),t.jsx("li",{children:"Processing time is the p50 or p95 of the jobs completed in the window."}),t.jsx("li",{children:"A rule without channels is dashboard only; add Slack or a webhook to be notified as well."})]}),t.jsx("p",{className:"text-xs text-fg-subtle",children:r.length===0?"No enabled rule yet.":`${r.length} enabled: ${i("global")} on every queue, ${i("connection")} per connection, ${i("folder")} per folder, ${i("queue")} per queue.`}),t.jsx(Ee,{to:ue.alerts,className:"inline-flex text-xs text-accent hover:underline",children:"Manage rules →"})]})}function w3(){const{isAdmin:e}=mt(),n=z0(),r=P2(),[i,o]=w.useState(""),[c,d]=w.useState(""),h=n.data;if(w.useEffect(()=>{h&&(o(String(h.waitingAbove)),d(String(h.failedAbove)))},[h]),n.isLoading)return t.jsx(Kt,{});const f=Rk.safeParse({waitingAbove:Number(i===""?0:i),failedAbove:Number(c===""?0:c)}),g=!!h&&f.success&&(f.data.waitingAbove!==h.waitingAbove||f.data.failedAbove!==h.failedAbove),p=()=>{f.success&&r.mutate(f.data,{onSuccess:()=>X.success("Attention thresholds saved"),onError:v=>X.error(ve(v))})};return t.jsxs("div",{className:"max-w-xl space-y-5",children:[t.jsxs("p",{className:"text-xs text-fg-muted",children:["When a queue shows up in ",t.jsx("strong",{className:"font-medium text-fg",children:"Needs attention"})," at the top of the Overview. Failing, paused and stuck-with-no-worker queues are always flagged — these two add the cases only you can define.",t.jsx("span",{className:"text-fg-subtle",children:" Set 0 to turn a rule off."})]}),t.jsxs("p",{className:"rounded-md border border-border bg-surface-2/50 px-3 py-2 text-xs text-fg-muted",children:[t.jsx("span",{className:"font-medium text-fg",children:"Pro:"})," rules per queue, folder, connection or everywhere, on failure rate and processing time over a window, measured from BullMQ metrics — the same rules can notify Slack or a webhook."," ",t.jsx(Ee,{to:ue.alerts,className:"text-accent hover:underline",children:"See Alerts"})]}),t.jsx(Te,{label:"Waiting above",hint:"Flag a queue whose waiting backlog passes this, even when a worker is draining it. Leave at 0 if your queues run deep on purpose.",inputMode:"numeric",value:i,disabled:!e,onChange:v=>o(v.target.value.replace(/[^0-9]/g,""))}),t.jsx(Te,{label:"Failed above",hint:"Flag a queue whose failed list passes this. At 0 any failed job at all is flagged, which is the previous behaviour.",inputMode:"numeric",value:c,disabled:!e,onChange:v=>d(v.target.value.replace(/[^0-9]/g,""))}),e?t.jsxs("div",{className:"flex items-center gap-2",children:[t.jsx(V,{variant:"primary",disabled:!g||r.isPending,onClick:p,children:r.isPending?"Saving…":"Save"}),g&&t.jsx(V,{variant:"ghost",onClick:()=>{o(String((h==null?void 0:h.waitingAbove)??Lu.waitingAbove)),d(String((h==null?void 0:h.failedAbove)??Lu.failedAbove))},children:"Cancel"})]}):t.jsx("p",{className:"text-xs text-fg-subtle",children:"Only an administrator can change these."})]})}const yu={host:"localhost",port:"6379",username:"",password:"",db:"0",tls:!1};function N3(e){try{const n=new URL(e);if(n.protocol!=="redis:"&&n.protocol!=="rediss:")return{...yu};const r=Lv(n.password);return{host:n.hostname||yu.host,port:n.port||(n.protocol==="rediss:"?"6380":"6379"),username:Lv(n.username),password:r==="****"?"":r,db:n.pathname.replace(/^\//,"")||"0",tls:n.protocol==="rediss:"}}catch{return{...yu}}}function Av(e){const n=e.username||e.password?`${encodeURIComponent(e.username)}:${encodeURIComponent(e.password)}@`:"",r=e.host.includes(":")&&!e.host.startsWith("[")?`[${e.host}]`:e.host,i=e.db.trim()&&e.db.trim()!=="0"?`/${e.db.trim()}`:"";return`${e.tls?"rediss":"redis"}://${n}${r.trim()}:${e.port.trim()||"6379"}${i}`}function k3(e,n){return e.host!==n.host||e.port!==n.port||e.username!==n.username||e.db!==n.db||e.tls!==n.tls}function Lv(e){try{return decodeURIComponent(e)}catch{return e}}function S3(){var v;const{isAdmin:e}=mt(),{demo:n}=wt(),r=xs(),i=k2(),[o,c]=sl(),[d,h]=w.useState(null),[f,g]=w.useState(null);w.useEffect(()=>{if(e){if(o.get("new"))h({connection:null}),c({},{replace:!0});else if(o.get("edit")&&r.data){const j=r.data.find(S=>S.id===o.get("edit"));j&&h({connection:j}),c({},{replace:!0})}}},[o,c,r.data,e]);const p=r.data??[];return t.jsxs("div",{children:[t.jsxs("div",{className:"mb-3 flex items-center justify-between",children:[t.jsxs("p",{className:"text-xs text-fg-muted",children:["Each connection points at one Redis (or cluster) with a BullMQ key prefix, or at the Postgres schema of BullMQ 6's Postgres backend. On Redis, queues are discovered with ",t.jsx("span",{className:"font-mono",children:"SCAN"}),", never ",t.jsx("span",{className:"font-mono",children:"KEYS"}),"."]}),e&&t.jsx(V,{variant:"primary",size:"sm",leftIcon:t.jsx(es,{}),onClick:()=>h({connection:null}),disabled:n,title:n?"Locked in the demo":void 0,children:"Add connection"})]}),n&&t.jsx("p",{className:"mb-3 rounded-md border border-warning/40 bg-warning/10 px-3 py-2 text-xs text-warning",children:"Demo mode: connections are read-only."}),t.jsx("div",{className:"card overflow-hidden",children:t.jsxs(ms,{children:[t.jsx("thead",{children:t.jsxs("tr",{children:[t.jsx(pe,{children:"Name"}),t.jsx(pe,{children:"URL"}),t.jsx(pe,{children:"Prefix / schema"}),t.jsx(pe,{children:"Filter"}),t.jsx(pe,{children:"Status"}),t.jsx(pe,{children:"Added"}),t.jsx(pe,{align:"right",children:t.jsx("span",{className:"sr-only",children:"Actions"})})]})}),t.jsxs("tbody",{children:[r.isLoading&&t.jsx(yt,{colSpan:7,children:t.jsx(Kt,{})}),r.data&&p.length===0&&t.jsx("tr",{children:t.jsx("td",{colSpan:7,children:t.jsx(cn,{compact:!0,icon:t.jsx(Va,{}),title:"No connections",description:e?"Add your first Redis or Postgres connection.":"Ask an admin to add one."})})}),p.map(j=>{var S;return t.jsxs("tr",{children:[t.jsxs(xe,{className:"font-medium",children:[t.jsx(Ee,{to:ue.connection(j.id),className:"hover:underline",children:j.name}),j.kind==="postgres"&&t.jsx(be,{variant:"outline",size:"xs",className:"ml-1.5",children:"postgres"}),j.cluster&&t.jsx(be,{variant:"outline",size:"xs",className:"ml-1.5",children:"cluster"})]}),t.jsx(xe,{mono:!0,muted:!0,className:"max-w-xs truncate",title:j.url,children:j.url}),t.jsx(xe,{mono:!0,children:j.prefix}),t.jsx(xe,{mono:!0,muted:!0,children:j.queueFilter??"–"}),t.jsxs(xe,{children:[t.jsxs("span",{className:"flex items-center gap-2",children:[t.jsx(nd,{status:j.status,withLabel:!0,pulse:!0}),((S=j.status)==null?void 0:S.ok)&&j.status.redisVersion&&t.jsxs("span",{className:"text-[11px] text-fg-subtle",children:["v",j.status.redisVersion]})]}),j.status&&!j.status.ok&&j.status.error&&t.jsx("p",{className:"mt-0.5 max-w-xs truncate text-[11px] text-danger",title:j.status.error,children:j.status.error})]}),t.jsx(xe,{muted:!0,children:t.jsx(Yt,{value:j.createdAt})}),t.jsx(xe,{align:"right",children:e&&t.jsxs("div",{className:"flex items-center justify-end gap-1",children:[t.jsx(V,{size:"icon-xs",variant:"ghost","aria-label":"Edit connection",title:"Edit",onClick:()=>h({connection:j}),disabled:n,children:t.jsx(Uo,{})}),t.jsx(V,{size:"icon-xs",variant:"ghost","aria-label":"Delete connection",title:"Delete",className:"hover:text-danger",onClick:()=>g(j),disabled:n,children:t.jsx(Un,{})})]})})]},j.id)})]})]})}),d&&t.jsx(C3,{open:!0,onClose:()=>h(null),connection:d.connection},((v=d.connection)==null?void 0:v.id)??"new"),t.jsx(Ht,{open:!!f,onClose:()=>g(null),title:`Remove "${f==null?void 0:f.name}"`,description:"Only the dashboard entry is removed. Nothing in Redis or Postgres is touched. Folders and alerts pointing at this connection stop working.",confirmText:"Remove connection",danger:!0,typeToConfirm:f==null?void 0:f.name,loading:i.isPending,onConfirm:()=>f&&i.mutate(f.id,{onSuccess:()=>(g(null),X.success("Connection removed")),onError:j=>X.error(ve(j))})})]})}function C3({open:e,onClose:n,connection:r}){const i=w2(),o=N2(),c=S2(),[d,h]=w.useState({name:(r==null?void 0:r.name)??"",kind:(r==null?void 0:r.kind)??"redis",url:r?"":"redis://localhost:6379",prefix:(r==null?void 0:r.prefix)??"bull",cluster:(r==null?void 0:r.cluster)??!1,queueFilter:(r==null?void 0:r.queueFilter)??""}),[f,g]=w.useState({}),[p,v]=w.useState(null),[j,S]=w.useState("fields"),y=r?N3(r.url):yu,[b,k]=w.useState(y),C=(q,B)=>{h(de=>({...de,[q]:B})),v(null)},z=d.kind==="postgres",O=q=>{h(B=>({...B,kind:q,url:q==="postgres"?B.url.startsWith("redis")?"":B.url:B.url||"redis://localhost:6379",prefix:B.prefix===xu[B.kind]||!B.prefix?xu[q]:B.prefix,cluster:q==="postgres"?!1:B.cluster})),g({}),v(null)},T=(q,B)=>{k(de=>({...de,[q]:B})),v(null)},M=()=>j==="url"||z?d.url.trim():r&&!b.password&&!k3(b,y)?"":Av(b),E=()=>{const q=M(),B={name:d.name.trim(),kind:d.kind,url:q,prefix:d.prefix.trim()||xu[d.kind],cluster:d.cluster,queueFilter:d.queueFilter.trim()||null};r&&!B.url&&(B.url=r.url);const de=kk.safeParse(B);if(!de.success){const ce={};for(const Ne of de.error.issues)ce[String(Ne.path[0])]=Ne.message;return g(ce),null}return g({}),de.data},I=()=>{const q=E();if(!q)return;const B=de=>{X.success(`Connection "${de.name}" saved`),n()};if(r){const de={name:q.name,prefix:q.prefix,cluster:q.cluster,queueFilter:q.queueFilter};M()&&(de.url=q.url),o.mutate({id:r.id,input:de},{onSuccess:B,onError:ce=>X.error(ve(ce))})}else i.mutate(q,{onSuccess:B,onError:de=>X.error(ve(de))})},Q=()=>{const q=M();if(!q){g({url:r?j==="url"||z?"Enter the URL (with password) to test it":"Enter the password to test the stored connection":"URL is required"});return}c.mutate({kind:d.kind,url:q,prefix:d.prefix.trim()||void 0,cluster:d.cluster},{onSuccess:v,onError:B=>v({ok:!1,error:ve(B)})})},H=i.isPending||o.isPending;return t.jsx(bn,{open:e,onClose:n,size:"md",title:r?`Edit ${r.name}`:"Add connection",description:"Credentials are stored server-side and never sent back to the browser.",footer:t.jsxs(t.Fragment,{children:[t.jsx(V,{variant:"ghost",size:"sm",onClick:n,children:"Cancel"}),t.jsx(V,{variant:"secondary",size:"sm",leftIcon:t.jsx(Ky,{}),onClick:Q,loading:c.isPending,children:"Test connection"}),t.jsx(V,{variant:"primary",size:"sm",onClick:I,loading:H,children:r?"Save":"Add connection"})]}),children:t.jsxs("form",{className:"space-y-3",onSubmit:q=>{q.preventDefault(),I()},children:[t.jsx(Te,{label:"Name",autoFocus:!0,value:d.name,onChange:q=>C("name",q.target.value),error:f.name,placeholder:"production"}),t.jsxs("div",{className:"flex items-center justify-between",children:[t.jsx("span",{className:"text-xs font-medium text-fg-muted",children:"Backend"}),r?t.jsx("span",{className:"text-xs text-fg",children:z?"Postgres (BullMQ 6)":"Redis"}):t.jsx("div",{className:"inline-flex rounded-md border border-border p-0.5 text-xs",role:"tablist","aria-label":"Where the queues live",children:["redis","postgres"].map(q=>t.jsx("button",{type:"button",role:"tab","aria-selected":d.kind===q,className:`rounded px-2 py-0.5 ${d.kind===q?"bg-surface-3 text-fg":"text-fg-muted hover:text-fg"}`,onClick:()=>O(q),children:q==="redis"?"Redis":"Postgres (BullMQ 6)"},q))})]}),z?t.jsx(Te,{label:"Postgres URL",mono:!0,value:d.url,onChange:q=>C("url",q.target.value),error:f.url,placeholder:r?`${r.url} (leave empty to keep)`:"postgres://user:password@host:5432/app",hint:"The database your BullMQ workers use. Add ?sslmode=require for TLS. A read-only role is enough to browse; actions need write access.",autoComplete:"off",spellCheck:!1}):t.jsxs(t.Fragment,{children:[t.jsxs("div",{className:"flex items-center justify-between",children:[t.jsx("span",{className:"text-xs font-medium text-fg-muted",children:"Redis"}),t.jsx("div",{className:"inline-flex rounded-md border border-border p-0.5 text-xs",role:"tablist","aria-label":"How to enter the Redis address",children:["fields","url"].map(q=>t.jsx("button",{type:"button",role:"tab","aria-selected":j===q,className:`rounded px-2 py-0.5 ${j===q?"bg-surface-3 text-fg":"text-fg-muted hover:text-fg"}`,onClick:()=>(S(q),v(null)),children:q==="fields"?"Host & password":"Connection URL"},q))})]}),j==="url"?t.jsx(Te,{label:"Redis URL",mono:!0,value:d.url,onChange:q=>C("url",q.target.value),error:f.url,placeholder:r?`${r.url} (leave empty to keep)`:"redis://:password@host:6379/0",hint:"redis:// or rediss:// (TLS). Include the password; it is redacted everywhere in the UI.",autoComplete:"off",spellCheck:!1}):t.jsxs("div",{className:"space-y-3",children:[t.jsxs("div",{className:"grid gap-3 sm:grid-cols-[1fr_120px]",children:[t.jsx(Te,{label:"Host",mono:!0,value:b.host,onChange:q=>T("host",q.target.value),placeholder:"cache.internal",autoComplete:"off",spellCheck:!1}),t.jsx(Te,{label:"Port",mono:!0,inputMode:"numeric",value:b.port,onChange:q=>T("port",q.target.value)})]}),t.jsxs("div",{className:"grid gap-3 sm:grid-cols-2",children:[t.jsx(Te,{label:"Username (optional)",mono:!0,value:b.username,onChange:q=>T("username",q.target.value),placeholder:"default",autoComplete:"off",spellCheck:!1}),t.jsx(Te,{label:"Password",type:"password",mono:!0,value:b.password,onChange:q=>T("password",q.target.value),placeholder:r?"leave empty to keep the stored one":"optional",hint:r?"Stored server-side and never shown again. Changing the host or TLS needs it typed again.":"Stored server-side, redacted everywhere in the UI.",autoComplete:"new-password"})]}),t.jsxs("div",{className:"grid items-end gap-3 sm:grid-cols-[120px_1fr]",children:[t.jsx(Te,{label:"Database",mono:!0,inputMode:"numeric",value:b.db,onChange:q=>T("db",q.target.value)}),t.jsxs("div",{className:"flex items-start gap-2.5 pb-1",children:[t.jsx(el,{checked:b.tls,onChange:q=>T("tls",q),label:"TLS",className:"mt-0.5"}),t.jsxs("button",{type:"button",className:"text-left text-xs",onClick:()=>T("tls",!b.tls),children:[t.jsx("span",{className:"font-medium text-fg",children:"TLS"}),t.jsx("span",{className:"text-fg-muted",children:" (rediss://) — required by ElastiCache with in-transit encryption, Redis Cloud, Upstash and most managed Redis."})]})]})]}),f.url&&t.jsx("p",{className:"text-xs text-danger",children:f.url}),t.jsx("p",{className:"font-mono text-[11px] text-fg-subtle",children:M()?Av({...b,password:b.password?"****":""}):`${(r==null?void 0:r.url)??""} (unchanged)`})]})]}),t.jsxs("div",{className:"grid gap-3 sm:grid-cols-2",children:[z?t.jsx(Te,{label:"Schema",mono:!0,value:d.prefix,onChange:q=>C("prefix",q.target.value),error:f.prefix,hint:"BullMQ default is bullmq"}):t.jsx(Te,{label:"Key prefix",mono:!0,value:d.prefix,onChange:q=>C("prefix",q.target.value),error:f.prefix,hint:"BullMQ default is bull"}),t.jsx(Te,{label:"Queue filter (optional)",mono:!0,value:d.queueFilter,onChange:q=>C("queueFilter",q.target.value),error:f.queueFilter,placeholder:"payments-*",hint:"Glob over queue names; limits discovery."})]}),!z&&t.jsx(Pm,{label:"Redis Cluster",description:"Use cluster-aware client. Each queue lives in one hash slot, so all reads stay single-node.",checked:d.cluster,onChange:q=>C("cluster",q.target.checked)}),p&&t.jsxs("div",{className:`flex items-start gap-2 rounded-md border px-3 py-2 text-xs ${p.ok?"border-success/40 bg-success/10 text-success":"border-danger/40 bg-danger/10 text-danger"}`,role:"status",children:[p.ok?t.jsx(cm,{className:"mt-px size-4 shrink-0"}):t.jsx(Fy,{className:"mt-px size-4 shrink-0"}),t.jsx("div",{children:p.ok?t.jsxs(t.Fragment,{children:["Connected",p.latencyMs!=null&&` in ${p.latencyMs} ms`,p.redisVersion&&` · ${z?"Postgres":"Redis"} ${p.redisVersion}`,p.queuesFound!=null&&` · ${p.queuesFound} queues found`]}):t.jsxs(t.Fragment,{children:["Failed: ",p.error??"unknown error"]})})]})]})})}const Fv={active:{label:"active",variant:"success"},grace:{label:"grace period",variant:"warning"},expired:{label:"expired",variant:"danger"},invalid:{label:"invalid",variant:"danger"}};function _3(e){if(e.source==="offline")return e.status==="expired"?"This offline key has expired. Ask for a renewed key or activate a subscription key.":e.status==="invalid"?"This key does not verify against this build. Paste it again or ask for a new one.":null;switch(e.status){case"grace":return`bullpane.com could not be reached (${e.lastCheckError??"unknown error"}). Pro keeps working until ${gn(e.leaseExpiresAt)}; the server retries once a day, or check now.`;case"expired":return e.lastCheckError?`${e.lastCheckError} Renew the subscription on bullpane.com, then check again.`:"The lease ran out without reaching bullpane.com. Restore the connection and check now.";case"invalid":return e.lastCheckError??"The store rejected this key.";default:return null}}function P3(){const{isAdmin:e,setEdition:n}=mt(),{edition:r,isPro:i,demo:o,pricing:c,checkoutUrl:d,has:h}=wt(),f=Q2(),g=V2(),p=B2(),[v,j]=w.useState(""),[S,y]=w.useState(null),[b,k]=w.useState(!1),C=()=>{const E=v.trim();if(!E){y("Paste the license key");return}y(null),f.mutate(E,{onSuccess:I=>{n(I),j(""),X.success("Pro unlocked",I.license?`Licensed to ${I.license.licensee}`:void 0)},onError:I=>{Ts(I)&&(I.body.error==="invalid_license"||I.body.error==="license_already_activated"||I.body.error==="license_server_unavailable")?y(I.body.message||"This key is not valid"):y(ve(I))}})},z=()=>p.mutate(void 0,{onSuccess:E=>{var Q,H,q,B;n(E);const I=(Q=E.license)==null?void 0:Q.status;I==="active"?X.success("License verified",`Lease renewed until ${gn((H=E.license)==null?void 0:H.leaseExpiresAt)}`):I==="grace"?X.error("Could not reach bullpane.com",((q=E.license)==null?void 0:q.lastCheckError)??void 0):X.error("License not valid",((B=E.license)==null?void 0:B.lastCheckError)??void 0)},onError:E=>X.error(ve(E))}),O=r.license,T=O?_3(O):null,M=(O==null?void 0:O.source)==="online";return t.jsxs("div",{className:"grid gap-4 lg:grid-cols-[1fr_360px]",children:[t.jsxs("div",{className:"space-y-4",children:[t.jsxs("div",{className:"card p-4",children:[t.jsxs("div",{className:"flex items-center gap-3",children:[t.jsx("div",{className:"flex size-10 items-center justify-center rounded-lg bg-surface-2",children:i?t.jsx(Gu,{className:"size-5 text-pro"}):t.jsx(go,{className:"size-5 text-fg-subtle"})}),t.jsxs("div",{className:"min-w-0 flex-1",children:[t.jsxs("div",{className:"flex items-center gap-2",children:[t.jsx("h2",{className:"text-sm font-semibold",children:o?"Demo mode":i?"Pro edition":"Free edition"}),t.jsx(Nm,{})]}),t.jsx("p",{className:"text-xs text-fg-muted",children:o?"Every Pro feature is unlocked for the playground. Settings that could break the demo are read-only.":i?"All features unlocked for this installation.":"Everything bull-board does, plus search. Team features need a Pro key."})]}),M&&e&&!o&&t.jsx(V,{variant:"outline",size:"sm",leftIcon:t.jsx(dm,{}),onClick:z,loading:p.isPending,children:"Check now"})]}),O&&t.jsxs("dl",{className:"mt-4 grid grid-cols-2 gap-3 border-t border-border pt-4 text-xs sm:grid-cols-4",children:[t.jsxs("div",{children:[t.jsx("dt",{className:"text-[10px] tracking-wide text-fg-subtle uppercase",children:"Licensee"}),t.jsx("dd",{className:"truncate text-fg",children:O.licensee})]}),t.jsxs("div",{children:[t.jsx("dt",{className:"text-[10px] tracking-wide text-fg-subtle uppercase",children:"Email"}),t.jsx("dd",{className:"truncate text-fg",children:O.email})]}),t.jsxs("div",{children:[t.jsx("dt",{className:"text-[10px] tracking-wide text-fg-subtle uppercase",children:M?"Plan":"Issued"}),t.jsx("dd",{className:"text-fg",children:M?"Subscription":Fu(O.issuedAt)})]}),t.jsxs("div",{children:[t.jsx("dt",{className:"text-[10px] tracking-wide text-fg-subtle uppercase",children:M?"Paid until":"Expires"}),t.jsxs("dd",{className:"text-fg",children:[O.expiresAt?Fu(O.expiresAt):M?"Renews automatically":"Never"," ",t.jsx(be,{variant:Fv[O.status].variant,size:"xs",className:"ml-1",children:Fv[O.status].label})]})]}),M&&t.jsxs(t.Fragment,{children:[t.jsxs("div",{children:[t.jsx("dt",{className:"text-[10px] tracking-wide text-fg-subtle uppercase",children:"Last verified"}),t.jsx("dd",{className:"text-fg",title:O.lastCheckedAt?gn(O.lastCheckedAt):void 0,children:O.lastCheckedAt?Kr(O.lastCheckedAt):"never"})]}),t.jsxs("div",{children:[t.jsx("dt",{className:"text-[10px] tracking-wide text-fg-subtle uppercase",children:"Works offline until"}),t.jsx("dd",{className:"text-fg",children:gn(O.leaseExpiresAt)})]}),t.jsxs("div",{className:"col-span-2",children:[t.jsx("dt",{className:"text-[10px] tracking-wide text-fg-subtle uppercase",children:"Activation"}),t.jsx("dd",{className:"truncate font-mono text-fg",children:O.activationId})]})]})]}),T&&t.jsx("p",{className:`mt-3 rounded-md border px-3 py-2 text-xs ${(O==null?void 0:O.status)==="grace"?"border-warning/40 bg-warning/10 text-warning":"border-danger/40 bg-danger/10 text-danger"}`,children:T}),o&&t.jsx("p",{className:"mt-3 rounded-md border border-warning/40 bg-warning/10 px-3 py-2 text-xs text-warning",children:"Demo mode notice: license changes are blocked here. Run your own instance to activate a key."})]}),t.jsxs("div",{className:"card p-4",children:[t.jsx("h3",{className:"mb-3 text-xs font-semibold tracking-wider text-fg-subtle uppercase",children:"Features"}),t.jsx("ul",{className:"grid gap-2 sm:grid-cols-2",children:xm.map(E=>t.jsxs("li",{className:"flex items-start gap-2 rounded-md border border-border p-2.5 text-xs",children:[h(E)?t.jsx(Zr,{className:"mt-px size-4 shrink-0 text-success"}):t.jsx(go,{className:"mt-px size-4 shrink-0 text-fg-subtle"}),t.jsxs("div",{children:[t.jsx("p",{className:"font-medium text-fg",children:bo[E].title}),t.jsx("p",{className:"text-fg-muted",children:bo[E].tagline})]})]},E))})]})]}),t.jsxs("div",{className:"space-y-4",children:[e?t.jsxs("div",{className:"card p-4",children:[t.jsxs("h3",{className:"mb-1 flex items-center gap-2 text-sm font-semibold",children:[t.jsx(al,{className:"size-4"})," ",i&&!o?"Replace license key":"Activate a license key"]}),t.jsx("p",{className:"mb-3 text-xs text-fg-muted",children:"Paste the key from your bullpane.com receipt. One key runs one installation: it is activated once against bullpane.com, re-checked daily, and keeps working for 7 days without internet. Nothing about your queues or jobs is sent."}),t.jsx(Yi,{mono:!0,rows:3,value:v,onChange:E=>j(E.target.value),placeholder:"BULLPANE-XXXX-XXXX-XXXX",error:S,spellCheck:!1,disabled:o,"aria-label":"License key"}),t.jsxs("div",{className:"mt-3 flex items-center gap-2",children:[t.jsx(V,{variant:"primary",size:"sm",onClick:C,loading:f.isPending,disabled:o,children:"Activate"}),O&&!o&&t.jsx(V,{variant:"ghost",size:"sm",className:"hover:text-danger",leftIcon:t.jsx(Un,{}),onClick:()=>k(!0),children:"Remove license"})]})]}):t.jsx("div",{className:"card p-4 text-xs text-fg-muted",children:"Only admins can change the license."}),!i&&t.jsxs("div",{className:"card border-pro/30 p-4",children:[t.jsxs("p",{className:"text-sm font-semibold",children:["Unlock Pro · $",c.monthlyUsd,"/month or $",c.yearlyUsd,"/year"]}),t.jsx("p",{className:"mt-1 text-xs text-fg-muted",children:"One installation, unlimited connections, queues and users. Cancel any time; your data stays."}),t.jsxs("a",{href:d||"#",target:"_blank",rel:"noreferrer noopener","aria-disabled":!d,className:"mt-3 inline-flex h-8 items-center gap-2 rounded-md bg-accent px-3 text-xs font-medium text-accent-fg hover:bg-accent-hover aria-disabled:pointer-events-none aria-disabled:opacity-50",children:["Get a key ",t.jsx(Br,{className:"size-3.5"})]})]})]}),t.jsx(Ht,{open:b,onClose:()=>k(!1),title:"Remove license",description:M?"The installation goes back to the free edition, which has NO LOGIN: anyone who can reach this URL will be able to retry, promote and delete jobs. The key is released so it can be activated on another server. Alerts, folders, flow edges and your user accounts are kept in the database but become inaccessible until a key is activated again.":"The installation goes back to the free edition, which has NO LOGIN: anyone who can reach this URL will be able to retry, promote and delete jobs. Alerts, folders, flow edges and your user accounts are kept in the database but become inaccessible until a key is activated again.",confirmText:"Remove license",danger:!0,loading:g.isPending,onConfirm:()=>g.mutate(void 0,{onSuccess:E=>{n(E),k(!1),X.success("License removed")},onError:E=>X.error(ve(E))})})]})}function E3(){const e=l2(),{edition:n,checkoutUrl:r}=wt();return t.jsxs("div",{className:"grid gap-4 lg:grid-cols-2",children:[t.jsxs("div",{className:"card p-4",children:[t.jsxs("div",{className:"flex items-center gap-3",children:[t.jsx(km,{className:"size-9"}),t.jsxs("div",{children:[t.jsx("h2",{className:"text-sm font-semibold",children:"Bullpane"}),t.jsx("p",{className:"text-xs text-fg-muted",children:"Self-hosted dashboard for BullMQ and BullMQ Pro."})]})]}),t.jsxs("dl",{className:"mt-4 grid grid-cols-2 gap-3 border-t border-border pt-4 text-xs",children:[t.jsxs("div",{children:[t.jsx("dt",{className:"text-[10px] tracking-wide text-fg-subtle uppercase",children:"Server version"}),t.jsx("dd",{className:"font-mono text-fg",children:e.data?e.data.version:e.isError?"unknown":t.jsx(Cu,{})})]}),t.jsxs("div",{children:[t.jsx("dt",{className:"text-[10px] tracking-wide text-fg-subtle uppercase",children:"Server uptime"}),t.jsx("dd",{className:"text-fg",children:e.data?No(e.data.uptime):e.isError?"unknown":t.jsx(Cu,{})})]}),t.jsxs("div",{children:[t.jsx("dt",{className:"text-[10px] tracking-wide text-fg-subtle uppercase",children:"Edition"}),t.jsxs("dd",{className:"text-fg",children:[n.tier,n.demo&&" (demo)"]})]}),t.jsxs("div",{children:[t.jsx("dt",{className:"text-[10px] tracking-wide text-fg-subtle uppercase",children:"UI build"}),t.jsx("dd",{className:"font-mono text-fg",children:"production"})]})]})]}),t.jsxs("div",{className:"card p-4",children:[t.jsx("h3",{className:"mb-2 text-xs font-semibold tracking-wider text-fg-subtle uppercase",children:"Links"}),t.jsxs("ul",{className:"space-y-1.5 text-[13px]",children:[t.jsx("li",{children:t.jsxs("a",{href:"https://docs.bullmq.io",target:"_blank",rel:"noreferrer noopener",className:"inline-flex items-center gap-1.5 text-accent hover:underline",children:["BullMQ documentation ",t.jsx(Br,{className:"size-3.5"})]})}),r&&t.jsx("li",{children:t.jsxs("a",{href:r,target:"_blank",rel:"noreferrer noopener",className:"inline-flex items-center gap-1.5 text-accent hover:underline",children:["Buy a Pro license (from $",n.pricing.monthlyUsd,"/mo) ",t.jsx(Br,{className:"size-3.5"})]})}),t.jsx("li",{children:t.jsxs("a",{href:"/api/health",target:"_blank",rel:"noreferrer noopener",className:"inline-flex items-center gap-1.5 text-accent hover:underline",children:["API health ",t.jsx(Br,{className:"size-3.5"})]})})]}),t.jsx("h3",{className:"mt-5 mb-2 text-xs font-semibold tracking-wider text-fg-subtle uppercase",children:"How it reads Redis"}),t.jsxs("ul",{className:"list-disc space-y-1 pl-4 text-xs text-fg-muted",children:[t.jsxs("li",{children:["Discovery via ",t.jsx("span",{className:"font-mono",children:"SCAN"}),", never ",t.jsx("span",{className:"font-mono",children:"KEYS"}),"; cached 30 s."]}),t.jsx("li",{children:"Counts, pages and details are single Lua round trips per queue."}),t.jsx("li",{children:"Payloads are truncated inside Redis for list views."}),t.jsx("li",{children:"Writes go through the official bullmq library."})]})]})]})}const R3={oidc:"OIDC",saml:"SAML 2.0"};function M3(){const{has:e}=wt();return e("sso")?t.jsx(T3,{}):t.jsx(Wa,{feature:"sso"})}function ju({label:e,value:n}){const[r,i]=w.useState(!1);return t.jsxs("div",{className:"flex items-center gap-2",children:[t.jsx("span",{className:"w-24 shrink-0 text-[11px] uppercase tracking-wide text-fg-subtle",children:e}),t.jsx("code",{className:"min-w-0 flex-1 truncate rounded bg-surface-2 px-2 py-1 text-[11px] text-fg-muted",children:n}),t.jsx(V,{size:"icon-xs",variant:"ghost","aria-label":`Copy ${e}`,onClick:()=>{var o;(o=navigator.clipboard)==null||o.writeText(n).then(()=>{i(!0),setTimeout(()=>i(!1),1500)},()=>X.error("Could not copy to the clipboard"))},children:r?t.jsx(Zr,{className:"size-3 text-success"}):t.jsx(Uy,{className:"size-3"})})]})}function T3(){var k;const e=K2(),n=F0(),r=D0(),i=Z2(),o=G2(),c=J2(),[d,h]=w.useState(!1),[f,g]=w.useState(null),[p,v]=w.useState({}),j=e.data??[],S=j.filter(C=>C.enabled).length,y=((k=n.data)==null?void 0:k.requireSso)??!1,b=async C=>{try{const z=await c.mutateAsync(C.id);v(O=>({...O,[C.id]:z}))}catch(z){v(O=>({...O,[C.id]:{ok:!1,message:ve(z)}}))}};return t.jsxs("div",{className:"space-y-5",children:[t.jsxs("div",{className:"flex items-start justify-between gap-4",children:[t.jsxs("div",{children:[t.jsx("h2",{className:"text-sm font-semibold text-fg",children:"Single sign-on"}),t.jsxs("p",{className:"mt-1 max-w-2xl text-xs text-fg-muted",children:["Let your team sign in with your identity provider. By default accounts are not created automatically: add the person under ",t.jsx("span",{className:"text-fg",children:"Users & roles"})," first, then they can sign in with SSO using that same email. Or turn on ",t.jsx("span",{className:"text-fg",children:"auto-provisioning"})," below for your company's email domains."]})]}),t.jsx(V,{variant:"primary",leftIcon:t.jsx(es,{className:"size-4"}),onClick:()=>h(!0),children:"Add provider"})]}),e.isLoading?t.jsx("div",{className:"flex justify-center py-8",children:t.jsx(Kt,{})}):j.length===0?t.jsxs("div",{className:"card p-6 text-center",children:[t.jsx(Gu,{className:"mx-auto size-6 text-fg-subtle"}),t.jsx("p",{className:"mt-2 text-sm text-fg",children:"No identity provider yet"}),t.jsx("p",{className:"mx-auto mt-1 max-w-md text-xs text-fg-muted",children:"Add an OIDC provider (Google Workspace, Microsoft Entra ID, Okta, Keycloak, Authentik) or a SAML 2.0 provider."})]}):t.jsx("div",{className:"space-y-3",children:j.map(C=>{const z=p[C.id];return t.jsxs("div",{className:"card p-4",children:[t.jsxs("div",{className:"flex items-start justify-between gap-3",children:[t.jsxs("div",{className:"min-w-0",children:[t.jsxs("div",{className:"flex items-center gap-2",children:[t.jsx("span",{className:"truncate text-sm font-medium text-fg",children:C.name}),t.jsx(be,{variant:"neutral",children:R3[C.kind]}),!C.enabled&&t.jsx(be,{variant:"warning",children:"disabled"}),C.kind==="oidc"&&!C.hasSecret&&t.jsx(be,{variant:"danger",children:"no client secret"})]}),t.jsx("p",{className:"mt-1 truncate text-xs text-fg-muted",children:C.kind==="oidc"?String(C.config.issuer??""):String(C.config.entryPoint??"")})]}),t.jsxs("div",{className:"flex shrink-0 items-center gap-2",children:[t.jsx(el,{checked:C.enabled,label:"Enabled",onChange:O=>{i.mutate({id:C.id,input:{enabled:O}},{onError:T=>X.error(ve(T))})}}),t.jsx(V,{size:"sm",variant:"secondary",leftIcon:t.jsx(Ky,{className:"size-3.5"}),loading:c.isPending&&c.variables===C.id,onClick:()=>void b(C),children:"Test"}),t.jsx(V,{size:"icon-sm",variant:"ghost","aria-label":"Delete provider",onClick:()=>g(C),children:t.jsx(Un,{className:"size-3.5"})})]})]}),t.jsx("div",{className:"mt-3 space-y-1.5 border-t border-border pt-3",children:C.kind==="oidc"?t.jsx(ju,{label:"Redirect URI",value:C.callbackUrl}):t.jsxs(t.Fragment,{children:[t.jsx(ju,{label:"ACS URL",value:C.callbackUrl}),C.entityId&&t.jsx(ju,{label:"Entity ID",value:C.entityId})]})}),z&&t.jsxs("div",{className:`mt-3 rounded-md border px-3 py-2 text-xs ${z.ok?"border-success/40 bg-success/10 text-success":"border-danger/40 bg-danger/10 text-danger"}`,children:[t.jsxs("p",{className:"flex items-center gap-1.5 font-medium",children:[z.ok?t.jsx(Zr,{className:"size-3.5"}):t.jsx(vn,{className:"size-3.5"}),z.message]}),z.details&&t.jsx("dl",{className:"mt-2 space-y-0.5 text-fg-muted",children:Object.entries(z.details).map(([O,T])=>t.jsxs("div",{className:"flex gap-2",children:[t.jsx("dt",{className:"w-44 shrink-0 font-mono text-[10px] uppercase",children:O}),t.jsx("dd",{className:"min-w-0 truncate font-mono text-[10px]",children:T})]},O))})]})]},C.id)})}),t.jsxs("div",{className:"card p-4",children:[t.jsxs("div",{className:"flex items-start justify-between gap-4",children:[t.jsxs("div",{children:[t.jsx("p",{className:"text-sm font-medium text-fg",children:"Require SSO"}),t.jsxs("p",{className:"mt-1 max-w-2xl text-xs text-fg-muted",children:["Hide the password form and send everyone through your identity provider."," ",t.jsx("span",{className:"text-fg",children:"Admin accounts keep password sign-in"})," so a misconfigured provider cannot lock you out of your own installation. Set ",t.jsx("code",{className:"text-[11px]",children:"BULLPANE_ALLOW_PASSWORD_LOGIN=true"})," to allow it for everyone."]})]}),t.jsx(el,{checked:y,disabled:n.isLoading||r.isPending,onChange:C=>{r.mutate({requireSso:C},{onSuccess:()=>X.success(C?"SSO is now required":"Password sign-in is available again"),onError:z=>X.error(ve(z))})}})]}),y&&S===0&&t.jsxs("p",{className:"mt-3 flex items-center gap-1.5 rounded-md border border-warning/40 bg-warning/10 px-3 py-2 text-xs text-warning",children:[t.jsx(ts,{className:"size-3.5 shrink-0"}),"SSO is required but no provider is enabled. Only admins can sign in right now."]})]}),t.jsx(q3,{}),d&&t.jsx($3,{onClose:()=>h(!1)}),t.jsx(Ht,{open:f!==null,title:"Delete this provider?",confirmText:"Delete",danger:!0,description:f?`Anyone who signs in through "${f.name}" will have to use another method. The Bullpane accounts themselves are not touched.`:"",loading:o.isPending,onClose:()=>g(null),onConfirm:()=>{f&&o.mutate(f.id,{onSuccess:()=>{X.success(`Deleted ${f.name}`),g(null)},onError:C=>{X.error(ve(C)),g(null)}})}})]})}function q3(){var p,v;const e=F0(),n=D0(),r=((p=e.data)==null?void 0:p.autoProvisionDomains)??[],i=((v=e.data)==null?void 0:v.autoProvision)??!1,[o,c]=w.useState(null),[d,h]=w.useState(null),f=o??r.join(", "),g=()=>{h(null);const j=f.split(/[\s,]+/).map(y=>y.trim()).filter(y=>y!==""),S=[];for(const y of j){const b=h0.safeParse(y);if(!b.success){h(`"${y}" is not a domain. Use something like example.com.`);return}S.push(b.data)}n.mutate({autoProvisionDomains:S},{onSuccess:()=>{c(null),X.success("Domains saved")},onError:y=>h(ve(y))})};return t.jsxs("div",{className:"card p-4",children:[t.jsxs("div",{className:"flex items-start justify-between gap-4",children:[t.jsxs("div",{children:[t.jsx("p",{className:"text-sm font-medium text-fg",children:"Let anyone from your domains sign in"}),t.jsxs("p",{className:"mt-1 max-w-2xl text-xs text-fg-muted",children:["When someone your identity provider authenticates has no Bullpane account yet and their email ends in one of the domains below, create one for them as a ",t.jsx("span",{className:"text-fg",children:"viewer"})," instead of refusing. They can look at every queue but change nothing; promote them under Users & roles if they need more. Disabled accounts stay disabled."]})]}),t.jsx(el,{checked:i,label:"Auto-provision SSO accounts",disabled:e.isLoading||n.isPending,onChange:j=>{if(j&&r.length===0){h("Save at least one domain first.");return}n.mutate({autoProvision:j},{onSuccess:()=>X.success(j?"New SSO users from your domains now get a viewer account":"SSO accounts must be invited again"),onError:S=>X.error(ve(S))})}})]}),t.jsxs("div",{className:"mt-3 flex items-start gap-2",children:[t.jsx(Te,{label:"Allowed email domains",hint:"Comma separated. Exact match: example.com does not include sub.example.com.",placeholder:"example.com",mono:!0,wrapperClassName:"flex-1",value:f,onChange:j=>c(j.target.value),error:d??void 0}),t.jsx(V,{className:"mt-5",variant:"secondary",disabled:o===null,loading:n.isPending,onClick:g,children:"Save"})]})]})}function $3({onClose:e}){const n=W2(),[r,i]=w.useState("oidc"),[o,c]=w.useState(""),[d,h]=w.useState(""),[f,g]=w.useState(""),[p,v]=w.useState(""),[j,S]=w.useState(""),[y,b]=w.useState(""),[k,C]=w.useState(""),[z,O]=w.useState(""),[T,M]=w.useState(""),[E,I]=w.useState(null),Q=()=>{var B;I(null);const H=r==="oidc"?{kind:"oidc",name:o.trim(),config:{issuer:d.trim(),clientId:f.trim(),clientSecret:p,...j.trim()?{emailClaim:j.trim()}:{}}}:{kind:"saml",name:o.trim(),config:{entryPoint:y.trim(),issuer:k.trim(),idpCert:z.trim(),...T.trim()?{emailAttribute:T.trim()}:{}}},q=wk.safeParse(H);if(!q.success){I(((B=q.error.issues[0])==null?void 0:B.message)??"Check the fields above");return}n.mutate(q.data,{onSuccess:de=>{X.success(`Added ${de.name}. Enter the redirect URI at your IdP, then use Test.`),e()},onError:de=>I(ve(de))})};return t.jsx(bn,{open:!0,onClose:e,title:"Add an identity provider",description:"Unless auto-provisioning is on, invite people under Users & roles first.",size:"md",footer:t.jsxs(t.Fragment,{children:[t.jsx(V,{variant:"ghost",onClick:e,children:"Cancel"}),t.jsx(V,{variant:"primary",loading:n.isPending,onClick:Q,children:"Add provider"})]}),children:t.jsxs("div",{className:"space-y-3",children:[t.jsxs(dt,{label:"Protocol",value:r,onChange:H=>i(H.target.value),children:[t.jsx("option",{value:"oidc",children:"OIDC / OpenID Connect"}),t.jsx("option",{value:"saml",children:"SAML 2.0"})]}),t.jsx(Te,{label:"Display name",placeholder:r==="oidc"?"Google Workspace":"Corporate SSO",hint:"Shown on the sign-in button.",value:o,onChange:H=>c(H.target.value),required:!0}),r==="oidc"?t.jsxs(t.Fragment,{children:[t.jsx(Te,{label:"Issuer URL",placeholder:"https://accounts.google.com",hint:"Endpoints are discovered from /.well-known/openid-configuration, so this is the only URL you need.",value:d,onChange:H=>h(H.target.value),required:!0}),t.jsx(Te,{label:"Client ID",value:f,onChange:H=>g(H.target.value),required:!0}),t.jsx(Te,{label:"Client secret",type:"password",hint:"Stored encrypted and never shown again.",value:p,onChange:H=>v(H.target.value),required:!0}),t.jsx(Te,{label:"Email claim (optional)",placeholder:"email",hint:"Override only if your provider puts the email somewhere else, e.g. upn.",value:j,onChange:H=>S(H.target.value)})]}):t.jsxs(t.Fragment,{children:[t.jsx(Te,{label:"Sign-in URL (SSO endpoint)",placeholder:"https://idp.example.com/sso/saml",value:y,onChange:H=>b(H.target.value),required:!0}),t.jsx(Te,{label:"IdP entity ID",placeholder:"https://idp.example.com/metadata",value:k,onChange:H=>C(H.target.value),required:!0}),t.jsx(Yi,{label:"IdP signing certificate",rows:5,placeholder:"-----BEGIN CERTIFICATE-----",hint:"PEM or base64. Assertions must be signed; there is no way to disable that.",value:z,onChange:H=>O(H.target.value),required:!0}),t.jsx(Te,{label:"Email attribute (optional)",placeholder:"http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress",value:T,onChange:H=>M(H.target.value)})]}),E&&t.jsx("p",{role:"alert",className:"rounded-md border border-danger/40 bg-danger/10 px-3 py-2 text-xs text-danger",children:E})]})})}const Dv=[{value:"off",label:"Off",hint:"No MCP client can connect or call anything."},{value:"read",label:"Read only",hint:"Clients can list queues, read jobs, logs and schedulers. Nothing changes."},{value:"write",label:"Read & write",hint:"Operators and admins may also let a client retry, promote, remove and add jobs and pause queues. Viewers still only read."}];function I3(){const{has:e}=wt();return e("mcp")?t.jsx(z3,{}):t.jsx(Wa,{feature:"mcp"})}function z3(){var S;const{isAdmin:e}=mt(),n=X2(),r=Y2(),[i,o]=w.useState(!1),c=eS(e&&i),d=tS(),[h,f]=w.useState(null);if(n.isLoading||!n.data)return t.jsx("div",{className:"flex justify-center py-8",children:t.jsx(Kt,{})});const{maxAccess:g,endpoint:p,reachableFromCloud:v}=n.data,j=c.data??[];return t.jsxs("div",{className:"space-y-5",children:[t.jsxs("div",{children:[t.jsx("h2",{className:"text-sm font-semibold text-fg",children:"MCP"}),t.jsx("p",{className:"mt-1 max-w-2xl text-xs text-fg-muted",children:"Connect your AI to this Bullpane: Claude, or any MCP client that supports OAuth. Each person signs in with their own Bullpane login (or SSO) and picks read or read & write. A client acts as that person, with their role: what they cannot do in the dashboard, the client cannot do either. Every change is in the audit log, and draining, cleaning or obliterating a queue always comes back here for a human to confirm."})]}),t.jsxs("div",{className:"card space-y-3 p-4",children:[t.jsx("h3",{className:"text-xs font-semibold uppercase tracking-wide text-fg-subtle",children:"Access for MCP clients"}),t.jsx(dt,{label:"Most a client can do on this install",value:g,disabled:!e||r.isPending,onChange:y=>r.mutate({maxAccess:y.target.value},{onSuccess:()=>X.success("MCP access updated. It applies to connected clients on their next call."),onError:b=>X.error(ve(b))}),options:Dv.map(y=>({value:y.value,label:y.label})),hint:e?(S=Dv.find(y=>y.value===g))==null?void 0:S.hint:"Only an admin can change this.",wrapperClassName:"max-w-md"})]}),t.jsxs("div",{className:"card space-y-3 p-4",children:[t.jsx("h3",{className:"text-xs font-semibold uppercase tracking-wide text-fg-subtle",children:"Connect a client"}),t.jsx(ju,{label:"Server URL",value:p}),!v&&t.jsxs("div",{className:"flex gap-2 rounded-md border border-warning/40 bg-warning/10 px-3 py-2 text-xs text-fg",children:[t.jsx(ts,{className:"mt-0.5 size-3.5 shrink-0 text-warning"}),t.jsxs("span",{children:["Cloud-hosted clients such as claude.ai and Claude Desktop connect from their provider's servers, so they need this URL to be public HTTPS. It looks private (check ",t.jsx("span",{className:"font-mono",children:"PUBLIC_URL"}),"). Clients that run on your machine, such as Claude Code, work on a private network."]})]}),t.jsxs("dl",{className:"space-y-2 text-xs text-fg-muted",children:[t.jsxs("div",{children:[t.jsx("dt",{className:"font-medium text-fg",children:"claude.ai and Claude Desktop"}),t.jsx("dd",{children:"Settings → Connectors → Add custom connector, paste the server URL, then Connect and sign in."})]}),t.jsxs("div",{children:[t.jsx("dt",{className:"font-medium text-fg",children:"Claude Code"}),t.jsxs("dd",{children:[t.jsxs("code",{className:"rounded bg-surface-2 px-1.5 py-0.5 font-mono text-[11px]",children:["claude mcp add --transport http bullpane ",p]}),", then run ",t.jsx("code",{className:"font-mono",children:"/mcp"})," to sign in."]})]}),t.jsxs("div",{children:[t.jsx("dt",{className:"font-medium text-fg",children:"Any other MCP client"}),t.jsx("dd",{children:"Add the server URL as a remote (HTTP) MCP server. The client registers itself and opens this Bullpane to sign in."})]})]})]}),t.jsxs("div",{className:"space-y-2",children:[t.jsxs("div",{className:"flex items-center justify-between gap-3",children:[t.jsx("h3",{className:"text-xs font-semibold uppercase tracking-wide text-fg-subtle",children:i?"All connected clients":"Your connected clients"}),e&&t.jsx(V,{size:"sm",variant:"ghost",onClick:()=>o(y=>!y),children:i?"Show only mine":"Show everyone's"})]}),c.isLoading?t.jsx("div",{className:"flex justify-center py-6",children:t.jsx(Kt,{})}):j.length===0?t.jsxs("div",{className:"card p-6 text-center",children:[t.jsx(Ay,{className:"mx-auto size-6 text-fg-subtle"}),t.jsx("p",{className:"mt-2 text-sm text-fg",children:"No client connected"}),t.jsx("p",{className:"mx-auto mt-1 max-w-md text-xs text-fg-muted",children:"Add the server URL to Claude and sign in; the connection shows up here."})]}):t.jsx("div",{className:"card divide-y divide-border",children:j.map(y=>t.jsxs("div",{className:"flex items-center justify-between gap-3 px-4 py-3",children:[t.jsxs("div",{className:"min-w-0",children:[t.jsxs("div",{className:"flex items-center gap-2",children:[t.jsx("span",{className:"truncate text-sm font-medium text-fg",children:y.clientName}),t.jsx(be,{variant:y.access==="write"?"warning":"neutral",children:y.access==="write"?"read & write":"read"})]}),t.jsxs("p",{className:"mt-0.5 truncate text-xs text-fg-muted",children:[i&&t.jsxs(t.Fragment,{children:[y.userEmail," · "]}),y.redirectHost," · connected ",Kr(y.createdAt)," · ",y.lastUsedAt?`last used ${Kr(y.lastUsedAt)}`:"not used yet"]})]}),t.jsx(V,{size:"sm",variant:"ghost",leftIcon:t.jsx(fm,{className:"size-3.5"}),onClick:()=>f(y),children:"Disconnect"})]},y.id))})]}),t.jsx(Ht,{open:h!==null,onClose:()=>f(null),title:"Disconnect client",description:h?`${h.clientName} (${h.userEmail}) loses access on its next call. Connecting again needs a new sign-in.`:void 0,confirmText:"Disconnect",danger:!0,loading:d.isPending,onConfirm:()=>h&&d.mutate(h.id,{onSuccess:()=>{X.success(`${h.clientName} disconnected`),f(null)},onError:y=>X.error(ve(y))})})]})}const O3=["connections","attention","sso","mcp","license","about"];function A3(){const{tab:e}=Fn(),n=un();if(!e||!O3.includes(e))return t.jsx(Vr,{to:"/settings/connections",replace:!0});const r=e;return t.jsxs(bt,{children:[t.jsx(gs,{title:"Settings"}),t.jsx(Um,{"aria-label":"Settings sections",className:"mb-5",value:r,onChange:i=>n(`/settings/${i}`),items:[{value:"connections",label:"Connections",icon:t.jsx(Va,{className:"size-3.5"})},{value:"attention",label:"Attention",icon:t.jsx(ts,{className:"size-3.5"})},{value:"sso",label:"SSO",icon:t.jsx(Gu,{className:"size-3.5"})},{value:"mcp",label:"MCP",icon:t.jsx(Ay,{className:"size-3.5"})},{value:"license",label:"License",icon:t.jsx(al,{className:"size-3.5"})},{value:"about",label:"About",icon:t.jsx(Ha,{className:"size-3.5"})}]}),r==="connections"&&t.jsx(S3,{}),r==="attention"&&t.jsx(j3,{}),r==="sso"&&t.jsx(M3,{}),r==="mcp"&&t.jsx(I3,{}),r==="license"&&t.jsx(P3,{}),r==="about"&&t.jsx(E3,{})]})}const L3=[{label:"Any time",ms:0},{label:"Next hour",ms:36e5},{label:"Next 24 hours",ms:864e5},{label:"Next 7 days",ms:6048e5}];function F3(){var r;const e=xs();if(e.isLoading)return t.jsx(bt,{children:t.jsx(Kt,{label:"Loading…"})});const n=(r=e.data)==null?void 0:r[0];return n?t.jsx(Vr,{to:ue.schedulers(n.id),replace:!0}):t.jsx(bt,{children:t.jsx(cn,{icon:t.jsx(Lo,{}),title:"No connections",description:"Add a Redis connection first; schedulers are listed per connection."})})}function D3(){var p;const{connectionId:e}=Fn(),n=xs(),r=un(),[i,o]=w.useState(""),[c,d]=w.useState(0),h=j2(e,{...i.trim()?{q:i.trim()}:{},...c>0?{withinMs:c}:{}}),f=((p=h.data)==null?void 0:p.schedulers)??[],g=h.data;return t.jsxs(bt,{children:[t.jsx(gs,{title:"Schedulers",description:g?`${K(g.total)} across ${K(g.queuesWithSchedulers)} of ${K(g.queuesScanned)} queues`:void 0,actions:n.data&&n.data.length>1?t.jsx(dt,{"aria-label":"Connection",value:e??"",onChange:v=>r(ue.schedulers(v.target.value)),children:n.data.map(v=>t.jsx("option",{value:v.id,children:v.name},v.id))}):void 0}),t.jsxs("div",{className:"mb-3 flex flex-wrap items-center gap-2",children:[t.jsx(Te,{value:i,onChange:v=>o(v.target.value),placeholder:"Filter by scheduler id, job name or queue…","aria-label":"Filter schedulers",leftIcon:t.jsx(Yn,{className:"size-3.5"}),className:"w-full sm:w-80"}),t.jsx(dt,{"aria-label":"Next run within",value:String(c),onChange:v=>d(Number(v.target.value)),children:L3.map(v=>t.jsx("option",{value:v.ms,children:v.label},v.ms))}),h.isFetching&&t.jsx(Kt,{className:"size-3.5"})]}),g&&g.failed.length>0&&t.jsxs("div",{className:"mb-3 flex items-start gap-2 rounded-md border border-warning/40 bg-warning/10 px-3 py-2 text-xs text-fg-muted",children:[t.jsx(ts,{className:"mt-0.5 size-3.5 shrink-0 text-warning","aria-hidden":!0}),t.jsxs("span",{children:["Could not read schedulers from ",g.failed.length," queue",g.failed.length===1?"":"s",":"," ",t.jsx("span",{className:"font-mono",children:g.failed.map(v=>v.queueName).join(", ")}),". The rest of the list is complete."]})]}),t.jsx("div",{className:"card overflow-hidden",children:t.jsxs(ms,{children:[t.jsx("thead",{children:t.jsxs("tr",{children:[t.jsx(pe,{children:"Queue"}),t.jsx(pe,{children:"Scheduler"}),t.jsx(pe,{children:"Job name"}),t.jsx(pe,{children:"Repeats"}),t.jsx(pe,{align:"right",children:"Next run"})]})}),t.jsxs("tbody",{children:[h.isLoading&&t.jsx(yt,{colSpan:5,children:t.jsx(Kt,{label:"Reading schedulers…"})}),h.isError&&!g&&t.jsx(yt,{colSpan:5,className:"text-danger",children:ve(h.error)}),g&&f.length===0&&t.jsx(yt,{colSpan:5,children:t.jsx(Q3,{filtered:!!i.trim()||c>0,total:g.total})}),f.map(v=>t.jsx(U3,{s:v,connectionId:e},`${v.queueName}:${v.key}`))]})]})}),g&&f.length>0&&f.length<g.total&&t.jsxs("p",{className:"mt-2 text-[11px] text-fg-subtle",children:["Showing ",K(f.length)," of ",K(g.total),". Narrow the filter to see the rest."]})]})}function U3({s:e,connectionId:n}){const r=e.next!=null&&e.next<=Date.now();return t.jsxs(cl,{children:[t.jsx(xe,{children:t.jsx(Ee,{to:ue.queueSchedulers(n,e.queueName),className:"text-accent hover:underline",children:e.queueName})}),t.jsx(xe,{mono:!0,children:t.jsx("span",{className:"text-fg",title:e.key,children:e.key})}),t.jsx(xe,{mono:!0,muted:!0,children:e.name}),t.jsx(xe,{children:t.jsxs("span",{className:"flex flex-wrap items-center gap-1.5",children:[t.jsx(be,{variant:"outline",size:"xs",className:"font-mono",children:hj(e)}),e.tz&&t.jsx("span",{className:"text-[11px] text-fg-subtle",children:e.tz}),e.iterationCount===0&&t.jsx("span",{className:"text-[11px] text-warning",title:"This scheduler has never produced a job",children:"never ran"})]})}),t.jsx(xe,{align:"right",num:!0,children:e.next==null?t.jsx("span",{className:"text-fg-subtle",title:"No next run: the scheduler ended or hit its limit",children:"–"}):t.jsxs("span",{className:F("inline-flex items-center gap-1",r&&"text-warning"),title:gn(e.next),children:[r&&t.jsx(Dy,{className:"size-3","aria-hidden":!0}),Kr(e.next)]})})]})}function Q3({filtered:e,total:n}){return e&&n>0?t.jsxs("div",{className:"py-6 text-center text-sm text-fg-muted",children:["No scheduler matches this filter. This connection has ",K(n)," in total."]}):t.jsxs("div",{className:"mx-auto flex max-w-xl flex-col items-center gap-2 py-6 text-center",children:[t.jsx(Lo,{className:"size-6 text-fg-subtle","aria-hidden":!0}),t.jsx("p",{className:"text-sm font-medium text-fg",children:"No job schedulers on this connection"}),t.jsx("p",{className:"text-xs text-fg-muted",children:"A job scheduler (BullMQ calls it a repeatable job) stamps out the same job on a cron pattern or a fixed interval. It lives outside the job states, so it never shows up under Waiting or Delayed — only the single job it has queued next does."}),t.jsxs("p",{className:"flex items-center gap-1.5 text-[11px] text-fg-subtle",children:[t.jsx(Wy,{className:"size-3","aria-hidden":!0}),"Create one with ",t.jsx("span",{className:"font-mono",children:"queue.upsertJobScheduler()"}),"."]})]})}function B3(){return t.jsx(bt,{children:t.jsx(cn,{icon:t.jsx(gN,{}),title:"Page not found",description:"The link may be stale, or the queue or connection was removed.",action:t.jsx(Ee,{to:"/",className:"text-accent hover:underline",children:"Back to overview"})})})}const V3=w.lazy(()=>Bu(()=>import("./FlowsPage-BOHg_j5s.js"),__vite__mapDeps([0,1,2,3])).then(e=>({default:e.FlowsPage}))),H3=w.lazy(()=>Bu(()=>import("./FlowsPage-BOHg_j5s.js"),__vite__mapDeps([0,1,2,3])).then(e=>({default:e.FlowsIndexPage}))),K3=w.lazy(()=>Bu(()=>import("./McpConsentPage-YpDqETHG.js"),[]).then(e=>({default:e.McpConsentPage}))),W3=w.lazy(()=>Bu(()=>import("./JobTreePage-DWE60jpd.js"),__vite__mapDeps([4,1,2])).then(e=>({default:e.JobTreePage})));function pu({children:e}){return t.jsx(w.Suspense,{fallback:t.jsx(il,{}),children:e})}const Z3=new tN({defaultOptions:{queries:{retry:(e,n)=>Ts(n)&&n.status>0&&n.status<500?!1:e<2,retryDelay:e=>Math.min(1e3*2**e,8e3),staleTime:1e3,refetchOnWindowFocus:!0,refetchIntervalInBackground:!1},mutations:{retry:!1}}});function G3(){return t.jsx(_w,{client:Z3,children:t.jsx(bw,{children:t.jsxs(Wk,{children:[t.jsxs(hw,{children:[t.jsx(ct,{path:"/login",element:t.jsx(iv,{children:t.jsx(PS,{})})}),t.jsx(ct,{path:"/setup",element:t.jsx(iv,{children:t.jsx(ES,{})})}),t.jsx(ct,{path:"/oauth/consent",element:t.jsx(pu,{children:t.jsx(K3,{})})}),t.jsx(ct,{element:t.jsx(Zk,{}),children:t.jsxs(ct,{element:t.jsx(_S,{}),children:[t.jsx(ct,{index:!0,element:t.jsx(oC,{})}),t.jsx(ct,{path:"c/:connectionId",element:t.jsx(uC,{})}),t.jsx(ct,{path:"c/:connectionId/q/:queue",element:t.jsx(sf,{})}),t.jsx(ct,{path:"c/:connectionId/q/:queue/metrics",element:t.jsx(sf,{view:"metrics"})}),t.jsx(ct,{path:"c/:connectionId/q/:queue/schedulers",element:t.jsx(sf,{view:"schedulers"})}),t.jsx(ct,{path:"c/:connectionId/q/:queue/groups",element:t.jsx(B_,{})}),t.jsx(ct,{path:"c/:connectionId/q/:queue/groups/:groupId",element:t.jsx(Z_,{})}),t.jsx(ct,{path:"c/:connectionId/q/:queue/j/:jobId",element:t.jsx(O_,{})}),t.jsx(ct,{path:"c/:connectionId/q/:queue/j/:jobId/tree",element:t.jsx(pu,{children:t.jsx(W3,{})})}),t.jsx(ct,{path:"health",element:t.jsx(yC,{})}),t.jsx(ct,{path:"schedulers",element:t.jsx(F3,{})}),t.jsx(ct,{path:"schedulers/:connectionId",element:t.jsx(D3,{})}),t.jsx(ct,{path:"folders",element:t.jsx(G_,{})}),t.jsx(ct,{path:"folders/:folderId",element:t.jsx(l3,{})}),t.jsx(ct,{path:"alerts",element:t.jsx(N_,{})}),t.jsx(ct,{path:"users",element:t.jsx(u3,{})}),t.jsx(ct,{path:"audit",element:t.jsx(p3,{})}),t.jsxs(t.Fragment,{children:[t.jsx(ct,{path:"flows",element:t.jsx(pu,{children:t.jsx(H3,{})})}),t.jsx(ct,{path:"flows/:connectionId",element:t.jsx(pu,{children:t.jsx(V3,{})})})]}),t.jsx(ct,{path:"settings",element:t.jsx(Vr,{to:"/settings/connections",replace:!0})}),t.jsx(ct,{path:"settings/:tab",element:t.jsx(A3,{})}),t.jsx(ct,{path:"*",element:t.jsx(B3,{})})]})})]}),t.jsx(e2,{}),t.jsx(Kk,{})]})})})}bb.createRoot(document.getElementById("root")).render(t.jsx(w.StrictMode,{children:t.jsx(G3,{})}));export{mt as $,h5 as A,V as B,Dn as C,Va as D,Br as E,f5 as F,p5 as G,x5 as H,Te as I,g5 as J,m5 as K,Ee as L,d5 as M,Ts as N,cn as O,es as P,Uy as Q,ON as R,Cu as S,Pe as T,u5 as U,Uo as V,DN as W,vn as X,Un as Y,Ht as Z,un as _,Yu as a,s5 as a0,r5 as a1,a5 as a2,dm as a3,Ha as a4,wt as a5,Wa as a6,Fn as a7,sl as a8,i5 as a9,Ay as aa,Ln as ab,Z0 as ac,ts as ad,Vr as ae,v5 as af,y5 as ag,n5 as ah,bt as ai,gs as aj,kN as ak,ad as al,Vy as am,FS as an,Kr as ao,Gf as ap,db as aq,pb as ar,X3 as as,F as b,ie as c,Kt as d,K as e,ft as f,lt as g,be as h,ue as i,t as j,Yn as k,Zr as l,e5 as m,o5 as n,bn as o,Yi as p,dt as q,w as r,t5 as s,X as t,ll as u,ve as v,So as w,c5 as x,l5 as y,xs as z};
|