brakit 0.10.1 → 0.10.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/api.d.ts +41 -14
- package/dist/api.js +105 -17
- package/dist/bin/brakit.js +307 -37
- package/dist/dashboard-client.global.js +204 -191
- package/dist/dashboard.html +216 -192
- package/dist/mcp/server.js +78 -1
- package/dist/runtime/index.js +1330 -1122
- package/package.json +1 -1
package/dist/dashboard.html
CHANGED
|
@@ -840,13 +840,24 @@ span.perf-breakdown-dot.perf-breakdown-app{background:var(--breakdown-app)}
|
|
|
840
840
|
.insights-chip-count{font-size:10px;font-family:var(--mono);background:rgba(0,0,0,.08);padding:1px 5px;border-radius:8px}
|
|
841
841
|
.insights-chip.active .insights-chip-count{background:rgba(255,255,255,.25)}
|
|
842
842
|
|
|
843
|
+
/* Summary bar */
|
|
844
|
+
.insights-summary{display:flex;gap:14px;padding:10px 28px;font-size:12px;font-weight:500;border-bottom:1px solid var(--border)}
|
|
845
|
+
.insights-summary-stat{display:flex;align-items:center;gap:4px}
|
|
846
|
+
.insights-summary-stat.critical{color:var(--red)}
|
|
847
|
+
.insights-summary-stat.warning{color:var(--amber)}
|
|
848
|
+
.insights-summary-stat.resolved{color:var(--green)}
|
|
849
|
+
|
|
850
|
+
/* AI hint */
|
|
851
|
+
.insights-ai-hint{font-size:11px;color:var(--text-muted);padding:0 0 12px}
|
|
852
|
+
.insights-ai-hint code{background:var(--bg-muted);padding:2px 6px;border-radius:4px;font-family:var(--mono);font-size:11px}
|
|
853
|
+
|
|
843
854
|
/* Insights card list */
|
|
844
855
|
.insights-list{padding:16px 28px}
|
|
845
856
|
|
|
846
857
|
.insights-empty{display:flex;align-items:center;gap:10px;padding:24px;color:var(--green);font-size:14px;font-weight:500}
|
|
847
858
|
.insights-empty-icon{font-size:18px}
|
|
848
859
|
|
|
849
|
-
.insights-card{display:flex;align-items:flex-start;gap:12px;padding:
|
|
860
|
+
.insights-card{display:flex;align-items:flex-start;gap:12px;padding:12px 16px;background:var(--bg-card);border:1px solid var(--border);border-radius:10px;cursor:pointer;transition:all .15s;margin-bottom:6px}
|
|
850
861
|
.insights-card:hover{border-color:var(--border-light);box-shadow:0 2px 8px rgba(0,0,0,.04)}
|
|
851
862
|
.insights-card.expanded{border-color:var(--border-light);box-shadow:0 2px 8px rgba(0,0,0,.04)}
|
|
852
863
|
.insights-card.resolved{opacity:.55}
|
|
@@ -892,20 +903,20 @@ span.perf-breakdown-dot.perf-breakdown-app{background:var(--breakdown-app)}
|
|
|
892
903
|
<body>
|
|
893
904
|
<bk-dashboard></bk-dashboard>
|
|
894
905
|
<script>window.__BRAKIT_CONFIG__={port:{{PORT}},version:"{{VERSION}}"};</script>
|
|
895
|
-
<script>(function(){'use strict';var
|
|
896
|
-
\f\r]`,qt=/<(?:(!--|\/[^a-zA-Z])|(\/?[a-zA-Z][^>\s]*)|(\/?$))/g,_s
|
|
897
|
-
\f\r"'\`<>=]|("|')|))|$)`,"g"),xs=/'/g,Ss=/"/g,As=/^(?:script|style|textarea|title)$/i,De=o=>(r,...t)=>({_$litType$:o,strings:r,values:t}),l=De(1),k=De(2),z=Symbol.for("lit-noChange"),p=Symbol.for("lit-nothing"),Ts=new WeakMap,lt=ct.createTreeWalker(ct,129);function Is(o,r){if(!Oe(o)||!o.hasOwnProperty("raw"))throw Error("invalid template strings array");return ys!==void 0?ys.createHTML(r):r}var jr=(o,r)=>{let t=o.length-1,e=[],s,i=r===2?"<svg>":r===3?"<math>":"",n=qt;for(let a=0;a<t;a++){let c=o[a],d,h,m=-1,f=0;for(;f<c.length&&(n.lastIndex=f,h=n.exec(c),h!==null);)f=n.lastIndex,n===qt?h[1]==="!--"?n=_s:h[1]!==void 0?n=$s:h[2]!==void 0?(As.test(h[2])&&(s=RegExp("</"+h[2],"g")),n=at):h[3]!==void 0&&(n=at):n===at?h[0]===">"?(n=s??qt,m=-1):h[1]===void 0?m=-2:(m=n.lastIndex-h[2].length,d=h[1],n=h[3]===void 0?at:h[3]==='"'?Ss:xs):n===Ss||n===xs?n=at:n===_s||n===$s?n=qt:(n=at,s=void 0);let S=n===at&&o[a+1].startsWith("/>")?" ":"";i+=n===qt?c+Wr:m>=0?(e.push(d),c.slice(0,m)+ws+c.slice(m)+st+S):c+st+(m===-2?a:S);}return [Is(o,i+(o[t]||"<?>")+(r===2?"</svg>":r===3?"</math>":"")),e]},Bt=class o{constructor({strings:r,_$litType$:t},e){let s;this.parts=[];let i=0,n=0,a=r.length-1,c=this.parts,[d,h]=jr(r,t);if(this.el=o.createElement(d,e),lt.currentNode=this.el.content,t===2||t===3){let m=this.el.content.firstChild;m.replaceWith(...m.childNodes);}for(;(s=lt.nextNode())!==null&&c.length<a;){if(s.nodeType===1){if(s.hasAttributes())for(let m of s.getAttributeNames())if(m.endsWith(ws)){let f=h[n++],S=s.getAttribute(m).split(st),R=/([.?@])?(.*)/.exec(f);c.push({type:1,index:i,name:R[2],strings:S,ctor:R[1]==="."?Le:R[1]==="?"?Me:R[1]==="@"?Ne:gt}),s.removeAttribute(m);}else m.startsWith(st)&&(c.push({type:6,index:i}),s.removeAttribute(m));if(As.test(s.tagName)){let m=s.textContent.split(st),f=m.length-1;if(f>0){s.textContent=ce?ce.emptyScript:"";for(let S=0;S<f;S++)s.append(m[S],Ft()),lt.nextNode(),c.push({type:2,index:++i});s.append(m[f],Ft());}}}else if(s.nodeType===8)if(s.data===Rs)c.push({type:2,index:i});else {let m=-1;for(;(m=s.data.indexOf(st,m+1))!==-1;)c.push({type:7,index:i}),m+=st.length-1;}i++;}}static createElement(r,t){let e=ct.createElement("template");return e.innerHTML=r,e}};function vt(o,r,t=o,e){if(r===z)return r;let s=e!==void 0?t._$Co?.[e]:t._$Cl,i=Gt(r)?void 0:r._$litDirective$;return s?.constructor!==i&&(s?._$AO?.(false),i===void 0?s=void 0:(s=new i(o),s._$AT(o,t,e)),e!==void 0?(t._$Co??(t._$Co=[]))[e]=s:t._$Cl=s),s!==void 0&&(r=vt(o,s._$AS(o,r.values),s,e)),r}var Ce=class{constructor(r,t){this._$AV=[],this._$AN=void 0,this._$AD=r,this._$AM=t;}get parentNode(){return this._$AM.parentNode}get _$AU(){return this._$AM._$AU}u(r){let{el:{content:t},parts:e}=this._$AD,s=(r?.creationScope??ct).importNode(t,true);lt.currentNode=s;let i=lt.nextNode(),n=0,a=0,c=e[0];for(;c!==void 0;){if(n===c.index){let d;c.type===2?d=new Wt(i,i.nextSibling,this,r):c.type===1?d=new c.ctor(i,c.name,c.strings,this,r):c.type===6&&(d=new ke(i,this,r)),this._$AV.push(d),c=e[++a];}n!==c?.index&&(i=lt.nextNode(),n++);}return lt.currentNode=ct,s}p(r){let t=0;for(let e of this._$AV)e!==void 0&&(e.strings!==void 0?(e._$AI(r,e,t),t+=e.strings.length-2):e._$AI(r[t])),t++;}},Wt=class o{get _$AU(){return this._$AM?._$AU??this._$Cv}constructor(r,t,e,s){this.type=2,this._$AH=p,this._$AN=void 0,this._$AA=r,this._$AB=t,this._$AM=e,this.options=s,this._$Cv=s?.isConnected??true;}get parentNode(){let r=this._$AA.parentNode,t=this._$AM;return t!==void 0&&r?.nodeType===11&&(r=t.parentNode),r}get startNode(){return this._$AA}get endNode(){return this._$AB}_$AI(r,t=this){r=vt(this,r,t),Gt(r)?r===p||r==null||r===""?(this._$AH!==p&&this._$AR(),this._$AH=p):r!==this._$AH&&r!==z&&this._(r):r._$litType$!==void 0?this.$(r):r.nodeType!==void 0?this.T(r):Qr(r)?this.k(r):this._(r);}O(r){return this._$AA.parentNode.insertBefore(r,this._$AB)}T(r){this._$AH!==r&&(this._$AR(),this._$AH=this.O(r));}_(r){this._$AH!==p&&Gt(this._$AH)?this._$AA.nextSibling.data=r:this.T(ct.createTextNode(r)),this._$AH=r;}$(r){let{values:t,_$litType$:e}=r,s=typeof e=="number"?this._$AC(r):(e.el===void 0&&(e.el=Bt.createElement(Is(e.h,e.h[0]),this.options)),e);if(this._$AH?._$AD===s)this._$AH.p(t);else {let i=new Ce(s,this),n=i.u(this.options);i.p(t),this.T(n),this._$AH=i;}}_$AC(r){let t=Ts.get(r.strings);return t===void 0&&Ts.set(r.strings,t=new Bt(r)),t}k(r){Oe(this._$AH)||(this._$AH=[],this._$AR());let t=this._$AH,e,s=0;for(let i of r)s===t.length?t.push(e=new o(this.O(Ft()),this.O(Ft()),this,this.options)):e=t[s],e._$AI(i),s++;s<t.length&&(this._$AR(e&&e._$AB.nextSibling,s),t.length=s);}_$AR(r=this._$AA.nextSibling,t){for(this._$AP?.(false,true,t);r!==this._$AB;){let e=bs(r).nextSibling;bs(r).remove(),r=e;}}setConnected(r){this._$AM===void 0&&(this._$Cv=r,this._$AP?.(r));}},gt=class{get tagName(){return this.element.tagName}get _$AU(){return this._$AM._$AU}constructor(r,t,e,s,i){this.type=1,this._$AH=p,this._$AN=void 0,this.element=r,this.name=t,this._$AM=s,this.options=i,e.length>2||e[0]!==""||e[1]!==""?(this._$AH=Array(e.length-1).fill(new String),this.strings=e):this._$AH=p;}_$AI(r,t=this,e,s){let i=this.strings,n=false;if(i===void 0)r=vt(this,r,t,0),n=!Gt(r)||r!==this._$AH&&r!==z,n&&(this._$AH=r);else {let a=r,c,d;for(r=i[0],c=0;c<i.length-1;c++)d=vt(this,a[e+c],t,c),d===z&&(d=this._$AH[c]),n||(n=!Gt(d)||d!==this._$AH[c]),d===p?r=p:r!==p&&(r+=(d??"")+i[c+1]),this._$AH[c]=d;}n&&!s&&this.j(r);}j(r){r===p?this.element.removeAttribute(this.name):this.element.setAttribute(this.name,r??"");}},Le=class extends gt{constructor(){super(...arguments),this.type=3;}j(r){this.element[this.name]=r===p?void 0:r;}},Me=class extends gt{constructor(){super(...arguments),this.type=4;}j(r){this.element.toggleAttribute(this.name,!!r&&r!==p);}},Ne=class extends gt{constructor(r,t,e,s,i){super(r,t,e,s,i),this.type=5;}_$AI(r,t=this){if((r=vt(this,r,t,0)??p)===z)return;let e=this._$AH,s=r===p&&e!==p||r.capture!==e.capture||r.once!==e.once||r.passive!==e.passive,i=r!==p&&(e===p||s);s&&this.element.removeEventListener(this.name,this,e),i&&this.element.addEventListener(this.name,this,r),this._$AH=r;}handleEvent(r){typeof this._$AH=="function"?this._$AH.call(this.options?.host??this.element,r):this._$AH.handleEvent(r);}},ke=class{constructor(r,t,e){this.element=r,this.type=6,this._$AN=void 0,this._$AM=t,this.options=e;}get _$AU(){return this._$AM._$AU}_$AI(r){vt(this,r);}};var Yr=Ut.litHtmlPolyfillSupport;Yr?.(Bt,Wt),(Ut.litHtmlVersions??(Ut.litHtmlVersions=[])).push("3.3.2");var Cs=(o,r,t)=>{let e=t?.renderBefore??r,s=e._$litPart$;if(s===void 0){let i=t?.renderBefore??null;e._$litPart$=s=new Wt(r.insertBefore(Ft(),i),i,void 0,t??{});}return s._$AI(o),s};var Qt=globalThis,b=class extends K{constructor(){super(...arguments),this.renderOptions={host:this},this._$Do=void 0;}createRenderRoot(){var t;let r=super.createRenderRoot();return (t=this.renderOptions).renderBefore??(t.renderBefore=r.firstChild),r}update(r){let t=this.render();this.hasUpdated||(this.renderOptions.isConnected=this.isConnected),super.update(r),this._$Do=Cs(t,this.renderRoot,this.renderOptions);}connectedCallback(){super.connectedCallback(),this._$Do?.setConnected(true);}disconnectedCallback(){super.disconnectedCallback(),this._$Do?.setConnected(false);}render(){return z}};b._$litElement$=true,b.finalized=true,Qt.litElementHydrateSupport?.({LitElement:b});var Vr=Qt.litElementPolyfillSupport;Vr?.({LitElement:b});(Qt.litElementVersions??(Qt.litElementVersions=[])).push("4.2.2");var $=o=>(r,t)=>{t!==void 0?t.addInitializer(()=>{customElements.define(o,r);}):customElements.define(o,r);};var Xr={attribute:true,type:String,converter:Ht,reflect:false,hasChanged:le},Kr=(o=Xr,r,t)=>{let{kind:e,metadata:s}=t,i=globalThis.litPropertyMetadata.get(s);if(i===void 0&&globalThis.litPropertyMetadata.set(s,i=new Map),e==="setter"&&((o=Object.create(o)).wrapped=true),i.set(t.name,o),e==="accessor"){let{name:n}=t;return {set(a){let c=r.get.call(this);r.set.call(this,a),this.requestUpdate(n,c,o,true,a);},init(a){return a!==void 0&&this.C(n,void 0,o,a),a}}}if(e==="setter"){let{name:n}=t;return function(a){let c=this[n];r.call(this,a),this.requestUpdate(n,c,o,true,a);}}throw Error("Unsupported decorator location: "+e)};function L(o){return (r,t)=>typeof t=="object"?Kr(o,r,t):((e,s,i)=>{let n=s.hasOwnProperty(i);return s.constructor.createProperty(i,e),n?Object.getOwnPropertyDescriptor(s,i):void 0})(o,r,t)}function E(o){return L({...o,state:true,attribute:false})}var jt=class extends b{constructor(){super(...arguments);this.method="";}createRenderRoot(){return this}render(){let t=this.method.toUpperCase();return l`<span class="method-badge method-badge-${t}">${t}</span>`}};u([L()],jt.prototype,"method",2),jt=u([$("bk-method-badge")],jt);var q="/__brakit/api",U="/__brakit",T={flows:`${q}/flows`,requests:`${q}/requests`,events:`${q}/events`,clear:`${q}/clear`,fetches:`${q}/fetches`,errors:`${q}/errors`,logs:`${q}/logs`,queries:`${q}/queries`,metricsLive:`${q}/metrics/live`,insights:`${q}/insights`,tab:`${q}/tab`,activity:`${q}/activity`,graph:`${q}/graph`};var Et="polling",pe="static",zr="auth-handshake",Jr="auth-check",Zr="middleware",Yt={[zr]:1,[Jr]:1,[Zr]:1};var he="fetch";var ue="error_event",me="query",fe="issues";var Pe={overview:"Overview",actions:"Actions",insights:"Insights",performance:"Performance",graph:"Graph",explorer:"Explorer",requests:"Requests",fetches:"Server Fetches",queries:"Queries",errors:"Errors",logs:"Logs",security:"Security"},He={overview:"Live summary of your application",actions:"User actions captured as sequences of HTTP requests",insights:"Security findings, error patterns, and issue tracking",performance:"Endpoint health and response time trends",graph:"Runtime dependency graph of your application",explorer:"Browse raw requests, fetches, queries, logs, and errors",requests:"All HTTP requests proxied through brakit",fetches:"Outbound HTTP calls made by your server to external services",queries:"Database queries executed during request handling",errors:"Unhandled exceptions and errors thrown by your application",logs:"Console output from your application",security:"Security findings and recommendations"},ve=[{key:"requests",label:"Requests"},{key:"fetches",label:"Fetches"},{key:"queries",label:"Queries"},{key:"logs",label:"Logs"},{key:"errors",label:"Errors"}];var Ls=new Set(["exposed-secret","token-in-url","stack-trace-leak","error-info-leak","insecure-cookie","sensitive-logs","cors-credentials","response-pii-leak"]),Ms=new Set(["slow-endpoint","n1","high-query-count"]);function Vt(o){let r=o.issue.rule||o.issue.type||"";return Ls.has(r)?"security":Ms.has(r)?"performance":"quality"}var O={CLEAR_CONFIRM:"This will clear all data including performance metrics history. Continue?",CLEARED_TOAST:"Cleared",EMPTY_TITLE:"Waiting for requests...",EMPTY_SUBTITLE_OVERVIEW:"Start using your app to see your dashboard here",ALL_CLEAR:"All clear",ALL_CLEAR_DETAIL:"No issues detected",NO_ACTIONS:"No actions captured yet",NO_REQUEST_DATA:"No request data yet",ALL_FAST:"All fast",NO_SLOW_ENDPOINTS:"No slow endpoints detected",ZERO_ERRORS:"0 errors",ALL_REQUESTS_OK:"All requests successful",BUILD_GRAPH:"Navigate your app to build the graph",REVIEW_RECOMMENDED:"review recommended"};var Fe=100,yt=300,_t=800,Ge=2e3,Be=100,We=50,Qe=500;var rt="__all__",Ee={SELECT:"var(--blue)",INSERT:"var(--green)",UPDATE:"var(--amber)",DELETE:"var(--red)",COUNT:"var(--text-muted)"},qs={error:"var(--red)",warn:"var(--amber)",info:"var(--blue)",debug:"var(--text-muted)",log:"var(--text-dim)"},Ve=["#2563eb","#7c3aed","#16a34a","#d97706","#dc2626","#0891b2","#ea580c","#c026d3","#059669","#db2777"],Xt={green:"#4ade80",amber:"#fbbf24",red:"#f87171"},xt=[{max:Fe,label:"Fast",color:"var(--green)",bg:"var(--green-bg)",border:"var(--green-border)"},{max:yt,label:"Good",color:"var(--green)",bg:"var(--green-bg-subtle)",border:"var(--green-border-subtle)"},{max:_t,label:"OK",color:"var(--amber)",bg:"var(--amber-bg)",border:"var(--amber-border)"},{max:Ge,label:"Slow",color:"var(--red)",bg:"var(--red-bg)",border:"var(--red-border)"},{max:1/0,label:"Critical",color:"var(--red)",bg:"var(--red-bg)",border:"var(--red-border)"}],Us="rgba(228,228,231,0.8)",Xe="rgba(113,113,122,0.7)",Fs="10px monospace",Ke="9px monospace";var Gs={top:16,right:16,bottom:28,left:52},Bs={fetch:"var(--blue)",log:"var(--text-muted)",error:"var(--red)",query:"var(--accent)"},Ws={fetch:"FETCH",log:"LOG",error:"ERROR",query:"QUERY"},Qs=new Set(["cookie","set-cookie","authorization","proxy-authorization","x-api-key","x-auth-token"]),js={400:"Bad Request",401:"Unauthorized",403:"Forbidden",404:"Not Found",405:"Method Not Allowed",408:"Timeout",409:"Conflict",422:"Unprocessable",429:"Too Many Requests",500:"Internal Server Error",502:"Bad Gateway",503:"Service Unavailable",504:"Gateway Timeout"},Ys=new Set(["host","connection","accept-encoding"]),Y={critical:{icon:"\u2717",cls:"critical",sort:0},warning:{icon:"\u26A0",cls:"warning",sort:1},info:{icon:"\u2139",cls:"info",sort:2}};function y(o){return o<1e3?o+"ms":(o/1e3).toFixed(1)+"s"}function ot(o){return !o||o===0?"":o<1024?o+"b":(o/1024).toFixed(1)+"kb"}function it(o){return o?o.replaceAll("&","&").replaceAll("<","<").replaceAll(">",">").replaceAll('"',"""):""}function St(o){return o>=500?"status-pill-5xx":o>=400?"status-pill-4xx":o>=300?"status-pill-3xx":"status-pill-2xx"}function Vs(o){return js[o]||(o>=500?"Server Error":o>=400?"Client Error":"OK")}function ti(o,r){if(Qs.has(o.toLowerCase())){let t=String(r);return t.length<=8?"****":t.slice(0,4)+"..."+t.slice(-4)+" ("+t.length+" chars)"}return String(r)}function Tt(o){return !o||Object.keys(o).length===0?'<span style="color:var(--text-muted)">No headers</span>':Object.entries(o).map(([r,t])=>'<span class="json-key">'+it(r)+"</span>: "+it(ti(r,t))).join(`
|
|
898
|
-
`)}function dt(o){if(!o)return '<span style="color:var(--text-muted)">No body</span>';try{let r=JSON.parse(o);return
|
|
906
|
+
<script>(function(){'use strict';var Or=Object.defineProperty;var Nr=Object.getOwnPropertyDescriptor;var u=(o,r,t,e)=>{for(var s=e>1?void 0:e?Nr(r,t):r,i=o.length-1,n;i>=0;i--)(n=o[i])&&(s=(e?n(r,t,s):n(s))||s);return e&&s&&Or(r,t,s),s};var oe=globalThis,ae=oe.ShadowRoot&&(oe.ShadyCSS===void 0||oe.ShadyCSS.nativeShadow)&&"adoptedStyleSheets"in Document.prototype&&"replace"in CSSStyleSheet.prototype,ms=Symbol(),us=new WeakMap,ne=class{constructor(r,t,e){if(this._$cssResult$=true,e!==ms)throw Error("CSSResult is not constructable. Use `unsafeCSS` or `css` instead.");this.cssText=r,this.t=t;}get styleSheet(){let r=this.o,t=this.t;if(ae&&r===void 0){let e=t!==void 0&&t.length===1;e&&(r=us.get(t)),r===void 0&&((this.o=r=new CSSStyleSheet).replaceSync(this.cssText),e&&us.set(t,r));}return r}toString(){return this.cssText}},fs=o=>new ne(typeof o=="string"?o:o+"",void 0,ms);var vs=(o,r)=>{if(ae)o.adoptedStyleSheets=r.map(t=>t instanceof CSSStyleSheet?t:t.styleSheet);else for(let t of r){let e=document.createElement("style"),s=oe.litNonce;s!==void 0&&e.setAttribute("nonce",s),e.textContent=t.cssText,o.appendChild(e);}},Ae=ae?o=>o:o=>o instanceof CSSStyleSheet?(r=>{let t="";for(let e of r.cssRules)t+=e.cssText;return fs(t)})(o):o;var{is:Dr,defineProperty:Pr,getOwnPropertyDescriptor:Hr,getOwnPropertyNames:qr,getOwnPropertySymbols:Ur,getPrototypeOf:Fr}=Object,et=globalThis,gs=et.trustedTypes,Gr=gs?gs.emptyScript:"",Br=et.reactiveElementPolyfillSupport,Pt=(o,r)=>o,Ht={toAttribute(o,r){switch(r){case Boolean:o=o?Gr:null;break;case Object:case Array:o=o==null?o:JSON.stringify(o);}return o},fromAttribute(o,r){let t=o;switch(r){case Boolean:t=o!==null;break;case Number:t=o===null?null:Number(o);break;case Object:case Array:try{t=JSON.parse(o);}catch{t=null;}}return t}},le=(o,r)=>!Dr(o,r),bs={attribute:true,type:String,converter:Ht,reflect:false,useDefault:false,hasChanged:le};Symbol.metadata??(Symbol.metadata=Symbol("metadata")),et.litPropertyMetadata??(et.litPropertyMetadata=new WeakMap);var K=class extends HTMLElement{static addInitializer(r){this._$Ei(),(this.l??(this.l=[])).push(r);}static get observedAttributes(){return this.finalize(),this._$Eh&&[...this._$Eh.keys()]}static createProperty(r,t=bs){if(t.state&&(t.attribute=false),this._$Ei(),this.prototype.hasOwnProperty(r)&&((t=Object.create(t)).wrapped=true),this.elementProperties.set(r,t),!t.noAccessor){let e=Symbol(),s=this.getPropertyDescriptor(r,e,t);s!==void 0&&Pr(this.prototype,r,s);}}static getPropertyDescriptor(r,t,e){let{get:s,set:i}=Hr(this.prototype,r)??{get(){return this[t]},set(n){this[t]=n;}};return {get:s,set(n){let a=s?.call(this);i?.call(this,n),this.requestUpdate(r,a,e);},configurable:true,enumerable:true}}static getPropertyOptions(r){return this.elementProperties.get(r)??bs}static _$Ei(){if(this.hasOwnProperty(Pt("elementProperties")))return;let r=Fr(this);r.finalize(),r.l!==void 0&&(this.l=[...r.l]),this.elementProperties=new Map(r.elementProperties);}static finalize(){if(this.hasOwnProperty(Pt("finalized")))return;if(this.finalized=true,this._$Ei(),this.hasOwnProperty(Pt("properties"))){let t=this.properties,e=[...qr(t),...Ur(t)];for(let s of e)this.createProperty(s,t[s]);}let r=this[Symbol.metadata];if(r!==null){let t=litPropertyMetadata.get(r);if(t!==void 0)for(let[e,s]of t)this.elementProperties.set(e,s);}this._$Eh=new Map;for(let[t,e]of this.elementProperties){let s=this._$Eu(t,e);s!==void 0&&this._$Eh.set(s,t);}this.elementStyles=this.finalizeStyles(this.styles);}static finalizeStyles(r){let t=[];if(Array.isArray(r)){let e=new Set(r.flat(1/0).reverse());for(let s of e)t.unshift(Ae(s));}else r!==void 0&&t.push(Ae(r));return t}static _$Eu(r,t){let e=t.attribute;return e===false?void 0:typeof e=="string"?e:typeof r=="string"?r.toLowerCase():void 0}constructor(){super(),this._$Ep=void 0,this.isUpdatePending=false,this.hasUpdated=false,this._$Em=null,this._$Ev();}_$Ev(){this._$ES=new Promise(r=>this.enableUpdating=r),this._$AL=new Map,this._$E_(),this.requestUpdate(),this.constructor.l?.forEach(r=>r(this));}addController(r){(this._$EO??(this._$EO=new Set)).add(r),this.renderRoot!==void 0&&this.isConnected&&r.hostConnected?.();}removeController(r){this._$EO?.delete(r);}_$E_(){let r=new Map,t=this.constructor.elementProperties;for(let e of t.keys())this.hasOwnProperty(e)&&(r.set(e,this[e]),delete this[e]);r.size>0&&(this._$Ep=r);}createRenderRoot(){let r=this.shadowRoot??this.attachShadow(this.constructor.shadowRootOptions);return vs(r,this.constructor.elementStyles),r}connectedCallback(){this.renderRoot??(this.renderRoot=this.createRenderRoot()),this.enableUpdating(true),this._$EO?.forEach(r=>r.hostConnected?.());}enableUpdating(r){}disconnectedCallback(){this._$EO?.forEach(r=>r.hostDisconnected?.());}attributeChangedCallback(r,t,e){this._$AK(r,e);}_$ET(r,t){let e=this.constructor.elementProperties.get(r),s=this.constructor._$Eu(r,e);if(s!==void 0&&e.reflect===true){let i=(e.converter?.toAttribute!==void 0?e.converter:Ht).toAttribute(t,e.type);this._$Em=r,i==null?this.removeAttribute(s):this.setAttribute(s,i),this._$Em=null;}}_$AK(r,t){let e=this.constructor,s=e._$Eh.get(r);if(s!==void 0&&this._$Em!==s){let i=e.getPropertyOptions(s),n=typeof i.converter=="function"?{fromAttribute:i.converter}:i.converter?.fromAttribute!==void 0?i.converter:Ht;this._$Em=s;let a=n.fromAttribute(t,i.type);this[s]=a??this._$Ej?.get(s)??a,this._$Em=null;}}requestUpdate(r,t,e,s=false,i){if(r!==void 0){let n=this.constructor;if(s===false&&(i=this[r]),e??(e=n.getPropertyOptions(r)),!((e.hasChanged??le)(i,t)||e.useDefault&&e.reflect&&i===this._$Ej?.get(r)&&!this.hasAttribute(n._$Eu(r,e))))return;this.C(r,t,e);}this.isUpdatePending===false&&(this._$ES=this._$EP());}C(r,t,{useDefault:e,reflect:s,wrapped:i},n){e&&!(this._$Ej??(this._$Ej=new Map)).has(r)&&(this._$Ej.set(r,n??t??this[r]),i!==true||n!==void 0)||(this._$AL.has(r)||(this.hasUpdated||e||(t=void 0),this._$AL.set(r,t)),s===true&&this._$Em!==r&&(this._$Eq??(this._$Eq=new Set)).add(r));}async _$EP(){this.isUpdatePending=true;try{await this._$ES;}catch(t){Promise.reject(t);}let r=this.scheduleUpdate();return r!=null&&await r,!this.isUpdatePending}scheduleUpdate(){return this.performUpdate()}performUpdate(){if(!this.isUpdatePending)return;if(!this.hasUpdated){if(this.renderRoot??(this.renderRoot=this.createRenderRoot()),this._$Ep){for(let[s,i]of this._$Ep)this[s]=i;this._$Ep=void 0;}let e=this.constructor.elementProperties;if(e.size>0)for(let[s,i]of e){let{wrapped:n}=i,a=this[s];n!==true||this._$AL.has(s)||a===void 0||this.C(s,void 0,i,a);}}let r=false,t=this._$AL;try{r=this.shouldUpdate(t),r?(this.willUpdate(t),this._$EO?.forEach(e=>e.hostUpdate?.()),this.update(t)):this._$EM();}catch(e){throw r=false,this._$EM(),e}r&&this._$AE(t);}willUpdate(r){}_$AE(r){this._$EO?.forEach(t=>t.hostUpdated?.()),this.hasUpdated||(this.hasUpdated=true,this.firstUpdated(r)),this.updated(r);}_$EM(){this._$AL=new Map,this.isUpdatePending=false;}get updateComplete(){return this.getUpdateComplete()}getUpdateComplete(){return this._$ES}shouldUpdate(r){return true}update(r){this._$Eq&&(this._$Eq=this._$Eq.forEach(t=>this._$ET(t,this[t]))),this._$EM();}updated(r){}firstUpdated(r){}};K.elementStyles=[],K.shadowRootOptions={mode:"open"},K[Pt("elementProperties")]=new Map,K[Pt("finalized")]=new Map,Br?.({ReactiveElement:K}),(et.reactiveElementVersions??(et.reactiveElementVersions=[])).push("2.1.2");var Ut=globalThis,Es=o=>o,ce=Ut.trustedTypes,ys=ce?ce.createPolicy("lit-html",{createHTML:o=>o}):void 0,ws="$lit$",st=`lit$${Math.random().toFixed(9).slice(2)}$`,Rs="?"+st,Wr=`<${Rs}>`,ct=document,Ft=()=>ct.createComment(""),Gt=o=>o===null||typeof o!="object"&&typeof o!="function",Ne=Array.isArray,jr=o=>Ne(o)||typeof o?.[Symbol.iterator]=="function",Ce=`[
|
|
907
|
+
\f\r]`,qt=/<(?:(!--|\/[^a-zA-Z])|(\/?[a-zA-Z][^>\s]*)|(\/?$))/g,$s=/-->/g,_s=/>/g,at=RegExp(`>|${Ce}(?:([^\\s"'>=/]+)(${Ce}*=${Ce}*(?:[^
|
|
908
|
+
\f\r"'\`<>=]|("|')|))|$)`,"g"),xs=/'/g,Ss=/"/g,As=/^(?:script|style|textarea|title)$/i,De=o=>(r,...t)=>({_$litType$:o,strings:r,values:t}),l=De(1),O=De(2),z=Symbol.for("lit-noChange"),d=Symbol.for("lit-nothing"),Ts=new WeakMap,lt=ct.createTreeWalker(ct,129);function Cs(o,r){if(!Ne(o)||!o.hasOwnProperty("raw"))throw Error("invalid template strings array");return ys!==void 0?ys.createHTML(r):r}var Qr=(o,r)=>{let t=o.length-1,e=[],s,i=r===2?"<svg>":r===3?"<math>":"",n=qt;for(let a=0;a<t;a++){let c=o[a],p,h,m=-1,f=0;for(;f<c.length&&(n.lastIndex=f,h=n.exec(c),h!==null);)f=n.lastIndex,n===qt?h[1]==="!--"?n=$s:h[1]!==void 0?n=_s:h[2]!==void 0?(As.test(h[2])&&(s=RegExp("</"+h[2],"g")),n=at):h[3]!==void 0&&(n=at):n===at?h[0]===">"?(n=s??qt,m=-1):h[1]===void 0?m=-2:(m=n.lastIndex-h[2].length,p=h[1],n=h[3]===void 0?at:h[3]==='"'?Ss:xs):n===Ss||n===xs?n=at:n===$s||n===_s?n=qt:(n=at,s=void 0);let S=n===at&&o[a+1].startsWith("/>")?" ":"";i+=n===qt?c+Wr:m>=0?(e.push(p),c.slice(0,m)+ws+c.slice(m)+st+S):c+st+(m===-2?a:S);}return [Cs(o,i+(o[t]||"<?>")+(r===2?"</svg>":r===3?"</math>":"")),e]},Bt=class o{constructor({strings:r,_$litType$:t},e){let s;this.parts=[];let i=0,n=0,a=r.length-1,c=this.parts,[p,h]=Qr(r,t);if(this.el=o.createElement(p,e),lt.currentNode=this.el.content,t===2||t===3){let m=this.el.content.firstChild;m.replaceWith(...m.childNodes);}for(;(s=lt.nextNode())!==null&&c.length<a;){if(s.nodeType===1){if(s.hasAttributes())for(let m of s.getAttributeNames())if(m.endsWith(ws)){let f=h[n++],S=s.getAttribute(m).split(st),R=/([.?@])?(.*)/.exec(f);c.push({type:1,index:i,name:R[2],strings:S,ctor:R[1]==="."?Le:R[1]==="?"?Me:R[1]==="@"?ke:gt}),s.removeAttribute(m);}else m.startsWith(st)&&(c.push({type:6,index:i}),s.removeAttribute(m));if(As.test(s.tagName)){let m=s.textContent.split(st),f=m.length-1;if(f>0){s.textContent=ce?ce.emptyScript:"";for(let S=0;S<f;S++)s.append(m[S],Ft()),lt.nextNode(),c.push({type:2,index:++i});s.append(m[f],Ft());}}}else if(s.nodeType===8)if(s.data===Rs)c.push({type:2,index:i});else {let m=-1;for(;(m=s.data.indexOf(st,m+1))!==-1;)c.push({type:7,index:i}),m+=st.length-1;}i++;}}static createElement(r,t){let e=ct.createElement("template");return e.innerHTML=r,e}};function vt(o,r,t=o,e){if(r===z)return r;let s=e!==void 0?t._$Co?.[e]:t._$Cl,i=Gt(r)?void 0:r._$litDirective$;return s?.constructor!==i&&(s?._$AO?.(false),i===void 0?s=void 0:(s=new i(o),s._$AT(o,t,e)),e!==void 0?(t._$Co??(t._$Co=[]))[e]=s:t._$Cl=s),s!==void 0&&(r=vt(o,s._$AS(o,r.values),s,e)),r}var Ie=class{constructor(r,t){this._$AV=[],this._$AN=void 0,this._$AD=r,this._$AM=t;}get parentNode(){return this._$AM.parentNode}get _$AU(){return this._$AM._$AU}u(r){let{el:{content:t},parts:e}=this._$AD,s=(r?.creationScope??ct).importNode(t,true);lt.currentNode=s;let i=lt.nextNode(),n=0,a=0,c=e[0];for(;c!==void 0;){if(n===c.index){let p;c.type===2?p=new Wt(i,i.nextSibling,this,r):c.type===1?p=new c.ctor(i,c.name,c.strings,this,r):c.type===6&&(p=new Oe(i,this,r)),this._$AV.push(p),c=e[++a];}n!==c?.index&&(i=lt.nextNode(),n++);}return lt.currentNode=ct,s}p(r){let t=0;for(let e of this._$AV)e!==void 0&&(e.strings!==void 0?(e._$AI(r,e,t),t+=e.strings.length-2):e._$AI(r[t])),t++;}},Wt=class o{get _$AU(){return this._$AM?._$AU??this._$Cv}constructor(r,t,e,s){this.type=2,this._$AH=d,this._$AN=void 0,this._$AA=r,this._$AB=t,this._$AM=e,this.options=s,this._$Cv=s?.isConnected??true;}get parentNode(){let r=this._$AA.parentNode,t=this._$AM;return t!==void 0&&r?.nodeType===11&&(r=t.parentNode),r}get startNode(){return this._$AA}get endNode(){return this._$AB}_$AI(r,t=this){r=vt(this,r,t),Gt(r)?r===d||r==null||r===""?(this._$AH!==d&&this._$AR(),this._$AH=d):r!==this._$AH&&r!==z&&this._(r):r._$litType$!==void 0?this.$(r):r.nodeType!==void 0?this.T(r):jr(r)?this.k(r):this._(r);}O(r){return this._$AA.parentNode.insertBefore(r,this._$AB)}T(r){this._$AH!==r&&(this._$AR(),this._$AH=this.O(r));}_(r){this._$AH!==d&&Gt(this._$AH)?this._$AA.nextSibling.data=r:this.T(ct.createTextNode(r)),this._$AH=r;}$(r){let{values:t,_$litType$:e}=r,s=typeof e=="number"?this._$AC(r):(e.el===void 0&&(e.el=Bt.createElement(Cs(e.h,e.h[0]),this.options)),e);if(this._$AH?._$AD===s)this._$AH.p(t);else {let i=new Ie(s,this),n=i.u(this.options);i.p(t),this.T(n),this._$AH=i;}}_$AC(r){let t=Ts.get(r.strings);return t===void 0&&Ts.set(r.strings,t=new Bt(r)),t}k(r){Ne(this._$AH)||(this._$AH=[],this._$AR());let t=this._$AH,e,s=0;for(let i of r)s===t.length?t.push(e=new o(this.O(Ft()),this.O(Ft()),this,this.options)):e=t[s],e._$AI(i),s++;s<t.length&&(this._$AR(e&&e._$AB.nextSibling,s),t.length=s);}_$AR(r=this._$AA.nextSibling,t){for(this._$AP?.(false,true,t);r!==this._$AB;){let e=Es(r).nextSibling;Es(r).remove(),r=e;}}setConnected(r){this._$AM===void 0&&(this._$Cv=r,this._$AP?.(r));}},gt=class{get tagName(){return this.element.tagName}get _$AU(){return this._$AM._$AU}constructor(r,t,e,s,i){this.type=1,this._$AH=d,this._$AN=void 0,this.element=r,this.name=t,this._$AM=s,this.options=i,e.length>2||e[0]!==""||e[1]!==""?(this._$AH=Array(e.length-1).fill(new String),this.strings=e):this._$AH=d;}_$AI(r,t=this,e,s){let i=this.strings,n=false;if(i===void 0)r=vt(this,r,t,0),n=!Gt(r)||r!==this._$AH&&r!==z,n&&(this._$AH=r);else {let a=r,c,p;for(r=i[0],c=0;c<i.length-1;c++)p=vt(this,a[e+c],t,c),p===z&&(p=this._$AH[c]),n||(n=!Gt(p)||p!==this._$AH[c]),p===d?r=d:r!==d&&(r+=(p??"")+i[c+1]),this._$AH[c]=p;}n&&!s&&this.j(r);}j(r){r===d?this.element.removeAttribute(this.name):this.element.setAttribute(this.name,r??"");}},Le=class extends gt{constructor(){super(...arguments),this.type=3;}j(r){this.element[this.name]=r===d?void 0:r;}},Me=class extends gt{constructor(){super(...arguments),this.type=4;}j(r){this.element.toggleAttribute(this.name,!!r&&r!==d);}},ke=class extends gt{constructor(r,t,e,s,i){super(r,t,e,s,i),this.type=5;}_$AI(r,t=this){if((r=vt(this,r,t,0)??d)===z)return;let e=this._$AH,s=r===d&&e!==d||r.capture!==e.capture||r.once!==e.once||r.passive!==e.passive,i=r!==d&&(e===d||s);s&&this.element.removeEventListener(this.name,this,e),i&&this.element.addEventListener(this.name,this,r),this._$AH=r;}handleEvent(r){typeof this._$AH=="function"?this._$AH.call(this.options?.host??this.element,r):this._$AH.handleEvent(r);}},Oe=class{constructor(r,t,e){this.element=r,this.type=6,this._$AN=void 0,this._$AM=t,this.options=e;}get _$AU(){return this._$AM._$AU}_$AI(r){vt(this,r);}};var Yr=Ut.litHtmlPolyfillSupport;Yr?.(Bt,Wt),(Ut.litHtmlVersions??(Ut.litHtmlVersions=[])).push("3.3.2");var Is=(o,r,t)=>{let e=t?.renderBefore??r,s=e._$litPart$;if(s===void 0){let i=t?.renderBefore??null;e._$litPart$=s=new Wt(r.insertBefore(Ft(),i),i,void 0,t??{});}return s._$AI(o),s};var jt=globalThis,E=class extends K{constructor(){super(...arguments),this.renderOptions={host:this},this._$Do=void 0;}createRenderRoot(){var t;let r=super.createRenderRoot();return (t=this.renderOptions).renderBefore??(t.renderBefore=r.firstChild),r}update(r){let t=this.render();this.hasUpdated||(this.renderOptions.isConnected=this.isConnected),super.update(r),this._$Do=Is(t,this.renderRoot,this.renderOptions);}connectedCallback(){super.connectedCallback(),this._$Do?.setConnected(true);}disconnectedCallback(){super.disconnectedCallback(),this._$Do?.setConnected(false);}render(){return z}};E._$litElement$=true,E.finalized=true,jt.litElementHydrateSupport?.({LitElement:E});var Xr=jt.litElementPolyfillSupport;Xr?.({LitElement:E});(jt.litElementVersions??(jt.litElementVersions=[])).push("4.2.2");var _=o=>(r,t)=>{t!==void 0?t.addInitializer(()=>{customElements.define(o,r);}):customElements.define(o,r);};var Vr={attribute:true,type:String,converter:Ht,reflect:false,hasChanged:le},Kr=(o=Vr,r,t)=>{let{kind:e,metadata:s}=t,i=globalThis.litPropertyMetadata.get(s);if(i===void 0&&globalThis.litPropertyMetadata.set(s,i=new Map),e==="setter"&&((o=Object.create(o)).wrapped=true),i.set(t.name,o),e==="accessor"){let{name:n}=t;return {set(a){let c=r.get.call(this);r.set.call(this,a),this.requestUpdate(n,c,o,true,a);},init(a){return a!==void 0&&this.C(n,void 0,o,a),a}}}if(e==="setter"){let{name:n}=t;return function(a){let c=this[n];r.call(this,a),this.requestUpdate(n,c,o,true,a);}}throw Error("Unsupported decorator location: "+e)};function L(o){return (r,t)=>typeof t=="object"?Kr(o,r,t):((e,s,i)=>{let n=s.hasOwnProperty(i);return s.constructor.createProperty(i,e),n?Object.getOwnPropertyDescriptor(s,i):void 0})(o,r,t)}function b(o){return L({...o,state:true,attribute:false})}var Qt=class extends E{constructor(){super(...arguments);this.method="";}createRenderRoot(){return this}render(){let t=this.method.toUpperCase();return l`<span class="method-badge method-badge-${t}">${t}</span>`}};u([L()],Qt.prototype,"method",2),Qt=u([_("bk-method-badge")],Qt);var q="/__brakit/api",U="/__brakit",T={flows:`${q}/flows`,requests:`${q}/requests`,events:`${q}/events`,clear:`${q}/clear`,fetches:`${q}/fetches`,errors:`${q}/errors`,logs:`${q}/logs`,queries:`${q}/queries`,metricsLive:`${q}/metrics/live`,insights:`${q}/insights`,tab:`${q}/tab`,activity:`${q}/activity`,graph:`${q}/graph`};var bt="polling",pe="static",zr="auth-handshake",Jr="auth-check",Zr="middleware",Yt={[zr]:1,[Jr]:1,[Zr]:1};var he="fetch";var ue="error_event",me="query",fe="issues";var Pe={overview:"Overview",actions:"Actions",insights:"Insights",performance:"Performance",graph:"Graph",explorer:"Explorer",requests:"Requests",fetches:"Server Fetches",queries:"Queries",errors:"Errors",logs:"Logs",security:"Security"},He={overview:"Live summary of your application",actions:"User actions captured as sequences of HTTP requests",insights:"Security findings, error patterns, and issue tracking",performance:"Endpoint health and response time trends",graph:"Runtime dependency graph of your application",explorer:"Browse raw requests, fetches, queries, logs, and errors",requests:"All HTTP requests proxied through brakit",fetches:"Outbound HTTP calls made by your server to external services",queries:"Database queries executed during request handling",errors:"Unhandled exceptions and errors thrown by your application",logs:"Console output from your application",security:"Security findings and recommendations"},ve=[{key:"requests",label:"Requests"},{key:"fetches",label:"Fetches"},{key:"queries",label:"Queries"},{key:"logs",label:"Logs"},{key:"errors",label:"Errors"}];var Ls=new Set(["exposed-secret","token-in-url","stack-trace-leak","error-info-leak","insecure-cookie","sensitive-logs","cors-credentials","response-pii-leak"]),Ms=new Set(["slow-endpoint","n1","high-query-count"]);function Xt(o){let r=o.issue.rule;return Ls.has(r)?"security":Ms.has(r)?"performance":"reliability"}var N={CLEAR_CONFIRM:"This will clear all data including performance metrics history. Continue?",CLEARED_TOAST:"Cleared",EMPTY_TITLE:"Waiting for requests...",EMPTY_SUBTITLE_OVERVIEW:"Start using your app to see your dashboard here",ALL_CLEAR:"All clear",ALL_CLEAR_DETAIL:"No issues detected",NO_ACTIONS:"No actions captured yet",NO_REQUEST_DATA:"No request data yet",ALL_FAST:"All fast",NO_SLOW_ENDPOINTS:"No slow endpoints detected",ZERO_ERRORS:"0 errors",ALL_REQUESTS_OK:"All requests successful",BUILD_GRAPH:"Navigate your app to build the graph",REVIEW_RECOMMENDED:"review recommended"};var Fe=100,yt=300,$t=800,Ge=2e3,Be=100,We=50,je=500;var rt="__all__",ti={SELECT:"var(--blue)",INSERT:"var(--green)",UPDATE:"var(--amber)",DELETE:"var(--red)",OTHER:"var(--text-muted)"},be=ti,ei={error:"var(--red)",warn:"var(--amber)",info:"var(--blue)",debug:"var(--text-muted)",log:"var(--text-dim)"},qs=ei,Xe=["#2563eb","#7c3aed","#16a34a","#d97706","#dc2626","#0891b2","#ea580c","#c026d3","#059669","#db2777"],Vt={green:"#4ade80",amber:"#fbbf24",red:"#f87171"},xt=[{max:Fe,label:"Fast",color:"var(--green)",bg:"var(--green-bg)",border:"var(--green-border)"},{max:yt,label:"Good",color:"var(--green)",bg:"var(--green-bg-subtle)",border:"var(--green-border-subtle)"},{max:$t,label:"OK",color:"var(--amber)",bg:"var(--amber-bg)",border:"var(--amber-border)"},{max:Ge,label:"Slow",color:"var(--red)",bg:"var(--red-bg)",border:"var(--red-border)"},{max:1/0,label:"Critical",color:"var(--red)",bg:"var(--red-bg)",border:"var(--red-border)"}],Us="rgba(228,228,231,0.8)",Ve="rgba(113,113,122,0.7)",Fs="10px monospace",Ke="9px monospace";var Gs={top:16,right:16,bottom:28,left:52},Bs={fetch:"var(--blue)",log:"var(--text-muted)",error:"var(--red)",query:"var(--accent)"},Ws={fetch:"FETCH",log:"LOG",error:"ERROR",query:"QUERY"},js=new Set(["cookie","set-cookie","authorization","proxy-authorization","x-api-key","x-auth-token"]),Qs={400:"Bad Request",401:"Unauthorized",403:"Forbidden",404:"Not Found",405:"Method Not Allowed",408:"Timeout",409:"Conflict",422:"Unprocessable",429:"Too Many Requests",500:"Internal Server Error",502:"Bad Gateway",503:"Service Unavailable",504:"Gateway Timeout"},Ys=new Set(["host","connection","accept-encoding"]),Y={critical:{icon:"\u2717",cls:"critical",sort:0},warning:{icon:"\u26A0",cls:"warning",sort:1},info:{icon:"\u2139",cls:"info",sort:2}};function y(o){return o<1e3?o+"ms":(o/1e3).toFixed(1)+"s"}function ot(o){return !o||o===0?"":o<1024?o+"b":(o/1024).toFixed(1)+"kb"}function it(o){return o?o.replaceAll("&","&").replaceAll("<","<").replaceAll(">",">").replaceAll('"',"""):""}function St(o){return o>=500?"status-pill-5xx":o>=400?"status-pill-4xx":o>=300?"status-pill-3xx":"status-pill-2xx"}function Xs(o){return Qs[o]||(o>=500?"Server Error":o>=400?"Client Error":"OK")}function si(o,r){if(js.has(o.toLowerCase())){let t=String(r);return t.length<=8?"****":t.slice(0,4)+"..."+t.slice(-4)+" ("+t.length+" chars)"}return String(r)}function Tt(o){return !o||Object.keys(o).length===0?'<span style="color:var(--text-muted)">No headers</span>':Object.entries(o).map(([r,t])=>'<span class="json-key">'+it(r)+"</span>: "+it(si(r,t))).join(`
|
|
909
|
+
`)}function dt(o){if(!o)return '<span style="color:var(--text-muted)">No body</span>';try{let r=JSON.parse(o);return ri(JSON.stringify(r,null,2))}catch{return it(o)}}function ri(o){return it(o).replace(/("(?:[^"\\]|\\.)*")(\s*:)?|\b(true|false)\b|\bnull\b|(-?\d+\.?\d*(?:[eE][+-]?\d+)?)/g,(r,t,e,s,i)=>t?e?'<span class="json-key">'+t+"</span>"+e:'<span class="json-str">'+t+"</span>":s?'<span class="json-bool">'+r+"</span>":i?'<span class="json-num">'+r+"</span>":r==="null"?'<span class="json-null">null</span>':r)}var Kt=class extends E{constructor(){super(...arguments);this.code=0;}createRenderRoot(){return this}render(){let t=St(this.code);return l`<span class="status-pill ${t}">${this.code}</span>`}};u([L({type:Number})],Kt.prototype,"code",2),Kt=u([_("bk-status-pill")],Kt);var zt=class extends E{constructor(){super(...arguments);this.ms=0;}createRenderRoot(){return this}render(){return l`<span class="req-duration">${y(this.ms)}</span>`}};u([L({type:Number})],zt.prototype,"ms",2),zt=u([_("bk-duration-label")],zt);var wt=class extends E{constructor(){super(...arguments);this.title="";this.subtitle="";}createRenderRoot(){return this}render(){return l`
|
|
899
910
|
<div class="empty">
|
|
900
911
|
<span class="empty-title">${this.title}</span>
|
|
901
912
|
<span class="empty-sub">${this.subtitle}</span>
|
|
902
913
|
</div>
|
|
903
|
-
`}};u([L()],wt.prototype,"title",2),u([L()],wt.prototype,"subtitle",2),wt=u([
|
|
914
|
+
`}};u([L()],wt.prototype,"title",2),u([L()],wt.prototype,"subtitle",2),wt=u([_("bk-empty-state")],wt);var D=class extends E{constructor(){super(...arguments);this.message="";this.visible=false;}createRenderRoot(){return this}static show(t){let e=document.querySelector("bk-toast");e&&e.showMessage(t);}showMessage(t){this.hideTimer&&clearTimeout(this.hideTimer),this.message=t,this.visible=true,this.hideTimer=setTimeout(()=>{this.visible=false;},2e3);}render(){return l`<div class="toast ${this.visible?"show":""}">${this.message}</div>`}};u([b()],D.prototype,"message",2),u([b()],D.prototype,"visible",2),D=u([_("bk-toast")],D);var pt=class extends E{constructor(){super(...arguments);this.text="";this.label="Copy";this.toastMessage="Copied";}createRenderRoot(){return this}async copy(t){t.stopPropagation();try{await navigator.clipboard.writeText(this.text),D.show(this.toastMessage);}catch{}}render(){return l`<button class="query-detail-copy" @click=${this.copy}>${this.label}</button>`}};u([L()],pt.prototype,"text",2),u([L()],pt.prototype,"label",2),u([L({attribute:"toast-message"})],pt.prototype,"toastMessage",2),pt=u([_("bk-copy-button")],pt);var ht=class extends E{constructor(){super(...arguments);this.value="";this.label="";this.color="";}createRenderRoot(){return this}render(){return l`
|
|
904
915
|
<div class="fetch-stat">
|
|
905
916
|
<span class="fetch-stat-value" style="color:${this.color}">${this.value}</span>
|
|
906
917
|
<span class="fetch-stat-label">${this.label}</span>
|
|
907
918
|
</div>
|
|
908
|
-
`}};u([L()],ht.prototype,"value",2),u([L()],ht.prototype,"label",2),u([L()],ht.prototype,"color",2),ht=u([
|
|
919
|
+
`}};u([L()],ht.prototype,"value",2),u([L()],ht.prototype,"label",2),u([L()],ht.prototype,"color",2),ht=u([_("bk-stat-card")],ht);var nt=class extends Event{constructor(r,t,e,s){super("context-request",{bubbles:true,composed:true}),this.context=r,this.contextTarget=t,this.callback=e,this.subscribe=s??false;}};var Rt=class{constructor(r,t,e,s){if(this.subscribe=false,this.provided=false,this.value=void 0,this.t=(i,n)=>{this.unsubscribe&&(this.unsubscribe!==n&&(this.provided=false,this.unsubscribe()),this.subscribe||this.unsubscribe()),this.value=i,this.host.requestUpdate(),this.provided&&!this.subscribe||(this.provided=true,this.callback&&this.callback(i,n)),this.unsubscribe=n;},this.host=r,t.context!==void 0){let i=t;this.context=i.context,this.callback=i.callback,this.subscribe=i.subscribe??false;}else this.context=t,this.callback=e,this.subscribe=s??false;this.host.addController(this);}hostConnected(){this.dispatchRequest();}hostDisconnected(){this.unsubscribe&&(this.unsubscribe(),this.unsubscribe=void 0);}dispatchRequest(){this.host.dispatchEvent(new nt(this.context,this.host,this.t,this.subscribe));}};var Ee=class{get value(){return this.o}set value(r){this.setValue(r);}setValue(r,t=false){let e=t||!Object.is(r,this.o);this.o=r,e&&this.updateObservers();}constructor(r){this.subscriptions=new Map,this.updateObservers=()=>{for(let[t,{disposer:e}]of this.subscriptions)t(this.o,e);},r!==void 0&&(this.value=r);}addCallback(r,t,e){if(!e)return void r(this.value);this.subscriptions.has(r)||this.subscriptions.set(r,{disposer:()=>{this.subscriptions.delete(r);},consumerHost:t});let{disposer:s}=this.subscriptions.get(r);r(this.value,s);}clearCallbacks(){this.subscriptions.clear();}};var ze=class extends Event{constructor(r,t){super("context-provider",{bubbles:true,composed:true}),this.context=r,this.contextTarget=t;}},At=class extends Ee{constructor(r,t,e){super(t.context!==void 0?t.initialValue:e),this.onContextRequest=s=>{if(s.context!==this.context)return;let i=s.contextTarget??s.composedPath()[0];i!==this.host&&(s.stopPropagation(),this.addCallback(s.callback,i,s.subscribe));},this.onProviderRequest=s=>{if(s.context!==this.context||(s.contextTarget??s.composedPath()[0])===this.host)return;let i=new Set;for(let[n,{consumerHost:a}]of this.subscriptions)i.has(n)||(i.add(n),a.dispatchEvent(new nt(this.context,a,n,true)));s.stopPropagation();},this.host=r,t.context!==void 0?this.context=t.context:this.context=t,this.attachListeners(),this.host.addController?.(this);}attachListeners(){this.host.addEventListener("context-request",this.onContextRequest),this.host.addEventListener("context-provider",this.onProviderRequest);}hostConnected(){this.host.dispatchEvent(new ze(this.context,this.host));}};function Je({context:o}){return (r,t)=>{let e=new WeakMap;if(typeof t=="object")return {get(){return r.get.call(this)},set(s){return e.get(this).setValue(s),r.set.call(this,s)},init(s){return e.set(this,new At(this,{context:o,initialValue:s})),s}};{r.constructor.addInitializer((n=>{e.set(n,new At(n,{context:o}));}));let s=Object.getOwnPropertyDescriptor(r,t),i;if(s===void 0){let n=new WeakMap;i={get(){return n.get(this)},set(a){e.get(this).setValue(a),n.set(this,a);},configurable:true,enumerable:true};}else {let n=s.set;i={...s,set(a){e.get(this).setValue(a),n?.call(this,a);}};}return void Object.defineProperty(r,t,i)}}}function C({context:o,subscribe:r}){return (t,e)=>{typeof e=="object"?e.addInitializer((function(){new Rt(this,{context:o,callback:s=>{t.set.call(this,s);},subscribe:r});})):t.constructor.addInitializer((s=>{new Rt(s,{context:o,callback:i=>{s[e]=i;},subscribe:r});}));}}var A="dashboard-store",ye=class extends EventTarget{constructor(){super(...arguments);this._state={flows:[],requests:[],fetches:[],errors:[],logs:[],queries:[],issues:[],metrics:[],viewMode:"simple",activeView:"overview"};}get state(){return this._state}setState(t,e){this._state={...this._state,[t]:e},this.notify(t);}setFlows(t){this.setState("flows",t);}setRequests(t){this.setState("requests",t);}setFetches(t){this.setState("fetches",t);}setErrors(t){this.setState("errors",t);}setLogs(t){this.setState("logs",t);}setQueries(t){this.setState("queries",t);}setIssues(t){this.setState("issues",t);}setMetrics(t){this.setState("metrics",t);}prependRequest(t){let e=[t,...this._state.requests.slice(0,999)];this._state={...this._state,requests:e},this.notify("requests");}prependFetch(t){let e=[t,...this._state.fetches.slice(0,999)];this._state={...this._state,fetches:e},this.notify("fetches");}prependError(t){let e=[t,...this._state.errors.slice(0,999)];this._state={...this._state,errors:e},this.notify("errors");}prependLog(t){let e=[t,...this._state.logs.slice(0,999)];this._state={...this._state,logs:e},this.notify("logs");}prependQuery(t){let e=[t,...this._state.queries.slice(0,999)];this._state={...this._state,queries:e},this.notify("queries");}setActiveView(t){this.setState("activeView",t);}setViewMode(t){this.setState("viewMode",t);}clearAll(){this._state={...this._state,flows:[],requests:[],fetches:[],errors:[],logs:[],queries:[],issues:[],metrics:[]},this.notify("all");}notify(t){this.dispatchEvent(new CustomEvent("state-changed",{detail:t}));}};var Ct=class extends E{constructor(){super(...arguments);this.expandedIdx=-1;}createRenderRoot(){return this}connectedCallback(){super.connectedCallback(),this.store.addEventListener("state-changed",()=>this.requestUpdate());}toggleError(t){this.expandedIdx=this.expandedIdx===t?-1:t;}renderErrorRow(t,e){let s=new Date(t.timestamp).toLocaleTimeString(),i=this.expandedIdx===e;return l`
|
|
909
920
|
<div
|
|
910
921
|
class="req-row tel-clickable ${i?"expanded":""}"
|
|
911
922
|
@click=${()=>this.toggleError(e)}
|
|
@@ -914,7 +925,7 @@ span.perf-breakdown-dot.perf-breakdown-app{background:var(--breakdown-app)}
|
|
|
914
925
|
<span class="tel-message" title=${t.message}>${t.message}</span>
|
|
915
926
|
<span class="tel-timestamp">${s}</span>
|
|
916
927
|
</div>
|
|
917
|
-
${i&&t.stack?l`<div class="error-stack">${t.stack}</div>`:
|
|
928
|
+
${i&&t.stack?l`<div class="error-stack">${t.stack}</div>`:d}
|
|
918
929
|
`}render(){let t=this.store.state.errors;return t.length===0?l`<bk-empty-state
|
|
919
930
|
title="No errors"
|
|
920
931
|
subtitle="No errors have been captured yet"
|
|
@@ -927,15 +938,15 @@ span.perf-breakdown-dot.perf-breakdown-app{background:var(--breakdown-app)}
|
|
|
927
938
|
<div id="error-list">
|
|
928
939
|
${t.map((e,s)=>this.renderErrorRow(e,s))}
|
|
929
940
|
</div>
|
|
930
|
-
`}};u([
|
|
941
|
+
`}};u([C({context:A})],Ct.prototype,"store",2),u([b()],Ct.prototype,"expandedIdx",2),Ct=u([_("bk-errors-view")],Ct);var Jt=class extends E{createRenderRoot(){return this}connectedCallback(){super.connectedCallback(),this.store.addEventListener("state-changed",()=>this.requestUpdate());}renderAnalysis(r){if(r.length===0)return d;let t={error:0,warn:0,info:0,debug:0,log:0};for(let e of r)t[e.level]!==void 0&&t[e.level]++;return l`
|
|
931
942
|
<div id="log-analysis">
|
|
932
943
|
<div class="fetch-summary">
|
|
933
944
|
<bk-stat-card value=${String(r.length)} label="Total Logs"></bk-stat-card>
|
|
934
|
-
${t.error>0?l`<bk-stat-card value=${String(t.error)} label="Errors" color="var(--red)"></bk-stat-card>`:
|
|
935
|
-
${t.warn>0?l`<bk-stat-card value=${String(t.warn)} label="Warnings" color="var(--amber)"></bk-stat-card>`:
|
|
945
|
+
${t.error>0?l`<bk-stat-card value=${String(t.error)} label="Errors" color="var(--red)"></bk-stat-card>`:d}
|
|
946
|
+
${t.warn>0?l`<bk-stat-card value=${String(t.warn)} label="Warnings" color="var(--amber)"></bk-stat-card>`:d}
|
|
936
947
|
<bk-stat-card value=${String(t.info)} label="Info"></bk-stat-card>
|
|
937
|
-
${t.debug>0?l`<bk-stat-card value=${String(t.debug)} label="Debug"></bk-stat-card>`:
|
|
938
|
-
${t.log>0?l`<bk-stat-card value=${String(t.log)} label="Log"></bk-stat-card>`:
|
|
948
|
+
${t.debug>0?l`<bk-stat-card value=${String(t.debug)} label="Debug"></bk-stat-card>`:d}
|
|
949
|
+
${t.log>0?l`<bk-stat-card value=${String(t.log)} label="Log"></bk-stat-card>`:d}
|
|
939
950
|
</div>
|
|
940
951
|
</div>
|
|
941
952
|
`}renderLogRow(r){let t=new Date(r.timestamp).toLocaleTimeString();return l`
|
|
@@ -957,7 +968,7 @@ span.perf-breakdown-dot.perf-breakdown-app{background:var(--breakdown-app)}
|
|
|
957
968
|
<div id="log-list">
|
|
958
969
|
${r.map(t=>this.renderLogRow(t))}
|
|
959
970
|
</div>
|
|
960
|
-
`}};u([
|
|
971
|
+
`}};u([C({context:A})],Jt.prototype,"store",2),Jt=u([_("bk-logs-view")],Jt);var Vs={CHILD:2},Ks=o=>(...r)=>({_$litDirective$:o,values:r}),$e=class{constructor(r){}get _$AU(){return this._$AM._$AU}_$AT(r,t,e){this._$Ct=r,this._$AM=t,this._$Ci=e;}_$AS(r,t){return this.update(r,t)}update(r,t){return this.render(...t)}};var Zt=class extends $e{constructor(r){if(super(r),this.it=d,r.type!==Vs.CHILD)throw Error(this.constructor.directiveName+"() can only be used in child bindings")}render(r){if(r===d||r==null)return this._t=void 0,this.it=r;if(r===z)return r;if(typeof r!="string")throw Error(this.constructor.directiveName+"() called with a non-string value");if(r===this.it)return this._t;this.it=r;let t=[r];return t.raw=t,this._t={_$litType$:this.constructor.resultType,strings:t,values:[]}}};Zt.directiveName="unsafeHTML",Zt.resultType=1;var G=Ks(Zt);var oi=new Set(["SELECT","FROM","WHERE","AND","OR","INSERT","INTO","VALUES","UPDATE","SET","DELETE","JOIN","LEFT","RIGHT","INNER","OUTER","ON","GROUP","BY","ORDER","HAVING","LIMIT","OFFSET","AS","IN","NOT","NULL","IS","LIKE","BETWEEN","EXISTS","CASE","WHEN","THEN","ELSE","END","COUNT","SUM","AVG","MIN","MAX","DISTINCT","UNION","ALL","CREATE","TABLE","ALTER","DROP","INDEX","RETURNING","WITH","RECURSIVE","OVER","PARTITION","WINDOW","FETCH","NEXT","ROWS","ONLY","CAST","COALESCE","NULLIF","EXTRACT","INTERVAL","TRUE","FALSE","ASC","DESC","USING","NATURAL","CROSS","FULL","ROLLBACK","COMMIT","BEGIN","TRANSACTION","SAVEPOINT","RELEASE"]);function zs(o){let r=o.trimStart().split(/\s/)[0];return r?r.toUpperCase():"?"}function Js(o){let r=o.replace(/\s+/g," ").trim(),t=r.match(/\bFROM\s+["'`]?(\w+)["'`]?/i);if(t)return t[1];let e=r.match(/\bINTO\s+["'`]?(\w+)["'`]?/i);if(e)return e[1];let s=r.match(/\bUPDATE\s+["'`]?(\w+)["'`]?/i);return s?s[1]:""}function Zs(o){return it(o).replace(/\b\w+\b/g,r=>oi.has(r.toUpperCase())?'<span class="sql-kw">'+r+"</span>":r)}var It=class extends E{constructor(){super(...arguments);this.expandedIdx=-1;}createRenderRoot(){return this}connectedCallback(){super.connectedCallback(),this.store.addEventListener("state-changed",()=>this.requestUpdate());}toggleQuery(t){this.expandedIdx=this.expandedIdx===t?-1:t;}queryDuration(t){return t===0?"<1ms":y(t)}getQueryInfo(t){let e=(t.normalizedOp||t.operation||(t.sql?zs(t.sql):"?")).toUpperCase(),s=t.table||t.model||(t.sql?Js(t.sql):""),i=t.sql||e+" "+s;return {op:e,table:s,sqlText:i}}renderQueryRow(t,e){let{op:s,table:i,sqlText:n}=this.getQueryInfo(t),a=be[s]||"var(--text-dim)",c=t.durationMs>Be,p=t.sql||s+" "+i,h=this.expandedIdx===e;return l`
|
|
961
972
|
<div>
|
|
962
973
|
<div
|
|
963
974
|
class="req-row query-row tel-clickable ${h?"expanded":""}"
|
|
@@ -965,14 +976,14 @@ span.perf-breakdown-dot.perf-breakdown-app{background:var(--breakdown-app)}
|
|
|
965
976
|
>
|
|
966
977
|
<span class="query-op" title=${s} style="color:${a}">${s}</span>
|
|
967
978
|
<span class="query-table" title=${i}>${i}</span>
|
|
968
|
-
<span class="query-preview" title=${
|
|
979
|
+
<span class="query-preview" title=${p}>${p}</span>
|
|
969
980
|
<span class="query-dur${c?" query-slow":""}">${this.queryDuration(t.durationMs)}</span>
|
|
970
981
|
</div>
|
|
971
982
|
<div class="query-detail ${h?"open":""}">
|
|
972
983
|
${h?l`
|
|
973
984
|
<pre class="query-detail-sql">${G(Zs(n))}</pre>
|
|
974
985
|
<bk-copy-button .text=${n} label="Copy"></bk-copy-button>
|
|
975
|
-
`:
|
|
986
|
+
`:d}
|
|
976
987
|
</div>
|
|
977
988
|
</div>
|
|
978
989
|
`}render(){let t=this.store.state.queries;return t.length===0?l`<bk-empty-state
|
|
@@ -988,12 +999,12 @@ span.perf-breakdown-dot.perf-breakdown-app{background:var(--breakdown-app)}
|
|
|
988
999
|
<div id="query-list">
|
|
989
1000
|
${t.map((e,s)=>this.renderQueryRow(e,s))}
|
|
990
1001
|
</div>
|
|
991
|
-
`}};u([
|
|
1002
|
+
`}};u([C({context:A})],It.prototype,"store",2),u([b()],It.prototype,"expandedIdx",2),It=u([_("bk-queries-view")],It);function Ze(o){return o.replaceAll("'","'\\''")}function ni(o,r){let t=Object.entries(o.headers||{}).filter(([i])=>!Ys.has(i)).map(([i,n])=>`-H '${Ze(i)}: ${Ze(n)}'`).join(" "),e=o.requestBody?` -d '${Ze(o.requestBody)}'`:"",s=r?`http://localhost:${r}`:"";return `curl -X ${o.method} ${t}${e} '${s}${o.url}'`}function Lt(o){let r=window.__BRAKIT_CONFIG__?.port??"",t=ni(o,r);navigator.clipboard.writeText(t).then(()=>D.show("Copied cURL command"));}var Mt=class extends E{constructor(){super(...arguments);this.expandedId=null;}createRenderRoot(){return this}connectedCallback(){super.connectedCallback(),this.store.addEventListener("state-changed",()=>this.requestUpdate());}toggleRequest(t){this.expandedId=this.expandedId===t?null:t;}handleCopyAsCurl(t,e){e.stopPropagation(),Lt(t);}renderDetail(t){return l`
|
|
992
1003
|
<div class="detail-meta">
|
|
993
1004
|
<span><bk-method-badge .method=${t.method}></bk-method-badge> ${t.url}</span>
|
|
994
1005
|
<span><bk-status-pill .code=${t.statusCode}></bk-status-pill></span>
|
|
995
1006
|
<span>${t.durationMs}ms</span>
|
|
996
|
-
${t.responseSize?l`<span>${ot(t.responseSize)}</span>`:
|
|
1007
|
+
${t.responseSize?l`<span>${ot(t.responseSize)}</span>`:d}
|
|
997
1008
|
</div>
|
|
998
1009
|
<div class="request-timeline tl-hidden" data-request-id=${t.id} data-request-started=${String(t.startedAt)}></div>
|
|
999
1010
|
<div class="detail-grid">
|
|
@@ -1015,7 +1026,7 @@ span.perf-breakdown-dot.perf-breakdown-app{background:var(--breakdown-app)}
|
|
|
1015
1026
|
<span class="req-size">${ot(t.responseSize)}</span>
|
|
1016
1027
|
</div>
|
|
1017
1028
|
</div>
|
|
1018
|
-
<div class="req-detail ${e?"open":""}">${e?this.renderDetail(t):
|
|
1029
|
+
<div class="req-detail ${e?"open":""}">${e?this.renderDetail(t):d}</div>
|
|
1019
1030
|
`}render(){let t=this.store.state.requests.filter(e=>!e.path?.startsWith(U));return t.length===0?l`<bk-empty-state title="No requests" subtitle="No HTTP requests have been captured yet"></bk-empty-state>`:l`
|
|
1020
1031
|
<div class="col-header">
|
|
1021
1032
|
<span style="width:60px">Method</span>
|
|
@@ -1025,7 +1036,7 @@ span.perf-breakdown-dot.perf-breakdown-app{background:var(--breakdown-app)}
|
|
|
1025
1036
|
<span style="width:60px;text-align:right">Size</span>
|
|
1026
1037
|
</div>
|
|
1027
1038
|
<div id="request-list">${t.map(e=>this.renderRequestRow(e))}</div>
|
|
1028
|
-
`}};u([
|
|
1039
|
+
`}};u([C({context:A})],Mt.prototype,"store",2),u([b()],Mt.prototype,"expandedId",2),Mt=u([_("bk-requests-view")],Mt);var te=class extends E{createRenderRoot(){return this}connectedCallback(){super.connectedCallback(),this.store.addEventListener("state-changed",()=>this.requestUpdate());}buildGroups(r,t){let e=new Map;for(let i of t)e.set(i.id,i);let s={};for(let i of r){let n=i.method+" "+i.url;s[n]||(s[n]={method:i.method,url:i.url,count:0,totalDur:0,maxDur:0,errors:0,callers:{},statusCodes:{},firstTs:i.timestamp,lastTs:i.timestamp});let a=s[n];if(a.count++,a.totalDur+=i.durationMs,i.durationMs>a.maxDur&&(a.maxDur=i.durationMs),i.statusCode>=400&&a.errors++,a.statusCodes[i.statusCode]=(a.statusCodes[i.statusCode]||0)+1,i.timestamp<a.firstTs&&(a.firstTs=i.timestamp),i.timestamp>a.lastTs&&(a.lastTs=i.timestamp),i.parentRequestId){let c=e.get(i.parentRequestId);c&&(a.callers[c.method+" "+(c.path||c.url)]=1);}}return Object.values(s).sort((i,n)=>n.count-i.count)}renderSummary(r){let t=new Set,e=0,s=0;for(let n of r)t.add(n.url),n.statusCode>=400&&e++,s+=n.durationMs;let i=Math.round(s/r.length);return l`
|
|
1029
1040
|
<div class="fetch-summary">
|
|
1030
1041
|
<bk-stat-card value=${String(r.length)} label="Total Fetches"></bk-stat-card>
|
|
1031
1042
|
<bk-stat-card value=${String(t.size)} label="Unique URLs"></bk-stat-card>
|
|
@@ -1037,7 +1048,7 @@ span.perf-breakdown-dot.perf-breakdown-app{background:var(--breakdown-app)}
|
|
|
1037
1048
|
<div class="fetch-group-header">
|
|
1038
1049
|
<bk-method-badge .method=${r.method}></bk-method-badge>
|
|
1039
1050
|
<span class="fetch-group-url" title=${r.url}>${r.url}</span>
|
|
1040
|
-
${n>0?l`<bk-status-pill .code=${n}></bk-status-pill>`:
|
|
1051
|
+
${n>0?l`<bk-status-pill .code=${n}></bk-status-pill>`:d}
|
|
1041
1052
|
<span class="fetch-group-count">${r.count}x</span>
|
|
1042
1053
|
</div>
|
|
1043
1054
|
<div class="fetch-group-meta">
|
|
@@ -1051,14 +1062,14 @@ span.perf-breakdown-dot.perf-breakdown-app{background:var(--breakdown-app)}
|
|
|
1051
1062
|
<div class="fetch-group-timeline">
|
|
1052
1063
|
<span class="fetch-group-timeline-dot"></span>
|
|
1053
1064
|
<span class="fetch-group-timeline-range">
|
|
1054
|
-
${this.formatTime(r.firstTs)}${r.firstTs!==r.lastTs?l` \u2192 ${this.formatTime(r.lastTs)}`:
|
|
1065
|
+
${this.formatTime(r.firstTs)}${r.firstTs!==r.lastTs?l` \u2192 ${this.formatTime(r.lastTs)}`:d}
|
|
1055
1066
|
</span>
|
|
1056
|
-
</div>`:
|
|
1067
|
+
</div>`:d}
|
|
1057
1068
|
${s.length>0?l`
|
|
1058
1069
|
<div class="fetch-group-callers">
|
|
1059
1070
|
<span class="fetch-group-callers-label">Called by</span>
|
|
1060
1071
|
${s.map(a=>l`<span class="fetch-group-caller-pill">${a}</span>`)}
|
|
1061
|
-
</div>`:
|
|
1072
|
+
</div>`:d}
|
|
1062
1073
|
</div>
|
|
1063
1074
|
`}render(){let r=this.store.state.fetches,t=this.store.state.requests;if(r.length===0)return l`<bk-empty-state title="No fetches" subtitle="No outbound HTTP calls have been captured yet"></bk-empty-state>`;let e=this.buildGroups(r,t);return l`
|
|
1064
1075
|
<div class="fetch-analysis" id="fetch-analysis">
|
|
@@ -1066,9 +1077,9 @@ span.perf-breakdown-dot.perf-breakdown-app{background:var(--breakdown-app)}
|
|
|
1066
1077
|
${e.length>0?l`
|
|
1067
1078
|
<div class="fetch-groups-title">Grouped by URL (${e.length})</div>
|
|
1068
1079
|
<div class="fetch-groups">${e.map(s=>this.renderGroup(s))}</div>
|
|
1069
|
-
`:
|
|
1080
|
+
`:d}
|
|
1070
1081
|
</div>
|
|
1071
|
-
`}};u([
|
|
1082
|
+
`}};u([C({context:A})],te.prototype,"store",2),te=u([_("bk-fetches-view")],te);function tr(o,r){if(r>=400)return "var(--red)";switch(o){case "GET":return "var(--green)";case "POST":return "var(--blue)";case "PUT":case "PATCH":return "var(--amber)";case "DELETE":return "var(--red)";default:return "var(--text-muted)"}}function ts(o){return o==="query"?"var(--accent)":"var(--cyan)"}function di(o){return o.type==="query"||o.type==="fetch"}function pi(o){let r=(o.normalizedOp||o.operation||"QUERY").toUpperCase(),t=o.table||o.model||"";return {label:`${r} ${t}`,tooltip:o.sql||`${r} ${t}`}}function hi(o){return {label:`${o.method} ${o.url}`,tooltip:`${o.method} ${o.url}`}}function ui(o,r,t,e,s,i){let n=o.data.durationMs||0,a,c;if(i){let p=Math.max(o.timestamp-e,0);a=Math.min(p/s*100,95),c=Math.max(n/s*100,1.5);}else {let p=t[0].timestamp,m=t[t.length-1].timestamp-p;a=m>0?(o.timestamp-p)/m*85:r/Math.max(t.length-1,1)*85,c=Math.max(n/s*100,1.5);}return a+c>100&&(c=Math.max(100-a,1.5)),{leftPct:a,widthPct:c}}function mi(o,r){let t=o.timeline.filter(di);if(t.length===0)return [];let e=r.startedAt,s=r.durationMs||1,i=Math.abs(t[0].timestamp-e)<s*10;return t.map((n,a)=>{let c=n.data.durationMs||0,{leftPct:p,widthPct:h}=ui(n,a,t,e,s,i),m=n.type==="query"?pi(n.data):hi(n.data);return {type:n.type,label:m.label,durMs:c,durLabel:y(c),tooltip:m.tooltip,leftPct:p,widthPct:h}})}function sr(o,r){let t=o.requests.filter(a=>!a.isStrictModeDupe);if(t.length===0)return {rows:[],totalMs:0};let e=Math.min(...t.map(a=>a.startedAt)),i=Math.max(...t.map(a=>a.startedAt+a.durationMs))-e;return i===0?{rows:[],totalMs:0}:{rows:t.map(a=>{let c=(a.startedAt-e)/i*100,p=Math.max(a.durationMs/i*100,.5),h=r?.activities?.[a.id],m=h?mi(h,a):[];return {label:`${a.method} ${a.label}`,leftPct:c,widthPct:p,color:tr(a.method,a.statusCode),durMs:a.durationMs,durLabel:y(a.durationMs),tooltip:`${a.method} ${a.label} (${y(a.durationMs)})`,subEvents:m}}),totalMs:i}}function rr(o){let r=o.requests,t=[],e=[],s=[],i=[],n=new Map;for(let p of r){let h=p.label,m=p.pollingDurationMs||p.durationMs;if(!Yt[p.category||""]){if(p.isDuplicate){let f=n.get(h);f?(f.count++,f.wastedMs+=m):n.set(h,{name:h,count:2,wastedMs:m});continue}if(p.statusCode>=400){e.push(h+" ("+Xs(p.statusCode)+")");continue}p.responseSize>51200&&s.push("Large response: "+h+" returned "+ot(p.responseSize)),t.push(h);}}for(let p of n.values())i.push(p);let a="";if(i.length>0){let p=i.map(m=>m.name).join(", "),h=i.reduce((m,f)=>m+f.wastedMs,0);a="Your app fetches "+p+" multiple times on this page. This wastes ~"+y(h)+". Try caching these calls, deduplicating with React Query/SWR, or moving them to a shared layout.";}else e.length>0&&(a="Some requests are failing. Check your API routes and make sure the endpoints exist.");let c=r.filter(p=>p.durationMs>2e3&&p.category!==bt);return c.length>0&&!a&&(a=c.map(p=>p.label).join(", ")+` is taking over ${y(2e3)}. Consider adding caching or optimizing the backend query.`),{successes:t,errors:e,warnings:s,duplicates:i,tip:a}}var X=class extends E{constructor(){super(...arguments);this.expandedFlowIdx=-1;this.expandedSubReqIdx=-1;this.flowDetailTab="insights";this.flowTimeline=null;this.flowTimelineLoading=false;}createRenderRoot(){return this}connectedCallback(){super.connectedCallback(),this.store.addEventListener("state-changed",()=>this.requestUpdate());}get flows(){return this.store.state.flows}get viewMode(){return this.store.state.viewMode}flowDotClass(t){return t.hasErrors?"dot-error":t.redundancyPct>0?"dot-warn":"dot-clean"}flowBadgeInfo(t){if(t.hasErrors){let e=t.requests.filter(s=>s.statusCode>=400).length;return {text:e+" error"+(e!==1?"s":""),cls:"badge-error"}}return t.redundancyPct>0?{text:t.redundancyPct+"% redundant",cls:"badge-warn"}:{text:"clean",cls:"badge-clean"}}toggleFlow(t){this.expandedFlowIdx===t?this.expandedFlowIdx=-1:(this.expandedFlowIdx=t,this.expandedSubReqIdx=-1,this.flowDetailTab="insights",this.flowTimeline=null);}toggleSubReq(t,e){e.stopPropagation(),this.expandedSubReqIdx=this.expandedSubReqIdx===t?-1:t;}toggleBodyBlock(t){t.stopPropagation();let e=t.currentTarget,s=e.parentElement;if(!s)return;e.classList.toggle("open");let i=s.querySelector("pre");i&&i.classList.toggle("open");}switchTab(t,e,s){s.stopPropagation(),this.flowDetailTab=t,t==="timeline"&&!this.flowTimeline&&this.loadFlowTimeline(e);}async loadFlowTimeline(t){if(this.flowTimelineLoading)return;let e=t.requests.map(s=>s.id).filter(Boolean);if(e.length!==0){this.flowTimelineLoading=true;try{let s=await fetch(`${T.activity}?requestIds=${e.join(",")}`);if(!s.ok){this.flowTimelineLoading=!1;return}this.flowTimeline=await s.json();}catch{}this.flowTimelineLoading=false;}}loadTimelineForContainer(t){let e=t.querySelectorAll(".request-timeline");for(let s of e){let i=s.getAttribute("data-request-id");if(i&&!s.hasAttribute("data-loaded")){s.setAttribute("data-loaded","1");let n=document.createElement("bk-timeline-panel");n.setAttribute("request-id",i),n.setAttribute("request-started",s.getAttribute("data-request-started")||"0"),s.appendChild(n),s.classList.remove("tl-hidden");}}}updated(){if(this.expandedFlowIdx>=0&&this.flowDetailTab==="insights"){let t=this.querySelector(".flow-expand.open");t&&this.loadTimelineForContainer(t);}}render(){let t=this.flows;return t.length===0?l`<bk-empty-state
|
|
1072
1083
|
title="No actions yet"
|
|
1073
1084
|
subtitle="Start using your app to see user action flows here"
|
|
1074
1085
|
></bk-empty-state>`:l`
|
|
@@ -1101,7 +1112,7 @@ span.perf-breakdown-dot.perf-breakdown-app{background:var(--breakdown-app)}
|
|
|
1101
1112
|
</div>
|
|
1102
1113
|
</div>
|
|
1103
1114
|
<div class="flow-expand ${s?"open":""}">
|
|
1104
|
-
${s?this.renderFlowDetail(t):
|
|
1115
|
+
${s?this.renderFlowDetail(t):d}
|
|
1105
1116
|
</div>
|
|
1106
1117
|
`}renderFlowDetail(t){let e=this.viewMode==="simple"?"Insights":"Details";return l`
|
|
1107
1118
|
<div class="flow-detail-tabs">
|
|
@@ -1119,7 +1130,7 @@ span.perf-breakdown-dot.perf-breakdown-app{background:var(--breakdown-app)}
|
|
|
1119
1130
|
</button>
|
|
1120
1131
|
</div>
|
|
1121
1132
|
${this.flowDetailTab==="insights"?this.viewMode==="simple"?this.renderFlowInsights(t):this.renderFlowSubReqs(t):this.renderFlowWaterfall(t)}
|
|
1122
|
-
`}renderFlowWaterfall(t){if(this.flowTimelineLoading)return l`<div class="wf-loading">Loading timeline...</div>`;let{rows:e,totalMs:s}=sr(t,this.flowTimeline);if(e.length===0)return
|
|
1133
|
+
`}renderFlowWaterfall(t){if(this.flowTimelineLoading)return l`<div class="wf-loading">Loading timeline...</div>`;let{rows:e,totalMs:s}=sr(t,this.flowTimeline);if(e.length===0)return d;let i=[];for(let n=0;n<=5;n++)i.push(y(s/5*n));return l`
|
|
1123
1134
|
<div class="flow-waterfall">
|
|
1124
1135
|
<div class="wf-time-axis">
|
|
1125
1136
|
${i.map(n=>l`<span>${n}</span>`)}
|
|
@@ -1157,7 +1168,7 @@ span.perf-breakdown-dot.perf-breakdown-app{background:var(--breakdown-app)}
|
|
|
1157
1168
|
</div>
|
|
1158
1169
|
<div class="wf-sub-dur">${e.durLabel}</div>
|
|
1159
1170
|
</div>
|
|
1160
|
-
`):
|
|
1171
|
+
`):d}
|
|
1161
1172
|
</div>
|
|
1162
1173
|
`}renderFlowInsights(t){let e=rr(t),s=e.errors.length>0||e.duplicates.length>0||e.warnings.length>0||!!e.tip;return l`
|
|
1163
1174
|
<div>
|
|
@@ -1177,11 +1188,11 @@ span.perf-breakdown-dot.perf-breakdown-app{background:var(--breakdown-app)}
|
|
|
1177
1188
|
${e.warnings.map(i=>l`<div class="insight-line insight-warn">⚠ ${i}</div>`)}
|
|
1178
1189
|
${e.tip?l`<div class="insight-line insight-tip">
|
|
1179
1190
|
Tip: ${e.tip}
|
|
1180
|
-
</div>`:
|
|
1191
|
+
</div>`:d}
|
|
1181
1192
|
</div>
|
|
1182
|
-
`:
|
|
1193
|
+
`:d}
|
|
1183
1194
|
</div>
|
|
1184
|
-
`}renderTrafficCard(t){if(Yt[t.category||""])return
|
|
1195
|
+
`}renderTrafficCard(t){if(Yt[t.category||""])return d;let e=St(t.statusCode),s=y(t.pollingDurationMs||t.durationMs),i=!t.isDuplicate&&t.category!==pe&&t.category!==bt||t.requestBody&&t.method!=="GET"||!!t.responseBody;return l`
|
|
1185
1196
|
<div
|
|
1186
1197
|
class="traffic-card ${t.isStrictModeDupe?"strict-mode-dupe":""}"
|
|
1187
1198
|
>
|
|
@@ -1198,14 +1209,14 @@ span.perf-breakdown-dot.perf-breakdown-app{background:var(--breakdown-app)}
|
|
|
1198
1209
|
</div>
|
|
1199
1210
|
${t.isStrictModeDupe?l`<div class="strict-mode-banner">
|
|
1200
1211
|
React Strict Mode duplicate — does not happen in production
|
|
1201
|
-
</div>`:
|
|
1202
|
-
${!t.isDuplicate&&t.category!==pe&&t.category!==
|
|
1212
|
+
</div>`:d}
|
|
1213
|
+
${!t.isDuplicate&&t.category!==pe&&t.category!==bt?l`<div
|
|
1203
1214
|
class="request-timeline tl-hidden"
|
|
1204
1215
|
data-request-id=${t.id}
|
|
1205
1216
|
data-request-started=${String(t.startedAt)}
|
|
1206
|
-
></div>`:
|
|
1207
|
-
${t.requestBody&&t.method!=="GET"?this.renderBodyToggle("out","Request Body",t.requestBody):
|
|
1208
|
-
${t.responseBody?this.renderBodyToggle("in","Response Body",t.responseBody):
|
|
1217
|
+
></div>`:d}
|
|
1218
|
+
${t.requestBody&&t.method!=="GET"?this.renderBodyToggle("out","Request Body",t.requestBody):d}
|
|
1219
|
+
${t.responseBody?this.renderBodyToggle("in","Response Body",t.responseBody):d}
|
|
1209
1220
|
</div>
|
|
1210
1221
|
`}renderBodyToggle(t,e,s){let i=t==="out"?"\u2192":"\u2190";return l`
|
|
1211
1222
|
<div class="traffic-body">
|
|
@@ -1226,12 +1237,12 @@ span.perf-breakdown-dot.perf-breakdown-app{background:var(--breakdown-app)}
|
|
|
1226
1237
|
<span class="subreq-label ${t.isDuplicate?"is-dup":""}"
|
|
1227
1238
|
>${t.path||t.url}</span
|
|
1228
1239
|
>
|
|
1229
|
-
${t.isDuplicate?l`<span class="subreq-dup-tag">duplicate</span>`:
|
|
1240
|
+
${t.isDuplicate?l`<span class="subreq-dup-tag">duplicate</span>`:d}
|
|
1230
1241
|
<span class="status-pill ${i}">${t.statusCode}</span>
|
|
1231
1242
|
<span class="subreq-dur">${n}</span>
|
|
1232
1243
|
</div>
|
|
1233
1244
|
<div class="flow-subreq-detail ${s?"open":""}">
|
|
1234
|
-
${s?this.renderSubReqDetail(t):
|
|
1245
|
+
${s?this.renderSubReqDetail(t):d}
|
|
1235
1246
|
</div>
|
|
1236
1247
|
`}renderSubReqDetail(t){let e=St(t.statusCode);return l`
|
|
1237
1248
|
<div class="detail-meta">
|
|
@@ -1242,7 +1253,7 @@ span.perf-breakdown-dot.perf-breakdown-app{background:var(--breakdown-app)}
|
|
|
1242
1253
|
><span class="status-pill ${e}">${t.statusCode}</span></span
|
|
1243
1254
|
>
|
|
1244
1255
|
<span>${t.durationMs}ms</span>
|
|
1245
|
-
${t.responseSize?l`<span>${ot(t.responseSize)}</span>`:
|
|
1256
|
+
${t.responseSize?l`<span>${ot(t.responseSize)}</span>`:d}
|
|
1246
1257
|
</div>
|
|
1247
1258
|
<div
|
|
1248
1259
|
class="request-timeline tl-hidden"
|
|
@@ -1275,7 +1286,7 @@ span.perf-breakdown-dot.perf-breakdown-app{background:var(--breakdown-app)}
|
|
|
1275
1286
|
Copy cURL
|
|
1276
1287
|
</button>
|
|
1277
1288
|
</div>
|
|
1278
|
-
`}};u([
|
|
1289
|
+
`}};u([C({context:A})],X.prototype,"store",2),u([b()],X.prototype,"expandedFlowIdx",2),u([b()],X.prototype,"expandedSubReqIdx",2),u([b()],X.prototype,"flowDetailTab",2),u([b()],X.prototype,"flowTimeline",2),u([b()],X.prototype,"flowTimelineLoading",2),X=u([_("bk-flows-view")],X);var ee=class extends E{createRenderRoot(){return this}connectedCallback(){super.connectedCallback(),this.store.addEventListener("state-changed",()=>this.requestUpdate());}render(){let r=(this.store.state.issues||[]).slice(),t=r.filter(a=>a.state==="open"||a.state==="fixing"||a.state==="regressed"),e=r.filter(a=>a.state==="resolved");if(t.length===0&&e.length===0)return this.store.state.requests.length>0||this.store.state.logs.length>0||this.store.state.queries.length>0?l`
|
|
1279
1290
|
<div class="sec-clear">
|
|
1280
1291
|
<span class="sec-clear-icon">\u2713</span>
|
|
1281
1292
|
<div class="sec-clear-text">
|
|
@@ -1294,39 +1305,39 @@ span.perf-breakdown-dot.perf-breakdown-app{background:var(--breakdown-app)}
|
|
|
1294
1305
|
<div class="sec-clear-sub">${e.length} finding${e.length!==1?"s were":" was"} detected and fixed</div>
|
|
1295
1306
|
</div>
|
|
1296
1307
|
</div>
|
|
1297
|
-
`:
|
|
1298
|
-
${t.length>0?this.renderOpenGroups(t):
|
|
1299
|
-
${e.length>0?this.renderResolved(e):
|
|
1308
|
+
`:d}
|
|
1309
|
+
${t.length>0?this.renderOpenGroups(t):d}
|
|
1310
|
+
${e.length>0?this.renderResolved(e):d}
|
|
1300
1311
|
</div>
|
|
1301
1312
|
`}renderSummary(r,t,e,s,i){return l`
|
|
1302
1313
|
<div class="sec-summary">
|
|
1303
1314
|
<div class="sec-summary-left">
|
|
1304
1315
|
<span class="sec-summary-count">${r}</span>
|
|
1305
1316
|
<span class="sec-summary-label">open issue${r!==1?"s":""}</span>
|
|
1306
|
-
${t>0?l`<span class="sec-resolved-badge">${t} resolved</span>`:
|
|
1317
|
+
${t>0?l`<span class="sec-resolved-badge">${t} resolved</span>`:d}
|
|
1307
1318
|
</div>
|
|
1308
1319
|
<div class="sec-summary-right">
|
|
1309
|
-
${e>0?l`<span class="sec-badge critical">${e} critical</span>`:
|
|
1310
|
-
${s>0?l`<span class="sec-badge warning">${s} warning</span>`:
|
|
1311
|
-
${i>0?l`<span class="sec-badge info">${i} info</span>`:
|
|
1320
|
+
${e>0?l`<span class="sec-badge critical">${e} critical</span>`:d}
|
|
1321
|
+
${s>0?l`<span class="sec-badge warning">${s} warning</span>`:d}
|
|
1322
|
+
${i>0?l`<span class="sec-badge info">${i} info</span>`:d}
|
|
1312
1323
|
</div>
|
|
1313
1324
|
</div>
|
|
1314
|
-
`}renderOpenGroups(r){let t={},e=[];for(let s of r){let i=s.issue,n=i.rule
|
|
1325
|
+
`}renderOpenGroups(r){let t={},e=[];for(let s of r){let i=s.issue,n=i.rule;t[n]||(t[n]={rule:n,title:i.title,severity:i.severity,hint:i.hint,items:[]},e.push(n)),t[n].items.push(s);}return e.sort((s,i)=>{let n=Y[t[s].severity]?.sort??2,a=Y[t[i].severity]?.sort??2;return n!==a?n-a:t[i].items.length-t[s].items.length}),l`${e.map(s=>this.renderGroup(t[s]))}`}renderGroup(r){let t=Y[r.severity]||Y.info;return l`
|
|
1315
1326
|
<div class="sec-group">
|
|
1316
1327
|
<div class="sec-group-header">
|
|
1317
1328
|
<span class="sec-group-icon ${t.cls}">${t.icon}</span>
|
|
1318
1329
|
<span class="sec-group-title">${r.title}</span>
|
|
1319
1330
|
<span class="sec-group-count">${r.items.length}</span>
|
|
1320
1331
|
</div>
|
|
1321
|
-
${r.hint?l`<div class="sec-hint">${r.hint}</div>`:
|
|
1332
|
+
${r.hint?l`<div class="sec-hint">${r.hint}</div>`:d}
|
|
1322
1333
|
<div class="sec-items">${r.items.map(e=>this.renderIssueItem(e))}</div>
|
|
1323
1334
|
</div>
|
|
1324
1335
|
`}renderIssueItem(r){let t=r.issue;return l`
|
|
1325
1336
|
<div class="sec-item">
|
|
1326
1337
|
<div class="sec-item-desc">${t.desc}</div>
|
|
1327
|
-
${r.occurrences>1?l`<span class="sec-item-count">${r.occurrences}x</span>`:
|
|
1328
|
-
${r.state==="fixing"&&r.aiStatus==="fixed"?l`<span class="sec-ai-badge sec-ai-fixing">AI fixed \u2014 awaiting verification</span>`:r.aiStatus==="wont_fix"?l`<span class="sec-ai-badge sec-ai-wontfix">AI: won\u2019t fix</span>`:r.state==="regressed"?l`<span class="sec-ai-badge sec-ai-fixing" style="background:var(--red)">regressed</span>`:
|
|
1329
|
-
${r.aiNotes?l`<div class="sec-ai-notes">${r.aiNotes}</div>`:
|
|
1338
|
+
${r.occurrences>1?l`<span class="sec-item-count">${r.occurrences}x</span>`:d}
|
|
1339
|
+
${r.state==="fixing"&&r.aiStatus==="fixed"?l`<span class="sec-ai-badge sec-ai-fixing">AI fixed \u2014 awaiting verification</span>`:r.aiStatus==="wont_fix"?l`<span class="sec-ai-badge sec-ai-wontfix">AI: won\u2019t fix</span>`:r.state==="regressed"?l`<span class="sec-ai-badge sec-ai-fixing" style="background:var(--red)">regressed</span>`:d}
|
|
1340
|
+
${r.aiNotes?l`<div class="sec-ai-notes">${r.aiNotes}</div>`:d}
|
|
1330
1341
|
</div>
|
|
1331
1342
|
`}renderResolved(r){return l`
|
|
1332
1343
|
<div class="sec-resolved-title">
|
|
@@ -1339,13 +1350,13 @@ span.perf-breakdown-dot.perf-breakdown-app{background:var(--breakdown-app)}
|
|
|
1339
1350
|
<div class="sec-item sec-item-resolved">
|
|
1340
1351
|
<span class="sec-resolved-item-icon">\u2713</span>
|
|
1341
1352
|
<div class="sec-item-desc">${t.issue.title} \u2014 ${t.issue.endpoint||"global"}</div>
|
|
1342
|
-
${t.aiStatus==="fixed"?l`<span class="sec-ai-badge sec-ai-verified">Verified fix</span>`:
|
|
1343
|
-
${t.aiNotes?l`<div class="sec-ai-notes">${t.aiNotes}</div>`:
|
|
1353
|
+
${t.aiStatus==="fixed"?l`<span class="sec-ai-badge sec-ai-verified">Verified fix</span>`:d}
|
|
1354
|
+
${t.aiNotes?l`<div class="sec-ai-notes">${t.aiNotes}</div>`:d}
|
|
1344
1355
|
</div>
|
|
1345
1356
|
`)}
|
|
1346
1357
|
</div>
|
|
1347
1358
|
</div>
|
|
1348
|
-
`}};u([
|
|
1359
|
+
`}};u([C({context:A})],ee.prototype,"store",2),ee=u([_("bk-security-view")],ee);var J=class extends E{constructor(){super(...arguments);this.handleStateChanged=()=>this.requestUpdate();}createRenderRoot(){return this}connectedCallback(){super.connectedCallback(),this.store.addEventListener("state-changed",this.handleStateChanged);}disconnectedCallback(){super.disconnectedCallback(),this.store.removeEventListener("state-changed",this.handleStateChanged);}};u([C({context:A})],J.prototype,"store",2);async function j(o){let r=await fetch(o);if(!r.ok)throw new Error(`HTTP ${r.status}: ${o}`);return r.json()}function B(o,r,t){return o===1?r:t??`${r}s`}function ir(o){return o.state!=="stale"}function _e(o){return (o.state==="open"||o.state==="regressed")&&o.aiStatus!=="wont_fix"}var se=class extends J{constructor(){super(...arguments);this.graphSummary=null;}connectedCallback(){super.connectedCallback(),this.loadGraphSummary();}async loadGraphSummary(){try{let e=(await j(`${T.graph}?level=endpoints`)).nodes||[];this.graphSummary={endpoints:e.filter(s=>s.type==="endpoint").length,tables:e.filter(s=>s.type==="table").length,externals:e.filter(s=>s.type==="external").length};}catch{}}navigateTo(t){this.store.setActiveView(t);}navigateToExplorerErrors(){this.store.setActiveView("explorer"),window.dispatchEvent(new CustomEvent("navigate-explorer",{detail:"errors"}));}render(){let t=this.store.state,e=t.requests.filter(i=>!i.isStatic&&!i.isHealthCheck&&(!i.path||i.path.indexOf(U)!==0));return e.length>0||t.queries.length>0?l`
|
|
1349
1360
|
<div class="ov-container">
|
|
1350
1361
|
<div class="ov-grid">
|
|
1351
1362
|
${this.renderActionsCard(t.flows)}
|
|
@@ -1356,9 +1367,9 @@ span.perf-breakdown-dot.perf-breakdown-app{background:var(--breakdown-app)}
|
|
|
1356
1367
|
</div>
|
|
1357
1368
|
</div>
|
|
1358
1369
|
`:l`<bk-empty-state
|
|
1359
|
-
title="${
|
|
1360
|
-
subtitle="${
|
|
1361
|
-
></bk-empty-state>`}renderActionsCard(t){let e=t.length;if(e===0)return this.renderEmptyCard("\u25B6","Actions",
|
|
1370
|
+
title="${N.EMPTY_TITLE}"
|
|
1371
|
+
subtitle="${N.EMPTY_SUBTITLE_OVERVIEW}"
|
|
1372
|
+
></bk-empty-state>`}renderActionsCard(t){let e=t.length;if(e===0)return this.renderEmptyCard("\u25B6","Actions",N.NO_ACTIONS,"actions");let s=Math.round(t.reduce((n,a)=>n+a.totalDurationMs,0)/e),i=t[0]?.label||"";return this.renderCard("\u25B6",`${e} ${B(e,"action")}`,`avg ${y(s)}${i?` \xB7 "${i}"`:""}`,"actions","var(--accent)")}renderInsightsCard(t){let e=(t||[]).filter(_e);if(e.length===0)return this.renderCard("\u2713",N.ALL_CLEAR,N.ALL_CLEAR_DETAIL,"insights","var(--green)");let s=e.filter(a=>a.issue.severity==="critical").length,i=e.filter(a=>a.issue.severity==="warning").length,n=[];return s>0&&n.push(`${s} critical`),i>0&&n.push(`${i} warning`),this.renderCard("\u{1F4A1}",`${e.length} ${B(e.length,"issue")}`,n.join(" \xB7 ")||N.REVIEW_RECOMMENDED,"insights","var(--amber)")}renderPerformanceCard(t){if(t.length===0)return this.renderEmptyCard("\u26A1","Performance",N.NO_REQUEST_DATA,"performance");let e=new Map;for(let n of t){let a=`${n.method} ${n.path}`,c=e.get(a);c||(c=[],e.set(a,c)),c.push(n.durationMs);}let s=[];for(let[n,a]of e){let c=Math.round(a.reduce((p,h)=>p+h,0)/a.length);c>2e3&&s.push({key:n,avg:c});}if(s.sort((n,a)=>a.avg-n.avg),s.length===0)return this.renderCard("\u26A1",N.ALL_FAST,N.NO_SLOW_ENDPOINTS,"performance","var(--green)");let i=s[0];return this.renderCard("\u26A1",`${s.length} slow ${B(s.length,"endpoint")}`,`worst: ${i.key} \xB7 ${y(i.avg)}`,"performance","var(--amber)")}renderErrorsCard(t){let e=t.filter(n=>n.statusCode>=400);if(e.length===0)return this.renderCard("\u2713",N.ZERO_ERRORS,N.ALL_REQUESTS_OK,"explorer","var(--green)");let s=new Map;for(let n of e)s.set(n.statusCode,(s.get(n.statusCode)||0)+1);let i=[...s.entries()].sort((n,a)=>a[1]-n[1]).slice(0,3).map(([n,a])=>`${a}\xD7 ${n}`);return l`
|
|
1362
1373
|
<div class="ov-card-nav" @click=${()=>this.navigateToExplorerErrors()}>
|
|
1363
1374
|
<div class="ov-card-icon-lg" style="color:var(--red)">\u2715</div>
|
|
1364
1375
|
<div class="ov-card-content">
|
|
@@ -1367,12 +1378,12 @@ span.perf-breakdown-dot.perf-breakdown-app{background:var(--breakdown-app)}
|
|
|
1367
1378
|
</div>
|
|
1368
1379
|
<span class="ov-card-arrow">\u2192</span>
|
|
1369
1380
|
</div>
|
|
1370
|
-
`}renderGraphCard(){let t=this.graphSummary;if(!t||t.endpoints===0&&t.tables===0)return this.renderEmptyCard("\u25CE","Graph",
|
|
1381
|
+
`}renderGraphCard(){let t=this.graphSummary;if(!t||t.endpoints===0&&t.tables===0)return this.renderEmptyCard("\u25CE","Graph",N.BUILD_GRAPH,"graph");let e=[];t.endpoints>0&&e.push(`${t.endpoints} ${B(t.endpoints,"endpoint")}`),t.tables>0&&e.push(`${t.tables} ${B(t.tables,"table")}`);let s=t.externals>0?`${t.externals} external ${B(t.externals,"service")}`:"";return this.renderCard("\u25CE",e.join(" \xB7 "),s,"graph","var(--accent)")}renderCard(t,e,s,i,n){return l`
|
|
1371
1382
|
<div class="ov-card-nav" @click=${()=>this.navigateTo(i)}>
|
|
1372
1383
|
<div class="ov-card-icon-lg" style="color:${n}">${t}</div>
|
|
1373
1384
|
<div class="ov-card-content">
|
|
1374
1385
|
<div class="ov-card-headline">${e}</div>
|
|
1375
|
-
${s?l`<div class="ov-card-context">${s}</div>`:
|
|
1386
|
+
${s?l`<div class="ov-card-context">${s}</div>`:d}
|
|
1376
1387
|
</div>
|
|
1377
1388
|
<span class="ov-card-arrow">\u2192</span>
|
|
1378
1389
|
</div>
|
|
@@ -1385,7 +1396,7 @@ span.perf-breakdown-dot.perf-breakdown-app{background:var(--breakdown-app)}
|
|
|
1385
1396
|
</div>
|
|
1386
1397
|
<span class="ov-card-arrow">\u2192</span>
|
|
1387
1398
|
</div>
|
|
1388
|
-
`}};u([
|
|
1399
|
+
`}};u([b()],se.prototype,"graphSummary",2),se=u([_("bk-overview-view")],se);function or(o){return o<1?"<1ms":o<1e3?Math.round(o)+"ms":(o/1e3).toFixed(1)+"s"}function fi(o){return o<yt?Vt.green:o<$t?Vt.amber:Vt.red}function vi(o){return o.statusCode>=400?Vt.red:fi(o.durationMs)}function nr(o){return [parseInt(o.slice(1,3),16),parseInt(o.slice(3,5),16),parseInt(o.slice(5,7),16)]}function gi(o){let r=o.getContext("2d");if(!r)return null;let t=window.devicePixelRatio||1,e=o.clientWidth,s=o.clientHeight;return o.width=e*t,o.height=s*t,r.scale(t,t),{ctx:r,w:e,h:s}}function bi(o,r,t,e,s){let[i,n,a]=nr(s);o.beginPath(),o.arc(r,t,e+2,0,Math.PI*2),o.fillStyle=`rgba(${i},${n},${a},0.25)`,o.fill(),o.beginPath(),o.arc(r,t,e,0,Math.PI*2),o.fillStyle=s,o.fill();}function Ei(o,r,t,e,s,i){let[n,a,c]=nr(s);o.strokeStyle=`rgba(${n},${a},${c},0.3)`,o.lineWidth=i+2,o.beginPath(),o.moveTo(r-e,t-e),o.lineTo(r+e,t+e),o.moveTo(r+e,t-e),o.lineTo(r-e,t+e),o.stroke(),o.strokeStyle=s,o.lineWidth=i,o.beginPath(),o.moveTo(r-e,t-e),o.lineTo(r+e,t+e),o.moveTo(r+e,t-e),o.lineTo(r-e,t+e),o.stroke();}function ar(o,r){let t=[],e=gi(o);if(!e||r.length===0)return t;let{ctx:s,w:i,h:n}=e,a=Gs,c=i-a.left-a.right,p=n-a.top-a.bottom,h=0,m=r[0].timestamp,f=r[0].timestamp;for(let $ of r)$.durationMs>h&&(h=$.durationMs),$.timestamp<m&&(m=$.timestamp),$.timestamp>f&&(f=$.timestamp);h=Math.max(h,10),h=Math.ceil(h*1.15/10)*10;let S=f-m||1;s.strokeStyle=Us,s.lineWidth=1;let R=4;for(let $=0;$<=R;$++){let v=a.top+p-$/R*p;s.beginPath(),s.moveTo(a.left,v),s.lineTo(a.left+c,v),s.stroke(),s.fillStyle=Ve,s.font=Fs,s.textAlign="right",s.fillText(or(Math.round($/R*h)),a.left-8,v+3);}for(let $ of [{ms:yt},{ms:$t}]){if($.ms>=h)continue;let v=a.top+p-$.ms/h*p;s.beginPath(),s.setLineDash([4,4]),s.strokeStyle="rgba(113,113,122,0.3)",s.lineWidth=1,s.moveTo(a.left,v),s.lineTo(a.left+c,v),s.stroke(),s.setLineDash([]),s.fillStyle="rgba(113,113,122,0.5)",s.font=Ke,s.textAlign="left",s.fillText(or($.ms),a.left+c+2,v+3);}for(let $=0;$<r.length;$++){let v=r[$],g=r.length===1?a.left+c/2:a.left+(v.timestamp-m)/S*c,x=a.top+p-v.durationMs/h*p,w=vi(v);t.push({x:g,y:x,idx:$,r:v}),v.statusCode>=400?Ei(s,g,x,4,w,2):bi(s,g,x,4,w);}s.fillStyle=Ve,s.font=Ke,s.textAlign="center";let P=[m,m+S/2,f];for(let $=0;$<P.length;$++){let v=a.left+$/2*c,g=new Date(P[$]);s.fillText(g.toLocaleTimeString([],{hour:"2-digit",minute:"2-digit",second:"2-digit"}),v,a.top+p+14);}return t}var Ti={max:1/0,label:"Pending",color:"var(--text-muted)",bg:"var(--bg-muted)",border:"var(--border)"};function lr(o,r,t){return t>=20?o:r}function ss(o,r){if(!r||r<=0)return Ti;let t=o/r;return t<.7?xt[0]:t<1.2?xt[1]:t<2?xt[2]:t<3?xt[3]:xt[4]}var V=class extends E{constructor(){super(...arguments);this.selectedEndpoint=rt;this.graphData=[];this.loadError=false;this.queryBreakdown=[];this.queryBreakdownLoading=false;this.scatterDots=[];}createRenderRoot(){return this}connectedCallback(){super.connectedCallback(),this.store.addEventListener("state-changed",()=>this.requestUpdate()),this.loadMetrics();}async loadMetrics(){try{let e=await(await fetch(T.metricsLive)).json();this.graphData=e.endpoints||[],this.loadError=!1,(!this.selectedEndpoint||this.selectedEndpoint===rt)&&(this.selectedEndpoint=rt);}catch{this.loadError=true;}}healthGradeForEndpoint(t){let e=lr(t.summary.p95Ms,t.summary.medianMs,t.summary.totalRequests);return ss(e,t.baselineP95Ms)}healthGradeForDuration(t,e){return ss(t,e)}getCallers(t){let e=this.store.state.flows,s=new Map;for(let i of e)for(let n of i.requests)if(`${n.method} ${n.path}`===t||this.normalizeEndpoint(n)===t){let c=s.get(i.label);c?(c.count++,c.totalMs+=n.durationMs):s.set(i.label,{count:1,totalMs:n.durationMs});}return [...s.entries()].map(([i,n])=>({label:i,count:n.count,avgMs:Math.round(n.totalMs/n.count)})).sort((i,n)=>n.count-i.count)}normalizeEndpoint(t){let s=t.path.split("?")[0].split("/").map(i=>{if(!i)return i;let n=i.length>0;for(let a=0;a<i.length;a++){let c=i.charCodeAt(a);if(c<48||c>57){n=false;break}}return n||i.length===36&&i[8]==="-"&&i[13]==="-"&&i[18]==="-"&&i[23]==="-"?":id":i}).join("/");return `${t.method} ${s}`}async loadQueryBreakdown(t){if(this.queryBreakdownLoading)return;let s=this.store.state.requests.filter(i=>`${i.method} ${i.path}`===t||this.normalizeEndpoint(i)===t).slice(-20).map(i=>i.id).filter(Boolean);if(s.length===0){this.queryBreakdown=[];return}this.queryBreakdownLoading=true;try{let i=await fetch(`${T.activity}?requestIds=${s.join(",")}`);if(!i.ok){this.queryBreakdownLoading=!1;return}let n=await i.json(),a=new Map;for(let c of Object.values(n.activities))for(let p of c.timeline){if(p.type!=="query")continue;let h=p.data,m=(h.normalizedOp||h.operation||"QUERY").toUpperCase(),f=h.table||h.model||"",S=`${m} ${f}`.trim(),R=a.get(S);R?(R.totalMs+=h.durationMs,R.count++):a.set(S,{label:S,totalMs:h.durationMs,count:1});}this.queryBreakdown=[...a.values()].map(c=>({...c,avgMs:Math.round(c.totalMs/c.count)})).sort((c,p)=>p.totalMs-c.totalMs);}catch{}this.queryBreakdownLoading=false;}renderScatterChart(t,e){this.scatterDots=ar(t,e),t.style.cursor="pointer",t.onclick=s=>{let i=t.getBoundingClientRect(),n=s.clientX-i.left,a=s.clientY-i.top,c=null,p=1/0;for(let h of this.scatterDots){let m=Math.sqrt((h.x-n)**2+(h.y-a)**2);m<p&&(p=m,c=h);}c&&p<16&&this.highlightRow(c.idx);};}highlightRow(t){let e=this.querySelector(".perf-hist-row-hl");e&&e.classList.remove("perf-hist-row-hl");let s=this.querySelector(`[data-req-idx="${t}"]`);s&&(s.classList.add("perf-hist-row-hl"),s.scrollIntoView({behavior:"smooth",block:"center"}));}updated(){if(this.selectedEndpoint===rt)return;let t=this.querySelector("#perf-detail-canvas");if(t){let e=this.graphData.find(s=>s.endpoint===this.selectedEndpoint);e&&this.renderScatterChart(t,e.requests);}}render(){return !this.graphData||this.graphData.length===0?l`<bk-empty-state title="No performance data yet" subtitle="Hit some endpoints and data will appear here"></bk-empty-state>`:l`
|
|
1389
1400
|
<div id="graph-content">
|
|
1390
1401
|
${this.renderSelector()}
|
|
1391
1402
|
${this.selectedEndpoint===rt?this.renderOverview():this.renderDetail()}
|
|
@@ -1397,11 +1408,11 @@ span.perf-breakdown-dot.perf-breakdown-app{background:var(--breakdown-app)}
|
|
|
1397
1408
|
${this.graphData.map((t,e)=>l`
|
|
1398
1409
|
<button class="perf-selector-btn ${t.endpoint===this.selectedEndpoint?"active":""}"
|
|
1399
1410
|
@click=${()=>{this.selectedEndpoint=t.endpoint,this.queryBreakdown=[],this.loadQueryBreakdown(t.endpoint);}}>
|
|
1400
|
-
<span class="perf-dot" style="background:${
|
|
1411
|
+
<span class="perf-dot" style="background:${Xe[e%Xe.length]}"></span>${t.endpoint}
|
|
1401
1412
|
</button>
|
|
1402
1413
|
`)}
|
|
1403
1414
|
</div>
|
|
1404
|
-
`}renderOverview(){let t=this.graphData.filter(c=>c.requests.length>0);if(t.length===0)return
|
|
1415
|
+
`}renderOverview(){let t=this.graphData.filter(c=>c.requests.length>0);if(t.length===0)return d;let e=t.reduce((c,p)=>c+p.summary.totalRequests,0),s=e>0?Math.round(t.reduce((c,p)=>c+p.summary.p95Ms*p.summary.totalRequests,0)/e):0,i=t.reduce((c,p)=>c+Math.round(p.summary.errorRate*p.summary.totalRequests),0),n=e>0?i/e:0,a=t[0];return l`
|
|
1405
1416
|
<div class="perf-overview">
|
|
1406
1417
|
<div class="perf-summary-row">
|
|
1407
1418
|
<div class="perf-summary-card">
|
|
@@ -1438,7 +1449,7 @@ span.perf-breakdown-dot.perf-breakdown-app{background:var(--breakdown-app)}
|
|
|
1438
1449
|
</tbody>
|
|
1439
1450
|
</table>
|
|
1440
1451
|
</div>
|
|
1441
|
-
`}renderHeatmapRow(t){let e=t.summary,s=this.healthGradeForEndpoint(t),i=Math.round(e.errorRate*e.totalRequests),n=(e.avgQueryTimeMs||0)+(e.avgFetchTimeMs||0)+(e.avgAppTimeMs||0),a=0,c=0,
|
|
1452
|
+
`}renderHeatmapRow(t){let e=t.summary,s=this.healthGradeForEndpoint(t),i=Math.round(e.errorRate*e.totalRequests),n=(e.avgQueryTimeMs||0)+(e.avgFetchTimeMs||0)+(e.avgAppTimeMs||0),a=0,c=0,p=100;return n>0&&(a=Math.round((e.avgQueryTimeMs||0)/n*100),c=Math.round((e.avgFetchTimeMs||0)/n*100),p=Math.max(0,100-a-c)),l`
|
|
1442
1453
|
<tr class="perf-table-row" @click=${()=>{this.selectedEndpoint=t.endpoint,this.queryBreakdown=[],this.loadQueryBreakdown(t.endpoint);}}>
|
|
1443
1454
|
<td class="perf-td-name">${t.endpoint}</td>
|
|
1444
1455
|
<td class="perf-td-right">${e.totalRequests}</td>
|
|
@@ -1449,9 +1460,9 @@ span.perf-breakdown-dot.perf-breakdown-app{background:var(--breakdown-app)}
|
|
|
1449
1460
|
<td class="perf-td-center" style="color:${e.avgQueryCount>5?"var(--amber)":"var(--text-muted)"}">${e.avgQueryCount}</td>
|
|
1450
1461
|
<td>
|
|
1451
1462
|
<span class="perf-hm-split-bar">
|
|
1452
|
-
${a>0?l`<span class="perf-breakdown-seg perf-breakdown-db" style="width:${a}%"></span>`:
|
|
1453
|
-
${c>0?l`<span class="perf-breakdown-seg perf-breakdown-fetch" style="width:${c}%"></span>`:
|
|
1454
|
-
${
|
|
1463
|
+
${a>0?l`<span class="perf-breakdown-seg perf-breakdown-db" style="width:${a}%"></span>`:d}
|
|
1464
|
+
${c>0?l`<span class="perf-breakdown-seg perf-breakdown-fetch" style="width:${c}%"></span>`:d}
|
|
1465
|
+
${p>0?l`<span class="perf-breakdown-seg perf-breakdown-app" style="width:${p}%"></span>`:d}
|
|
1455
1466
|
</span>
|
|
1456
1467
|
</td>
|
|
1457
1468
|
</tr>
|
|
@@ -1469,7 +1480,7 @@ span.perf-breakdown-dot.perf-breakdown-app{background:var(--breakdown-app)}
|
|
|
1469
1480
|
<div class="perf-detail-title">
|
|
1470
1481
|
<span class="perf-badge perf-badge-lg" style="color:${e.color};background:${e.bg};border-color:${e.border}">${e.label}</span>
|
|
1471
1482
|
<span>${t.endpoint}</span>
|
|
1472
|
-
${t.baselineP95Ms?l`<span class="perf-baseline-hint">Baseline: ${y(t.baselineP95Ms)}</span>`:
|
|
1483
|
+
${t.baselineP95Ms?l`<span class="perf-baseline-hint">Baseline: ${y(t.baselineP95Ms)}</span>`:d}
|
|
1473
1484
|
</div>
|
|
1474
1485
|
</div>
|
|
1475
1486
|
`}renderDetailMetrics(t,e,s){return l`
|
|
@@ -1489,13 +1500,13 @@ span.perf-breakdown-dot.perf-breakdown-app{background:var(--breakdown-app)}
|
|
|
1489
1500
|
<span class="perf-metric-value" style="color:${t.avgQueryCount>5?"var(--amber)":"var(--text)"}">${t.avgQueryCount}</span>
|
|
1490
1501
|
</div>
|
|
1491
1502
|
</div>
|
|
1492
|
-
`}renderDetailBreakdown(t){let e=(t.avgQueryTimeMs||0)+(t.avgFetchTimeMs||0)+(t.avgAppTimeMs||0);if(e<=0)return
|
|
1503
|
+
`}renderDetailBreakdown(t){let e=(t.avgQueryTimeMs||0)+(t.avgFetchTimeMs||0)+(t.avgAppTimeMs||0);if(e<=0)return d;let s=Math.round((t.avgQueryTimeMs||0)/e*100),i=Math.round((t.avgFetchTimeMs||0)/e*100),n=Math.max(0,100-s-i);return l`
|
|
1493
1504
|
<div class="perf-breakdown">
|
|
1494
1505
|
<div class="perf-section-title">Time Breakdown</div>
|
|
1495
1506
|
<div class="perf-breakdown-bar">
|
|
1496
|
-
${s>0?l`<div class="perf-breakdown-seg perf-breakdown-db" style="width:${s}%"></div>`:
|
|
1497
|
-
${i>0?l`<div class="perf-breakdown-seg perf-breakdown-fetch" style="width:${i}%"></div>`:
|
|
1498
|
-
${n>0?l`<div class="perf-breakdown-seg perf-breakdown-app" style="width:${n}%"></div>`:
|
|
1507
|
+
${s>0?l`<div class="perf-breakdown-seg perf-breakdown-db" style="width:${s}%"></div>`:d}
|
|
1508
|
+
${i>0?l`<div class="perf-breakdown-seg perf-breakdown-fetch" style="width:${i}%"></div>`:d}
|
|
1509
|
+
${n>0?l`<div class="perf-breakdown-seg perf-breakdown-app" style="width:${n}%"></div>`:d}
|
|
1499
1510
|
</div>
|
|
1500
1511
|
<div class="perf-breakdown-legend">
|
|
1501
1512
|
<span class="perf-breakdown-item"><span class="perf-breakdown-dot perf-breakdown-db"></span>DB ${y(t.avgQueryTimeMs||0)} (${s}%)</span>
|
|
@@ -1503,7 +1514,7 @@ span.perf-breakdown-dot.perf-breakdown-app{background:var(--breakdown-app)}
|
|
|
1503
1514
|
<span class="perf-breakdown-item"><span class="perf-breakdown-dot perf-breakdown-app"></span>App ${y(t.avgAppTimeMs||0)} (${n}%)</span>
|
|
1504
1515
|
</div>
|
|
1505
1516
|
</div>
|
|
1506
|
-
`}renderCallers(t){let e=this.getCallers(t);return e.length===0?
|
|
1517
|
+
`}renderCallers(t){let e=this.getCallers(t);return e.length===0?d:l`
|
|
1507
1518
|
<div class="perf-callers">
|
|
1508
1519
|
<div class="perf-section-title">Called By</div>
|
|
1509
1520
|
<div class="perf-callers-list">
|
|
@@ -1516,7 +1527,7 @@ span.perf-breakdown-dot.perf-breakdown-app{background:var(--breakdown-app)}
|
|
|
1516
1527
|
`)}
|
|
1517
1528
|
</div>
|
|
1518
1529
|
</div>
|
|
1519
|
-
`}renderQueryBreakdown(){return this.queryBreakdownLoading?l`<div class="perf-queries"><div class="perf-section-title">DB Queries</div><div class="perf-queries-loading">Loading...</div></div>`:this.queryBreakdown.length===0?
|
|
1530
|
+
`}renderQueryBreakdown(){return this.queryBreakdownLoading?l`<div class="perf-queries"><div class="perf-section-title">DB Queries</div><div class="perf-queries-loading">Loading...</div></div>`:this.queryBreakdown.length===0?d:l`
|
|
1520
1531
|
<div class="perf-queries">
|
|
1521
1532
|
<div class="perf-section-title">DB Queries</div>
|
|
1522
1533
|
<div class="perf-queries-list">
|
|
@@ -1529,13 +1540,13 @@ span.perf-breakdown-dot.perf-breakdown-app{background:var(--breakdown-app)}
|
|
|
1529
1540
|
`)}
|
|
1530
1541
|
</div>
|
|
1531
1542
|
</div>
|
|
1532
|
-
`}renderTrends(t){let e=t.sessions;if(!e||e.length===0)return
|
|
1543
|
+
`}renderTrends(t){let e=t.sessions;if(!e||e.length===0)return d;let s=e.slice(-10);return l`
|
|
1533
1544
|
<div class="perf-trends">
|
|
1534
1545
|
<div class="perf-section-title">Session Trend</div>
|
|
1535
1546
|
<div class="perf-trends-list">
|
|
1536
|
-
${s.map((i,n)=>{let a=n>0?s[n-1].p95DurationMs:null,c=a!==null?i.p95DurationMs>a*1.2?"slower":i.p95DurationMs<a*.8?"faster":"":"",
|
|
1547
|
+
${s.map((i,n)=>{let a=n>0?s[n-1].p95DurationMs:null,c=a!==null?i.p95DurationMs>a*1.2?"slower":i.p95DurationMs<a*.8?"faster":"":"",p=this.formatTimeAgo(i.startedAt),h=n===s.length-1,m=this.healthGradeForDuration(i.p95DurationMs,t.baselineP95Ms);return l`
|
|
1537
1548
|
<div class="perf-trend-row ${h?"perf-trend-current":""}">
|
|
1538
|
-
<span class="perf-trend-time">${h?"Current":
|
|
1549
|
+
<span class="perf-trend-time">${h?"Current":p}</span>
|
|
1539
1550
|
<span class="perf-trend-p95">
|
|
1540
1551
|
<span class="perf-hm-p95" style="color:${m.color};background:${m.bg};border-color:${m.border}">
|
|
1541
1552
|
p95: ${y(i.p95DurationMs)}
|
|
@@ -1543,7 +1554,7 @@ span.perf-breakdown-dot.perf-breakdown-app{background:var(--breakdown-app)}
|
|
|
1543
1554
|
</span>
|
|
1544
1555
|
<span class="perf-trend-reqs">${i.requestCount} req${i.requestCount!==1?"s":""}</span>
|
|
1545
1556
|
<span class="perf-trend-errs" style="color:${i.errorCount>0?"var(--red)":"var(--text-dim)"}">${i.errorCount} err${i.errorCount!==1?"s":""}</span>
|
|
1546
|
-
${c?l`<span class="perf-trend-arrow ${c==="slower"?"perf-trend-slower":"perf-trend-faster"}">${c==="slower"?"\u2191 slower":"\u2193 faster"}</span>`:
|
|
1557
|
+
${c?l`<span class="perf-trend-arrow ${c==="slower"?"perf-trend-slower":"perf-trend-faster"}">${c==="slower"?"\u2191 slower":"\u2193 faster"}</span>`:d}
|
|
1547
1558
|
</div>
|
|
1548
1559
|
`})}
|
|
1549
1560
|
</div>
|
|
@@ -1553,7 +1564,7 @@ span.perf-breakdown-dot.perf-breakdown-app{background:var(--breakdown-app)}
|
|
|
1553
1564
|
<div class="perf-section-title">Response Time</div>
|
|
1554
1565
|
<canvas id="perf-detail-canvas" class="perf-canvas" style="width:100%;height:240px"></canvas>
|
|
1555
1566
|
</div>
|
|
1556
|
-
`}renderDetailHistory(t){if(t.requests.length===0)return
|
|
1567
|
+
`}renderDetailHistory(t){if(t.requests.length===0)return d;let e=[];for(let s=t.requests.length-1;s>=0&&e.length<50;s--)e.push({point:t.requests[s],originalIndex:s});return l`
|
|
1557
1568
|
<div class="perf-history-wrap">
|
|
1558
1569
|
<table class="perf-table">
|
|
1559
1570
|
<thead>
|
|
@@ -1571,7 +1582,7 @@ span.perf-breakdown-dot.perf-breakdown-app{background:var(--breakdown-app)}
|
|
|
1571
1582
|
</tbody>
|
|
1572
1583
|
</table>
|
|
1573
1584
|
</div>
|
|
1574
|
-
`}renderHistoryRow(t,e,s){let i=this.healthGradeForDuration(t.durationMs,s),n=new Date(t.timestamp).toLocaleTimeString([],{hour:"2-digit",minute:"2-digit",second:"2-digit"}),a=t.statusCode>=400,c=t.queryTimeMs||0,
|
|
1585
|
+
`}renderHistoryRow(t,e,s){let i=this.healthGradeForDuration(t.durationMs,s),n=new Date(t.timestamp).toLocaleTimeString([],{hour:"2-digit",minute:"2-digit",second:"2-digit"}),a=t.statusCode>=400,c=t.queryTimeMs||0,p=t.fetchTimeMs||0,h=Math.max(0,t.durationMs-c-p);return l`
|
|
1575
1586
|
<tr class="perf-table-row ${a?"perf-row-err":""}" data-req-idx=${e}>
|
|
1576
1587
|
<td class="perf-td-muted">${n}</td>
|
|
1577
1588
|
<td>
|
|
@@ -1579,27 +1590,27 @@ span.perf-breakdown-dot.perf-breakdown-app{background:var(--breakdown-app)}
|
|
|
1579
1590
|
</td>
|
|
1580
1591
|
<td>${y(t.durationMs)}</td>
|
|
1581
1592
|
<td>
|
|
1582
|
-
${c>0?l`<span class="perf-bd-tag perf-bd-tag-db">DB ${y(c)}</span>`:
|
|
1583
|
-
${
|
|
1593
|
+
${c>0?l`<span class="perf-bd-tag perf-bd-tag-db">DB ${y(c)}</span>`:d}
|
|
1594
|
+
${p>0?l`<span class="perf-bd-tag perf-bd-tag-fetch">Fetch ${y(p)}</span>`:d}
|
|
1584
1595
|
<span class="perf-bd-tag perf-bd-tag-app">App ${y(h)}</span>
|
|
1585
1596
|
</td>
|
|
1586
1597
|
<td class="perf-td-center" style="color:${a?"var(--red)":"var(--text-muted)"}">${t.statusCode}</td>
|
|
1587
1598
|
<td class="perf-td-right perf-td-muted">${t.queryCount}</td>
|
|
1588
1599
|
</tr>
|
|
1589
|
-
`}};u([I({context:A})],X.prototype,"store",2),u([E()],X.prototype,"selectedEndpoint",2),u([E()],X.prototype,"graphData",2),u([E()],X.prototype,"loadError",2),u([E()],X.prototype,"queryBreakdown",2),u([E()],X.prototype,"queryBreakdownLoading",2),X=u([$("bk-performance-view")],X);var rs={auth:{label:"Auth",color:"#059669",icon:"\u{1F6E1}",tooltip:"Highlight which endpoints require authentication and which are unprotected"},security:{label:"Security",color:"#dc2626",icon:"\u26A0",tooltip:"Show security findings like exposed secrets, token leaks, and PII exposure"},performance:{label:"Perf",color:"#2563eb",icon:"\u26A1",tooltip:"Color endpoints by P95 latency \u2014 green (fast) to red (slow)"},issues:{label:"Issues",color:"#d97706",icon:"\u25CF",tooltip:"Badge endpoints with open issues like N+1 queries or redundant calls"},heat:{label:"Heat",color:"#ef4444",icon:"\u{1F525}",tooltip:"Color nodes and edges by traffic volume \u2014 blue (low) to red (hot)"}},Nt={action:{fill:"#faf5ff",stroke:"#a855f7",icon:"\u25B6",columnHeader:"ACTIONS"},endpoint:{fill:"#f8fafc",stroke:"#6366f1",icon:"\u26A1",columnHeader:"ENDPOINTS"},table:{fill:"#f0fdf4",stroke:"#16a34a",icon:"\u229E",columnHeader:"TABLES"},external:{fill:"#fffbeb",stroke:"#d97706",icon:"\u25C6",columnHeader:"EXTERNAL"}},xe={triggers:"#a855f7",reads:"#6366f1",writes:"#ef4444",fetches:"#f59e0b",calls:"#22c55e"},Ai=100,Ii=300,Ci=800;function kt(o){return o<Ai?"#22c55e":o<Ii?"#3b82f6":o<Ci?"#eab308":"#ef4444"}var Li=.25,Mi=.5,Ni=.75;function is(o){return o<Li?"#3b82f6":o<Mi?"#22c55e":o<Ni?"#eab308":"#ef4444"}var cr="#4338ca",dr="#e0e7ff",pr="#818cf8",hr="#eef2ff",os="#7c3aed",ur="#6366f1",Se="#f97316",mr="#ecfdf5",ns="#059669",fr="#fef2f2",as="#dc2626",vr="#fffbeb",ls="#d97706",ut="#ef4444",gr=.2,Er=3,cs=1.2,re=40;var br=800,yr=500;function Hi(o){return Math.max(140,o.length*7.2+36)}function ds(o,r){return Math.round(36+o.stats.requestCount/r*28)}function qi(o){return o.length>0?Math.max(140,...o.map(r=>Hi(r.label))):0}function $r(o,r,t){let e=[];for(let s of r){let i=s.source===o?s.target:s.target===o?s.source:null;if(i){let n=t.get(i);n&&e.push(n.y+n.h/2);}}return e.length>0?e.reduce((s,i)=>s+i,0)/e.length:1/0}function Sr(o,r){let t=v=>o.filter(g=>g.type===v).sort((g,x)=>x.stats.requestCount-g.stats.requestCount),e=t("action"),s=t("endpoint"),i=t("table"),n=t("external"),a=Math.max(1,...o.map(v=>v.stats.requestCount)),c=new Map,d=[],h=[],m=50,f=[{type:"action",items:e},{type:"endpoint",items:s},{type:"table",items:i},{type:"external",items:n}];for(let v of f)if(v.items.length>0){let g=qi(v.items);h.push({type:v.type,items:v.items,width:g,x:m}),m+=g+160;}let S=h[0];if(S){let v=74;for(let g of S.items){let x=ds(g,a),w={id:g.id,x:S.x,y:v,w:S.width,h:x,label:g.label,type:g.type,stats:g.stats,annotations:g.annotations};d.push(w),c.set(g.id,w),v+=x+10;}}for(let v=1;v<h.length;v++){let g=h[v],x=[...g.items].sort((C,F)=>$r(C.id,r,c)-$r(F.id,r,c)),w=d.filter(C=>C.x===h[v-1].x),H=Math.min(...w.map(C=>C.y)),j=Math.max(...w.map(C=>C.y+C.h))-H,tt=x.reduce((C,F)=>C+ds(F,a)+10,-10),W=H+Math.max(0,(j-tt)/2);for(let C of x){let F=ds(C,a),hs={id:C.id,x:g.x,y:W,w:g.width,h:F,label:C.label,type:C.type,stats:C.stats,annotations:C.annotations};d.push(hs),c.set(C.id,hs),W+=F+10;}}let R=[];for(let v of r){let g=c.get(v.source),x=c.get(v.target);if(!g||!x)continue;let w=g.x<x.x,H=w?g.x+g.w:g.x,Z=g.y+g.h/2,j=w?x.x:x.x+x.w,tt=x.y+x.h/2,W=[];v.stats.frequency>1&&W.push(`${v.stats.frequency}\xD7`),W.push(v.type),v.stats.avgLatencyMs>0&&W.push(`${v.stats.avgLatencyMs}ms`),R.push({key:v.id,sx:H,sy:Z,tx:j,ty:tt,label:W.join(" \xB7 "),color:xe[v.type]||"#94a3b8",thickness:Math.min(.75+Math.log2(v.stats.frequency+1)*.35,2.5),dashed:v.type==="reads"||v.type==="writes",data:v});}let P=d.reduce((v,g)=>Math.max(v,g.x+g.w),0),_=d.reduce((v,g)=>Math.max(v,g.y+g.h),0);return {nodes:d,edges:R,width:P+100,height:Math.max(_+50,250)}}function Tr(o){let r=o.charCodeAt(0);return r>=48&&r<=57||r>=65&&r<=70||r>=97&&r<=102}function Ui(o){if(o.length!==36)return false;for(let r=0;r<o.length;r++)if(r===8||r===13||r===18||r===23){if(o[r]!=="-")return false}else if(!Tr(o[r]))return false;return true}function Fi(o){if(!o.length)return false;for(let r=0;r<o.length;r++){let t=o.charCodeAt(r);if(t<48||t>57)return false}return true}function Gi(o){if(o.length<12)return false;for(let r=0;r<o.length;r++)if(!Tr(o[r]))return false;return true}function Bi(o){if(o.length<8)return false;let r=false,t=false;for(let e=0;e<o.length;e++){let s=o.charCodeAt(e);if(s>=65&&s<=90||s>=97&&s<=122)r=true;else if(s>=48&&s<=57)t=true;else if(s!==95&&s!==45)return false}return r&&t}var Wi=":id";function Qi(o){return Ui(o)||Fi(o)||Gi(o)||Bi(o)?Wi:o}function ps(o,r){let t=r.split("?")[0];return `${o} ${t.split("/").map(e=>e&&Qi(e)).join("/")}`}function wr(o,r,t){let e=[...o],s=[...r],i=new Set(e.map(a=>a.id)),n=new Map;for(let a of t){let c=a.label||"Unknown",d=n.get(c);d||(d={endpointKeys:new Set,count:0,totalMs:0},n.set(c,d)),d.count++,d.totalMs+=a.totalDurationMs;for(let h of a.requests)h.path?.startsWith(U)||d.endpointKeys.add(ps(h.method,h.path));}for(let[a,c]of n){let d=`action:${a}`;i.has(d)||(e.push({id:d,type:"action",label:a,stats:{requestCount:c.count,avgLatencyMs:c.count>0?Math.round(c.totalMs/c.count):0,errorRate:0,avgQueryCount:0}}),i.add(d));for(let h of c.endpointKeys){let m=`endpoint:${h}`;if(i.has(m)){let f=`${d} -> ${m}`;s.find(S=>S.id===f)||s.push({id:f,source:d,target:m,type:"triggers",stats:{frequency:c.count,avgLatencyMs:0}});}}}return {nodes:e,edges:s}}function Rr(o){let r=new Map;for(let t of o){let e=t.label||"Unknown",s=r.get(e);s||(s={keys:new Set,count:0,totalMs:0},r.set(e,s)),s.count++,s.totalMs+=t.totalDurationMs;for(let i of t.requests)i.path?.startsWith(U)||s.keys.add(ps(i.method,i.path));}return [...r.entries()].map(([t,e])=>({label:t,occurrences:e.count,endpointKeys:e.keys,avgDurationMs:e.count>0?Math.round(e.totalMs/e.count):0}))}function we(o,r){let t=`event=${encodeURIComponent(o)}${r?`&detail=${encodeURIComponent(r)}`:""}`;fetch(`${T.tab}?${t}`).catch(()=>{});}var M=class extends b{constructor(){super(...arguments);this.graphNodes=[];this.graphEdges=[];this.locked=null;this.hovered=null;this.loading=true;this.activeLayers=new Set;this.searchQuery="";this.viewTransform={x:0,y:0,scale:1};this.isPanning=false;this.panStart={x:0,y:0,vtx:0,vty:0};this.dragging=null;this.wasDragging=false;this.nodePositionOverrides=new Map;this.detailTab="overview";this.consolidatedFlows=[];this.activeFlowIdx=-1;this.focusIdx=-1;this.refreshTimer=null;}createRenderRoot(){return this}connectedCallback(){super.connectedCallback(),this.loadData(),this.refreshTimer=setInterval(()=>this.loadData(),4e3);}disconnectedCallback(){super.disconnectedCallback(),this.refreshTimer&&clearInterval(this.refreshTimer);}async loadData(){try{let[t,e]=await Promise.all([fetch(`${T.graph}?level=endpoints`),fetch(T.flows)]),s=await t.json(),i=await e.json(),n=wr(s.nodes||[],s.edges||[],i.flows||[]);this.graphNodes=n.nodes,this.graphEdges=n.edges,this.consolidatedFlows=Rr(i.flows||[]),this.nodePositionOverrides.size===0&&this.graphNodes.length>0&&this.tryLoadPersistedPositions(),this.loading=!1;}catch{this.loading=false;}}getPositionStorageKey(){let t=this.graphNodes.map(s=>s.id).sort().join(","),e=0;for(let s=0;s<t.length;s++)e=(e<<5)-e+t.charCodeAt(s)|0;return `bk-graph-pos-${e}`}persistPositions(){if(this.nodePositionOverrides.size!==0)try{let t=Object.fromEntries(this.nodePositionOverrides);localStorage.setItem(this.getPositionStorageKey(),JSON.stringify(t));}catch{}}tryLoadPersistedPositions(){try{let t=localStorage.getItem(this.getPositionStorageKey());if(t){let e=JSON.parse(t);this.nodePositionOverrides=new Map(Object.entries(e));}}catch{}}get activeNodeId(){return this.locked??this.hovered}getHighlightedNodeIds(){let t=this.activeNodeId;if(!t)return null;let e=new Set([t]),s=true;for(;s;){s=false;for(let i of this.graphEdges)e.has(i.source)&&!e.has(i.target)&&(e.add(i.target),s=true);}return e}getFlowTraceNodeIds(){if(this.activeFlowIdx<0||this.activeFlowIdx>=this.consolidatedFlows.length)return null;let t=this.consolidatedFlows[this.activeFlowIdx],e=new Set;e.add(`action:${t.label}`);for(let s of t.endpointKeys)e.add(`endpoint:${s}`);for(let s of this.graphEdges)e.has(s.source)&&e.add(s.target);return e}getFlowTraceEdgeIds(){let t=this.getFlowTraceNodeIds();if(!t)return null;let e=new Set;for(let s of this.graphEdges)t.has(s.source)&&t.has(s.target)&&e.add(s.id);return e}matchesSearch(t){return this.searchQuery?t.toLowerCase().includes(this.searchQuery.toLowerCase()):true}handlePanStart(t){t.button===0&&(t.target.closest(".graph-g")||(this.isPanning=true,this.panStart={x:t.clientX,y:t.clientY,vtx:this.viewTransform.x,vty:this.viewTransform.y}));}handlePanMove(t){if(this.dragging){let e=t.currentTarget.getBoundingClientRect(),s=(t.clientX-e.left-this.viewTransform.x)/this.viewTransform.scale,i=(t.clientY-e.top-this.viewTransform.y)/this.viewTransform.scale;this.nodePositionOverrides.set(this.dragging.nodeId,{x:s-this.dragging.offsetX,y:i-this.dragging.offsetY}),this.requestUpdate();return}this.isPanning&&(this.viewTransform={...this.viewTransform,x:this.panStart.vtx+(t.clientX-this.panStart.x),y:this.panStart.vty+(t.clientY-this.panStart.y)});}handlePanEnd(){this.dragging&&(this.persistPositions(),this.dragging=null,this.wasDragging=true,requestAnimationFrame(()=>{this.wasDragging=false;})),this.isPanning=false;}resetView(){this.viewTransform={x:0,y:0,scale:1};}zoomIn(){this.viewTransform={...this.viewTransform,scale:Math.min(Er,this.viewTransform.scale*cs)};}zoomOut(){this.viewTransform={...this.viewTransform,scale:Math.max(gr,this.viewTransform.scale/cs)};}resetLayout(){this.nodePositionOverrides.clear();try{localStorage.removeItem(this.getPositionStorageKey());}catch{}this.viewTransform={x:0,y:0,scale:1},this.requestUpdate(),we("layout_reset");}startNodeDrag(t,e,s){t.stopPropagation();let i=t.currentTarget.closest("svg").getBoundingClientRect(),n=(t.clientX-i.left-this.viewTransform.x)/this.viewTransform.scale,a=(t.clientY-i.top-this.viewTransform.y)/this.viewTransform.scale;this.dragging={nodeId:e,offsetX:n-s.x,offsetY:a-s.y};}handleKeyDown(t){let e=this.graphNodes;if(t.key==="/"){t.preventDefault(),this.querySelector(".graph-search-input")?.focus();return}if(t.key==="Escape"){this.locked=null,this.searchQuery="",this.focusIdx=-1,this.activeFlowIdx=-1;return}if(t.key==="Tab"){t.preventDefault(),this.focusIdx=t.shiftKey?this.focusIdx<=0?e.length-1:this.focusIdx-1:(this.focusIdx+1)%e.length,this.hovered=e[this.focusIdx]?.id??null;return}if(t.key==="Enter"&&this.focusIdx>=0){let s=e[this.focusIdx];s&&(this.locked=this.locked===s.id?null:s.id);return}if(t.key==="+"||t.key==="="){this.zoomIn();return}if(t.key==="-"){this.zoomOut();return}if(t.key==="ArrowUp"){this.viewTransform={...this.viewTransform,y:this.viewTransform.y+re};return}if(t.key==="ArrowDown"){this.viewTransform={...this.viewTransform,y:this.viewTransform.y-re};return}if(t.key==="ArrowLeft"){this.viewTransform={...this.viewTransform,x:this.viewTransform.x+re};return}if(t.key==="ArrowRight"){this.viewTransform={...this.viewTransform,x:this.viewTransform.x-re};return}}render(){if(this.loading&&this.graphNodes.length===0)return l`<div class="graph-loading">Loading graph…</div>`;if(this.graphNodes.length===0)return l`
|
|
1600
|
+
`}};u([C({context:A})],V.prototype,"store",2),u([b()],V.prototype,"selectedEndpoint",2),u([b()],V.prototype,"graphData",2),u([b()],V.prototype,"loadError",2),u([b()],V.prototype,"queryBreakdown",2),u([b()],V.prototype,"queryBreakdownLoading",2),V=u([_("bk-performance-view")],V);var rs={auth:{label:"Auth",color:"#059669",icon:"\u{1F6E1}",tooltip:"Highlight which endpoints require authentication and which are unprotected"},security:{label:"Security",color:"#dc2626",icon:"\u26A0",tooltip:"Show security findings like exposed secrets, token leaks, and PII exposure"},performance:{label:"Perf",color:"#2563eb",icon:"\u26A1",tooltip:"Color endpoints by P95 latency \u2014 green (fast) to red (slow)"},issues:{label:"Issues",color:"#d97706",icon:"\u25CF",tooltip:"Badge endpoints with open issues like N+1 queries or redundant calls"},heat:{label:"Heat",color:"#ef4444",icon:"\u{1F525}",tooltip:"Color nodes and edges by traffic volume \u2014 blue (low) to red (hot)"}},kt={action:{fill:"#faf5ff",stroke:"#a855f7",icon:"\u25B6",columnHeader:"ACTIONS"},endpoint:{fill:"#f8fafc",stroke:"#6366f1",icon:"\u26A1",columnHeader:"ENDPOINTS"},table:{fill:"#f0fdf4",stroke:"#16a34a",icon:"\u229E",columnHeader:"TABLES"},external:{fill:"#fffbeb",stroke:"#d97706",icon:"\u25C6",columnHeader:"EXTERNAL"}},xe={triggers:"#a855f7",reads:"#6366f1",writes:"#ef4444",fetches:"#f59e0b",calls:"#22c55e"},Ii=100,Li=300,Mi=800;function Ot(o){return o<Ii?"#22c55e":o<Li?"#3b82f6":o<Mi?"#eab308":"#ef4444"}var ki=.25,Oi=.5,Ni=.75;function is(o){return o<ki?"#3b82f6":o<Oi?"#22c55e":o<Ni?"#eab308":"#ef4444"}var cr="#4338ca",dr="#e0e7ff",pr="#818cf8",hr="#eef2ff",os="#7c3aed",ur="#6366f1",Se="#f97316",mr="#ecfdf5",ns="#059669",fr="#fef2f2",as="#dc2626",vr="#fffbeb",ls="#d97706",ut="#ef4444",gr=.2,br=3,cs=1.2,re=40;var Er=800,yr=500;function Ui(o){return Math.max(140,o.length*7.2+36)}function ds(o,r){return Math.round(36+o.stats.requestCount/r*28)}function Fi(o){return o.length>0?Math.max(140,...o.map(r=>Ui(r.label))):0}function _r(o,r,t){let e=[];for(let s of r){let i=s.source===o?s.target:s.target===o?s.source:null;if(i){let n=t.get(i);n&&e.push(n.y+n.h/2);}}return e.length>0?e.reduce((s,i)=>s+i,0)/e.length:1/0}function Sr(o,r){let t=v=>o.filter(g=>g.type===v).sort((g,x)=>x.stats.requestCount-g.stats.requestCount),e=t("action"),s=t("endpoint"),i=t("table"),n=t("external"),a=Math.max(1,...o.map(v=>v.stats.requestCount)),c=new Map,p=[],h=[],m=50,f=[{type:"action",items:e},{type:"endpoint",items:s},{type:"table",items:i},{type:"external",items:n}];for(let v of f)if(v.items.length>0){let g=Fi(v.items);h.push({type:v.type,items:v.items,width:g,x:m}),m+=g+160;}let S=h[0];if(S){let v=74;for(let g of S.items){let x=ds(g,a),w={id:g.id,x:S.x,y:v,w:S.width,h:x,label:g.label,type:g.type,stats:g.stats,annotations:g.annotations};p.push(w),c.set(g.id,w),v+=x+10;}}for(let v=1;v<h.length;v++){let g=h[v],x=[...g.items].sort((I,F)=>_r(I.id,r,c)-_r(F.id,r,c)),w=p.filter(I=>I.x===h[v-1].x),H=Math.min(...w.map(I=>I.y)),Q=Math.max(...w.map(I=>I.y+I.h))-H,tt=x.reduce((I,F)=>I+ds(F,a)+10,-10),W=H+Math.max(0,(Q-tt)/2);for(let I of x){let F=ds(I,a),hs={id:I.id,x:g.x,y:W,w:g.width,h:F,label:I.label,type:I.type,stats:I.stats,annotations:I.annotations};p.push(hs),c.set(I.id,hs),W+=F+10;}}let R=[];for(let v of r){let g=c.get(v.source),x=c.get(v.target);if(!g||!x)continue;let w=g.x<x.x,H=w?g.x+g.w:g.x,Z=g.y+g.h/2,Q=w?x.x:x.x+x.w,tt=x.y+x.h/2,W=[];v.stats.frequency>1&&W.push(`${v.stats.frequency}\xD7`),W.push(v.type),v.stats.avgLatencyMs>0&&W.push(`${v.stats.avgLatencyMs}ms`),R.push({key:v.id,sx:H,sy:Z,tx:Q,ty:tt,label:W.join(" \xB7 "),color:xe[v.type]||"#94a3b8",thickness:Math.min(.75+Math.log2(v.stats.frequency+1)*.35,2.5),dashed:v.type==="reads"||v.type==="writes",data:v});}let P=p.reduce((v,g)=>Math.max(v,g.x+g.w),0),$=p.reduce((v,g)=>Math.max(v,g.y+g.h),0);return {nodes:p,edges:R,width:P+100,height:Math.max($+50,250)}}function Tr(o){let r=o.charCodeAt(0);return r>=48&&r<=57||r>=65&&r<=70||r>=97&&r<=102}function Gi(o){if(o.length!==36)return false;for(let r=0;r<o.length;r++)if(r===8||r===13||r===18||r===23){if(o[r]!=="-")return false}else if(!Tr(o[r]))return false;return true}function Bi(o){if(!o.length)return false;for(let r=0;r<o.length;r++){let t=o.charCodeAt(r);if(t<48||t>57)return false}return true}function Wi(o){if(o.length<12)return false;for(let r=0;r<o.length;r++)if(!Tr(o[r]))return false;return true}function ji(o){if(o.length<8)return false;let r=false,t=false;for(let e=0;e<o.length;e++){let s=o.charCodeAt(e);if(s>=65&&s<=90||s>=97&&s<=122)r=true;else if(s>=48&&s<=57)t=true;else if(s!==95&&s!==45)return false}return r&&t}var Qi=":id";function Yi(o){return Gi(o)||Bi(o)||Wi(o)||ji(o)?Qi:o}function ps(o,r){let t=r.split("?")[0];return `${o} ${t.split("/").map(e=>e&&Yi(e)).join("/")}`}function wr(o,r,t){let e=[...o],s=[...r],i=new Set(e.map(a=>a.id)),n=new Map;for(let a of t){let c=a.label||"Unknown",p=n.get(c);p||(p={endpointKeys:new Set,count:0,totalMs:0},n.set(c,p)),p.count++,p.totalMs+=a.totalDurationMs;for(let h of a.requests)h.path?.startsWith(U)||p.endpointKeys.add(ps(h.method,h.path));}for(let[a,c]of n){let p=`action:${a}`;i.has(p)||(e.push({id:p,type:"action",label:a,stats:{requestCount:c.count,avgLatencyMs:c.count>0?Math.round(c.totalMs/c.count):0,errorRate:0,avgQueryCount:0}}),i.add(p));for(let h of c.endpointKeys){let m=`endpoint:${h}`;if(i.has(m)){let f=`${p} -> ${m}`;s.find(S=>S.id===f)||s.push({id:f,source:p,target:m,type:"triggers",stats:{frequency:c.count,avgLatencyMs:0}});}}}return {nodes:e,edges:s}}function Rr(o){let r=new Map;for(let t of o){let e=t.label||"Unknown",s=r.get(e);s||(s={keys:new Set,count:0,totalMs:0},r.set(e,s)),s.count++,s.totalMs+=t.totalDurationMs;for(let i of t.requests)i.path?.startsWith(U)||s.keys.add(ps(i.method,i.path));}return [...r.entries()].map(([t,e])=>({label:t,occurrences:e.count,endpointKeys:e.keys,avgDurationMs:e.count>0?Math.round(e.totalMs/e.count):0}))}function we(o,r){let t=`event=${encodeURIComponent(o)}${r?`&detail=${encodeURIComponent(r)}`:""}`;fetch(`${T.tab}?${t}`).catch(()=>{});}var M=class extends E{constructor(){super(...arguments);this.graphNodes=[];this.graphEdges=[];this.locked=null;this.hovered=null;this.loading=true;this.activeLayers=new Set;this.searchQuery="";this.viewTransform={x:0,y:0,scale:1};this.isPanning=false;this.panStart={x:0,y:0,vtx:0,vty:0};this.dragging=null;this.wasDragging=false;this.nodePositionOverrides=new Map;this.detailTab="overview";this.consolidatedFlows=[];this.activeFlowIdx=-1;this.focusIdx=-1;this.refreshTimer=null;}createRenderRoot(){return this}connectedCallback(){super.connectedCallback(),this.loadData(),this.refreshTimer=setInterval(()=>this.loadData(),4e3);}disconnectedCallback(){super.disconnectedCallback(),this.refreshTimer&&clearInterval(this.refreshTimer);}async loadData(){try{let[t,e]=await Promise.all([fetch(`${T.graph}?level=endpoints`),fetch(T.flows)]),s=await t.json(),i=await e.json(),n=wr(s.nodes||[],s.edges||[],i.flows||[]);this.graphNodes=n.nodes,this.graphEdges=n.edges,this.consolidatedFlows=Rr(i.flows||[]),this.nodePositionOverrides.size===0&&this.graphNodes.length>0&&this.tryLoadPersistedPositions(),this.loading=!1;}catch{this.loading=false;}}getPositionStorageKey(){let t=this.graphNodes.map(s=>s.id).sort().join(","),e=0;for(let s=0;s<t.length;s++)e=(e<<5)-e+t.charCodeAt(s)|0;return `bk-graph-pos-${e}`}persistPositions(){if(this.nodePositionOverrides.size!==0)try{let t=Object.fromEntries(this.nodePositionOverrides);localStorage.setItem(this.getPositionStorageKey(),JSON.stringify(t));}catch{}}tryLoadPersistedPositions(){try{let t=localStorage.getItem(this.getPositionStorageKey());if(t){let e=JSON.parse(t);this.nodePositionOverrides=new Map(Object.entries(e));}}catch{}}get activeNodeId(){return this.locked??this.hovered}getHighlightedNodeIds(){let t=this.activeNodeId;if(!t)return null;let e=new Set([t]),s=true;for(;s;){s=false;for(let i of this.graphEdges)e.has(i.source)&&!e.has(i.target)&&(e.add(i.target),s=true);}return e}getFlowTraceNodeIds(){if(this.activeFlowIdx<0||this.activeFlowIdx>=this.consolidatedFlows.length)return null;let t=this.consolidatedFlows[this.activeFlowIdx],e=new Set;e.add(`action:${t.label}`);for(let s of t.endpointKeys)e.add(`endpoint:${s}`);for(let s of this.graphEdges)e.has(s.source)&&e.add(s.target);return e}getFlowTraceEdgeIds(){let t=this.getFlowTraceNodeIds();if(!t)return null;let e=new Set;for(let s of this.graphEdges)t.has(s.source)&&t.has(s.target)&&e.add(s.id);return e}matchesSearch(t){return this.searchQuery?t.toLowerCase().includes(this.searchQuery.toLowerCase()):true}handlePanStart(t){t.button===0&&(t.target.closest(".graph-g")||(this.isPanning=true,this.panStart={x:t.clientX,y:t.clientY,vtx:this.viewTransform.x,vty:this.viewTransform.y}));}handlePanMove(t){if(this.dragging){let e=t.currentTarget.getBoundingClientRect(),s=(t.clientX-e.left-this.viewTransform.x)/this.viewTransform.scale,i=(t.clientY-e.top-this.viewTransform.y)/this.viewTransform.scale;this.nodePositionOverrides.set(this.dragging.nodeId,{x:s-this.dragging.offsetX,y:i-this.dragging.offsetY}),this.requestUpdate();return}this.isPanning&&(this.viewTransform={...this.viewTransform,x:this.panStart.vtx+(t.clientX-this.panStart.x),y:this.panStart.vty+(t.clientY-this.panStart.y)});}handlePanEnd(){this.dragging&&(this.persistPositions(),this.dragging=null,this.wasDragging=true,requestAnimationFrame(()=>{this.wasDragging=false;})),this.isPanning=false;}resetView(){this.viewTransform={x:0,y:0,scale:1};}zoomIn(){this.viewTransform={...this.viewTransform,scale:Math.min(br,this.viewTransform.scale*cs)};}zoomOut(){this.viewTransform={...this.viewTransform,scale:Math.max(gr,this.viewTransform.scale/cs)};}resetLayout(){this.nodePositionOverrides.clear();try{localStorage.removeItem(this.getPositionStorageKey());}catch{}this.viewTransform={x:0,y:0,scale:1},this.requestUpdate(),we("layout_reset");}startNodeDrag(t,e,s){t.stopPropagation();let i=t.currentTarget.closest("svg").getBoundingClientRect(),n=(t.clientX-i.left-this.viewTransform.x)/this.viewTransform.scale,a=(t.clientY-i.top-this.viewTransform.y)/this.viewTransform.scale;this.dragging={nodeId:e,offsetX:n-s.x,offsetY:a-s.y};}handleKeyDown(t){let e=this.graphNodes;if(t.key==="/"){t.preventDefault(),this.querySelector(".graph-search-input")?.focus();return}if(t.key==="Escape"){this.locked=null,this.searchQuery="",this.focusIdx=-1,this.activeFlowIdx=-1;return}if(t.key==="Tab"){t.preventDefault(),this.focusIdx=t.shiftKey?this.focusIdx<=0?e.length-1:this.focusIdx-1:(this.focusIdx+1)%e.length,this.hovered=e[this.focusIdx]?.id??null;return}if(t.key==="Enter"&&this.focusIdx>=0){let s=e[this.focusIdx];s&&(this.locked=this.locked===s.id?null:s.id);return}if(t.key==="+"||t.key==="="){this.zoomIn();return}if(t.key==="-"){this.zoomOut();return}if(t.key==="ArrowUp"){this.viewTransform={...this.viewTransform,y:this.viewTransform.y+re};return}if(t.key==="ArrowDown"){this.viewTransform={...this.viewTransform,y:this.viewTransform.y-re};return}if(t.key==="ArrowLeft"){this.viewTransform={...this.viewTransform,x:this.viewTransform.x+re};return}if(t.key==="ArrowRight"){this.viewTransform={...this.viewTransform,x:this.viewTransform.x-re};return}}render(){if(this.loading&&this.graphNodes.length===0)return l`<div class="graph-loading">Loading graph…</div>`;if(this.graphNodes.length===0)return l`
|
|
1590
1601
|
<div class="graph-empty">
|
|
1591
1602
|
<div class="graph-empty-icon">◎</div>
|
|
1592
1603
|
<div class="graph-empty-title">No data yet</div>
|
|
1593
1604
|
<div class="graph-empty-desc">Navigate your app to build the dependency graph.</div>
|
|
1594
1605
|
</div>
|
|
1595
|
-
`;let t=Sr(this.graphNodes,this.graphEdges);this.applyPositionOverrides(t);let e=this.getSelectedNodeDetail(),s=this.getHighlightedNodeIds(),i=this.getFlowTraceNodeIds(),n=this.getFlowTraceEdgeIds(),a=this.deduplicateColumnHeaders(t.nodes),c=Math.max(1,...this.graphNodes.map(h=>h.stats.requestCount)),
|
|
1606
|
+
`;let t=Sr(this.graphNodes,this.graphEdges);this.applyPositionOverrides(t);let e=this.getSelectedNodeDetail(),s=this.getHighlightedNodeIds(),i=this.getFlowTraceNodeIds(),n=this.getFlowTraceEdgeIds(),a=this.deduplicateColumnHeaders(t.nodes),c=Math.max(1,...this.graphNodes.map(h=>h.stats.requestCount)),p=this.viewTransform;return l`
|
|
1596
1607
|
<div class="graph-wrapper" tabindex="0" @keydown=${this.handleKeyDown}
|
|
1597
1608
|
@click=${h=>{let m=h.target;m.closest(".graph-detail")||m.closest(".graph-toolbar")||m.closest(".graph-float")||m.closest(".graph-g")||(this.locked=null);}}>
|
|
1598
1609
|
${this.renderToolbar()}
|
|
1599
1610
|
<div class="graph-body">
|
|
1600
1611
|
<div class="graph-canvas" style="position:relative">
|
|
1601
1612
|
<svg width="100%" height="100%"
|
|
1602
|
-
viewBox="0 0 ${Math.max(t.width,
|
|
1613
|
+
viewBox="0 0 ${Math.max(t.width,Er)} ${Math.max(t.height,yr)}"
|
|
1603
1614
|
class="graph-svg"
|
|
1604
1615
|
style="cursor:${this.isPanning?"grabbing":"grab"}"
|
|
1605
1616
|
@mousedown=${this.handlePanStart}
|
|
@@ -1607,8 +1618,8 @@ span.perf-breakdown-dot.perf-breakdown-app{background:var(--breakdown-app)}
|
|
|
1607
1618
|
@mouseup=${this.handlePanEnd}
|
|
1608
1619
|
@mouseleave=${this.handlePanEnd}>
|
|
1609
1620
|
|
|
1610
|
-
<g transform="translate(${
|
|
1611
|
-
${
|
|
1621
|
+
<g transform="translate(${p.x},${p.y}) scale(${p.scale})">
|
|
1622
|
+
${O`${a.map(h=>O`
|
|
1612
1623
|
<text x="${h.x}" y="${58}" class="graph-col-header">${h.label}</text>
|
|
1613
1624
|
`)}`}
|
|
1614
1625
|
|
|
@@ -1618,10 +1629,10 @@ span.perf-breakdown-dot.perf-breakdown-app{background:var(--breakdown-app)}
|
|
|
1618
1629
|
</svg>
|
|
1619
1630
|
${this.renderFloatingControls()}
|
|
1620
1631
|
</div>
|
|
1621
|
-
${e?this.renderDetailPanel(e):
|
|
1632
|
+
${e?this.renderDetailPanel(e):d}
|
|
1622
1633
|
</div>
|
|
1623
1634
|
</div>
|
|
1624
|
-
`}applyPositionOverrides(t){for(let s of t.nodes){let i=this.nodePositionOverrides.get(s.id);i&&(s.x=i.x,s.y=i.y);}let e=new Map(t.nodes.map(s=>[s.id,s]));for(let s of t.edges){let i=e.get(s.data.source),n=e.get(s.data.target);if(i&&n){let a=i.x<n.x;s.sx=a?i.x+i.w:i.x,s.sy=i.y+i.h/2,s.tx=a?n.x:n.x+n.w,s.ty=n.y+n.h/2;}}}deduplicateColumnHeaders(t){let e=[],s=new Set;for(let i of t)s.has(i.type)||(s.add(i.type),e.push({x:i.x,label:
|
|
1635
|
+
`}applyPositionOverrides(t){for(let s of t.nodes){let i=this.nodePositionOverrides.get(s.id);i&&(s.x=i.x,s.y=i.y);}let e=new Map(t.nodes.map(s=>[s.id,s]));for(let s of t.edges){let i=e.get(s.data.source),n=e.get(s.data.target);if(i&&n){let a=i.x<n.x;s.sx=a?i.x+i.w:i.x,s.sy=i.y+i.h/2,s.tx=a?n.x:n.x+n.w,s.ty=n.y+n.h/2;}}}deduplicateColumnHeaders(t){let e=[],s=new Set;for(let i of t)s.has(i.type)||(s.add(i.type),e.push({x:i.x,label:kt[i.type]?.columnHeader||i.type.toUpperCase()}));return e}renderToolbar(){return l`
|
|
1625
1636
|
<div class="graph-toolbar">
|
|
1626
1637
|
<div class="graph-layer-toggles">
|
|
1627
1638
|
${Object.keys(rs).map(t=>{let e=rs[t],s=this.activeLayers.has(t);return l`
|
|
@@ -1641,7 +1652,7 @@ span.perf-breakdown-dot.perf-breakdown-app{background:var(--breakdown-app)}
|
|
|
1641
1652
|
@input=${t=>{this.searchQuery=t.target.value;}}>
|
|
1642
1653
|
${this.searchQuery?l`
|
|
1643
1654
|
<button class="graph-search-clear" @click=${()=>{this.searchQuery="";}}>✕</button>
|
|
1644
|
-
`:
|
|
1655
|
+
`:d}
|
|
1645
1656
|
</div>
|
|
1646
1657
|
|
|
1647
1658
|
${this.consolidatedFlows.length>0?l`
|
|
@@ -1651,14 +1662,14 @@ span.perf-breakdown-dot.perf-breakdown-app{background:var(--breakdown-app)}
|
|
|
1651
1662
|
<option value="${e}" ?selected=${this.activeFlowIdx===e}>${t.label} → ${t.endpointKeys.size} ep · ${t.occurrences}×</option>
|
|
1652
1663
|
`)}
|
|
1653
1664
|
</select>
|
|
1654
|
-
`:
|
|
1665
|
+
`:d}
|
|
1655
1666
|
|
|
1656
1667
|
${this.activeLayers.has("auth")?l`
|
|
1657
1668
|
<div class="graph-auth-legend">
|
|
1658
1669
|
<span class="graph-auth-legend-item"><span style="color:${ns}">🛡</span> protected</span>
|
|
1659
1670
|
<span class="graph-auth-legend-item"><span style="color:${Se};font-weight:700">!</span> no auth</span>
|
|
1660
1671
|
</div>
|
|
1661
|
-
`:
|
|
1672
|
+
`:d}
|
|
1662
1673
|
</div>
|
|
1663
1674
|
`}renderFloatingControls(){let t=this.nodePositionOverrides.size>0,e=Math.round(this.viewTransform.scale*100);return l`
|
|
1664
1675
|
<div class="graph-float">
|
|
@@ -1672,7 +1683,7 @@ span.perf-breakdown-dot.perf-breakdown-app{background:var(--breakdown-app)}
|
|
|
1672
1683
|
<button class="graph-float-btn graph-float-btn-accent" @click=${()=>this.resetLayout()} title="Reset layout to auto-arrange">
|
|
1673
1684
|
⟲ Reformat
|
|
1674
1685
|
</button>
|
|
1675
|
-
`:
|
|
1686
|
+
`:d}
|
|
1676
1687
|
<span class="graph-float-sep"></span>
|
|
1677
1688
|
<button class="graph-float-btn" @click=${()=>this.captureScreenshot()} title="Save graph as PNG">
|
|
1678
1689
|
📷
|
|
@@ -1683,22 +1694,22 @@ span.perf-breakdown-dot.perf-breakdown-app{background:var(--breakdown-app)}
|
|
|
1683
1694
|
.graph-col-header { fill: #c4c4cc; font-size: 9px; font-weight: 600; letter-spacing: 1.5px; }
|
|
1684
1695
|
.graph-flow-edge { stroke-dasharray: 6,4; }
|
|
1685
1696
|
.graph-pulse { }
|
|
1686
|
-
`,e.insertBefore(s,e.firstChild);let n=document.createElementNS("http://www.w3.org/2000/svg","rect");n.setAttribute("width","100%"),n.setAttribute("height","100%"),n.setAttribute("fill","#ffffff"),e.insertBefore(n,e.firstChild);let a=e.getAttribute("viewBox")||"0 0 800 500",[,,c,
|
|
1687
|
-
<g class="graph-g" transform="translate(${t.x},${t.y})" style="opacity:${
|
|
1697
|
+
`,e.insertBefore(s,e.firstChild);let n=document.createElementNS("http://www.w3.org/2000/svg","rect");n.setAttribute("width","100%"),n.setAttribute("height","100%"),n.setAttribute("fill","#ffffff"),e.insertBefore(n,e.firstChild);let a=e.getAttribute("viewBox")||"0 0 800 500",[,,c,p]=a.split(" ").map(Number),h=2,m=c*h,f=p*h,S=new XMLSerializer().serializeToString(e),R=new Blob([S],{type:"image/svg+xml;charset=utf-8"}),P=URL.createObjectURL(R),$=new Image;$.onload=()=>{let v=document.createElement("canvas");v.width=m,v.height=f;let g=v.getContext("2d");g.fillStyle="#ffffff",g.fillRect(0,0,m,f),g.drawImage($,0,0,m,f),URL.revokeObjectURL(P),v.toBlob(x=>{if(!x)return;let w=document.createElement("a");w.href=URL.createObjectURL(x),w.download=`brakit-graph-${new Date().toISOString().slice(0,19).replace(/[T:]/g,"-")}.png`,document.body.appendChild(w),w.click(),document.body.removeChild(w),URL.revokeObjectURL(w.href);},"image/png");},$.src=P;}toggleLayer(t){let e=new Set(this.activeLayers);e.has(t)?e.delete(t):(e.add(t),we("layer_toggled",t)),this.activeLayers=e;}renderNode(t,e,s,i){let n=this.activeNodeId,a=e===null||e.has(t.id),c=n===t.id,p=this.locked===t.id,h=s?.has(t.id)??false,m=this.matchesSearch(t.label),f=kt[t.type]||kt.endpoint,S=p?cr:c?pr:f.stroke,R=p?dr:c?hr:f.fill,P=p?2:c?1.5:.75,$=a?1:.08;this.searchQuery&&!m&&($=.05),s&&!h&&($=Math.min($,.08)),h&&($=1,S=os);let v=this.searchQuery&&m,g=t.annotations,x=this.activeLayers;x.has("performance")&&g?.p95Ms!==void 0&&t.type==="endpoint"&&(R=Ot(g.p95Ms)+"18"),x.has("heat")&&(R=is(t.stats.requestCount/i)+"20");let w=x.has("auth")&&t.type==="endpoint"&&!g?.hasAuth,H=x.has("auth")&&g?.hasAuth,Z=x.has("security")?g?.securityFindings?.length??0:0,Q=g?.securityFindings?.some(F=>F.severity==="critical"),tt=x.has("issues")?g?.openIssueCount??0:0,W=this.nodeSubtitle(t),I=x.has("performance")&&g?.p95Ms!==void 0&&t.type==="endpoint";return O`
|
|
1698
|
+
<g class="graph-g" transform="translate(${t.x},${t.y})" style="opacity:${$};cursor:pointer;transition:opacity .15s,transform .1s"
|
|
1688
1699
|
@click=${F=>{F.stopPropagation(),!this.wasDragging&&(this.locked=this.locked===t.id?null:t.id,this.detailTab="overview");}}
|
|
1689
1700
|
@mouseenter=${()=>{this.hovered=t.id;}}
|
|
1690
1701
|
@mouseleave=${()=>{this.hovered=null;}}
|
|
1691
1702
|
@mousedown=${F=>{F.detail>=2||this.startNodeDrag(F,t.id,t);}}>
|
|
1692
1703
|
|
|
1693
|
-
${v?
|
|
1704
|
+
${v?O`
|
|
1694
1705
|
<rect x="-3" y="-3" width="${t.w+6}" height="${t.h+6}" rx="9" fill="none"
|
|
1695
1706
|
stroke="${ur}" stroke-width="2" stroke-dasharray="4,2"/>
|
|
1696
|
-
`:
|
|
1707
|
+
`:d}
|
|
1697
1708
|
|
|
1698
|
-
${w?
|
|
1709
|
+
${w?O`
|
|
1699
1710
|
<rect width="${t.w}" height="${t.h}" rx="8" fill="${R}" stroke="${Se}"
|
|
1700
1711
|
stroke-width="1.2" stroke-dasharray="5,3"/>
|
|
1701
|
-
`:
|
|
1712
|
+
`:O`
|
|
1702
1713
|
<rect width="${t.w}" height="${t.h}" rx="8" fill="${R}" stroke="${S}" stroke-width="${P}"/>
|
|
1703
1714
|
`}
|
|
1704
1715
|
|
|
@@ -1707,75 +1718,75 @@ span.perf-breakdown-dot.perf-breakdown-app{background:var(--breakdown-app)}
|
|
|
1707
1718
|
<text x="12" y="${t.h/2+10}" fill="#a1a1aa" font-size="9"
|
|
1708
1719
|
font-family="ui-monospace,monospace">${W}</text>
|
|
1709
1720
|
|
|
1710
|
-
${
|
|
1711
|
-
<text x="${t.w-8}" y="${t.h-6}" fill="${
|
|
1721
|
+
${I?O`
|
|
1722
|
+
<text x="${t.w-8}" y="${t.h-6}" fill="${Ot(g.p95Ms)}" font-size="9"
|
|
1712
1723
|
font-family="ui-monospace,monospace" text-anchor="end">p95: ${g.p95Ms}ms</text>
|
|
1713
|
-
`:
|
|
1724
|
+
`:d}
|
|
1714
1725
|
|
|
1715
|
-
${H?
|
|
1726
|
+
${H?O`
|
|
1716
1727
|
<g transform="translate(${t.w-24},3)">
|
|
1717
1728
|
<title>Auth protected</title>
|
|
1718
1729
|
<rect width="18" height="18" rx="3" fill="${mr}" stroke="${ns}" stroke-width="0.5"/>
|
|
1719
1730
|
<text x="9" y="13" text-anchor="middle" font-size="10">🛡</text>
|
|
1720
1731
|
</g>
|
|
1721
|
-
`:
|
|
1732
|
+
`:d}
|
|
1722
1733
|
|
|
1723
|
-
${w?
|
|
1734
|
+
${w?O`
|
|
1724
1735
|
<g transform="translate(${t.w-24},3)">
|
|
1725
1736
|
<title>No auth detected — this endpoint may be unprotected</title>
|
|
1726
1737
|
<rect width="18" height="18" rx="3" fill="#fff7ed" stroke="${Se}" stroke-width="0.5"/>
|
|
1727
1738
|
<text x="9" y="13" text-anchor="middle" font-size="10" fill="#ea580c">!</text>
|
|
1728
1739
|
</g>
|
|
1729
|
-
`:
|
|
1740
|
+
`:d}
|
|
1730
1741
|
|
|
1731
|
-
${Z>0?
|
|
1742
|
+
${Z>0?O`
|
|
1732
1743
|
<g transform="translate(${t.w-(H||w?46:24)},3)">
|
|
1733
|
-
<rect width="18" height="18" rx="3" fill="${
|
|
1734
|
-
stroke="${
|
|
1735
|
-
class="${
|
|
1744
|
+
<rect width="18" height="18" rx="3" fill="${Q?fr:vr}"
|
|
1745
|
+
stroke="${Q?as:ls}" stroke-width="0.5"
|
|
1746
|
+
class="${Q?"graph-pulse":""}"/>
|
|
1736
1747
|
<text x="9" y="13" text-anchor="middle" font-size="9" font-weight="600"
|
|
1737
|
-
fill="${
|
|
1748
|
+
fill="${Q?as:ls}">${Z}</text>
|
|
1738
1749
|
</g>
|
|
1739
|
-
`:
|
|
1750
|
+
`:d}
|
|
1740
1751
|
|
|
1741
|
-
${tt>0?
|
|
1752
|
+
${tt>0?O`
|
|
1742
1753
|
<circle cx="${t.w-8}" cy="8" r="5" fill="${ut}" stroke="white" stroke-width="1"/>
|
|
1743
1754
|
<text x="${t.w-8}" y="11" text-anchor="middle" font-size="7" fill="white" font-weight="700">${tt}</text>
|
|
1744
|
-
`:t.stats.errorRate>.05?
|
|
1755
|
+
`:t.stats.errorRate>.05?O`<circle cx="${t.w-12}" cy="12" r="4" fill="${ut}"/>`:d}
|
|
1745
1756
|
|
|
1746
|
-
${g?.isMiddleware&&x.has("auth")?
|
|
1757
|
+
${g?.isMiddleware&&x.has("auth")?O`
|
|
1747
1758
|
<text x="${t.w}" y="${t.h+12}" text-anchor="end" font-size="8" fill="#6b7280"
|
|
1748
1759
|
font-family="ui-monospace,monospace">middleware</text>
|
|
1749
|
-
`:
|
|
1760
|
+
`:d}
|
|
1750
1761
|
</g>
|
|
1751
|
-
`}nodeSubtitle(t){switch(t.type){case "endpoint":return `${t.stats.requestCount} req \xB7 ${t.stats.avgLatencyMs}ms${t.stats.avgQueryCount>0?` \xB7 ${t.stats.avgQueryCount}q`:""}`;case "action":return `${t.stats.requestCount}\xD7 \xB7 ${t.stats.avgLatencyMs}ms`;case "table":return "table";default:return "service"}}renderEdge(t,e,s,i){let n=this.activeNodeId,a=e===null||e.has(t.data.source)&&e.has(t.data.target),c=s?.has(t.key)??false,
|
|
1762
|
+
`}nodeSubtitle(t){switch(t.type){case "endpoint":return `${t.stats.requestCount} req \xB7 ${t.stats.avgLatencyMs}ms${t.stats.avgQueryCount>0?` \xB7 ${t.stats.avgQueryCount}q`:""}`;case "action":return `${t.stats.requestCount}\xD7 \xB7 ${t.stats.avgLatencyMs}ms`;case "table":return "table";default:return "service"}}renderEdge(t,e,s,i){let n=this.activeNodeId,a=e===null||e.has(t.data.source)&&e.has(t.data.target),c=s?.has(t.key)??false,p=a?n===null?.25:.6:.04,h=a&&n!==null,m=t.color,f=t.thickness;if(s&&!c&&(p=.04),c&&(p=.85,m=os,f=Math.max(f,1.8)),this.activeLayers.has("heat")&&!c){let tt=Math.max(1,...this.graphEdges.map(I=>I.stats.frequency)),W=t.data.stats.frequency/tt;m=is(W),a&&(p=Math.max(p,.4));}let S=this.activeLayers.has("issues")&&t.data.annotations?.hasIssue,R=Math.abs(t.tx-t.sx),P=Math.min(R*.45,120),$=t.sx<t.tx,v=$?t.sx+P:t.sx-P,g=$?t.tx-P:t.tx+P,x=(t.sx+t.tx)/2,w=(t.sy+t.ty)/2,H=4,Z=S?ut:m,Q=S?Math.max(f,1.5):f;return O`
|
|
1752
1763
|
<g style="transition:opacity .15s">
|
|
1753
1764
|
<path d="M${t.sx},${t.sy} C${v},${t.sy} ${g},${t.ty} ${t.tx},${t.ty}"
|
|
1754
|
-
fill="none" stroke="${Z}" stroke-width="${
|
|
1755
|
-
stroke-opacity="${
|
|
1765
|
+
fill="none" stroke="${Z}" stroke-width="${Q}"
|
|
1766
|
+
stroke-opacity="${p}" stroke-linecap="round"
|
|
1756
1767
|
stroke-dasharray="${c?"6,4":t.dashed?"3,3":"none"}"
|
|
1757
1768
|
class="${c?"graph-flow-edge":""}"/>
|
|
1758
|
-
<polygon points="${t.tx},${t.ty} ${t.tx+(
|
|
1759
|
-
fill="${Z}" fill-opacity="${
|
|
1760
|
-
${h?
|
|
1769
|
+
<polygon points="${t.tx},${t.ty} ${t.tx+($?-H*1.5:H*1.5)},${t.ty-H} ${t.tx+($?-H*1.5:H*1.5)},${t.ty+H}"
|
|
1770
|
+
fill="${Z}" fill-opacity="${p}"/>
|
|
1771
|
+
${h?O`
|
|
1761
1772
|
<rect x="${x-t.label.length*2.8-2}" y="${w-7}" width="${t.label.length*5.6+8}" height="14"
|
|
1762
1773
|
rx="4" fill="white" fill-opacity="0.92" stroke="${m}" stroke-width="0.4" stroke-opacity="0.15"/>
|
|
1763
1774
|
<text x="${x}" y="${w+3.5}" fill="${m}" font-size="8" font-weight="500"
|
|
1764
1775
|
font-family="ui-monospace,monospace" text-anchor="middle" opacity="0.85">${t.label}</text>
|
|
1765
|
-
`:
|
|
1766
|
-
${S?
|
|
1776
|
+
`:d}
|
|
1777
|
+
${S?O`
|
|
1767
1778
|
<text x="${x}" y="${w-10}" fill="${ut}" font-size="8" font-weight="600"
|
|
1768
1779
|
text-anchor="middle">⚠ N+1</text>
|
|
1769
|
-
`:
|
|
1780
|
+
`:d}
|
|
1770
1781
|
</g>
|
|
1771
|
-
`}renderDetailPanel(t){let{node:e,edges:s}=t,i=
|
|
1782
|
+
`}renderDetailPanel(t){let{node:e,edges:s}=t,i=kt[e.type]||kt.endpoint,n=e.annotations,a=(n?.securityFindings?.length??0)>0,c=(n?.openIssueCount??0)>0,p=n?.p95Ms!==void 0,m=[{key:"overview",label:"Overview",show:true},{key:"security",label:`Security${a?` (${n.securityFindings.length})`:""}`,show:a},{key:"performance",label:"Perf",show:p},{key:"issues",label:`Issues${c?` (${n.openIssueCount})`:""}`,show:c}].filter(f=>f.show);return l`
|
|
1772
1783
|
<div class="graph-detail">
|
|
1773
1784
|
<div class="graph-detail-head">
|
|
1774
1785
|
<div>
|
|
1775
1786
|
<div class="graph-detail-badge" style="color:${i.stroke}">${i.icon} ${e.type}</div>
|
|
1776
1787
|
<div class="graph-detail-name">${e.label}</div>
|
|
1777
|
-
${n?.hasAuth?l`<span class="graph-detail-auth-badge">🛡 Authenticated</span>`:
|
|
1778
|
-
${n?.isMiddleware?l`<span class="graph-detail-mw-badge">middleware</span>`:
|
|
1788
|
+
${n?.hasAuth?l`<span class="graph-detail-auth-badge">🛡 Authenticated</span>`:d}
|
|
1789
|
+
${n?.isMiddleware?l`<span class="graph-detail-mw-badge">middleware</span>`:d}
|
|
1779
1790
|
</div>
|
|
1780
1791
|
<button class="graph-detail-close" @click=${()=>{this.locked=null;}}>✕</button>
|
|
1781
1792
|
</div>
|
|
@@ -1787,12 +1798,12 @@ span.perf-breakdown-dot.perf-breakdown-app{background:var(--breakdown-app)}
|
|
|
1787
1798
|
@click=${()=>{this.detailTab=f.key;}}>${f.label}</button>
|
|
1788
1799
|
`)}
|
|
1789
1800
|
</div>
|
|
1790
|
-
`:
|
|
1801
|
+
`:d}
|
|
1791
1802
|
|
|
1792
|
-
${this.detailTab==="overview"?this.renderOverviewTab(e,s):
|
|
1793
|
-
${this.detailTab==="security"?this.renderSecurityTab(n):
|
|
1794
|
-
${this.detailTab==="performance"?this.renderPerformanceTab(e,n):
|
|
1795
|
-
${this.detailTab==="issues"?this.renderIssuesTab(n):
|
|
1803
|
+
${this.detailTab==="overview"?this.renderOverviewTab(e,s):d}
|
|
1804
|
+
${this.detailTab==="security"?this.renderSecurityTab(n):d}
|
|
1805
|
+
${this.detailTab==="performance"?this.renderPerformanceTab(e,n):d}
|
|
1806
|
+
${this.detailTab==="issues"?this.renderIssuesTab(n):d}
|
|
1796
1807
|
</div>
|
|
1797
1808
|
`}renderOverviewTab(t,e){return l`
|
|
1798
1809
|
<div class="graph-detail-stats">
|
|
@@ -1801,7 +1812,7 @@ span.perf-breakdown-dot.perf-breakdown-app{background:var(--breakdown-app)}
|
|
|
1801
1812
|
<div class="graph-detail-lbl">${t.type==="action"?"OCCURRENCES":"REQUESTS"}</div>
|
|
1802
1813
|
</div>
|
|
1803
1814
|
<div class="graph-detail-stat">
|
|
1804
|
-
<div class="graph-detail-val" style="color:${
|
|
1815
|
+
<div class="graph-detail-val" style="color:${Ot(t.stats.avgLatencyMs)}">${t.stats.avgLatencyMs}ms</div>
|
|
1805
1816
|
<div class="graph-detail-lbl">AVG LATENCY</div>
|
|
1806
1817
|
</div>
|
|
1807
1818
|
${t.stats.avgQueryCount>0?l`
|
|
@@ -1809,13 +1820,13 @@ span.perf-breakdown-dot.perf-breakdown-app{background:var(--breakdown-app)}
|
|
|
1809
1820
|
<div class="graph-detail-val">${t.stats.avgQueryCount}</div>
|
|
1810
1821
|
<div class="graph-detail-lbl">QUERIES/REQ</div>
|
|
1811
1822
|
</div>
|
|
1812
|
-
`:
|
|
1823
|
+
`:d}
|
|
1813
1824
|
${t.stats.errorRate>.01?l`
|
|
1814
1825
|
<div class="graph-detail-stat">
|
|
1815
1826
|
<div class="graph-detail-val" style="color:${ut}">${Math.round(t.stats.errorRate*100)}%</div>
|
|
1816
1827
|
<div class="graph-detail-lbl">ERRORS</div>
|
|
1817
1828
|
</div>
|
|
1818
|
-
`:
|
|
1829
|
+
`:d}
|
|
1819
1830
|
</div>
|
|
1820
1831
|
|
|
1821
1832
|
${e.length>0?l`
|
|
@@ -1828,14 +1839,14 @@ span.perf-breakdown-dot.perf-breakdown-app{background:var(--breakdown-app)}
|
|
|
1828
1839
|
<span class="graph-detail-dim">${s.stats.frequency}× · ${s.stats.avgLatencyMs}ms</span>
|
|
1829
1840
|
</div>
|
|
1830
1841
|
`})}
|
|
1831
|
-
`:
|
|
1842
|
+
`:d}
|
|
1832
1843
|
|
|
1833
1844
|
${e.some(s=>s.patterns?.length)?l`
|
|
1834
1845
|
<div class="graph-detail-sec">SQL Patterns</div>
|
|
1835
1846
|
${e.filter(s=>s.patterns).flatMap(s=>s.patterns).map(s=>l`
|
|
1836
1847
|
<pre class="graph-detail-sql">${s.length>200?s.slice(0,200)+"\u2026":s}</pre>
|
|
1837
1848
|
`)}
|
|
1838
|
-
`:
|
|
1849
|
+
`:d}
|
|
1839
1850
|
`}renderSecurityTab(t){return t?.securityFindings?.length?l`
|
|
1840
1851
|
${t.securityFindings.map(e=>l`
|
|
1841
1852
|
<div class="graph-detail-finding">
|
|
@@ -1848,12 +1859,12 @@ span.perf-breakdown-dot.perf-breakdown-app{background:var(--breakdown-app)}
|
|
|
1848
1859
|
<div class="graph-detail-stats">
|
|
1849
1860
|
${e?.p95Ms!==void 0?l`
|
|
1850
1861
|
<div class="graph-detail-stat">
|
|
1851
|
-
<div class="graph-detail-val" style="color:${
|
|
1862
|
+
<div class="graph-detail-val" style="color:${Ot(e.p95Ms)}">${e.p95Ms}ms</div>
|
|
1852
1863
|
<div class="graph-detail-lbl">P95 LATENCY</div>
|
|
1853
1864
|
</div>
|
|
1854
|
-
`:
|
|
1865
|
+
`:d}
|
|
1855
1866
|
<div class="graph-detail-stat">
|
|
1856
|
-
<div class="graph-detail-val" style="color:${
|
|
1867
|
+
<div class="graph-detail-val" style="color:${Ot(t.stats.avgLatencyMs)}">${t.stats.avgLatencyMs}ms</div>
|
|
1857
1868
|
<div class="graph-detail-lbl">AVG LATENCY</div>
|
|
1858
1869
|
</div>
|
|
1859
1870
|
${t.stats.avgQueryCount>0?l`
|
|
@@ -1861,7 +1872,7 @@ span.perf-breakdown-dot.perf-breakdown-app{background:var(--breakdown-app)}
|
|
|
1861
1872
|
<div class="graph-detail-val">${t.stats.avgQueryCount}</div>
|
|
1862
1873
|
<div class="graph-detail-lbl">QUERIES/REQ</div>
|
|
1863
1874
|
</div>
|
|
1864
|
-
`:
|
|
1875
|
+
`:d}
|
|
1865
1876
|
<div class="graph-detail-stat">
|
|
1866
1877
|
<div class="graph-detail-val">${t.stats.requestCount}</div>
|
|
1867
1878
|
<div class="graph-detail-lbl">TOTAL REQS</div>
|
|
@@ -1877,7 +1888,7 @@ span.perf-breakdown-dot.perf-breakdown-app{background:var(--breakdown-app)}
|
|
|
1877
1888
|
<div class="graph-detail-finding-meta">${s.type}</div>
|
|
1878
1889
|
</div>
|
|
1879
1890
|
`)}
|
|
1880
|
-
`:
|
|
1891
|
+
`:d}
|
|
1881
1892
|
`}renderIssuesTab(t){let e=t?.openIssueCount??0;return e===0?l`<div class="graph-detail-empty">No open issues</div>`:l`
|
|
1882
1893
|
<div class="graph-detail-issue-summary">
|
|
1883
1894
|
<div class="graph-detail-stat">
|
|
@@ -1886,7 +1897,7 @@ span.perf-breakdown-dot.perf-breakdown-app{background:var(--breakdown-app)}
|
|
|
1886
1897
|
</div>
|
|
1887
1898
|
</div>
|
|
1888
1899
|
<p class="graph-detail-hint">View the Issues tab for full details and remediation hints.</p>
|
|
1889
|
-
`}getSelectedNodeDetail(){if(!this.locked)return null;let t=this.graphNodes.find(s=>s.id===this.locked);if(!t)return null;let e=this.graphEdges.filter(s=>s.source===this.locked||s.target===this.locked);return {node:t,edges:e}}};u([
|
|
1900
|
+
`}getSelectedNodeDetail(){if(!this.locked)return null;let t=this.graphNodes.find(s=>s.id===this.locked);if(!t)return null;let e=this.graphEdges.filter(s=>s.source===this.locked||s.target===this.locked);return {node:t,edges:e}}};u([C({context:A})],M.prototype,"store",2),u([b()],M.prototype,"graphNodes",2),u([b()],M.prototype,"graphEdges",2),u([b()],M.prototype,"locked",2),u([b()],M.prototype,"hovered",2),u([b()],M.prototype,"loading",2),u([b()],M.prototype,"activeLayers",2),u([b()],M.prototype,"searchQuery",2),u([b()],M.prototype,"viewTransform",2),u([b()],M.prototype,"dragging",2),u([b()],M.prototype,"detailTab",2),u([b()],M.prototype,"consolidatedFlows",2),u([b()],M.prototype,"activeFlowIdx",2),u([b()],M.prototype,"focusIdx",2),M=u([_("bk-graph-view")],M);var ie=class extends J{constructor(){super(...arguments);this.activeTab="requests";this.handleNavigateExplorer=t=>{let e=t.detail;ve.some(s=>s.key===e)&&(this.activeTab=e);};}connectedCallback(){super.connectedCallback(),window.addEventListener("navigate-explorer",this.handleNavigateExplorer);}disconnectedCallback(){super.disconnectedCallback(),window.removeEventListener("navigate-explorer",this.handleNavigateExplorer);}switchTab(t){this.activeTab=t,fetch(`${T.tab}?event=explorer.${t}`).catch(()=>{});}getCount(t){let e=this.store.state;switch(t){case "requests":return e.requests.filter(s=>!s.path?.startsWith(U)).length;case "fetches":return e.fetches.length;case "queries":return e.queries.length;case "logs":return e.logs.length;case "errors":return e.errors.length}}render(){return l`
|
|
1890
1901
|
<div class="explorer-tabs">
|
|
1891
1902
|
${ve.map(t=>l`
|
|
1892
1903
|
<button class="explorer-tab ${this.activeTab===t.key?"active":""}"
|
|
@@ -1911,22 +1922,27 @@ span.perf-breakdown-dot.perf-breakdown-app{background:var(--breakdown-app)}
|
|
|
1911
1922
|
<div style="display:${this.activeTab==="errors"?"block":"none"}">
|
|
1912
1923
|
<bk-errors-view></bk-errors-view>
|
|
1913
1924
|
</div>
|
|
1914
|
-
`}};u([
|
|
1925
|
+
`}};u([b()],ie.prototype,"activeTab",2),ie=u([_("bk-explorer-view")],ie);var Vi=[{key:"all",label:"All"},{key:"security",label:"Security"},{key:"performance",label:"Performance"},{key:"reliability",label:"Reliability"}],mt=class extends J{constructor(){super(...arguments);this.filter="all";this.expandedIdx=-1;this.showDismissed=false;}getFilteredIssues(t){return (this.filter==="all"?t:t.filter(s=>Xt(s)===this.filter)).sort((s,i)=>{let n=h=>h==="open"||h==="regressed"?0:h==="fixing"?1:2,a=n(s.state)-n(i.state);if(a!==0)return a;let c=Y[s.issue.severity]?.sort??3,p=Y[i.issue.severity]?.sort??3;return c-p})}getCounts(t){let e={all:t.length,security:0,performance:0,reliability:0};for(let s of t)e[Xt(s)]++;return e}render(){if(!(this.store.state.requests.length>0||this.store.state.queries.length>0))return l`<bk-empty-state
|
|
1915
1926
|
title="Waiting for requests..."
|
|
1916
1927
|
subtitle="Start using your app to see insights here"
|
|
1917
|
-
></bk-empty-state>`;let e=(this.store.state.issues||[]).filter(ir),s=this.getFilteredIssues(e),i=this.getCounts(e),n=s.filter(f=>f.state==="open"&&f.aiStatus!=="wont_fix"),a=s.filter(f=>f.state==="regressed"&&f.aiStatus!=="wont_fix"),c=s.filter(f=>f.state==="fixing"),
|
|
1928
|
+
></bk-empty-state>`;let e=(this.store.state.issues||[]).filter(ir),s=this.getFilteredIssues(e),i=this.getCounts(e),n=s.filter(f=>f.state==="open"&&f.aiStatus!=="wont_fix"),a=s.filter(f=>f.state==="regressed"&&f.aiStatus!=="wont_fix"),c=s.filter(f=>f.state==="fixing"),p=s.filter(f=>f.state==="resolved"),h=s.filter(f=>f.aiStatus==="wont_fix"),m=0;return l`
|
|
1918
1929
|
<div class="insights-filters">
|
|
1919
|
-
${
|
|
1930
|
+
${Vi.map(f=>l`
|
|
1920
1931
|
<button class="insights-chip ${this.filter===f.key?"active":""}"
|
|
1921
1932
|
@click=${()=>{this.filter=f.key,this.expandedIdx=-1;}}>
|
|
1922
1933
|
${f.label}
|
|
1923
|
-
${i[f.key]>0?l`<span class="insights-chip-count">${i[f.key]}</span>`:
|
|
1934
|
+
${i[f.key]>0?l`<span class="insights-chip-count">${i[f.key]}</span>`:d}
|
|
1924
1935
|
</button>
|
|
1925
1936
|
`)}
|
|
1926
1937
|
</div>
|
|
1927
1938
|
|
|
1939
|
+
${this.renderSummaryBar(e)}
|
|
1940
|
+
|
|
1928
1941
|
<div class="insights-list">
|
|
1929
|
-
${n.length
|
|
1942
|
+
${n.length+a.length>0?l`
|
|
1943
|
+
<div class="insights-ai-hint">Copy to your AI: <code>"Fix brakit findings"</code></div>
|
|
1944
|
+
`:d}
|
|
1945
|
+
${n.length===0&&a.length===0&&c.length===0&&p.length===0&&h.length===0?l`<div class="insights-empty"><span class="insights-empty-icon">\u2713</span>${this.filter==="all"?"All clear \u2014 no issues detected":`No ${this.filter} issues`}</div>`:d}
|
|
1930
1946
|
|
|
1931
1947
|
${a.length>0?l`
|
|
1932
1948
|
<div class="insights-section insights-section-regressed">
|
|
@@ -1934,7 +1950,7 @@ span.perf-breakdown-dot.perf-breakdown-app{background:var(--breakdown-app)}
|
|
|
1934
1950
|
<span class="insights-section-count">${a.length}</span>
|
|
1935
1951
|
</div>
|
|
1936
1952
|
${a.map(f=>this.renderIssueCard(f,m++))}
|
|
1937
|
-
`:
|
|
1953
|
+
`:d}
|
|
1938
1954
|
|
|
1939
1955
|
${n.length>0?l`
|
|
1940
1956
|
<div class="insights-section">
|
|
@@ -1942,7 +1958,7 @@ span.perf-breakdown-dot.perf-breakdown-app{background:var(--breakdown-app)}
|
|
|
1942
1958
|
<span class="insights-section-count">${n.length}</span>
|
|
1943
1959
|
</div>
|
|
1944
1960
|
${n.map(f=>this.renderIssueCard(f,m++))}
|
|
1945
|
-
`:
|
|
1961
|
+
`:d}
|
|
1946
1962
|
|
|
1947
1963
|
${c.length>0?l`
|
|
1948
1964
|
<div class="insights-section insights-section-verifying">
|
|
@@ -1950,25 +1966,31 @@ span.perf-breakdown-dot.perf-breakdown-app{background:var(--breakdown-app)}
|
|
|
1950
1966
|
<span class="insights-section-count">${c.length}</span>
|
|
1951
1967
|
</div>
|
|
1952
1968
|
${c.map(f=>this.renderIssueCard(f,m++))}
|
|
1953
|
-
`:
|
|
1969
|
+
`:d}
|
|
1954
1970
|
|
|
1955
|
-
${
|
|
1971
|
+
${p.length>0?l`
|
|
1956
1972
|
<div class="insights-section insights-section-resolved">
|
|
1957
1973
|
<span class="insights-section-icon">\u2713</span> Resolved
|
|
1958
|
-
<span class="insights-section-count">${
|
|
1974
|
+
<span class="insights-section-count">${p.length}</span>
|
|
1959
1975
|
</div>
|
|
1960
|
-
${
|
|
1961
|
-
`:
|
|
1976
|
+
${p.map(f=>this.renderIssueCard(f,m++))}
|
|
1977
|
+
`:d}
|
|
1962
1978
|
|
|
1963
1979
|
${h.length>0?l`
|
|
1964
1980
|
<div class="insights-section insights-section-dismissed" @click=${()=>{this.showDismissed=!this.showDismissed;}}>
|
|
1965
1981
|
<span class="insights-section-icon">${this.showDismissed?"\u25BE":"\u25B8"}</span> Won't Fix
|
|
1966
1982
|
<span class="insights-section-count">${h.length}</span>
|
|
1967
1983
|
</div>
|
|
1968
|
-
${this.showDismissed?h.map(f=>this.renderIssueCard(f,m++)):
|
|
1969
|
-
`:
|
|
1984
|
+
${this.showDismissed?h.map(f=>this.renderIssueCard(f,m++)):d}
|
|
1985
|
+
`:d}
|
|
1986
|
+
</div>
|
|
1987
|
+
`}renderSummaryBar(t){let e=t.filter(a=>(a.state==="open"||a.state==="regressed")&&a.aiStatus!=="wont_fix"),s=e.filter(a=>a.issue.severity==="critical").length,i=e.filter(a=>a.issue.severity==="warning").length,n=t.filter(a=>a.state==="resolved").length;return s===0&&i===0&&n===0?d:l`
|
|
1988
|
+
<div class="insights-summary">
|
|
1989
|
+
${s>0?l`<span class="insights-summary-stat critical">${s} critical</span>`:d}
|
|
1990
|
+
${i>0?l`<span class="insights-summary-stat warning">${i} warning</span>`:d}
|
|
1991
|
+
${n>0?l`<span class="insights-summary-stat resolved">${n} resolved</span>`:d}
|
|
1970
1992
|
</div>
|
|
1971
|
-
`}renderIssueCard(t,e){let s=t.issue,i=Y[s.severity]||Y.info,n=this.expandedIdx===e,a=t.state==="resolved",c=t.state==="fixing",
|
|
1993
|
+
`}renderIssueCard(t,e){let s=t.issue,i=Y[s.severity]||Y.info,n=this.expandedIdx===e,a=t.state==="resolved",c=t.state==="fixing",p=Xt(t);return l`
|
|
1972
1994
|
<div class="insights-card ${n?"expanded":""} ${a?"resolved":""}"
|
|
1973
1995
|
@click=${()=>{this.expandedIdx=this.expandedIdx===e?-1:e;}}>
|
|
1974
1996
|
<div class="insights-card-left">
|
|
@@ -1977,59 +1999,61 @@ span.perf-breakdown-dot.perf-breakdown-app{background:var(--breakdown-app)}
|
|
|
1977
1999
|
<div class="insights-card-body">
|
|
1978
2000
|
<div class="insights-card-header">
|
|
1979
2001
|
<span class="insights-card-title ${a?"resolved":""}">${s.title}</span>
|
|
1980
|
-
<span class="insights-card-cat">${
|
|
1981
|
-
${s.count?l`<span class="insights-card-count">${s.count}\u00D7</span>`:
|
|
1982
|
-
${t.state==="regressed"?l`<span class="insights-badge-regressed">regressed</span>`:
|
|
1983
|
-
${c?l`<span class="insights-badge-verifying">verifying</span>`:
|
|
1984
|
-
${a?l`<span class="insights-badge-resolved">resolved</span>`:
|
|
2002
|
+
<span class="insights-card-cat">${p}</span>
|
|
2003
|
+
${s.count?l`<span class="insights-card-count">${s.count}\u00D7</span>`:d}
|
|
2004
|
+
${t.state==="regressed"?l`<span class="insights-badge-regressed">regressed</span>`:d}
|
|
2005
|
+
${c?l`<span class="insights-badge-verifying">verifying</span>`:d}
|
|
2006
|
+
${a?l`<span class="insights-badge-resolved">resolved</span>`:d}
|
|
1985
2007
|
</div>
|
|
1986
2008
|
<div class="insights-card-desc">${s.desc}</div>
|
|
1987
|
-
${
|
|
1988
|
-
|
|
1989
|
-
|
|
1990
|
-
|
|
1991
|
-
|
|
2009
|
+
${n?l`
|
|
2010
|
+
${s.detail?l`<div class="insights-card-detail">${s.detail}</div>`:d}
|
|
2011
|
+
${t.cleanHitsSinceLastSeen>0?l`
|
|
2012
|
+
<div class="insights-card-progress">${t.cleanHitsSinceLastSeen}/${5} clean requests</div>
|
|
2013
|
+
`:d}
|
|
2014
|
+
${s.hint?l`<div class="insights-card-hint">${s.hint}</div>`:d}
|
|
2015
|
+
`:d}
|
|
1992
2016
|
</div>
|
|
1993
|
-
${s.hint?l`<span class="insights-card-arrow">${n?"\u2193":"\u2192"}</span>`:
|
|
2017
|
+
${s.hint?l`<span class="insights-card-arrow">${n?"\u2193":"\u2192"}</span>`:d}
|
|
1994
2018
|
</div>
|
|
1995
|
-
`}};u([
|
|
2019
|
+
`}};u([b()],mt.prototype,"filter",2),u([b()],mt.prototype,"expandedIdx",2),u([b()],mt.prototype,"showDismissed",2),mt=u([_("bk-insights-view")],mt);function Ki(o){return o===0?"<1ms":y(o)}var k=class extends E{constructor(){super(...arguments);this.requestId="";this.requestStarted=0;this.data=null;this.loading=false;this.failed=false;this.expandedSqlIdx=-1;}createRenderRoot(){return this}connectedCallback(){super.connectedCallback(),this.store.addEventListener("state-changed",()=>this.requestUpdate()),this.requestId&&this.loadTimeline();}async loadTimeline(){if(!this.requestId)return;let t=k.cache.get(this.requestId);if(t){this.data=t;return}this.loading=true;try{let e=await fetch(`${T.activity}?requestId=${this.requestId}`);if(!e.ok){this.failed=!0,this.loading=!1;return}let s=await e.json();if(k.cache.size>=We){let i=k.cache.keys().next().value;i!==void 0&&k.cache.delete(i);}k.cache.set(this.requestId,s),this.data=s,this.loading=!1;}catch(e){console.debug("[brakit] timeline load failed:",e),this.failed=true,this.loading=false;}}toggleSql(t,e){e.stopPropagation(),this.expandedSqlIdx=this.expandedSqlIdx===t?-1:t;}copySql(t,e){e.stopPropagation(),navigator.clipboard.writeText(t).then(()=>D.show("SQL copied")).catch(()=>D.show("Copy failed"));}render(){if(this.loading)return l`<div class="tl-loading">Loading activity...</div>`;if(this.failed||!this.data||this.data.total===0)return d;let t=this.data,e=t.timeline[0]?.timestamp??0;return l`
|
|
1996
2020
|
<div class="tl-header">
|
|
1997
2021
|
<span class="tl-title">Activity Timeline</span>
|
|
1998
2022
|
<span class="tl-counts">
|
|
1999
|
-
${t.counts.queries>0?l`<span class="tl-count tl-count-query">${t.counts.queries} quer${t.counts.queries===1?"y":"ies"}</span>`:
|
|
2000
|
-
${t.counts.fetches>0?l`<span class="tl-count tl-count-fetch">${t.counts.fetches} fetch${t.counts.fetches===1?"":"es"}</span>`:
|
|
2001
|
-
${t.counts.logs>0?l`<span class="tl-count tl-count-log">${t.counts.logs} log${t.counts.logs===1?"":"s"}</span>`:
|
|
2002
|
-
${t.counts.errors>0?l`<span class="tl-count tl-count-error">${t.counts.errors} error${t.counts.errors===1?"":"s"}</span>`:
|
|
2023
|
+
${t.counts.queries>0?l`<span class="tl-count tl-count-query">${t.counts.queries} quer${t.counts.queries===1?"y":"ies"}</span>`:d}
|
|
2024
|
+
${t.counts.fetches>0?l`<span class="tl-count tl-count-fetch">${t.counts.fetches} fetch${t.counts.fetches===1?"":"es"}</span>`:d}
|
|
2025
|
+
${t.counts.logs>0?l`<span class="tl-count tl-count-log">${t.counts.logs} log${t.counts.logs===1?"":"s"}</span>`:d}
|
|
2026
|
+
${t.counts.errors>0?l`<span class="tl-count tl-count-error">${t.counts.errors} error${t.counts.errors===1?"":"s"}</span>`:d}
|
|
2003
2027
|
</span>
|
|
2004
2028
|
</div>
|
|
2005
2029
|
<div class="tl-events">${this.renderTimeline(t.timeline,e)}</div>
|
|
2006
|
-
`}renderTimeline(t,e){let s=new Map,i=[];for(let a of t){let c=a.type==="query"?a.data.parentFetchId:void 0;if(a.type==="query"&&c){let
|
|
2030
|
+
`}renderTimeline(t,e){let s=new Map,i=[];for(let a of t){let c=a.type==="query"?a.data.parentFetchId:void 0;if(a.type==="query"&&c){let p=s.get(c);p||(p=[],s.set(c,p)),p.push(a);}else i.push(a);}let n=0;return i.map(a=>{let c=n++,p=a.type==="fetch"?a.data.fetchId:void 0,h=p?s.get(p):void 0;if(h&&h.length>0){let m=h.length;return l`
|
|
2007
2031
|
${this.renderEvent(a,c,e)}
|
|
2008
2032
|
<div class="tl-nested">
|
|
2009
2033
|
<span class="tl-nested-label">${m} nested quer${m===1?"y":"ies"}</span>
|
|
2010
2034
|
${h.map(f=>{let S=n++;return this.renderEvent(f,S,e,true)})}
|
|
2011
2035
|
</div>
|
|
2012
|
-
`}return this.renderEvent(a,c,e)})}renderEvent(t,e,s,i=false){let n=Bs[t.type]||"var(--text-dim)",a=Ws[t.type]||t.type,c="+"+y(Math.round(t.timestamp-s)),
|
|
2036
|
+
`}return this.renderEvent(a,c,e)})}renderEvent(t,e,s,i=false){let n=Bs[t.type]||"var(--text-dim)",a=Ws[t.type]||t.type,c="+"+y(Math.round(t.timestamp-s)),p=t.type==="query"?t.data.sql:void 0,h=!!p,m=this.expandedSqlIdx===e;return l`
|
|
2013
2037
|
<div class="tl-event ${h?"tl-clickable":""} ${i?"tl-nested-event":""}"
|
|
2014
2038
|
style="${h?"":`border-left-color:${n}`}"
|
|
2015
|
-
@click=${h?f=>this.toggleSql(e,f):
|
|
2039
|
+
@click=${h?f=>this.toggleSql(e,f):d}>
|
|
2016
2040
|
<span class="tl-event-time">${c}</span>
|
|
2017
2041
|
<span class="tl-event-type" style="color:${n}">${a}</span>
|
|
2018
2042
|
${this.renderEventContent(t)}
|
|
2019
|
-
${
|
|
2043
|
+
${p?l`
|
|
2020
2044
|
<div class="tl-event-sql ${m?"open":""}">
|
|
2021
|
-
<button class="tl-sql-copy" @click=${f=>this.copySql(
|
|
2022
|
-
${
|
|
2023
|
-
</div>`:
|
|
2045
|
+
<button class="tl-sql-copy" @click=${f=>this.copySql(p,f)}>Copy</button>
|
|
2046
|
+
${p}
|
|
2047
|
+
</div>`:d}
|
|
2024
2048
|
</div>
|
|
2025
2049
|
`}renderEventContent(t){switch(t.type){case "fetch":{let e=t.data,s=e.statusCode>=400;return l`
|
|
2026
2050
|
<span class="tl-event-summary">${e.method} ${e.url}</span>
|
|
2027
2051
|
<span class="tl-event-status" style="${s?"color:var(--red)":""}">${e.statusCode}</span>
|
|
2028
2052
|
<span class="tl-event-dur">${y(e.durationMs)}</span>
|
|
2029
|
-
`}case "query":{let e=t.data,s=(e.normalizedOp||e.operation||"?").toUpperCase(),i=e.table||e.model||"",n=
|
|
2053
|
+
`}case "query":{let e=t.data,s=(e.normalizedOp||e.operation||"?").toUpperCase(),i=e.table||e.model||"",n=be[s]||"var(--text-dim)";return l`
|
|
2030
2054
|
<span class="tl-event-summary"><span style="color:${n};font-weight:600">${s}</span> ${i}</span>
|
|
2031
|
-
<span class="tl-event-dur">${
|
|
2032
|
-
`}case "log":{let e=t.data,s=qs[e.level]||"var(--text-dim)";return l`<span class="tl-event-summary"><span style="color:${s}">${e.level.toUpperCase()}</span> ${e.message}</span>`}case "error":{let e=t.data;return l`<span class="tl-event-summary" style="color:var(--red)">${e.name}: ${e.message}</span>`}default:return
|
|
2055
|
+
<span class="tl-event-dur">${Ki(e.durationMs)}</span>
|
|
2056
|
+
`}case "log":{let e=t.data,s=qs[e.level]||"var(--text-dim)";return l`<span class="tl-event-summary"><span style="color:${s}">${e.level.toUpperCase()}</span> ${e.message}</span>`}case "error":{let e=t.data;return l`<span class="tl-event-summary" style="color:var(--red)">${e.name}: ${e.message}</span>`}default:return d}}};k.cache=new Map,u([C({context:A})],k.prototype,"store",2),u([L({attribute:"request-id"})],k.prototype,"requestId",2),u([L({attribute:"request-started",type:Number})],k.prototype,"requestStarted",2),u([b()],k.prototype,"data",2),u([b()],k.prototype,"loading",2),u([b()],k.prototype,"failed",2),u([b()],k.prototype,"expandedSqlIdx",2),k=u([_("bk-timeline-panel")],k);function Dt(o){try{return JSON.parse(o)}catch{return null}}var Re=class{constructor(r,t){this.host=r;this.store=t;this.retryCount=0;this.boundHandlers={fetch:r=>{let t=Dt(r.data);t&&this.store.prependFetch(t);},log:r=>{let t=Dt(r.data);t&&this.store.prependLog(t);},error:r=>{let t=Dt(r.data);t&&this.store.prependError(t);},query:r=>{let t=Dt(r.data);t&&this.store.prependQuery(t);},issues:r=>{let t=Dt(r.data);t&&this.store.setIssues(t);}};r.addController(this);}hostConnected(){this.connect();}hostDisconnected(){this.removeListeners(),this.eventSource?.close(),clearTimeout(this.reloadTimer),clearTimeout(this.perfReloadTimer),clearTimeout(this.reconnectTimer);}removeListeners(){this.eventSource&&(this.eventSource.removeEventListener(he,this.boundHandlers.fetch),this.eventSource.removeEventListener("log",this.boundHandlers.log),this.eventSource.removeEventListener(ue,this.boundHandlers.error),this.eventSource.removeEventListener(me,this.boundHandlers.query),this.eventSource.removeEventListener(fe,this.boundHandlers.issues));}connect(){this.removeListeners(),this.eventSource?.close(),this.eventSource=new EventSource(T.events),this.eventSource.onopen=()=>{this.retryCount=0;},this.eventSource.onerror=()=>{this.eventSource?.close(),this.scheduleReconnect();},this.eventSource.onmessage=r=>{let t=Dt(r.data);t&&(t.path?.startsWith(U)||(this.store.prependRequest(t),clearTimeout(this.reloadTimer),this.reloadTimer=setTimeout(()=>this.reloadFlows(),300),this.store.state.activeView==="performance"&&(clearTimeout(this.perfReloadTimer),this.perfReloadTimer=setTimeout(()=>this.reloadMetrics(),je))));},this.eventSource.addEventListener(he,this.boundHandlers.fetch),this.eventSource.addEventListener("log",this.boundHandlers.log),this.eventSource.addEventListener(ue,this.boundHandlers.error),this.eventSource.addEventListener(me,this.boundHandlers.query),this.eventSource.addEventListener(fe,this.boundHandlers.issues);}scheduleReconnect(){if(this.retryCount>=10)return;let r=Math.min(1e3*2**this.retryCount,3e4);this.retryCount++,this.reconnectTimer=setTimeout(()=>this.connect(),r);}async reloadFlows(){try{let t=await(await fetch(T.flows)).json();this.store.setFlows(t.flows);}catch{}}async reloadMetrics(){try{let t=await(await fetch(T.metricsLive)).json();this.store.setMetrics(t.endpoints||[]);}catch{}}};function Ar(){return l`<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="3" width="7" height="7"/><rect x="14" y="3" width="7" height="7"/><rect x="14" y="14" width="7" height="7"/><rect x="3" y="14" width="7" height="7"/></svg>`}function Cr(){return l`<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polygon points="13 2 3 14 12 14 11 22 21 10 12 10 13 2"/></svg>`}function Ir(){return l`<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="18" y1="20" x2="18" y2="10"/><line x1="12" y1="20" x2="12" y2="4"/><line x1="6" y1="20" x2="6" y2="14"/></svg>`}function Lr(){return l`<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M9 18h6"/><path d="M10 22h4"/><path d="M12 2a7 7 0 0 0-4 12.7V17h8v-2.3A7 7 0 0 0 12 2z"/></svg>`}function Mr(){return l`<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>`}function kr(){return l`<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="6" cy="6" r="3"/><circle cx="18" cy="6" r="3"/><circle cx="6" cy="18" r="3"/><circle cx="18" cy="18" r="3"/><line x1="9" y1="6" x2="15" y2="6"/><line x1="6" y1="9" x2="6" y2="15"/><line x1="18" y1="9" x2="18" y2="15"/><line x1="9" y1="18" x2="15" y2="18"/></svg>`}var ft=class extends E{constructor(){super(...arguments);this.store=new ye;this.activeView="overview";this.viewMode="simple";this.sse=new Re(this,this.store);this.handleStateChanged=t=>{t.detail==="activeView"&&(this.activeView=this.store.state.activeView),this.requestUpdate();};}createRenderRoot(){return this}connectedCallback(){super.connectedCallback(),this.loadInitialData(),this.store.addEventListener("state-changed",this.handleStateChanged);}disconnectedCallback(){super.disconnectedCallback(),this.store.removeEventListener("state-changed",this.handleStateChanged);}async loadInitialData(){try{let[t,e]=await Promise.all([j(T.flows),j(T.requests)]);this.store.setFlows(t.flows),this.store.setRequests(e.requests);}catch(t){console.warn("[brakit]",t);}try{let[t,e,s,i,n]=await Promise.all([j(T.fetches),j(T.errors),j(T.logs),j(T.queries),j(T.metricsLive)]);this.store.setFetches(t.entries),this.store.setErrors(e.entries),this.store.setLogs(s.entries),this.store.setQueries(i.entries),this.store.setMetrics(n.endpoints||[]);}catch(t){console.warn("[brakit]",t);}try{let t=await j(T.insights);this.store.setIssues(t.issues||[]);}catch(t){console.warn("[brakit]",t);}}switchView(t){t!==this.activeView&&(this.activeView=t,this.store.setActiveView(t),fetch(`${T.tab}?tab=${encodeURIComponent(t)}`).catch(()=>{}),t==="performance"&&this.sse.reloadMetrics());}async handleClear(){confirm(N.CLEAR_CONFIRM)&&(await fetch(T.clear,{method:"POST"}),this.store.clearAll(),D.show(N.CLEARED_TOAST));}handleCopyAsCurl(t){Lt(t);}render(){let t=this.store.state,e=t.requests.filter(c=>!c.path?.startsWith(U)),s=e.filter(c=>c.statusCode>=400).length,i=e.length>0?Math.round(e.reduce((c,p)=>c+p.durationMs,0)/e.length):0,n=(t.issues||[]).filter(_e).length,a=window.__BRAKIT_CONFIG__;return l`
|
|
2033
2057
|
<div class="app" id="app">
|
|
2034
2058
|
<aside class="sidebar">
|
|
2035
2059
|
<div class="sidebar-logo">
|
|
@@ -2038,10 +2062,10 @@ span.perf-breakdown-dot.perf-breakdown-app{background:var(--breakdown-app)}
|
|
|
2038
2062
|
</div>
|
|
2039
2063
|
<nav class="sidebar-nav">
|
|
2040
2064
|
${this.renderSidebarItem("overview","Overview",Ar(),void 0)}
|
|
2041
|
-
${this.renderSidebarItem("actions","Actions",
|
|
2065
|
+
${this.renderSidebarItem("actions","Actions",Cr(),t.flows.length)}
|
|
2042
2066
|
${this.renderSidebarItem("insights","Insights",Lr(),n,n===0)}
|
|
2043
|
-
${this.renderSidebarItem("performance","Performance",
|
|
2044
|
-
${this.renderSidebarItem("graph","Graph",
|
|
2067
|
+
${this.renderSidebarItem("performance","Performance",Ir(),void 0)}
|
|
2068
|
+
${this.renderSidebarItem("graph","Graph",kr(),void 0)}
|
|
2045
2069
|
<div class="sidebar-divider"></div>
|
|
2046
2070
|
${this.renderSidebarItem("explorer","Explorer",Mr(),e.length+t.fetches.length+t.queries.length+t.logs.length+t.errors.length)}
|
|
2047
2071
|
</nav>
|
|
@@ -2059,7 +2083,7 @@ span.perf-breakdown-dot.perf-breakdown-app{background:var(--breakdown-app)}
|
|
|
2059
2083
|
<button class="segmented-btn ${this.viewMode==="simple"?"active":""}" @click=${()=>{this.viewMode="simple",this.store.setViewMode("simple");}}>Quick</button>
|
|
2060
2084
|
<button class="segmented-btn ${this.viewMode==="detailed"?"active":""}" @click=${()=>{this.viewMode="detailed",this.store.setViewMode("detailed");}}>Detailed</button>
|
|
2061
2085
|
</div>
|
|
2062
|
-
`:
|
|
2086
|
+
`:d}
|
|
2063
2087
|
<button class="btn btn-danger" @click=${this.handleClear}>Clear</button>
|
|
2064
2088
|
</div>
|
|
2065
2089
|
</div>
|
|
@@ -2096,9 +2120,9 @@ span.perf-breakdown-dot.perf-breakdown-app{background:var(--breakdown-app)}
|
|
|
2096
2120
|
<button class="sidebar-item ${this.activeView===t?"active":""}" @click=${()=>this.switchView(t)}>
|
|
2097
2121
|
<span class="item-icon">${s}</span>
|
|
2098
2122
|
<span class="item-label">${e}</span>
|
|
2099
|
-
${i!==void 0?l`<span class="item-count" style="display:${n?"none":""}">${i}</span>`:
|
|
2123
|
+
${i!==void 0?l`<span class="item-count" style="display:${n?"none":""}">${i}</span>`:d}
|
|
2100
2124
|
</button>
|
|
2101
|
-
`}};u([Je({context:A})],ft.prototype,"store",2),u([
|
|
2125
|
+
`}};u([Je({context:A})],ft.prototype,"store",2),u([b()],ft.prototype,"activeView",2),u([b()],ft.prototype,"viewMode",2),ft=u([_("bk-dashboard")],ft);
|
|
2102
2126
|
/*! Bundled license information:
|
|
2103
2127
|
|
|
2104
2128
|
@lit/reactive-element/css-tag.js:
|