@continuous-excellence/ze-great-dashboard-aws 0.12.0 → 0.12.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/client/.vite/manifest.json +2 -2
- package/client/assets/index-BpHlElUw.js +3 -0
- package/client/assets/index-BpHlElUw.js.map +1 -0
- package/client/assets/index-CzDoxNXL.css +1 -0
- package/client/index.html +2 -2
- package/dist/lambda.mjs +58 -28
- package/package.json +1 -1
- package/client/assets/index-BWGv4Ybw.js +0 -3
- package/client/assets/index-BWGv4Ybw.js.map +0 -1
- package/client/assets/index-ECp7RTfR.css +0 -1
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import{z as e}from"zod";import{StrictMode as t,useEffect as n,useRef as r,useState as i,useSyncExternalStore as a}from"react";import{createRoot as o}from"react-dom/client";import{Fragment as s,jsx as c,jsxs as l}from"react/jsx-runtime";(function(){let e=document.createElement(`link`).relList;if(e&&e.supports&&e.supports(`modulepreload`))return;for(let e of document.querySelectorAll(`link[rel="modulepreload"]`))n(e);new MutationObserver(e=>{for(let t of e)if(t.type===`childList`)for(let e of t.addedNodes)e.tagName===`LINK`&&e.rel===`modulepreload`&&n(e)}).observe(document,{childList:!0,subtree:!0});function t(e){let t={};return e.integrity&&(t.integrity=e.integrity),e.referrerPolicy&&(t.referrerPolicy=e.referrerPolicy),t.credentials=e.crossOrigin===`use-credentials`?`include`:e.crossOrigin===`anonymous`?`omit`:`same-origin`,t}function n(e){if(e.ep)return;e.ep=!0;let n=t(e);fetch(e.href,n)}})();var u=/^(\d+)(ms|s|m|h)$/,d={ms:1,s:1e3,m:6e4,h:36e5};function f(e){let t=u.exec(e);if(!t)return null;let[,n,r]=t;if(n===void 0||r===void 0)return null;let i=Number(n);return i<=0?null:i*d[r]}var p=e.string().refine(e=>f(e)!==null,{message:`must be a positive duration like "30s", "5m", or "1h"`}).brand(),m=e.object({x:e.number().int().min(0),y:e.number().int().min(0),w:e.number().int().min(1).max(12),h:e.number().int().min(1)}),ee=e.string().min(1),h=e.enum([`radial`,`runway`,`orbit`,`signal-field`,`off`]),g=e.looseObject({id:e.string().min(1),type:e.string().min(1),source:e.string().min(1).optional(),display:ee.optional(),position:m.optional(),refresh:p.optional(),running_animation:h.optional(),link:e.url().optional(),url:e.url().optional(),json_path:e.string().regex(/^\$(?:\.[A-Za-z_][A-Za-z0-9_]*|\[\d+\])*$/,`must be a simple JSON path`).optional()}),te=e.looseObject({type:e.string().min(1),token_env:e.string().min(1).optional()}),ne=e.object({refresh:p.optional(),panels:e.array(g).min(1).superRefine((e,t)=>{let n=new Map;e.forEach((e,r)=>{let i=n.get(e.id);if(i===void 0){n.set(e.id,r);return}t.addIssue({code:`custom`,path:[r,`id`],message:`duplicate panel id "${e.id}" (already used by panel at index ${i})`})})})}),re=e.object({issuer:e.url(),client_id:e.string().min(1).optional(),allow:e.object({groups:e.array(e.string().min(1)).optional(),subjects:e.array(e.string().min(1)).optional()}).optional()});e.object({sources:e.record(e.string().min(1),te).default({}),boards:e.record(e.string().min(1),ne),auth:re.optional()});function ie(e){let t=e.panelOverrideMillis??e.boardDefaultMillis;return Math.max(t,e.adapterFloorMillis)}var _=e.object({assetPath:e.string().min(1),proxyPath:e.string().min(1),board:e.string().min(1),clientVersion:e.string().min(1),auth:e.object({issuer:e.string().min(1),clientId:e.string().min(1).optional()}).optional()}),v=_.pick({assetPath:!0,clientVersion:!0});function y(t=globalThis.window?.env){let n=_.safeParse(t);if(!n.success)throw Error(`window.env is missing or invalid \u2014 the server did not inject usable configuration.
|
|
2
|
+
${e.prettifyError(n.error)}`);return n.data}var b=e.enum([`unreachable`,`unauthorized`,`not-found`,`no-runs`,`upstream-error`]),x=e.object({kind:b,message:e.string()}),S=e.discriminatedUnion(`state`,[e.object({panelId:e.string().min(1),state:e.literal(`ok`),observedAt:e.iso.datetime(),link:e.url().nullable(),signal:e.unknown()}),e.object({panelId:e.string().min(1),state:e.literal(`error`),observedAt:e.iso.datetime(),link:e.url().nullable(),error:x})]),C=e.object({type:e.literal(`pipeline-status`),status:e.enum([`passed`,`failed`,`running`,`cancelled`,`unknown`]),rawStatus:e.string(),name:e.string().min(1),branch:e.string().min(1).optional(),durationMs:e.number().int().nonnegative().optional(),runStartedAt:e.iso.datetime().optional(),estimatedDurationMs:e.number().int().positive().optional(),sourceUpdatedAt:e.iso.datetime().optional()}),w=e.object({label:e.string().min(1),status:C.shape.status,detail:e.string().min(1),link:e.url().nullable()}),T=e.object({type:e.literal(`pull-request-health`),status:C.shape.status,summary:e.string().min(1),workflows:e.array(w),pullRequests:e.array(w)}),ae=e.object({type:e.literal(`http-value`),value:e.union([e.string(),e.number(),e.boolean()])}),E={diagnostics:`_diagnostics_lseur_1`,button:`_button_lseur_5`,area:`_area_lseur_14`,warning:`_warning_lseur_31`,panels:`_panels_lseur_35`,actions:`_actions_lseur_43`};function oe({log:e}){let[t,n]=i(!1);a(e.subscribe,e.snapshot,e.snapshot);let r=e.count(),o=e.summary();return l(`section`,{className:E.diagnostics,children:[l(`button`,{className:E.button,type:`button`,"aria-expanded":t,onClick:()=>n(!t),children:[`Diagnostics (`,r,`)`]}),t&&l(`div`,{className:E.area,children:[l(`p`,{children:[o.retained.eventCount,` retained browser-local events across`,` `,o.retained.sessionCount,` session`,o.retained.sessionCount===1?``:`s`,o.retained.firstEventAt&&o.retained.lastEventAt?` (${se(o.retained.firstEventAt,o.retained.lastEventAt)})`:``,`. They are never uploaded.`]}),o.retained.evidenceMayBeIncomplete&&l(`p`,{className:E.warning,role:`alert`,children:[`Earlier evidence was pruned: `,o.retained.retention.eventsPrunedByCount,` at the 2,000-event cap and `,o.retained.retention.eventsPrunedByAge,` by the 7-day age limit. “No failures” applies only to the retained window.`]}),l(`p`,{children:[`Update failures: `,o.failures.clientUpdate,`; board fetch failures:`,` `,o.failures.boardFetch,`.`]}),o.panels.length>0&&c(`div`,{className:E.panels,children:o.panels.map(e=>l(`p`,{children:[c(`strong`,{children:e.panelId}),` — `,e.requests,` requests`,Object.keys(e.httpStatuses).length?`; HTTP ${Object.entries(e.httpStatuses).map(([e,t])=>`${e}×${t}`).join(`, `)}`:``,`; parse/network failures `,e.parseFailures,`/`,e.networkFailures,`; visible changes `,e.visibleStateChanges,`; latest`,` `,e.latestRendered?`${e.latestRendered.state}${e.latestRendered.status?`/${e.latestRendered.status}`:``}`:`not rendered`,`.`]},e.panelId))}),l(`div`,{className:E.actions,children:[c(`button`,{className:E.button,type:`button`,onClick:()=>{let t=new Blob([JSON.stringify(e.export(),null,2)],{type:`application/json`}),n=URL.createObjectURL(t),r=document.createElement(`a`);r.href=n,r.download=`dashboard-diagnostics-${new Date().toISOString().replaceAll(`:`,`-`)}.json`,r.click(),URL.revokeObjectURL(n)},children:`Download`}),c(`button`,{className:E.button,type:`button`,onClick:()=>{window.confirm(`Clear this browser’s retained dashboard diagnostics?`)&&e.clear()},children:`Clear`})]})]})]})}function se(e,t){return e===t?e:`${e} to ${t}`}function ce(e,t){let n=new Map,r=new Set,i=0,a=0;for(let t of e){if(r.add(t.sessionId),t.kind===`client-update-failure`&&i++,(t.kind===`board-fetch-failure`||t.kind===`board-fetch-parse-failure`)&&a++,!(`panelId`in t))continue;let e=n.get(t.panelId)??{panelId:t.panelId,requests:0,httpStatuses:{},parseFailures:0,networkFailures:0,visibleStateChanges:0};if(t.kind===`panel-fetch-start`&&e.requests++,t.kind===`panel-fetch-response`&&t.status!==void 0){let n=String(t.status);e.httpStatuses[n]=(e.httpStatuses[n]??0)+1}t.kind===`panel-fetch-parse-failure`&&e.parseFailures++,t.kind===`panel-fetch-failure`&&e.networkFailures++,t.kind===`panel-rendered`&&(e.visibleStateChanges++,e.latestRendered=t.rendered),n.set(t.panelId,e)}let o=e.map(e=>e.at).sort(),s=t.eventsPrunedByAge+t.eventsPrunedByCount;return{retained:{eventCount:e.length,firstEventAt:o[0],lastEventAt:o.at(-1),sessionCount:r.size,retention:t,evidenceMayBeIncomplete:s>0},failures:{clientUpdate:i,boardFetch:a},panels:[...n.values()].sort((e,t)=>e.panelId.localeCompare(t.panelId))}}var D=`ze-great-dashboard.diagnostics.v1`,le=2e3,ue=6048e5,de=[`session-start`,`client-update-check`,`client-update-failure`,`client-update-detected`,`board-fetch-start`,`board-fetch-response`,`board-fetch-parse-failure`,`board-fetch-failure`,`panel-fetch-start`,`panel-fetch-response`,`panel-fetch-parse-failure`,`panel-fetch-failure`,`panel-rendered`],fe=class{env;storage;now;events=[];retention=k();revision=0;listeners=new Set;sessionId=crypto.randomUUID?.()??`${Date.now()}-${Math.random()}`;constructor(e,t=N(),n=()=>new Date){this.env=e,this.storage=t,this.now=n,this.events=this.read(),this.record({kind:`session-start`})}record(e){let t=j([...this.events,{...e,schemaVersion:1,at:this.now().toISOString(),sessionId:this.sessionId,board:this.env.board}],this.now(),this.retention);this.events=t.events,this.retention=t.retention,this.persist(),this.revision++,this.notify()}count=()=>this.events.length;snapshot=()=>this.revision;summary=()=>ce(this.events,this.retention);clear(){this.events=[],this.retention=k();try{this.storage?.removeItem(D)}catch{}this.revision++,this.notify()}subscribe=e=>(this.listeners.add(e),()=>{this.listeners.delete(e)});export=()=>({schemaVersion:1,exportedAt:this.now().toISOString(),client:{version:this.env.clientVersion,assetPath:this.env.assetPath,board:this.env.board,sessionId:this.sessionId},events:this.events,summary:this.summary()});read(){try{let e=this.storage?.getItem(D);if(!e)return[];let t=JSON.parse(e);if(t.schemaVersion!==1||!Array.isArray(t.events)||!t.events.every(M))return this.storage?.removeItem(D),[];let n=j(t.events.map(e=>({...e,schemaVersion:1})),this.now(),A(t.retention));return this.retention=n.retention,n.events}catch{try{this.storage?.removeItem(D)}catch{}return[]}}persist(){try{this.storage?.setItem(D,JSON.stringify({schemaVersion:1,events:this.events,retention:this.retention}))}catch{}}notify(){for(let e of this.listeners)e()}};function O(e){let t=Object.fromEntries([[`cacheControl`,`cache-control`],[`etag`,`etag`],[`lastModified`,`last-modified`],[`date`,`date`],[`age`,`age`]].flatMap(([t,n])=>{let r=e.get(n);return r?[[t,r]]:[]}));return Object.keys(t).length?t:void 0}function k(){return{eventsPrunedByAge:0,eventsPrunedByCount:0}}function A(e){if(!e||typeof e!=`object`)return k();let t=e;return{eventsPrunedByAge:typeof t.eventsPrunedByAge==`number`&&t.eventsPrunedByAge>=0?t.eventsPrunedByAge:0,eventsPrunedByCount:typeof t.eventsPrunedByCount==`number`&&t.eventsPrunedByCount>=0?t.eventsPrunedByCount:0}}function j(e,t,n){let r=t.valueOf()-ue,i=e.filter(e=>Number.isFinite(new Date(e.at).valueOf())&&new Date(e.at).valueOf()>=r),a=e.length-i.length,o=Math.max(0,i.length-le);return{events:i.slice(-2e3),retention:{eventsPrunedByAge:n.eventsPrunedByAge+a,eventsPrunedByCount:n.eventsPrunedByCount+o}}}function M(e){if(!e||typeof e!=`object`)return!1;let t=e;return(t.schemaVersion===void 0||t.schemaVersion===1)&&typeof t.at==`string`&&Number.isFinite(new Date(t.at).valueOf())&&typeof t.sessionId==`string`&&typeof t.board==`string`&&de.includes(t.kind)}function N(){try{return window.localStorage}catch{return}}function P({label:e,hint:t,wide:n=!1}){return l(`section`,{className:n?`panel panel--wide`:`panel`,children:[c(`h2`,{className:`panel__label`,children:e}),c(`p`,{className:`panel__hint`,children:t})]})}function F({value:e,label:t=`As of`}){let n=new Date(e),r=n.toLocaleTimeString([],{hour:`2-digit`,minute:`2-digit`}),i=Date.now()-n.getTime(),a=i>3e5,o=I(i);return l(`p`,{className:`panel__hint panel__observed${a?` panel__observed--stale`:``}`,children:[c(`span`,{"aria-hidden":`true`,children:`◷`}),` `,t,` `,r,` · `,o]})}function I(e){if(e<6e4)return`just now`;let t=Math.floor(e/6e4);return t<60?`${t}m ago`:`${Math.floor(t/60)}h ${t%60}m ago`}function L(e){let t=e.position;if(t)return{"--panel-column":`${t.x+1} / span ${t.w}`,"--panel-row":`${t.y+1} / span ${t.h}`}}function R({panel:e,envelope:t,error:n=!1,children:r}){let i=e.display===`primary`||e.display===`compact`?e.display:`supporting`;return l(`section`,{className:`panel panel--${i}${n?` panel--error`:``}`,style:L(e),"aria-busy":!t||void 0,children:[c(`h2`,{className:`panel__label`,children:e.id}),r,c(z,{panelId:e.id,link:t?.link})]})}function z({panelId:e,link:t}){return t?l(`a`,{className:`panel__link`,href:t,target:`_blank`,rel:`noopener noreferrer`,"aria-label":`View source for ${e} (opens in a new tab)`,children:[`View source `,c(`span`,{"aria-hidden":`true`,children:`↗`})]}):null}function B({panel:e,envelope:t}){if(!t)return c(R,{panel:e,children:c(`p`,{className:`panel__hint`,children:`Loading…`})});if(t.state===`error`)return l(R,{panel:e,envelope:t,error:!0,children:[c(`p`,{className:`panel__status`,children:`⚠ Unable to read`}),c(`p`,{className:`panel__hint`,children:t.error.message}),c(F,{value:t.observedAt})]});let n=ae.safeParse(t.signal);return n.success?l(R,{panel:e,envelope:t,children:[c(`p`,{className:`panel__status`,children:String(n.data.value)}),c(F,{value:t.observedAt})]}):l(R,{panel:e,envelope:t,error:!0,children:[c(`p`,{className:`panel__status`,children:`⚠ Invalid value`}),c(F,{value:t.observedAt})]})}function V({animation:e,runStartedAt:t,estimatedDurationMs:n}){let r=pe(!!t),i=t?new Date(t).valueOf():NaN,a=Number.isFinite(i)?Math.max(0,r-i):void 0,o=a!==void 0&&n!==void 0,u=o&&a>n,d=o?Math.min(a/n,1):0,f=e===`runway`||e===`signal-field`,p=U(a,n,u),m={"--running-progress":`${d*100}%`,"--running-degrees":`${d*360}deg`};return l(`div`,{className:`running-progress running-progress--${e}${u?` running-progress--overdue`:``}${o?``:` running-progress--indeterminate`}`,style:m,children:[l(`div`,{className:`running-progress__visual`,"aria-hidden":`true`,children:[e===`radial`&&c(`span`,{className:`running-progress__radial-core`}),e===`runway`&&c(`span`,{className:`running-progress__runway-spark`}),e===`orbit`&&l(s,{children:[c(`span`,{className:`running-progress__orbit-core`}),c(`span`,{className:`running-progress__orbit-particle running-progress__orbit-particle--one`}),c(`span`,{className:`running-progress__orbit-particle running-progress__orbit-particle--two`})]}),e===`signal-field`&&l(s,{children:[c(`span`,{className:`running-progress__signal-rail`}),c(`span`,{className:`running-progress__signal-lead`}),c(`span`,{className:`running-progress__signal-pulse running-progress__signal-pulse--one`}),c(`span`,{className:`running-progress__signal-pulse running-progress__signal-pulse--two`}),c(`span`,{className:`running-progress__signal-tracks`,children:[0,1,2,3,4].map(e=>c(`span`,{className:`running-progress__signal-track`,children:c(`span`,{className:`running-progress__signal-marker`})},e))})]})]}),c(`p`,{className:`running-progress__timing${f?` running-progress__timing--readout`:``}`,children:f?l(s,{children:[c(`span`,{className:`screen-reader-only`,children:p}),c(`span`,{"aria-hidden":`true`,children:me(a,n,u)})]}):p})]})}function pe(e){let[t,r]=i(()=>Date.now());return n(()=>{if(!e)return;r(Date.now());let t=window.setInterval(()=>r(Date.now()),1e3);return()=>window.clearInterval(t)},[e]),t}function H(e){let t=Math.floor(e/1e3),n=Math.floor(t/3600),r=Math.floor(t%3600/60),i=t%60;return n>0?`${n}h ${r}m`:r>0?`${r}m ${i}s`:`${i}s`}function U(e,t,n){return`${e===void 0?`Run in progress`:`Elapsed ${H(e)}`} · ${t===void 0?`Expected duration unavailable`:`Expected ≈ ${H(t)}`}${n?` · Over estimate`:``}`}function me(e,t,n){let r=e===void 0?`—`:W(e),i=t===void 0?`?`:`~${W(t)}`;return`${n?`⚠`:`\xA0`}${r}/${i}`}function W(e){let t=Math.floor(e/1e3),n=Math.floor(t/3600),r=Math.floor(t%3600/60),i=t%60,a=`${r}:${String(i).padStart(2,`0`)}`;return n>0?`${n}:${a.padStart(5,`0`)}`:a}var G=2e4,he=15e3,K=[`radial`,`runway`,`orbit`,`signal-field`];function ge({panel:e}){let t=_e(),n=Math.floor(t/G),r=K[n%K.length]??`radial`,i=n*G;return l(R,{panel:e,children:[c(`p`,{className:`panel__status panel__status--running`,children:`↻ Running`}),l(`p`,{className:`pipeline-animation-demo__variant`,children:[`Demo treatment · `,r]}),c(V,{animation:r,runStartedAt:new Date(i).toISOString(),estimatedDurationMs:he},i)]})}function _e(){let[e,t]=i(()=>Date.now());return n(()=>{let e=window.setInterval(()=>t(Date.now()),1e3);return()=>window.clearInterval(e)},[]),e}function ve({panel:e,envelope:t}){if(!t)return c(R,{panel:e,children:c(`p`,{className:`panel__hint`,children:`Loading…`})});if(t.state===`error`)return l(R,{panel:e,envelope:t,error:!0,children:[l(`p`,{className:`panel__status`,children:[`⚠ `,t.error.kind===`no-runs`?`No workflow runs`:`Unable to read`]}),c(`p`,{className:`panel__hint`,children:t.error.message}),c(F,{value:t.observedAt})]});let n=C.safeParse(t.signal);if(!n.success)return l(R,{panel:e,envelope:t,error:!0,children:[c(`p`,{className:`panel__status`,children:`⚠ Invalid signal`}),c(F,{value:t.observedAt})]});let r=be(n.data.status);return l(R,{panel:e,envelope:t,children:[l(`p`,{className:`panel__status panel__status--${n.data.status}`,children:[r.glyph,` `,r.label]}),l(`p`,{className:`panel__hint`,children:[n.data.name,` · `,n.data.rawStatus,n.data.branch&&l(`span`,{className:`panel__branch`,title:`Branch: ${n.data.branch}`,children:[c(`span`,{"aria-hidden":`true`,children:` · ⎇ `}),c(`span`,{className:`screen-reader-only`,children:`Branch: `}),n.data.branch]})]}),n.data.status===`running`&&e.running_animation!==`off`&&c(V,{animation:e.running_animation??`orbit`,runStartedAt:n.data.runStartedAt,estimatedDurationMs:n.data.estimatedDurationMs}),n.data.status!==`running`&&n.data.durationMs!==void 0&&l(`p`,{className:`panel__hint`,children:[`Took `,ye(n.data.durationMs)]}),n.data.sourceUpdatedAt&&c(F,{value:n.data.sourceUpdatedAt,label:`Run updated`}),c(F,{value:t.observedAt})]})}function ye(e){let t=Math.floor(e/1e3),n=Math.floor(t/3600),r=Math.floor(t%3600/60),i=t%60;return n>0?`${n}h ${r}m`:r>0?`${r}m ${i}s`:`${i}s`}function be(e){switch(e){case`passed`:return{glyph:`✓`,label:`Passed`};case`failed`:return{glyph:`✕`,label:`Failed`};case`running`:return{glyph:`↻`,label:`Running`};case`cancelled`:return{glyph:`⊘`,label:`Cancelled`};case`unknown`:return{glyph:`?`,label:`Unknown`}}}function xe({panel:e,envelope:t}){if(!t)return c(R,{panel:e,children:c(`p`,{className:`panel__hint`,children:`Loading…`})});if(t.state===`error`)return l(R,{panel:e,envelope:t,error:!0,children:[c(`p`,{className:`panel__status`,children:`⚠ Unable to read`}),c(`p`,{className:`panel__hint`,children:t.error.message}),c(F,{value:t.observedAt})]});let n=T.safeParse(t.signal);if(!n.success)return c(R,{panel:e,envelope:t,error:!0,children:c(`p`,{className:`panel__status`,children:`⚠ Invalid signal`})});let r=Se(n.data.status);return l(R,{panel:e,envelope:t,children:[l(`p`,{className:`panel__status panel__status--${n.data.status}`,children:[r.glyph,` `,r.label]}),c(`p`,{className:`panel__hint`,children:n.data.summary}),c(F,{value:t.observedAt})]})}function Se(e){switch(e){case`passed`:return{glyph:`✓`,label:`Healthy`};case`failed`:return{glyph:`✕`,label:`Failed`};case`running`:return{glyph:`↻`,label:`Running`};case`cancelled`:return{glyph:`⊘`,label:`Cancelled`};case`unknown`:return{glyph:`?`,label:`Unknown`}}}var Ce={"pipeline-status":ve,"pull-request-health":xe,"http-value":B,"pipeline-animation-demo":ge};function we({panel:e,envelope:t}){let n=Ce[e.type];return n?c(n,{panel:e,envelope:t}):c(P,{label:e.type,hint:`Not wired yet`,wide:!0})}var Te=6e4,Ee=1e4,De=()=>globalThis.window.location.reload();function Oe({env:e,diagnostics:t,fetcher:r,reload:i=De}){n(()=>{let n=!1,a=!1,o,s=`${e.proxyPath}/client`,c=async()=>{if(n||a)return;a=!0;let l=new AbortController;o=l;let u=globalThis.setTimeout(()=>l.abort(),Ee);t.record({kind:`client-update-check`,path:s});try{let a=await(r??globalThis.fetch)(s,{cache:`no-store`,signal:l.signal});if(!a.ok)throw Error(`Client identity returned ${a.status}`);let o=v.safeParse(await a.json());if(!o.success)throw Error(`Client identity response was invalid`);if(n)return;o.data.assetPath!==e.assetPath&&(t.record({kind:`client-update-detected`,path:s,current:{assetPath:e.assetPath,clientVersion:e.clientVersion},next:o.data}),i())}catch(e){!n&&!(e instanceof DOMException&&e.name===`AbortError`)&&t.record({kind:`client-update-failure`,path:s,message:e instanceof Error?e.message:String(e)})}finally{globalThis.clearTimeout(u),a=!1,o===l&&(o=void 0),n||globalThis.setTimeout(()=>void c(),Te)}};return c(),()=>{n=!0,o?.abort()}},[t,e.assetPath,e.clientVersion,e.proxyPath,r,i])}function q(e,t){if(t.state===`error`)return{state:t.state,link:t.link};if(e.type===`pipeline-status`){let e=C.safeParse(t.signal);return{state:t.state,status:e.success?e.data.status:void 0,link:t.link}}if(e.type===`pull-request-health`){let e=T.safeParse(t.signal);return{state:t.state,status:e.success?e.data.status:void 0,link:t.link}}return{state:t.state,link:t.link}}function ke(e,t,n){if(!e)return!0;let r=q(t,e),i=q(t,n);return r.state!==i.state||r.status!==i.status||r.link!==i.link}function Ae({board:e,env:t,diagnostics:a}){let[o,s]=i({}),c=r({});return n(()=>{if(c.current={},s({}),!e)return;let n=!1,r=[];for(let i of e.panels){if(i.type!==`pipeline-status`&&i.type!==`pull-request-health`&&i.type!==`http-value`)continue;let o=!1,l=ie({boardDefaultMillis:f(e.refresh??`60s`)??6e4,panelOverrideMillis:i.refresh?f(i.refresh)??void 0:void 0,adapterFloorMillis:0}),u=`${t.proxyPath}/panel/${encodeURIComponent(t.board)}/${encodeURIComponent(i.id)}`,d=()=>{n||o||(o=!0,a.record({kind:`panel-fetch-start`,panelId:i.id,path:u}),fetch(u).then(async e=>{let t={kind:`panel-fetch-response`,panelId:i.id,path:u,status:e.status,cache:O(e.headers)};if(e.status===304){a.record(t);return}try{let n=je(await e.json());if(!n){a.record(t),a.record({kind:`panel-fetch-parse-failure`,panelId:i.id,path:u,message:`Response was not a valid signal envelope.`});return}return a.record({...t,envelope:n}),n}catch(e){throw a.record(t),a.record({kind:`panel-fetch-parse-failure`,panelId:i.id,path:u,message:J(e)}),new Y(e)}}).then(e=>{if(!n&&e){let t=c.current[i.id];ke(t,i,e)&&a.record({kind:`panel-rendered`,panelId:i.id,path:u,rendered:q(i,e)}),c.current={...c.current,[i.id]:e},s(c.current)}}).catch(e=>{e instanceof Y||a.record({kind:`panel-fetch-failure`,panelId:i.id,path:u,message:J(e)})}).finally(()=>{o=!1}))};d(),r.push(window.setInterval(d,l))}return()=>{n=!0;for(let e of r)window.clearInterval(e)}},[e,a,t.board,t.proxyPath]),o}function J(e){return e instanceof Error?e.message:String(e)}var Y=class extends Error{constructor(e){super(J(e))}};function je(e){let t=S.safeParse(e);return t.success?t.data:void 0}function Me({env:e}){let[t,a]=i(),[o,s]=i(),u=r(null);u.current||=new fe(e);let d=u.current;Oe({env:e,diagnostics:d});let f=Ae({board:o===e.board?t:void 0,env:e,diagnostics:d});return n(()=>{let t=!1;a(void 0),s(void 0);let n=`${e.proxyPath}/boards/${encodeURIComponent(e.board)}`;return d.record({kind:`board-fetch-start`,path:n}),fetch(n).then(async e=>{if(d.record({kind:`board-fetch-response`,path:n,status:e.status,cache:O(e.headers)}),!e.ok)throw Error(`Board configuration returned ${e.status}`);try{return await e.json()}catch(e){throw d.record({kind:`board-fetch-parse-failure`,path:n,message:X(e)}),new Z(e)}}).then(r=>{if(!t){a(r),s(e.board);let t=Array.isArray(r.panels)?r.panels:[];d.record({kind:`board-fetch-response`,path:n,boardSummary:{panelCount:t.length,panelIds:t.flatMap(e=>typeof e.id==`string`?[e.id]:[])}})}}).catch(r=>{r instanceof Z||d.record({kind:`board-fetch-failure`,path:n,message:X(r)}),t||(a({panels:[]}),s(e.board))}),()=>{t=!0}},[d,e.board,e.proxyPath]),l(`div`,{className:`board`,children:[l(`header`,{className:`board__header`,children:[c(`h1`,{className:`board__title`,children:e.board}),l(`dl`,{className:`board__meta`,children:[l(`div`,{children:[c(`dt`,{children:`client`}),c(`dd`,{children:e.clientVersion})]}),l(`div`,{children:[c(`dt`,{children:`assets`}),c(`dd`,{children:e.assetPath})]})]})]}),l(`main`,{className:`board__grid`,children:[!t&&c(P,{label:`board`,hint:`Loading configuration…`,wide:!0}),t?.panels.map(e=>c(we,{panel:e,envelope:f[e.id]},e.id))]}),l(`footer`,{className:`board__footer`,children:[c(`span`,{children:`Signals are read live from their configured authorities.`}),c(oe,{log:d})]})]})}function X(e){return e instanceof Error?e.message:String(e)}var Z=class extends Error{constructor(e){super(X(e))}};function Ne({message:e}){return l(`div`,{className:`config-error`,role:`alert`,children:[c(`h1`,{children:`⚠️ Dashboard misconfigured`}),c(`p`,{children:`The page loaded, but the server did not hand it usable configuration.`}),c(`pre`,{children:e})]})}var Q=document.getElementById(`root`);if(!Q)throw Error(`No #root element in the document — the template is not the one we expect.`);var $=o(Q);try{$.render(c(t,{children:c(Me,{env:y()})}))}catch(e){$.render(c(Ne,{message:e instanceof Error?e.message:String(e)}))}
|
|
3
|
+
//# sourceMappingURL=index-BpHlElUw.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index-BpHlElUw.js","names":[],"sources":["../../../shared/dist/index.js","../../src/Diagnostics.module.css","../../src/Diagnostics.tsx","../../src/diagnostics-summary.ts","../../src/diagnostics.ts","../../src/PanelPlaceholder.tsx","../../src/ObservedAt.tsx","../../src/panel-layout.ts","../../src/PanelFrame.tsx","../../src/HttpValuePanel.tsx","../../src/RunningProgress.tsx","../../src/PipelineAnimationDemoPanel.tsx","../../src/PipelinePanel.tsx","../../src/PullRequestHealthPanel.tsx","../../src/panel-registry.tsx","../../src/useClientUpdate.ts","../../src/panel-diagnostics.ts","../../src/usePanelSignals.ts","../../src/App.tsx","../../src/ConfigError.tsx","../../src/main.tsx"],"sourcesContent":["// packages/shared/src/board-config.ts\nimport { z as z2 } from \"zod\";\n\n// packages/shared/src/duration.ts\nimport { z } from \"zod\";\nvar DURATION_PATTERN = /^(\\d+)(ms|s|m|h)$/;\nvar UNIT_MILLIS = {\n ms: 1,\n s: 1e3,\n m: 6e4,\n h: 36e5\n};\nfunction parseDuration(value) {\n const match = DURATION_PATTERN.exec(value);\n if (!match) return null;\n const [, rawAmount, rawUnit] = match;\n if (rawAmount === void 0 || rawUnit === void 0) return null;\n const amount = Number(rawAmount);\n if (amount <= 0) return null;\n return amount * UNIT_MILLIS[rawUnit];\n}\nvar durationSchema = z.string().refine((value) => parseDuration(value) !== null, {\n message: 'must be a positive duration like \"30s\", \"5m\", or \"1h\"'\n}).brand();\n\n// packages/shared/src/board-config.ts\nvar positionSchema = z2.object({\n x: z2.number().int().min(0),\n y: z2.number().int().min(0),\n w: z2.number().int().min(1).max(12),\n h: z2.number().int().min(1)\n});\nvar panelDisplayRoles = [\"primary\", \"supporting\", \"compact\"];\nvar panelDisplaySchema = z2.string().min(1);\nvar runningAnimationSchema = z2.enum([\"radial\", \"runway\", \"orbit\", \"signal-field\", \"off\"]);\nvar panelSchema = z2.looseObject({\n id: z2.string().min(1),\n type: z2.string().min(1),\n source: z2.string().min(1).optional(),\n /** Semantic visual weight; position still controls the panel's explicit grid placement. */\n display: panelDisplaySchema.optional(),\n /** Advisory in v1 — a panel without a position renders in config order rather than not at all. */\n position: positionSchema.optional(),\n refresh: durationSchema.optional(),\n /** Optional progress treatment for an active pipeline run. Omitted currently means orbit. */\n running_animation: runningAnimationSchema.optional(),\n /** A deliberate override only. Adapters derive links; hand-written ones drift. */\n link: z2.url().optional(),\n /** Source-agnostic endpoint used by the http-value signal. */\n url: z2.url().optional(),\n /** Small, deliberate JSON path subset: $.version, $.deployment.version, or $.response.docs[0].latestVersion. */\n json_path: z2.string().regex(/^\\$(?:\\.[A-Za-z_][A-Za-z0-9_]*|\\[\\d+\\])*$/, \"must be a simple JSON path\").optional()\n});\nvar sourceSchema = z2.looseObject({\n type: z2.string().min(1),\n /** Credentials are never in the config — only the name of the env var holding one. */\n token_env: z2.string().min(1).optional()\n});\nvar boardSchema = z2.object({\n refresh: durationSchema.optional(),\n panels: z2.array(panelSchema).min(1).superRefine((panels, ctx) => {\n const seen = /* @__PURE__ */ new Map();\n panels.forEach((panel, index) => {\n const firstIndex = seen.get(panel.id);\n if (firstIndex === void 0) {\n seen.set(panel.id, index);\n return;\n }\n ctx.addIssue({\n code: \"custom\",\n path: [index, \"id\"],\n message: `duplicate panel id \"${panel.id}\" (already used by panel at index ${firstIndex})`\n });\n });\n })\n});\nvar authSchema = z2.object({\n issuer: z2.url(),\n /** Absent in gateway mode — the gateway does the flow, the proxy still validates. */\n client_id: z2.string().min(1).optional(),\n allow: z2.object({\n groups: z2.array(z2.string().min(1)).optional(),\n subjects: z2.array(z2.string().min(1)).optional()\n }).optional()\n});\nvar boardConfigSchema = z2.object({\n sources: z2.record(z2.string().min(1), sourceSchema).default({}),\n boards: z2.record(z2.string().min(1), boardSchema),\n auth: authSchema.optional()\n});\nfunction resolveRefreshMillis(args) {\n const requested = args.panelOverrideMillis ?? args.boardDefaultMillis;\n return Math.max(requested, args.adapterFloorMillis);\n}\n\n// packages/shared/src/client-env.ts\nimport { z as z3 } from \"zod\";\nvar clientEnvSchema = z3.object({\n /** Where the immutable client assets live. The one variable that repoints the whole client. */\n assetPath: z3.string().min(1),\n /** Same-origin path the proxy is mounted at, so there is no CORS and no cookie problem. */\n proxyPath: z3.string().min(1),\n /** Which board this is, resolved server-side so the client parses no URLs. */\n board: z3.string().min(1),\n /** The client version being served, so two published versions are visibly distinguishable. */\n clientVersion: z3.string().min(1),\n /** Omitted entirely when unauthenticated — presence is what turns auth on. */\n auth: z3.object({\n issuer: z3.string().min(1),\n clientId: z3.string().min(1).optional()\n }).optional()\n});\nvar clientIdentitySchema = clientEnvSchema.pick({ assetPath: true, clientVersion: true });\nfunction readClientEnv(source = globalThis.window?.env) {\n const result = clientEnvSchema.safeParse(source);\n if (!result.success) {\n throw new Error(\n `window.env is missing or invalid \\u2014 the server did not inject usable configuration.\n${z3.prettifyError(result.error)}`\n );\n }\n return result.data;\n}\n\n// packages/shared/src/envelope.ts\nimport { z as z4 } from \"zod\";\nvar errorKindSchema = z4.enum([\n \"unreachable\",\n \"unauthorized\",\n \"not-found\",\n \"no-runs\",\n \"upstream-error\"\n]);\nvar envelopeErrorSchema = z4.object({\n kind: errorKindSchema,\n message: z4.string()\n});\nvar envelopeSchema = z4.discriminatedUnion(\"state\", [\n z4.object({\n panelId: z4.string().min(1),\n state: z4.literal(\"ok\"),\n /** From the upstream response `Date`. A cached value must never be shown without its age. */\n observedAt: z4.iso.datetime(),\n /** Adapter-derived. The authority for this panel; the dashboard itself asserts nothing. */\n link: z4.url().nullable(),\n signal: z4.unknown()\n }),\n z4.object({\n panelId: z4.string().min(1),\n state: z4.literal(\"error\"),\n /**\n * Populated even on error: knowing *when* a failure was observed is the difference between\n * \"broken just now\" and \"broken all morning\", and a panel that can't reach its source is\n * exactly when a viewer most wants to click through.\n */\n observedAt: z4.iso.datetime(),\n link: z4.url().nullable(),\n error: envelopeErrorSchema\n })\n]);\nvar pipelineStatusSchema = z4.object({\n type: z4.literal(\"pipeline-status\"),\n status: z4.enum([\"passed\", \"failed\", \"running\", \"cancelled\", \"unknown\"]),\n /** The source's unmodified status/result vocabulary, for an honest display. */\n rawStatus: z4.string(),\n name: z4.string().min(1),\n /** The branch represented by this status, when the upstream supplies or filters by one. */\n branch: z4.string().min(1).optional(),\n /** Elapsed execution time, supplied only after the upstream run has completed. */\n durationMs: z4.number().int().nonnegative().optional(),\n /** When an active run began, so the client can advance its elapsed display between polls. */\n runStartedAt: z4.iso.datetime().optional(),\n /** Advisory median duration from recent completed runs from the same source response. */\n estimatedDurationMs: z4.number().int().positive().optional(),\n /** When this workflow run was last updated by its source, distinct from our observation time. */\n sourceUpdatedAt: z4.iso.datetime().optional()\n});\nvar pullRequestHealthItemSchema = z4.object({\n label: z4.string().min(1),\n status: pipelineStatusSchema.shape.status,\n detail: z4.string().min(1),\n link: z4.url().nullable()\n});\nvar pullRequestHealthSchema = z4.object({\n type: z4.literal(\"pull-request-health\"),\n status: pipelineStatusSchema.shape.status,\n summary: z4.string().min(1),\n workflows: z4.array(pullRequestHealthItemSchema),\n pullRequests: z4.array(pullRequestHealthItemSchema)\n});\nvar httpValueSchema = z4.object({\n type: z4.literal(\"http-value\"),\n value: z4.union([z4.string(), z4.number(), z4.boolean()])\n});\nexport {\n authSchema,\n boardConfigSchema,\n boardSchema,\n clientEnvSchema,\n clientIdentitySchema,\n durationSchema,\n envelopeSchema,\n errorKindSchema,\n httpValueSchema,\n panelDisplayRoles,\n panelDisplaySchema,\n panelSchema,\n parseDuration,\n pipelineStatusSchema,\n positionSchema,\n pullRequestHealthSchema,\n readClientEnv,\n resolveRefreshMillis,\n runningAnimationSchema,\n sourceSchema\n};\n",".diagnostics {\n position: relative;\n}\n\n.button {\n border: 1px solid var(--edge);\n border-radius: 0.25rem;\n background: var(--surface-raised);\n color: var(--ink-secondary);\n font: inherit;\n padding: 0.3em 0.55em;\n}\n\n.area {\n position: absolute;\n z-index: 1;\n right: 0;\n bottom: calc(100% + 0.5rem);\n width: min(24rem, 90vw);\n padding: 0.75rem;\n border: 1px solid var(--edge);\n border-radius: var(--radius);\n background: var(--surface-raised);\n box-shadow: 0 0.5rem 1.5rem #0008;\n}\n\n.area p {\n margin: 0 0 0.5rem;\n}\n\n.warning {\n color: var(--status-warning);\n}\n\n.panels {\n max-height: 12rem;\n overflow-y: auto;\n border-top: 1px solid var(--edge);\n margin: 0.5rem 0;\n padding-top: 0.5rem;\n}\n\n.actions {\n display: flex;\n gap: 0.5rem;\n}\n","import { useState, useSyncExternalStore } from 'react'\nimport styles from './Diagnostics.module.css'\nimport type { BrowserDiagnosticStore } from './diagnostics.ts'\n\nexport function Diagnostics({ log }: { log: BrowserDiagnosticStore }) {\n const [open, setOpen] = useState(false)\n useSyncExternalStore(log.subscribe, log.snapshot, log.snapshot)\n const count = log.count()\n const summary = log.summary()\n const download = () => {\n const blob = new Blob([JSON.stringify(log.export(), null, 2)], { type: 'application/json' })\n const url = URL.createObjectURL(blob)\n const link = document.createElement('a')\n link.href = url\n link.download = `dashboard-diagnostics-${new Date().toISOString().replaceAll(':', '-')}.json`\n link.click()\n URL.revokeObjectURL(url)\n }\n const clear = () => {\n if (!window.confirm('Clear this browser’s retained dashboard diagnostics?')) return\n log.clear()\n }\n\n return (\n <section className={styles.diagnostics}>\n <button\n className={styles.button}\n type=\"button\"\n aria-expanded={open}\n onClick={() => setOpen(!open)}\n >\n Diagnostics ({count})\n </button>\n {open && (\n <div className={styles.area}>\n <p>\n {summary.retained.eventCount} retained browser-local events across{' '}\n {summary.retained.sessionCount} session{summary.retained.sessionCount === 1 ? '' : 's'}\n {summary.retained.firstEventAt && summary.retained.lastEventAt\n ? ` (${formatWindow(summary.retained.firstEventAt, summary.retained.lastEventAt)})`\n : ''}\n . They are never uploaded.\n </p>\n {summary.retained.evidenceMayBeIncomplete && (\n <p className={styles.warning} role=\"alert\">\n Earlier evidence was pruned: {summary.retained.retention.eventsPrunedByCount} at the\n 2,000-event cap and {summary.retained.retention.eventsPrunedByAge} by the 7-day age\n limit. “No failures” applies only to the retained window.\n </p>\n )}\n <p>\n Update failures: {summary.failures.clientUpdate}; board fetch failures:{' '}\n {summary.failures.boardFetch}.\n </p>\n {summary.panels.length > 0 && (\n <div className={styles.panels}>\n {summary.panels.map((panel) => (\n <p key={panel.panelId}>\n <strong>{panel.panelId}</strong> — {panel.requests} requests\n {Object.keys(panel.httpStatuses).length\n ? `; HTTP ${Object.entries(panel.httpStatuses)\n .map(([status, count]) => `${status}×${count}`)\n .join(', ')}`\n : ''}\n ; parse/network failures {panel.parseFailures}/{panel.networkFailures}; visible\n changes {panel.visibleStateChanges}; latest{' '}\n {panel.latestRendered\n ? `${panel.latestRendered.state}${panel.latestRendered.status ? `/${panel.latestRendered.status}` : ''}`\n : 'not rendered'}\n .\n </p>\n ))}\n </div>\n )}\n <div className={styles.actions}>\n <button className={styles.button} type=\"button\" onClick={download}>\n Download\n </button>\n <button className={styles.button} type=\"button\" onClick={clear}>\n Clear\n </button>\n </div>\n </div>\n )}\n </section>\n )\n}\n\nfunction formatWindow(first: string, last: string) {\n return first === last ? first : `${first} to ${last}`\n}\n","import type {\n DiagnosticEvent,\n DiagnosticRetention,\n RenderedPanelDiagnostic,\n} from './diagnostics.ts'\n\nexport type PanelDiagnosticsSummary = {\n panelId: string\n requests: number\n httpStatuses: Record<string, number>\n parseFailures: number\n networkFailures: number\n visibleStateChanges: number\n latestRendered?: RenderedPanelDiagnostic\n}\n\nexport type DiagnosticsSummary = {\n retained: {\n eventCount: number\n firstEventAt?: string\n lastEventAt?: string\n sessionCount: number\n retention: DiagnosticRetention\n evidenceMayBeIncomplete: boolean\n }\n failures: {\n clientUpdate: number\n boardFetch: number\n }\n panels: PanelDiagnosticsSummary[]\n}\n\n/** Summarizes retained browser evidence only; omitted history is disclosed through retention. */\nexport function summarizeDiagnostics(\n events: readonly DiagnosticEvent[],\n retention: DiagnosticRetention,\n): DiagnosticsSummary {\n const panels = new Map<string, PanelDiagnosticsSummary>()\n const sessions = new Set<string>()\n let clientUpdate = 0\n let boardFetch = 0\n\n for (const event of events) {\n sessions.add(event.sessionId)\n if (event.kind === 'client-update-failure') clientUpdate++\n if (event.kind === 'board-fetch-failure' || event.kind === 'board-fetch-parse-failure')\n boardFetch++\n if (!('panelId' in event)) continue\n\n const panel = panels.get(event.panelId) ?? {\n panelId: event.panelId,\n requests: 0,\n httpStatuses: {},\n parseFailures: 0,\n networkFailures: 0,\n visibleStateChanges: 0,\n }\n if (event.kind === 'panel-fetch-start') panel.requests++\n if (event.kind === 'panel-fetch-response') {\n if (event.status !== undefined) {\n const status = String(event.status)\n panel.httpStatuses[status] = (panel.httpStatuses[status] ?? 0) + 1\n }\n }\n if (event.kind === 'panel-fetch-parse-failure') panel.parseFailures++\n if (event.kind === 'panel-fetch-failure') panel.networkFailures++\n if (event.kind === 'panel-rendered') {\n panel.visibleStateChanges++\n panel.latestRendered = event.rendered\n }\n panels.set(event.panelId, panel)\n }\n\n const timestamps = events.map((event) => event.at).sort()\n const discarded = retention.eventsPrunedByAge + retention.eventsPrunedByCount\n return {\n retained: {\n eventCount: events.length,\n firstEventAt: timestamps[0],\n lastEventAt: timestamps.at(-1),\n sessionCount: sessions.size,\n retention,\n evidenceMayBeIncomplete: discarded > 0,\n },\n failures: { clientUpdate, boardFetch },\n panels: [...panels.values()].sort((left, right) => left.panelId.localeCompare(right.panelId)),\n }\n}\n","import type { ClientEnv, Envelope } from '@ze-great-dashboard/shared'\nimport { type DiagnosticsSummary, summarizeDiagnostics } from './diagnostics-summary.ts'\n\nconst storageKey = 'ze-great-dashboard.diagnostics.v1'\nexport const diagnosticsSchemaVersion = 1\nconst maximumEvents = 2_000\nconst maximumAgeMillis = 7 * 24 * 60 * 60 * 1_000\nconst diagnosticKinds = [\n 'session-start',\n 'client-update-check',\n 'client-update-failure',\n 'client-update-detected',\n 'board-fetch-start',\n 'board-fetch-response',\n 'board-fetch-parse-failure',\n 'board-fetch-failure',\n 'panel-fetch-start',\n 'panel-fetch-response',\n 'panel-fetch-parse-failure',\n 'panel-fetch-failure',\n 'panel-rendered',\n] as const\n\nexport type CacheMetadata = Partial<\n Record<'cacheControl' | 'etag' | 'lastModified' | 'date' | 'age', string>\n>\n\ntype EventMetadata = {\n schemaVersion: typeof diagnosticsSchemaVersion\n at: string\n sessionId: string\n board: string\n}\n\nexport type RenderedPanelDiagnostic = {\n state: Envelope['state']\n status?: string\n link: string | null\n}\n\nexport type DiagnosticEventInput =\n | { kind: 'session-start' }\n | { kind: 'client-update-check'; path: string }\n | { kind: 'client-update-failure'; path: string; message: string }\n | {\n kind: 'client-update-detected'\n path: string\n current: { assetPath: string; clientVersion: string }\n next: { assetPath: string; clientVersion: string }\n }\n | { kind: 'board-fetch-start'; path: string }\n | {\n kind: 'board-fetch-response'\n path: string\n status?: number\n cache?: CacheMetadata\n boardSummary?: { panelCount: number; panelIds: string[] }\n }\n | { kind: 'board-fetch-parse-failure'; path: string; message: string }\n | { kind: 'board-fetch-failure'; path: string; message: string }\n | { kind: 'panel-fetch-start'; panelId: string; path: string }\n | {\n kind: 'panel-fetch-response'\n panelId: string\n path: string\n status?: number\n cache?: CacheMetadata\n envelope?: Envelope\n }\n | { kind: 'panel-fetch-parse-failure'; panelId: string; path: string; message: string }\n | { kind: 'panel-fetch-failure'; panelId: string; path: string; message: string }\n | {\n kind: 'panel-rendered'\n panelId: string\n path: string\n rendered: RenderedPanelDiagnostic\n }\n\nexport type DiagnosticEvent = DiagnosticEventInput extends infer Event\n ? Event extends DiagnosticEventInput\n ? Event & EventMetadata\n : never\n : never\n\n/** The only interface client features need in order to emit browser diagnostics. */\nexport interface DiagnosticSink {\n record(event: DiagnosticEventInput): void\n}\n\ntype PersistedDiagnosticEvent = Omit<DiagnosticEvent, 'schemaVersion'> & { schemaVersion?: number }\nexport type DiagnosticRetention = {\n eventsPrunedByAge: number\n eventsPrunedByCount: number\n}\n\ntype StoredDiagnostics = {\n schemaVersion: number\n events: PersistedDiagnosticEvent[]\n retention?: Partial<DiagnosticRetention>\n}\n\ntype StorageLike = Pick<Storage, 'getItem' | 'setItem' | 'removeItem'>\n\n/** Browser-local diagnostic evidence. It deliberately has no server or shared-contract counterpart. */\nexport class BrowserDiagnosticStore implements DiagnosticSink {\n private events: DiagnosticEvent[] = []\n private retention: DiagnosticRetention = emptyRetention()\n private revision = 0\n private readonly listeners = new Set<() => void>()\n private readonly sessionId = crypto.randomUUID?.() ?? `${Date.now()}-${Math.random()}`\n\n constructor(\n private readonly env: ClientEnv,\n private readonly storage: StorageLike | undefined = storageOrUndefined(),\n private readonly now: () => Date = () => new Date(),\n ) {\n this.events = this.read()\n this.record({ kind: 'session-start' })\n }\n\n record(event: DiagnosticEventInput) {\n const pruned = prune(\n [\n ...this.events,\n {\n ...event,\n schemaVersion: diagnosticsSchemaVersion,\n at: this.now().toISOString(),\n sessionId: this.sessionId,\n board: this.env.board,\n },\n ],\n this.now(),\n this.retention,\n )\n this.events = pruned.events\n this.retention = pruned.retention\n this.persist()\n this.revision++\n this.notify()\n }\n\n count = () => {\n return this.events.length\n }\n\n snapshot = () => this.revision\n\n summary = (): DiagnosticsSummary => summarizeDiagnostics(this.events, this.retention)\n\n clear() {\n this.events = []\n this.retention = emptyRetention()\n try {\n this.storage?.removeItem(storageKey)\n } catch {\n // Diagnostics must not interrupt the radiator when browser storage is unavailable.\n }\n this.revision++\n this.notify()\n }\n\n subscribe = (listener: () => void) => {\n this.listeners.add(listener)\n return () => {\n this.listeners.delete(listener)\n }\n }\n\n export = () => {\n return {\n schemaVersion: diagnosticsSchemaVersion,\n exportedAt: this.now().toISOString(),\n client: {\n version: this.env.clientVersion,\n assetPath: this.env.assetPath,\n board: this.env.board,\n sessionId: this.sessionId,\n },\n events: this.events,\n summary: this.summary(),\n }\n }\n\n private read(): DiagnosticEvent[] {\n try {\n const raw = this.storage?.getItem(storageKey)\n if (!raw) return []\n const parsed = JSON.parse(raw) as Partial<StoredDiagnostics>\n if (parsed.schemaVersion !== diagnosticsSchemaVersion || !Array.isArray(parsed.events)) {\n this.storage?.removeItem(storageKey)\n return []\n }\n if (!parsed.events.every(isDiagnosticEvent)) {\n this.storage?.removeItem(storageKey)\n return []\n }\n // v1 retained events predate per-event versions. Their containing store was already v1, so\n // retain them and normalize on the next write rather than discarding viewer evidence.\n const pruned = prune(\n parsed.events.map(\n (event) => ({ ...event, schemaVersion: diagnosticsSchemaVersion }) as DiagnosticEvent,\n ),\n this.now(),\n validRetention(parsed.retention),\n )\n this.retention = pruned.retention\n return pruned.events\n } catch {\n try {\n this.storage?.removeItem(storageKey)\n } catch {\n // Storage can fail on both reads and writes (for example, private browsing policies).\n }\n return []\n }\n }\n\n private persist() {\n try {\n this.storage?.setItem(\n storageKey,\n JSON.stringify({\n schemaVersion: diagnosticsSchemaVersion,\n events: this.events,\n retention: this.retention,\n }),\n )\n } catch {\n // Keep the in-memory record for this page, but never make diagnostics a rendering failure.\n }\n }\n\n private notify() {\n for (const listener of this.listeners) listener()\n }\n}\n\nexport function cacheMetadata(headers: Headers): CacheMetadata | undefined {\n const entries = [\n ['cacheControl', 'cache-control'],\n ['etag', 'etag'],\n ['lastModified', 'last-modified'],\n ['date', 'date'],\n ['age', 'age'],\n ] as const\n const metadata = Object.fromEntries(\n entries.flatMap(([key, header]) => {\n const value = headers.get(header)\n return value ? [[key, value]] : []\n }),\n ) as CacheMetadata\n return Object.keys(metadata).length ? metadata : undefined\n}\n\nfunction emptyRetention(): DiagnosticRetention {\n return { eventsPrunedByAge: 0, eventsPrunedByCount: 0 }\n}\n\nfunction validRetention(value: unknown): DiagnosticRetention {\n if (!value || typeof value !== 'object') return emptyRetention()\n const retention = value as Partial<DiagnosticRetention>\n return {\n eventsPrunedByAge:\n typeof retention.eventsPrunedByAge === 'number' && retention.eventsPrunedByAge >= 0\n ? retention.eventsPrunedByAge\n : 0,\n eventsPrunedByCount:\n typeof retention.eventsPrunedByCount === 'number' && retention.eventsPrunedByCount >= 0\n ? retention.eventsPrunedByCount\n : 0,\n }\n}\n\nfunction prune(events: DiagnosticEvent[], now: Date, priorRetention: DiagnosticRetention) {\n const cutoff = now.valueOf() - maximumAgeMillis\n const current = events.filter(\n (event) =>\n Number.isFinite(new Date(event.at).valueOf()) && new Date(event.at).valueOf() >= cutoff,\n )\n const discardedByAge = events.length - current.length\n const discardedByCount = Math.max(0, current.length - maximumEvents)\n return {\n events: current.slice(-maximumEvents),\n retention: {\n eventsPrunedByAge: priorRetention.eventsPrunedByAge + discardedByAge,\n eventsPrunedByCount: priorRetention.eventsPrunedByCount + discardedByCount,\n },\n }\n}\n\nfunction isDiagnosticEvent(value: unknown): value is PersistedDiagnosticEvent {\n if (!value || typeof value !== 'object') return false\n const event = value as Partial<DiagnosticEvent>\n return (\n (event.schemaVersion === undefined || event.schemaVersion === diagnosticsSchemaVersion) &&\n typeof event.at === 'string' &&\n Number.isFinite(new Date(event.at).valueOf()) &&\n typeof event.sessionId === 'string' &&\n typeof event.board === 'string' &&\n diagnosticKinds.includes(event.kind as (typeof diagnosticKinds)[number])\n )\n}\n\nfunction storageOrUndefined(): StorageLike | undefined {\n try {\n return window.localStorage\n } catch {\n return undefined\n }\n}\n","/**\n * A panel-shaped hole, so the grid can be looked at and argued with before any signal exists.\n * Replaced by real panels in Stage 2 — nothing here is meant to survive.\n */\nexport function PanelPlaceholder({\n label,\n hint,\n wide = false,\n}: {\n label: string\n hint: string\n wide?: boolean\n}) {\n return (\n <section className={wide ? 'panel panel--wide' : 'panel'}>\n <h2 className=\"panel__label\">{label}</h2>\n <p className=\"panel__hint\">{hint}</p>\n </section>\n )\n}\n","export function ObservedAt({ value, label = 'As of' }: { value: string; label?: string }) {\n const observed = new Date(value)\n const formatted = observed.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' })\n const age = Date.now() - observed.getTime()\n const stale = age > 5 * 60 * 1000\n const ageText = formatAge(age)\n return (\n <p className={`panel__hint panel__observed${stale ? ' panel__observed--stale' : ''}`}>\n <span aria-hidden=\"true\">◷</span> {label} {formatted} · {ageText}\n </p>\n )\n}\n\nexport function formatAge(milliseconds: number) {\n if (milliseconds < 60_000) return 'just now'\n const minutes = Math.floor(milliseconds / 60_000)\n if (minutes < 60) return `${minutes}m ago`\n const hours = Math.floor(minutes / 60)\n return `${hours}h ${minutes % 60}m ago`\n}\n","import type { Panel } from '@ze-great-dashboard/shared'\nimport type { CSSProperties } from 'react'\n\n/** Convert the advisory board position into CSS grid placement. */\nexport function panelLayout(panel: Panel): CSSProperties | undefined {\n const position = panel.position\n if (!position) return undefined\n\n return {\n '--panel-column': `${position.x + 1} / span ${position.w}`,\n '--panel-row': `${position.y + 1} / span ${position.h}`,\n } as CSSProperties\n}\n","import type { Envelope, Panel } from '@ze-great-dashboard/shared'\nimport type { ReactNode } from 'react'\nimport { panelLayout } from './panel-layout.ts'\n\nexport function PanelFrame({\n panel,\n envelope,\n error = false,\n children,\n}: {\n panel: Panel\n envelope?: Envelope\n error?: boolean\n children: ReactNode\n}) {\n const display =\n panel.display === 'primary' || panel.display === 'compact' ? panel.display : 'supporting'\n return (\n <section\n className={`panel panel--${display}${error ? ' panel--error' : ''}`}\n style={panelLayout(panel)}\n aria-busy={envelope ? undefined : true}\n >\n <h2 className=\"panel__label\">{panel.id}</h2>\n {children}\n <PanelSourceLink panelId={panel.id} link={envelope?.link} />\n </section>\n )\n}\n\nfunction PanelSourceLink({ panelId, link }: { panelId: string; link?: string | null }) {\n if (!link) return null\n\n return (\n <a\n className=\"panel__link\"\n href={link}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n aria-label={`View source for ${panelId} (opens in a new tab)`}\n >\n View source <span aria-hidden=\"true\">↗</span>\n </a>\n )\n}\n","import type { Panel } from '@ze-great-dashboard/shared'\nimport { type Envelope, httpValueSchema } from '@ze-great-dashboard/shared'\nimport { ObservedAt } from './ObservedAt.tsx'\nimport { PanelFrame } from './PanelFrame.tsx'\n\nexport function HttpValuePanel({\n panel,\n envelope,\n}: {\n panel: Panel\n envelope: Envelope | undefined\n}) {\n if (!envelope)\n return (\n <PanelFrame panel={panel}>\n <p className=\"panel__hint\">Loading…</p>\n </PanelFrame>\n )\n if (envelope.state === 'error')\n return (\n <PanelFrame panel={panel} envelope={envelope} error>\n <p className=\"panel__status\">⚠ Unable to read</p>\n <p className=\"panel__hint\">{envelope.error.message}</p>\n <ObservedAt value={envelope.observedAt} />\n </PanelFrame>\n )\n const signal = httpValueSchema.safeParse(envelope.signal)\n if (!signal.success)\n return (\n <PanelFrame panel={panel} envelope={envelope} error>\n <p className=\"panel__status\">⚠ Invalid value</p>\n <ObservedAt value={envelope.observedAt} />\n </PanelFrame>\n )\n return (\n <PanelFrame panel={panel} envelope={envelope}>\n <p className=\"panel__status\">{String(signal.data.value)}</p>\n <ObservedAt value={envelope.observedAt} />\n </PanelFrame>\n )\n}\n","import type { RunningAnimation } from '@ze-great-dashboard/shared'\nimport { type CSSProperties, useEffect, useState } from 'react'\n\nexport function RunningProgress({\n animation,\n runStartedAt,\n estimatedDurationMs,\n}: {\n animation: Exclude<RunningAnimation, 'off'>\n runStartedAt?: string\n estimatedDurationMs?: number\n}) {\n const now = useClock(Boolean(runStartedAt))\n const startedAt = runStartedAt ? new Date(runStartedAt).valueOf() : Number.NaN\n const elapsedMs = Number.isFinite(startedAt) ? Math.max(0, now - startedAt) : undefined\n const hasEstimate = elapsedMs !== undefined && estimatedDurationMs !== undefined\n const overdue = hasEstimate && elapsedMs > estimatedDurationMs\n const progress = hasEstimate ? Math.min(elapsedMs / estimatedDurationMs, 1) : 0\n const usesReadout = animation === 'runway' || animation === 'signal-field'\n const timingText = timingDescription(elapsedMs, estimatedDurationMs, overdue)\n const style = {\n '--running-progress': `${progress * 100}%`,\n '--running-degrees': `${progress * 360}deg`,\n } as CSSProperties\n\n return (\n <div\n className={`running-progress running-progress--${animation}${overdue ? ' running-progress--overdue' : ''}${hasEstimate ? '' : ' running-progress--indeterminate'}`}\n style={style}\n >\n <div className=\"running-progress__visual\" aria-hidden=\"true\">\n {animation === 'radial' && <span className=\"running-progress__radial-core\" />}\n {animation === 'runway' && <span className=\"running-progress__runway-spark\" />}\n {animation === 'orbit' && (\n <>\n <span className=\"running-progress__orbit-core\" />\n <span className=\"running-progress__orbit-particle running-progress__orbit-particle--one\" />\n <span className=\"running-progress__orbit-particle running-progress__orbit-particle--two\" />\n </>\n )}\n {animation === 'signal-field' && (\n <>\n <span className=\"running-progress__signal-rail\" />\n <span className=\"running-progress__signal-lead\" />\n <span className=\"running-progress__signal-pulse running-progress__signal-pulse--one\" />\n <span className=\"running-progress__signal-pulse running-progress__signal-pulse--two\" />\n <span className=\"running-progress__signal-tracks\">\n {[0, 1, 2, 3, 4].map((track) => (\n <span className=\"running-progress__signal-track\" key={track}>\n <span className=\"running-progress__signal-marker\" />\n </span>\n ))}\n </span>\n </>\n )}\n </div>\n <p\n className={`running-progress__timing${usesReadout ? ' running-progress__timing--readout' : ''}`}\n >\n {usesReadout ? (\n <>\n <span className=\"screen-reader-only\">{timingText}</span>\n <span aria-hidden=\"true\">{compactTiming(elapsedMs, estimatedDurationMs, overdue)}</span>\n </>\n ) : (\n timingText\n )}\n </p>\n </div>\n )\n}\n\nfunction useClock(enabled: boolean) {\n const [now, setNow] = useState(() => Date.now())\n useEffect(() => {\n if (!enabled) return\n setNow(Date.now())\n const interval = window.setInterval(() => setNow(Date.now()), 1_000)\n return () => window.clearInterval(interval)\n }, [enabled])\n return now\n}\n\nfunction formatDuration(durationMs: number) {\n const totalSeconds = Math.floor(durationMs / 1_000)\n const hours = Math.floor(totalSeconds / 3_600)\n const minutes = Math.floor((totalSeconds % 3_600) / 60)\n const seconds = totalSeconds % 60\n if (hours > 0) return `${hours}h ${minutes}m`\n if (minutes > 0) return `${minutes}m ${seconds}s`\n return `${seconds}s`\n}\n\nfunction timingDescription(\n elapsedMs: number | undefined,\n estimatedDurationMs: number | undefined,\n overdue: boolean,\n) {\n const elapsed =\n elapsedMs === undefined ? 'Run in progress' : `Elapsed ${formatDuration(elapsedMs)}`\n const expected =\n estimatedDurationMs === undefined\n ? 'Expected duration unavailable'\n : `Expected ≈ ${formatDuration(estimatedDurationMs)}`\n return `${elapsed} · ${expected}${overdue ? ' · Over estimate' : ''}`\n}\n\nfunction compactTiming(\n elapsedMs: number | undefined,\n estimatedDurationMs: number | undefined,\n overdue: boolean,\n) {\n const elapsed = elapsedMs === undefined ? '—' : formatClockDuration(elapsedMs)\n const expected =\n estimatedDurationMs === undefined ? '?' : `~${formatClockDuration(estimatedDurationMs)}`\n return `${overdue ? '⚠' : '\\u00a0'}${elapsed}/${expected}`\n}\n\nfunction formatClockDuration(durationMs: number) {\n const totalSeconds = Math.floor(durationMs / 1_000)\n const hours = Math.floor(totalSeconds / 3_600)\n const minutes = Math.floor((totalSeconds % 3_600) / 60)\n const seconds = totalSeconds % 60\n const clock = `${minutes}:${String(seconds).padStart(2, '0')}`\n return hours > 0 ? `${hours}:${clock.padStart(5, '0')}` : clock\n}\n","import type { Panel } from '@ze-great-dashboard/shared'\nimport { useEffect, useState } from 'react'\nimport { PanelFrame } from './PanelFrame.tsx'\nimport { RunningProgress } from './RunningProgress.tsx'\n\nconst RUN_DURATION_MS = 20_000\nconst ESTIMATED_DURATION_MS = 15_000\nconst variants = ['radial', 'runway', 'orbit', 'signal-field'] as const\n\n/**\n * A local comparison aid for the active-run treatments. It deliberately creates no signal or\n * diagnostic evidence: its state is derived only from the wall clock and repeats forever.\n */\nexport function PipelineAnimationDemoPanel({ panel }: { panel: Panel }) {\n const now = useClock()\n const runNumber = Math.floor(now / RUN_DURATION_MS)\n const animation = variants[runNumber % variants.length] ?? 'radial'\n const runStartedAt = runNumber * RUN_DURATION_MS\n\n return (\n <PanelFrame panel={panel}>\n <p className=\"panel__status panel__status--running\">↻ Running</p>\n <p className=\"pipeline-animation-demo__variant\">Demo treatment · {animation}</p>\n <RunningProgress\n key={runStartedAt}\n animation={animation}\n runStartedAt={new Date(runStartedAt).toISOString()}\n estimatedDurationMs={ESTIMATED_DURATION_MS}\n />\n </PanelFrame>\n )\n}\n\nfunction useClock() {\n const [now, setNow] = useState(() => Date.now())\n useEffect(() => {\n const interval = window.setInterval(() => setNow(Date.now()), 1_000)\n return () => window.clearInterval(interval)\n }, [])\n return now\n}\n","import { type Envelope, type Panel, pipelineStatusSchema } from '@ze-great-dashboard/shared'\nimport { ObservedAt } from './ObservedAt.tsx'\nimport { PanelFrame } from './PanelFrame.tsx'\nimport { RunningProgress } from './RunningProgress.tsx'\n\nexport function PipelinePanel({\n panel,\n envelope,\n}: {\n panel: Panel\n envelope: Envelope | undefined\n}) {\n if (!envelope)\n return (\n <PanelFrame panel={panel}>\n <p className=\"panel__hint\">Loading…</p>\n </PanelFrame>\n )\n if (envelope.state === 'error') {\n return (\n <PanelFrame panel={panel} envelope={envelope} error>\n <p className=\"panel__status\">\n ⚠ {envelope.error.kind === 'no-runs' ? 'No workflow runs' : 'Unable to read'}\n </p>\n <p className=\"panel__hint\">{envelope.error.message}</p>\n <ObservedAt value={envelope.observedAt} />\n </PanelFrame>\n )\n }\n\n const signal = pipelineStatusSchema.safeParse(envelope.signal)\n if (!signal.success)\n return (\n <PanelFrame panel={panel} envelope={envelope} error>\n <p className=\"panel__status\">⚠ Invalid signal</p>\n <ObservedAt value={envelope.observedAt} />\n </PanelFrame>\n )\n const presentation = statusPresentation(signal.data.status)\n return (\n <PanelFrame panel={panel} envelope={envelope}>\n <p className={`panel__status panel__status--${signal.data.status}`}>\n {presentation.glyph} {presentation.label}\n </p>\n <p className=\"panel__hint\">\n {signal.data.name} · {signal.data.rawStatus}\n {signal.data.branch && (\n <span className=\"panel__branch\" title={`Branch: ${signal.data.branch}`}>\n <span aria-hidden=\"true\"> · ⎇ </span>\n <span className=\"screen-reader-only\">Branch: </span>\n {signal.data.branch}\n </span>\n )}\n </p>\n {signal.data.status === 'running' && panel.running_animation !== 'off' && (\n <RunningProgress\n animation={panel.running_animation ?? 'orbit'}\n runStartedAt={signal.data.runStartedAt}\n estimatedDurationMs={signal.data.estimatedDurationMs}\n />\n )}\n {signal.data.status !== 'running' && signal.data.durationMs !== undefined && (\n <p className=\"panel__hint\">Took {formatDuration(signal.data.durationMs)}</p>\n )}\n {signal.data.sourceUpdatedAt && (\n <ObservedAt value={signal.data.sourceUpdatedAt} label=\"Run updated\" />\n )}\n <ObservedAt value={envelope.observedAt} />\n </PanelFrame>\n )\n}\n\nfunction formatDuration(durationMs: number) {\n const totalSeconds = Math.floor(durationMs / 1_000)\n const hours = Math.floor(totalSeconds / 3_600)\n const minutes = Math.floor((totalSeconds % 3_600) / 60)\n const seconds = totalSeconds % 60\n\n if (hours > 0) return `${hours}h ${minutes}m`\n if (minutes > 0) return `${minutes}m ${seconds}s`\n return `${seconds}s`\n}\n\nfunction statusPresentation(status: 'passed' | 'failed' | 'running' | 'cancelled' | 'unknown') {\n switch (status) {\n case 'passed':\n return { glyph: '✓', label: 'Passed' }\n case 'failed':\n return { glyph: '✕', label: 'Failed' }\n case 'running':\n return { glyph: '↻', label: 'Running' }\n case 'cancelled':\n return { glyph: '⊘', label: 'Cancelled' }\n case 'unknown':\n return { glyph: '?', label: 'Unknown' }\n }\n}\n","import { type Envelope, type Panel, pullRequestHealthSchema } from '@ze-great-dashboard/shared'\nimport { ObservedAt } from './ObservedAt.tsx'\nimport { PanelFrame } from './PanelFrame.tsx'\n\nexport function PullRequestHealthPanel({\n panel,\n envelope,\n}: {\n panel: Panel\n envelope: Envelope | undefined\n}) {\n if (!envelope)\n return (\n <PanelFrame panel={panel}>\n <p className=\"panel__hint\">Loading…</p>\n </PanelFrame>\n )\n if (envelope.state === 'error')\n return (\n <PanelFrame panel={panel} envelope={envelope} error>\n <p className=\"panel__status\">⚠ Unable to read</p>\n <p className=\"panel__hint\">{envelope.error.message}</p>\n <ObservedAt value={envelope.observedAt} />\n </PanelFrame>\n )\n const signal = pullRequestHealthSchema.safeParse(envelope.signal)\n if (!signal.success)\n return (\n <PanelFrame panel={panel} envelope={envelope} error>\n <p className=\"panel__status\">⚠ Invalid signal</p>\n </PanelFrame>\n )\n const presentation = statusPresentation(signal.data.status)\n return (\n <PanelFrame panel={panel} envelope={envelope}>\n <p className={`panel__status panel__status--${signal.data.status}`}>\n {presentation.glyph} {presentation.label}\n </p>\n <p className=\"panel__hint\">{signal.data.summary}</p>\n <ObservedAt value={envelope.observedAt} />\n </PanelFrame>\n )\n}\n\nfunction statusPresentation(status: 'passed' | 'failed' | 'running' | 'cancelled' | 'unknown') {\n switch (status) {\n case 'passed':\n return { glyph: '✓', label: 'Healthy' }\n case 'failed':\n return { glyph: '✕', label: 'Failed' }\n case 'running':\n return { glyph: '↻', label: 'Running' }\n case 'cancelled':\n return { glyph: '⊘', label: 'Cancelled' }\n case 'unknown':\n return { glyph: '?', label: 'Unknown' }\n }\n}\n","import type { Envelope, Panel } from '@ze-great-dashboard/shared'\nimport type { ComponentType } from 'react'\nimport { HttpValuePanel } from './HttpValuePanel.tsx'\nimport { PanelPlaceholder } from './PanelPlaceholder.tsx'\nimport { PipelineAnimationDemoPanel } from './PipelineAnimationDemoPanel.tsx'\nimport { PipelinePanel } from './PipelinePanel.tsx'\nimport { PullRequestHealthPanel } from './PullRequestHealthPanel.tsx'\n\ntype PanelRendererProps = {\n panel: Panel\n envelope: Envelope | undefined\n}\n\n/** The one client-side dispatch point for panel types. */\nexport const panelRenderers: Record<string, ComponentType<PanelRendererProps>> = {\n 'pipeline-status': PipelinePanel,\n 'pull-request-health': PullRequestHealthPanel,\n 'http-value': HttpValuePanel,\n 'pipeline-animation-demo': PipelineAnimationDemoPanel,\n}\n\nexport function PanelRenderer({ panel, envelope }: PanelRendererProps) {\n const Renderer = panelRenderers[panel.type]\n return Renderer ? (\n <Renderer panel={panel} envelope={envelope} />\n ) : (\n <PanelPlaceholder label={panel.type} hint=\"Not wired yet\" wide />\n )\n}\n","import { type ClientEnv, clientIdentitySchema } from '@ze-great-dashboard/shared'\nimport { useEffect } from 'react'\nimport type { DiagnosticSink } from './diagnostics.ts'\n\nconst clientUpdateIntervalMillis = 60_000\nconst clientUpdateTimeoutMillis = 10_000\nconst defaultReload = () => globalThis.window.location.reload()\n\nexport function useClientUpdate({\n env,\n diagnostics,\n fetcher,\n reload = defaultReload,\n}: {\n env: ClientEnv\n diagnostics: DiagnosticSink\n fetcher?: typeof fetch\n reload?: () => void\n}) {\n useEffect(() => {\n let cancelled = false\n let inFlight = false\n let activeController: AbortController | undefined\n const path = `${env.proxyPath}/client`\n\n const check = async () => {\n if (cancelled || inFlight) return\n inFlight = true\n const controller = new AbortController()\n activeController = controller\n const timeout = globalThis.setTimeout(() => controller.abort(), clientUpdateTimeoutMillis)\n diagnostics.record({ kind: 'client-update-check', path })\n try {\n const response = await (fetcher ?? globalThis.fetch)(path, {\n cache: 'no-store',\n signal: controller.signal,\n })\n if (!response.ok) throw new Error(`Client identity returned ${response.status}`)\n const parsed = clientIdentitySchema.safeParse(await response.json())\n if (!parsed.success) throw new Error('Client identity response was invalid')\n if (cancelled) return\n // assetPath is the server's immutable deployment selector. clientVersion is a label and\n // can change independently without changing the code the browser should load.\n if (parsed.data.assetPath !== env.assetPath) {\n diagnostics.record({\n kind: 'client-update-detected',\n path,\n current: { assetPath: env.assetPath, clientVersion: env.clientVersion },\n next: parsed.data,\n })\n reload()\n }\n } catch (error) {\n if (!cancelled && !(error instanceof DOMException && error.name === 'AbortError')) {\n diagnostics.record({\n kind: 'client-update-failure',\n path,\n message: error instanceof Error ? error.message : String(error),\n })\n }\n } finally {\n globalThis.clearTimeout(timeout)\n inFlight = false\n if (activeController === controller) activeController = undefined\n if (!cancelled) globalThis.setTimeout(() => void check(), clientUpdateIntervalMillis)\n }\n }\n\n void check()\n return () => {\n cancelled = true\n activeController?.abort()\n }\n }, [diagnostics, env.assetPath, env.clientVersion, env.proxyPath, fetcher, reload])\n}\n","import {\n type Envelope,\n type Panel,\n pipelineStatusSchema,\n pullRequestHealthSchema,\n} from '@ze-great-dashboard/shared'\nimport type { RenderedPanelDiagnostic } from './diagnostics.ts'\n\n/**\n * The compact public fact a viewer saw. Keep new panel projections here beside their\n * presentation boundary; this is intentionally not a source or server event contract.\n */\nexport function projectPanelDiagnostic(panel: Panel, envelope: Envelope): RenderedPanelDiagnostic {\n if (envelope.state === 'error') return { state: envelope.state, link: envelope.link }\n\n if (panel.type === 'pipeline-status') {\n const signal = pipelineStatusSchema.safeParse(envelope.signal)\n return {\n state: envelope.state,\n status: signal.success ? signal.data.status : undefined,\n link: envelope.link,\n }\n }\n\n if (panel.type === 'pull-request-health') {\n const signal = pullRequestHealthSchema.safeParse(envelope.signal)\n return {\n state: envelope.state,\n status: signal.success ? signal.data.status : undefined,\n link: envelope.link,\n }\n }\n\n return { state: envelope.state, link: envelope.link }\n}\n\nexport function panelDiagnosticChanged(\n previous: Envelope | undefined,\n panel: Panel,\n next: Envelope,\n) {\n if (!previous) return true\n const before = projectPanelDiagnostic(panel, previous)\n const after = projectPanelDiagnostic(panel, next)\n return (\n before.state !== after.state || before.status !== after.status || before.link !== after.link\n )\n}\n","import {\n type Board,\n type ClientEnv,\n type Envelope,\n envelopeSchema,\n parseDuration,\n resolveRefreshMillis,\n} from '@ze-great-dashboard/shared'\nimport { useEffect, useRef, useState } from 'react'\nimport { cacheMetadata, type DiagnosticSink } from './diagnostics.ts'\nimport { panelDiagnosticChanged, projectPanelDiagnostic } from './panel-diagnostics.ts'\n\nexport function usePanelSignals({\n board,\n env,\n diagnostics,\n}: {\n board: Board | undefined\n env: ClientEnv\n diagnostics: DiagnosticSink\n}) {\n const [signals, setSignals] = useState<Record<string, Envelope | undefined>>({})\n const signalsRef = useRef<Record<string, Envelope | undefined>>({})\n\n useEffect(() => {\n signalsRef.current = {}\n setSignals({})\n if (!board) return\n\n let cancelled = false\n const timers: number[] = []\n for (const panel of board.panels) {\n if (\n panel.type !== 'pipeline-status' &&\n panel.type !== 'pull-request-health' &&\n panel.type !== 'http-value'\n )\n continue\n let inFlight = false\n const refreshMillis = resolveRefreshMillis({\n boardDefaultMillis: parseDuration(board.refresh ?? '60s') ?? 60_000,\n panelOverrideMillis: panel.refresh\n ? (parseDuration(panel.refresh) ?? undefined)\n : undefined,\n adapterFloorMillis: 0,\n })\n const path = `${env.proxyPath}/panel/${encodeURIComponent(env.board)}/${encodeURIComponent(panel.id)}`\n const refresh = () => {\n if (cancelled || inFlight) return\n inFlight = true\n diagnostics.record({ kind: 'panel-fetch-start', panelId: panel.id, path })\n fetch(path)\n .then(async (response) => {\n const transport = {\n kind: 'panel-fetch-response' as const,\n panelId: panel.id,\n path,\n status: response.status,\n cache: cacheMetadata(response.headers),\n }\n if (response.status === 304) {\n diagnostics.record(transport)\n return undefined\n }\n try {\n const value: unknown = await response.json()\n const envelope = parseEnvelope(value)\n if (!envelope) {\n diagnostics.record(transport)\n diagnostics.record({\n kind: 'panel-fetch-parse-failure',\n panelId: panel.id,\n path,\n message: 'Response was not a valid signal envelope.',\n })\n return undefined\n }\n diagnostics.record({ ...transport, envelope })\n return envelope\n } catch (error) {\n diagnostics.record(transport)\n diagnostics.record({\n kind: 'panel-fetch-parse-failure',\n panelId: panel.id,\n path,\n message: errorMessage(error),\n })\n throw new DiagnosticParseFailure(error)\n }\n })\n .then((envelope) => {\n if (!cancelled && envelope) {\n const previous = signalsRef.current[panel.id]\n if (panelDiagnosticChanged(previous, panel, envelope)) {\n diagnostics.record({\n kind: 'panel-rendered',\n panelId: panel.id,\n path,\n rendered: projectPanelDiagnostic(panel, envelope),\n })\n }\n signalsRef.current = { ...signalsRef.current, [panel.id]: envelope }\n setSignals(signalsRef.current)\n }\n })\n .catch((error) => {\n if (!(error instanceof DiagnosticParseFailure)) {\n diagnostics.record({\n kind: 'panel-fetch-failure',\n panelId: panel.id,\n path,\n message: errorMessage(error),\n })\n }\n })\n .finally(() => {\n inFlight = false\n })\n }\n refresh()\n timers.push(window.setInterval(refresh, refreshMillis))\n }\n return () => {\n cancelled = true\n for (const timer of timers) window.clearInterval(timer)\n }\n }, [board, diagnostics, env.board, env.proxyPath])\n\n return signals\n}\n\nfunction errorMessage(error: unknown) {\n return error instanceof Error ? error.message : String(error)\n}\n\nclass DiagnosticParseFailure extends Error {\n constructor(error: unknown) {\n super(errorMessage(error))\n }\n}\n\nfunction parseEnvelope(value: unknown): Envelope | undefined {\n const result = envelopeSchema.safeParse(value)\n return result.success ? result.data : undefined\n}\n","import type { Board, ClientEnv } from '@ze-great-dashboard/shared'\nimport { useEffect, useRef, useState } from 'react'\nimport { Diagnostics } from './Diagnostics.tsx'\nimport { BrowserDiagnosticStore, cacheMetadata } from './diagnostics.ts'\nimport { PanelPlaceholder } from './PanelPlaceholder.tsx'\nimport { PanelRenderer } from './panel-registry.tsx'\nimport { useClientUpdate } from './useClientUpdate.ts'\nimport { usePanelSignals } from './usePanelSignals.ts'\n\n/**\n * The board shell.\n *\n * Stage 1 has no data: there is no proxy endpoint to poll yet. What this proves is the plumbing —\n * that the client was handed its configuration by the server and knows which version of itself it\n * is. The version readout is what makes two published versions visibly different, which is the\n * whole point of the Stage 1 exit criterion.\n */\nexport function App({ env }: { env: ClientEnv }) {\n const [board, setBoard] = useState<Board>()\n const [loadedBoardName, setLoadedBoardName] = useState<string>()\n const diagnosticsRef = useRef<BrowserDiagnosticStore | null>(null)\n if (!diagnosticsRef.current) diagnosticsRef.current = new BrowserDiagnosticStore(env)\n const diagnostics = diagnosticsRef.current\n useClientUpdate({ env, diagnostics })\n const signals = usePanelSignals({\n board: loadedBoardName === env.board ? board : undefined,\n env,\n diagnostics,\n })\n\n useEffect(() => {\n let cancelled = false\n setBoard(undefined)\n setLoadedBoardName(undefined)\n const path = `${env.proxyPath}/boards/${encodeURIComponent(env.board)}`\n diagnostics.record({ kind: 'board-fetch-start', path })\n fetch(path)\n .then(async (response) => {\n diagnostics.record({\n kind: 'board-fetch-response',\n path,\n status: response.status,\n cache: cacheMetadata(response.headers),\n })\n if (!response.ok) throw new Error(`Board configuration returned ${response.status}`)\n try {\n return await response.json()\n } catch (error) {\n diagnostics.record({\n kind: 'board-fetch-parse-failure',\n path,\n message: errorMessage(error),\n })\n throw new DiagnosticParseFailure(error)\n }\n })\n .then((value: unknown) => {\n if (!cancelled) {\n setBoard(value as Board)\n setLoadedBoardName(env.board)\n const panels = Array.isArray((value as { panels?: unknown }).panels)\n ? (value as { panels: Array<{ id?: unknown }> }).panels\n : []\n diagnostics.record({\n kind: 'board-fetch-response',\n path,\n boardSummary: {\n panelCount: panels.length,\n panelIds: panels.flatMap((panel) => (typeof panel.id === 'string' ? [panel.id] : [])),\n },\n })\n }\n })\n .catch((error) => {\n if (!(error instanceof DiagnosticParseFailure)) {\n diagnostics.record({ kind: 'board-fetch-failure', path, message: errorMessage(error) })\n }\n if (!cancelled) {\n setBoard({ panels: [] })\n setLoadedBoardName(env.board)\n }\n })\n return () => {\n cancelled = true\n }\n }, [diagnostics, env.board, env.proxyPath])\n\n return (\n <div className=\"board\">\n <header className=\"board__header\">\n <h1 className=\"board__title\">{env.board}</h1>\n <dl className=\"board__meta\">\n <div>\n <dt>client</dt>\n <dd>{env.clientVersion}</dd>\n </div>\n <div>\n <dt>assets</dt>\n <dd>{env.assetPath}</dd>\n </div>\n </dl>\n </header>\n\n <main className=\"board__grid\">\n {!board && <PanelPlaceholder label=\"board\" hint=\"Loading configuration…\" wide />}\n {board?.panels.map((panel) => (\n <PanelRenderer key={panel.id} panel={panel} envelope={signals[panel.id]} />\n ))}\n </main>\n\n <footer className=\"board__footer\">\n <span>Signals are read live from their configured authorities.</span>\n <Diagnostics log={diagnostics} />\n </footer>\n </div>\n )\n}\n\nfunction errorMessage(error: unknown) {\n return error instanceof Error ? error.message : String(error)\n}\n\nclass DiagnosticParseFailure extends Error {\n constructor(error: unknown) {\n super(errorMessage(error))\n }\n}\n","export function ConfigError({ message }: { message: string }) {\n return (\n <div className=\"config-error\" role=\"alert\">\n <h1>⚠️ Dashboard misconfigured</h1>\n <p>The page loaded, but the server did not hand it usable configuration.</p>\n <pre>{message}</pre>\n </div>\n )\n}\n","import { readClientEnv } from '@ze-great-dashboard/shared'\nimport { StrictMode } from 'react'\nimport { createRoot } from 'react-dom/client'\nimport { App } from './App.tsx'\nimport { ConfigError } from './ConfigError.tsx'\nimport './styles.css'\n\nconst container = document.getElementById('root')\nif (!container) {\n throw new Error('No #root element in the document — the template is not the one we expect.')\n}\n\nconst root = createRoot(container)\n\ntry {\n root.render(\n <StrictMode>\n <App env={readClientEnv()} />\n </StrictMode>,\n )\n} catch (error) {\n // A radiator that fails silently is worse than one that says what's wrong. If configuration\n // never arrived, say so on screen rather than rendering an empty board.\n root.render(<ConfigError message={error instanceof Error ? error.message : String(error)} />)\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
._diagnostics_lseur_1{position:relative}._button_lseur_5{border:1px solid var(--edge);background:var(--surface-raised);color:var(--ink-secondary);font:inherit;border-radius:.25rem;padding:.3em .55em}._area_lseur_14{z-index:1;border:1px solid var(--edge);border-radius:var(--radius);background:var(--surface-raised);width:min(24rem,90vw);padding:.75rem;position:absolute;bottom:calc(100% + .5rem);right:0;box-shadow:0 .5rem 1.5rem #0008}._area_lseur_14 p{margin:0 0 .5rem}._warning_lseur_31{color:var(--status-warning)}._panels_lseur_35{border-top:1px solid var(--edge);max-height:12rem;margin:.5rem 0;padding-top:.5rem;overflow-y:auto}._actions_lseur_43{gap:.5rem;display:flex}:root{--surface:#12140f;--surface-raised:#1a1a19;--ink-primary:#fff;--ink-secondary:#c3c2b7;--ink-muted:#898781;--edge:#2f312b;--status-good:#0ca30c;--status-warning:#fab219;--status-serious:#ec835a;--status-critical:#d03b3b;--gap:1rem;--radius:.5rem;--lightningcss-light: ;--lightningcss-dark:initial;color-scheme:dark}*{box-sizing:border-box}.screen-reader-only{clip:rect(0, 0, 0, 0);white-space:nowrap;border:0;width:1px;height:1px;margin:-1px;padding:0;position:absolute;overflow:hidden}html,body{height:100%;margin:0}body{background:var(--surface);color:var(--ink-primary);font-family:ui-sans-serif,system-ui,-apple-system,Segoe UI,Helvetica,Arial,sans-serif;font-size:clamp(16px,1.1vw + .5rem,28px);line-height:1.4;overflow-x:hidden}.board{gap:var(--gap);height:100dvh;min-height:0;padding:var(--gap);flex-direction:column;display:flex;overflow:hidden auto}.board__header{justify-content:space-between;align-items:baseline;gap:var(--gap);border-bottom:1px solid var(--edge);padding-bottom:var(--gap);flex-wrap:wrap;flex:none;display:flex}.board__title{letter-spacing:-.01em;margin:0;font-size:1.75em;font-weight:650}.board__meta{gap:calc(var(--gap) * 1.5);flex-wrap:wrap;margin:0;font-size:.7em;display:flex}.board__meta div{flex-direction:column;display:flex}.board__meta dt{color:var(--ink-muted);text-transform:uppercase;letter-spacing:.08em;font-size:.8em}.board__meta dd{color:var(--ink-secondary);overflow-wrap:anywhere;margin:0;font-family:ui-monospace,SFMono-Regular,Menlo,monospace}.board__grid{gap:var(--gap);flex:1;grid-template-rows:repeat(12,minmax(0,1fr));grid-template-columns:repeat(12,1fr);grid-auto-rows:minmax(0,1fr);align-content:stretch;min-height:0;display:grid}.panel{grid-column:var(--panel-column,span 6);grid-row:var(--panel-row,auto);min-width:0;min-height:0;padding:var(--gap);border:1px solid var(--edge);border-radius:var(--radius);background:var(--surface-raised);flex-direction:column;justify-content:center;gap:.25em;line-height:1.2;display:flex;overflow:visible}.panel--wide{grid-column:span 12}.panel__label{color:var(--ink-secondary);margin:0;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:1em;font-weight:600}.panel__hint{color:var(--ink-muted);margin:0;font-size:.75em}.panel__branch{white-space:nowrap;font-family:ui-monospace,SFMono-Regular,Menlo,monospace}.panel__observed{align-items:center;gap:.35em;display:flex}.panel__observed--stale{color:var(--status-warning)}.panel__status{margin:0;font-size:1.35em;font-weight:650}.panel__status--passed{color:var(--status-good)}.panel__status--failed{color:var(--status-critical)}.panel__status--running{color:var(--status-warning)}.panel__status--cancelled,.panel__status--unknown{color:var(--ink-secondary)}.running-progress{min-width:0;color:var(--status-warning);align-items:center;gap:.6em;display:flex}.running-progress__visual{flex:none;position:relative}.running-progress__timing{color:var(--ink-secondary);margin:0;font-size:.72em}.running-progress__timing--readout{width:12ch;color:var(--ink-secondary);font-variant-numeric:tabular-nums;text-align:end;white-space:nowrap;flex:0 0 12ch;font-family:ui-monospace,SFMono-Regular,Menlo,monospace}.running-progress--radial .running-progress__visual{border:.14em solid var(--edge);background:conic-gradient(var(--status-warning) var(--running-progress), var(--edge) 0);width:2.35em;height:2.35em;box-shadow:inset 0 0 0 .22em var(--surface-raised), 0 0 .55em color-mix(in srgb, var(--status-warning) 45%, transparent);border-radius:50%}.running-progress--radial .running-progress__visual:after{content:"";border-top:.14em solid var(--status-warning);border-radius:50%;animation:1.7s linear infinite running-sweep;position:absolute;inset:-.14em}.running-progress--radial .running-progress__radial-core{background:var(--status-warning);box-shadow:0 0 .45em var(--status-warning);border-radius:50%;position:absolute;inset:.68em}.running-progress--runway .running-progress__visual{border:1px solid var(--edge);background:linear-gradient(90deg, var(--status-warning) var(--running-progress), var(--edge) 0);border-radius:999px;width:min(12em,36vw);height:.8em;overflow:hidden}.running-progress--runway .running-progress__visual:after{content:"";top:-.25em;bottom:-.25em;left:calc(var(--running-progress) - .06em);background:var(--ink-primary);width:.12em;box-shadow:0 0 .45em var(--ink-primary);position:absolute}.running-progress--runway .running-progress__runway-spark{background:var(--ink-primary);width:.35em;height:.35em;box-shadow:0 0 .4em var(--status-warning);border-radius:50%;animation:1.5s linear infinite runway-spark;position:absolute;top:50%;left:-.5em}.running-progress--runway{grid-template-columns:minmax(0,1fr) auto;align-self:stretch;display:grid;container-type:inline-size}@container (width>=26rem){.running-progress--runway .running-progress__visual{width:auto;height:clamp(1.1em,7cqw,2.7em);box-shadow:inset 0 0 1em color-mix(in srgb, var(--status-warning) 16%, transparent);flex:auto}.running-progress--runway .running-progress__visual:after{left:calc(var(--running-progress) - .08em);width:.16em;transition:left 1s linear}.running-progress--runway .running-progress__runway-spark{animation-name:runway-spark-wide}}.running-progress--orbit .running-progress__visual{border:1px solid var(--edge);border-radius:50%;width:2.4em;height:2.4em}.running-progress--orbit .running-progress__visual:before{content:"";border:.12em solid #0000;border-top-color:var(--status-warning);transform:rotate(var(--running-degrees));border-radius:50%;position:absolute;inset:.18em}.running-progress__orbit-core{background:var(--status-warning);box-shadow:0 0 .45em var(--status-warning);border-radius:50%;position:absolute;inset:.75em}.running-progress__orbit-particle{background:var(--ink-primary);transform-origin:.16em .95em;border-radius:50%;width:.32em;height:.32em;animation:1.8s linear infinite orbit-particle;position:absolute;top:.25em;left:calc(50% - .16em)}.running-progress__orbit-particle--two{background:var(--status-warning);animation-delay:-.9s}.running-progress--indeterminate .running-progress__visual{background-image:repeating-linear-gradient(135deg, color-mix(in srgb, var(--status-warning) 70%, transparent) 0 .25em, var(--edge) .25em .5em);animation:1s linear infinite indeterminate-shift}.running-progress--overdue,.running-progress--overdue .running-progress__timing{color:var(--status-serious)}.running-progress--signal-field{flex:auto;grid-template-columns:minmax(0,1fr) auto;align-self:stretch;min-height:2.8em;display:grid;container-type:size}.running-progress--signal-field .running-progress__visual{border:1px solid var(--edge);background:var(--surface);border-radius:999px;width:auto;height:1em;overflow:hidden}.running-progress__signal-rail{background:linear-gradient(90deg, var(--status-warning) var(--running-progress), var(--edge) 0);opacity:.75;position:absolute;inset:0}.running-progress__signal-lead{top:-.2em;bottom:-.2em;left:calc(var(--running-progress) - .08em);background:var(--ink-primary);width:.16em;box-shadow:0 0 .5em var(--status-warning);border-radius:999px;position:absolute}.running-progress__signal-pulse{background:var(--ink-primary);width:.3em;height:.3em;box-shadow:0 0 .4em var(--status-warning);border-radius:50%;animation:2.4s linear infinite signal-pulse;position:absolute;top:50%;left:-.5em}.running-progress__signal-pulse--two{animation-delay:-1.2s}.running-progress__signal-tracks{display:none}@container (width<=18rem){.running-progress--signal-field{flex:0 auto;min-height:0}.running-progress--signal-field .running-progress__visual{width:2.65em;height:1.15em}.running-progress--signal-field .running-progress__signal-rail{background:var(--edge)}.running-progress--signal-field .running-progress__signal-lead{border-radius:50%;width:.38em;top:.2em;bottom:.2em}.running-progress--signal-field .running-progress__signal-pulse{display:none}}@container (height<=5rem){.running-progress--signal-field{flex:0 auto;min-height:0}.running-progress--signal-field .running-progress__visual{width:2.65em;height:1.15em}.running-progress--signal-field .running-progress__signal-rail{background:var(--edge)}.running-progress--signal-field .running-progress__signal-lead{border-radius:50%;width:.38em;top:.2em;bottom:.2em}.running-progress--signal-field .running-progress__signal-pulse{display:none}}@container (width>=26rem) and (height>=10rem){.running-progress--signal-field .running-progress__visual{background:linear-gradient(180deg, color-mix(in srgb, var(--edge) 60%, transparent), transparent);border-radius:.25em;height:100%;min-height:8em}.running-progress--signal-field .running-progress__visual:before{content:"";width:var(--running-progress);background:repeating-linear-gradient(0deg, transparent 0 .55em, color-mix(in srgb, var(--status-warning) 16%, transparent) .55em .6em), linear-gradient(90deg, color-mix(in srgb, var(--status-warning) 19%, transparent), color-mix(in srgb, var(--status-warning) 7%, transparent));box-shadow:inset -.8em 0 1em color-mix(in srgb, var(--status-warning) 22%, transparent);transition:width 1s linear;position:absolute;inset:0 auto 0 0}.running-progress--signal-field .running-progress__signal-rail{background:linear-gradient(90deg, var(--status-warning) var(--running-progress), var(--edge) 0);height:1px;top:50%;bottom:auto}.running-progress--signal-field .running-progress__signal-lead{height:.9em;transition:left 1s linear;top:calc(50% - .45em);bottom:auto}.running-progress--signal-field .running-progress__signal-pulse{display:none}.running-progress--signal-field .running-progress__signal-tracks{flex-direction:column;justify-content:space-between;display:flex;position:absolute;inset:.8em 0}.running-progress--signal-field .running-progress__signal-track{background:linear-gradient(90deg, transparent, color-mix(in srgb, var(--edge) 85%, transparent), transparent);height:1px;position:relative}.running-progress--signal-field .running-progress__signal-marker{top:50%;left:var(--running-progress);background:var(--status-warning);width:.38em;height:.22em;box-shadow:0 0 .4em var(--status-warning);border-radius:.06em;transition:left 1s linear;animation:2.8s linear infinite signal-arrival;position:absolute}.running-progress--signal-field .running-progress__signal-track:nth-child(2) .running-progress__signal-marker{opacity:.7;animation-delay:-.55s}.running-progress--signal-field .running-progress__signal-track:nth-child(3) .running-progress__signal-marker{opacity:.45;animation-duration:3.4s;animation-delay:-1.8s}.running-progress--signal-field .running-progress__signal-track:nth-child(4) .running-progress__signal-marker{opacity:.7;animation-duration:2.3s;animation-delay:-1.1s}.running-progress--signal-field .running-progress__signal-track:nth-child(5) .running-progress__signal-marker{opacity:.55;animation-duration:3.1s;animation-delay:-2.5s}}.pipeline-animation-demo__variant{color:var(--ink-muted);text-transform:capitalize;margin:0;font-size:.72em;transition:color .18s}@keyframes running-sweep{to{transform:rotate(360deg)}}@keyframes runway-spark{to{transform:translate(13em)}}@keyframes runway-spark-wide{to{transform:translate(100cqw)}}@keyframes orbit-particle{to{transform:rotate(360deg)}}@keyframes indeterminate-shift{to{background-position:1em 0}}@keyframes signal-pulse{0%{transform:translate(-.5em,-50%)}to{transform:translate(calc(var(--running-progress) + .5em), -50%)}}@keyframes signal-arrival{0%{transform:translate(-12em,-50%)}to{transform:translate(-50%,-50%)}}@media (prefers-reduced-motion:reduce){.running-progress--radial .running-progress__visual:after,.running-progress--runway .running-progress__runway-spark,.running-progress--runway .running-progress__visual:after,.running-progress--orbit .running-progress__orbit-particle,.running-progress--signal-field .running-progress__signal-pulse,.running-progress--signal-field .running-progress__signal-lead,.running-progress--signal-field .running-progress__signal-marker,.running-progress--signal-field .running-progress__visual:before,.running-progress--indeterminate .running-progress__visual,.pipeline-animation-demo__variant{transition:none;animation:none}}.panel--error{border-color:var(--status-serious)}.panel__link{color:var(--ink-secondary);text-underline-offset:.18em;align-self:flex-start;margin-top:.2em;font-size:.75em;font-weight:600}.panel__link:hover{color:var(--ink-primary)}.panel--primary .panel__status{font-size:1.35em}.panel--primary{gap:.1em;padding:.65em}.panel--primary .panel__hint,.panel--primary .panel__observed,.panel--primary .panel__link{font-size:.65em}.panel--compact{gap:0;min-height:3.5em;padding:.2em;line-height:1.05}.panel--compact .panel__label{font-size:.8em}.panel--compact .panel__status{font-size:1.1em}.panel--compact .panel__hint,.panel--compact .panel__observed,.panel--compact .panel__link{font-size:.65em}.panel--compact .panel__link{margin-top:0}.board__footer{color:var(--ink-muted);flex-wrap:wrap;flex:none;justify-content:space-between;align-items:center;gap:.5rem;font-size:.75em;display:flex}.config-error{max-width:60ch;color:var(--ink-primary);margin:0 auto;padding:2rem}.config-error pre{border-radius:var(--radius);border:1px solid var(--status-critical);background:var(--surface-raised);color:var(--ink-secondary);white-space:pre-wrap;overflow-wrap:anywhere;padding:1rem;font-size:.75em}@media (width<=60rem){.board{height:auto;min-height:100dvh;overflow:visible}.board__grid{flex:none;grid-template-columns:1fr;grid-auto-rows:auto;min-height:auto}.panel{grid-area:auto/1/auto/-1;min-height:6em}}
|
package/client/index.html
CHANGED
|
@@ -11,8 +11,8 @@
|
|
|
11
11
|
<title>Trust Dashboard</title>
|
|
12
12
|
|
|
13
13
|
<script type="importmap">{"imports":{"react":"https://esm.sh/react@19.2.8","react/":"https://esm.sh/react@19.2.8/","react-dom":"https://esm.sh/react-dom@19.2.8","react-dom/":"https://esm.sh/react-dom@19.2.8/","scheduler":"https://esm.sh/scheduler@0.27.0","scheduler/":"https://esm.sh/scheduler@0.27.0/","zod":"https://esm.sh/zod@4.4.3","zod/":"https://esm.sh/zod@4.4.3/"}}</script>
|
|
14
|
-
<script type="module" crossorigin src="/__ASSET_PATH__/assets/index-
|
|
15
|
-
<link rel="stylesheet" crossorigin href="/__ASSET_PATH__/assets/index-
|
|
14
|
+
<script type="module" crossorigin src="/__ASSET_PATH__/assets/index-BpHlElUw.js"></script>
|
|
15
|
+
<link rel="stylesheet" crossorigin href="/__ASSET_PATH__/assets/index-CzDoxNXL.css">
|
|
16
16
|
</head>
|
|
17
17
|
<body>
|
|
18
18
|
<div id="root"></div>
|
package/dist/lambda.mjs
CHANGED
|
@@ -3316,12 +3316,12 @@ var init_schema_date_utils = __esm({
|
|
|
3316
3316
|
[, month, day, hour, minute, second, fraction, year2] = matches;
|
|
3317
3317
|
}
|
|
3318
3318
|
if (year2 && second) {
|
|
3319
|
-
const
|
|
3319
|
+
const timestamp2 = Date.UTC(Number(year2), months.indexOf(month), Number(day), Number(hour), Number(minute), Number(second), fraction ? Math.round(parseFloat(`0.${fraction}`) * 1e3) : 0);
|
|
3320
3320
|
range(day, 1, 31);
|
|
3321
3321
|
range(hour, 0, 23);
|
|
3322
3322
|
range(minute, 0, 59);
|
|
3323
3323
|
range(second, 0, 60);
|
|
3324
|
-
const date6 = new Date(
|
|
3324
|
+
const date6 = new Date(timestamp2);
|
|
3325
3325
|
date6.setUTCFullYear(Number(year2));
|
|
3326
3326
|
return date6;
|
|
3327
3327
|
}
|
|
@@ -10311,14 +10311,14 @@ var init_DefaultRateLimiter = __esm({
|
|
|
10311
10311
|
this.availableTokens = this.availableTokens - amount;
|
|
10312
10312
|
}
|
|
10313
10313
|
refillTokenBucket() {
|
|
10314
|
-
const
|
|
10314
|
+
const timestamp2 = this.getCurrentTimeInSeconds();
|
|
10315
10315
|
if (!this.lastTimestamp) {
|
|
10316
|
-
this.lastTimestamp =
|
|
10316
|
+
this.lastTimestamp = timestamp2;
|
|
10317
10317
|
return;
|
|
10318
10318
|
}
|
|
10319
|
-
const fillAmount = (
|
|
10319
|
+
const fillAmount = (timestamp2 - this.lastTimestamp) * this.fillRate;
|
|
10320
10320
|
this.availableTokens = Math.min(this.maxCapacity, this.availableTokens + fillAmount);
|
|
10321
|
-
this.lastTimestamp =
|
|
10321
|
+
this.lastTimestamp = timestamp2;
|
|
10322
10322
|
}
|
|
10323
10323
|
calculateTimeWindow() {
|
|
10324
10324
|
this.timeWindow = this.getPrecise(Math.pow(this.lastMaxRate * (1 - this.beta) / this.scaleConstant, 1 / 3));
|
|
@@ -10326,8 +10326,8 @@ var init_DefaultRateLimiter = __esm({
|
|
|
10326
10326
|
cubicThrottle(rateToUse) {
|
|
10327
10327
|
return this.getPrecise(rateToUse * this.beta);
|
|
10328
10328
|
}
|
|
10329
|
-
cubicSuccess(
|
|
10330
|
-
return this.getPrecise(this.scaleConstant * Math.pow(
|
|
10329
|
+
cubicSuccess(timestamp2) {
|
|
10330
|
+
return this.getPrecise(this.scaleConstant * Math.pow(timestamp2 - this.lastThrottleTime - this.timeWindow, 3) + this.lastMaxRate);
|
|
10331
10331
|
}
|
|
10332
10332
|
enableTokenBucket() {
|
|
10333
10333
|
this.enabled = true;
|
|
@@ -44846,7 +44846,7 @@ var require_timestamp = __commonJS({
|
|
|
44846
44846
|
resolve: (str) => parseSexagesimal(str, false),
|
|
44847
44847
|
stringify: stringifySexagesimal
|
|
44848
44848
|
};
|
|
44849
|
-
var
|
|
44849
|
+
var timestamp2 = {
|
|
44850
44850
|
identify: (value) => value instanceof Date,
|
|
44851
44851
|
default: true,
|
|
44852
44852
|
tag: "tag:yaml.org,2002:timestamp",
|
|
@@ -44855,7 +44855,7 @@ var require_timestamp = __commonJS({
|
|
|
44855
44855
|
// assumed to be 00:00:00Z (start of day, UTC).
|
|
44856
44856
|
test: RegExp("^([0-9]{4})-([0-9]{1,2})-([0-9]{1,2})(?:(?:t|T|[ \\t]+)([0-9]{1,2}):([0-9]{1,2}):([0-9]{1,2}(\\.[0-9]+)?)(?:[ \\t]*(Z|[-+][012]?[0-9](?::[0-9]{2})?))?)?$"),
|
|
44857
44857
|
resolve(str) {
|
|
44858
|
-
const match2 = str.match(
|
|
44858
|
+
const match2 = str.match(timestamp2.test);
|
|
44859
44859
|
if (!match2)
|
|
44860
44860
|
throw new Error("!!timestamp expects a date, starting with yyyy-mm-dd");
|
|
44861
44861
|
const [, year2, month, day, hour, minute, second] = match2.map(Number);
|
|
@@ -44874,7 +44874,7 @@ var require_timestamp = __commonJS({
|
|
|
44874
44874
|
};
|
|
44875
44875
|
exports.floatTime = floatTime;
|
|
44876
44876
|
exports.intTime = intTime;
|
|
44877
|
-
exports.timestamp =
|
|
44877
|
+
exports.timestamp = timestamp2;
|
|
44878
44878
|
}
|
|
44879
44879
|
});
|
|
44880
44880
|
|
|
@@ -44894,7 +44894,7 @@ var require_schema3 = __commonJS({
|
|
|
44894
44894
|
var omap = require_omap();
|
|
44895
44895
|
var pairs = require_pairs();
|
|
44896
44896
|
var set2 = require_set();
|
|
44897
|
-
var
|
|
44897
|
+
var timestamp2 = require_timestamp();
|
|
44898
44898
|
var schema = [
|
|
44899
44899
|
map4.map,
|
|
44900
44900
|
seq.seq,
|
|
@@ -44914,9 +44914,9 @@ var require_schema3 = __commonJS({
|
|
|
44914
44914
|
omap.omap,
|
|
44915
44915
|
pairs.pairs,
|
|
44916
44916
|
set2.set,
|
|
44917
|
-
|
|
44918
|
-
|
|
44919
|
-
|
|
44917
|
+
timestamp2.intTime,
|
|
44918
|
+
timestamp2.floatTime,
|
|
44919
|
+
timestamp2.timestamp
|
|
44920
44920
|
];
|
|
44921
44921
|
exports.schema = schema;
|
|
44922
44922
|
}
|
|
@@ -44941,7 +44941,7 @@ var require_tags = __commonJS({
|
|
|
44941
44941
|
var pairs = require_pairs();
|
|
44942
44942
|
var schema$2 = require_schema3();
|
|
44943
44943
|
var set2 = require_set();
|
|
44944
|
-
var
|
|
44944
|
+
var timestamp2 = require_timestamp();
|
|
44945
44945
|
var schemas = /* @__PURE__ */ new Map([
|
|
44946
44946
|
["core", schema.schema],
|
|
44947
44947
|
["failsafe", [map4.map, seq.seq, string4.string]],
|
|
@@ -44955,11 +44955,11 @@ var require_tags = __commonJS({
|
|
|
44955
44955
|
float: float.float,
|
|
44956
44956
|
floatExp: float.floatExp,
|
|
44957
44957
|
floatNaN: float.floatNaN,
|
|
44958
|
-
floatTime:
|
|
44958
|
+
floatTime: timestamp2.floatTime,
|
|
44959
44959
|
int: int2.int,
|
|
44960
44960
|
intHex: int2.intHex,
|
|
44961
44961
|
intOct: int2.intOct,
|
|
44962
|
-
intTime:
|
|
44962
|
+
intTime: timestamp2.intTime,
|
|
44963
44963
|
map: map4.map,
|
|
44964
44964
|
merge: merge3.merge,
|
|
44965
44965
|
null: _null4.nullTag,
|
|
@@ -44967,7 +44967,7 @@ var require_tags = __commonJS({
|
|
|
44967
44967
|
pairs: pairs.pairs,
|
|
44968
44968
|
seq: seq.seq,
|
|
44969
44969
|
set: set2.set,
|
|
44970
|
-
timestamp:
|
|
44970
|
+
timestamp: timestamp2.timestamp
|
|
44971
44971
|
};
|
|
44972
44972
|
var coreKnownTags = {
|
|
44973
44973
|
"tag:yaml.org,2002:binary": binary.binary,
|
|
@@ -44975,7 +44975,7 @@ var require_tags = __commonJS({
|
|
|
44975
44975
|
"tag:yaml.org,2002:omap": omap.omap,
|
|
44976
44976
|
"tag:yaml.org,2002:pairs": pairs.pairs,
|
|
44977
44977
|
"tag:yaml.org,2002:set": set2.set,
|
|
44978
|
-
"tag:yaml.org,2002:timestamp":
|
|
44978
|
+
"tag:yaml.org,2002:timestamp": timestamp2.timestamp
|
|
44979
44979
|
};
|
|
44980
44980
|
function getTags(customTags, schemaName, addMergeTag) {
|
|
44981
44981
|
const schemaTags = schemas.get(schemaName);
|
|
@@ -66124,8 +66124,9 @@ var runSchema = external_exports.object({
|
|
|
66124
66124
|
conclusion: external_exports.string().nullable(),
|
|
66125
66125
|
name: external_exports.string().min(1),
|
|
66126
66126
|
html_url: external_exports.url(),
|
|
66127
|
-
|
|
66128
|
-
|
|
66127
|
+
// Timestamp quality should only remove timing advice, never make an otherwise useful run unreadable.
|
|
66128
|
+
run_started_at: external_exports.string().nullable().optional(),
|
|
66129
|
+
updated_at: external_exports.string().optional()
|
|
66129
66130
|
});
|
|
66130
66131
|
var runsSchema = external_exports.object({ workflow_runs: external_exports.array(runSchema) });
|
|
66131
66132
|
var pullRequestsSchema = external_exports.array(
|
|
@@ -66143,7 +66144,7 @@ function permittedGithubActionsCalls(panel, source, credentials = environmentCre
|
|
|
66143
66144
|
`https://api.github.com/repos/${parsedSource.repo}/actions/workflows/${encodeURIComponent(parsedPanel.pipeline)}/runs`
|
|
66144
66145
|
);
|
|
66145
66146
|
if (parsedSource.branch) url2.searchParams.set("branch", parsedSource.branch);
|
|
66146
|
-
url2.searchParams.set("per_page", "
|
|
66147
|
+
url2.searchParams.set("per_page", "5");
|
|
66147
66148
|
const headers = new Headers({ accept: "application/vnd.github+json" });
|
|
66148
66149
|
const token = parsedSource.token_env ? credentials.get(parsedSource.token_env) : void 0;
|
|
66149
66150
|
if (token) headers.set("authorization", `Bearer ${token}`);
|
|
@@ -66352,7 +66353,8 @@ async function fetchGithubActionsPipeline(args) {
|
|
|
66352
66353
|
};
|
|
66353
66354
|
}
|
|
66354
66355
|
try {
|
|
66355
|
-
const
|
|
66356
|
+
const runs = runsSchema.parse(await upstream.json()).workflow_runs;
|
|
66357
|
+
const run = runs[0];
|
|
66356
66358
|
if (!run) {
|
|
66357
66359
|
return {
|
|
66358
66360
|
response: new Response(
|
|
@@ -66375,8 +66377,10 @@ async function fetchGithubActionsPipeline(args) {
|
|
|
66375
66377
|
rawStatus: run.conclusion ?? run.status,
|
|
66376
66378
|
name: run.name,
|
|
66377
66379
|
branch: parsedSource.branch,
|
|
66378
|
-
...run.updated_at ? { sourceUpdatedAt: run.updated_at } : {},
|
|
66379
|
-
...run.
|
|
66380
|
+
...timestamp(run.updated_at) ? { sourceUpdatedAt: timestamp(run.updated_at) } : {},
|
|
66381
|
+
...timestamp(run.run_started_at) ? { runStartedAt: timestamp(run.run_started_at) } : {},
|
|
66382
|
+
...run.status === "completed" ? completedRunDuration(run) : {},
|
|
66383
|
+
...run.status !== "completed" ? estimatedRunDuration(runs) : {}
|
|
66380
66384
|
};
|
|
66381
66385
|
const envelope = {
|
|
66382
66386
|
panelId: args.panel.id,
|
|
@@ -66404,10 +66408,29 @@ async function fetchGithubActionsPipeline(args) {
|
|
|
66404
66408
|
}
|
|
66405
66409
|
}
|
|
66406
66410
|
function completedRunDuration(run) {
|
|
66407
|
-
|
|
66408
|
-
const
|
|
66411
|
+
const startedAt = timestamp(run.run_started_at);
|
|
66412
|
+
const updatedAt = timestamp(run.updated_at);
|
|
66413
|
+
if (!startedAt || !updatedAt) return {};
|
|
66414
|
+
const durationMs = new Date(updatedAt).valueOf() - new Date(startedAt).valueOf();
|
|
66409
66415
|
return Number.isFinite(durationMs) && durationMs >= 0 ? { durationMs } : {};
|
|
66410
66416
|
}
|
|
66417
|
+
function timestamp(value) {
|
|
66418
|
+
if (!value || !external_exports.iso.datetime().safeParse(value).success) return void 0;
|
|
66419
|
+
return Number.isFinite(new Date(value).valueOf()) ? value : void 0;
|
|
66420
|
+
}
|
|
66421
|
+
function estimatedRunDuration(runs) {
|
|
66422
|
+
const durations = runs.filter((run) => run.status === "completed").map((run) => completedRunDuration(run).durationMs).filter((duration3) => duration3 !== void 0).sort((left, right) => left - right);
|
|
66423
|
+
if (durations.length === 0) return {};
|
|
66424
|
+
const middle = Math.floor(durations.length / 2);
|
|
66425
|
+
const estimatedDurationMs = durations[middle];
|
|
66426
|
+
if (estimatedDurationMs === void 0) return {};
|
|
66427
|
+
if (durations.length % 2 === 0) {
|
|
66428
|
+
const lowerDuration = durations[middle - 1];
|
|
66429
|
+
if (lowerDuration === void 0) return {};
|
|
66430
|
+
return { estimatedDurationMs: Math.floor((lowerDuration + estimatedDurationMs) / 2) };
|
|
66431
|
+
}
|
|
66432
|
+
return { estimatedDurationMs };
|
|
66433
|
+
}
|
|
66411
66434
|
function normalizeStatus(status, conclusion) {
|
|
66412
66435
|
if (status !== "completed") return "running";
|
|
66413
66436
|
if (conclusion === "success") return "passed";
|
|
@@ -66772,6 +66795,7 @@ var positionSchema = external_exports.object({
|
|
|
66772
66795
|
h: external_exports.number().int().min(1)
|
|
66773
66796
|
});
|
|
66774
66797
|
var panelDisplaySchema = external_exports.string().min(1);
|
|
66798
|
+
var runningAnimationSchema = external_exports.enum(["radial", "runway", "orbit", "signal-field", "off"]);
|
|
66775
66799
|
var panelSchema = external_exports.looseObject({
|
|
66776
66800
|
id: external_exports.string().min(1),
|
|
66777
66801
|
type: external_exports.string().min(1),
|
|
@@ -66781,6 +66805,8 @@ var panelSchema = external_exports.looseObject({
|
|
|
66781
66805
|
/** Advisory in v1 — a panel without a position renders in config order rather than not at all. */
|
|
66782
66806
|
position: positionSchema.optional(),
|
|
66783
66807
|
refresh: durationSchema.optional(),
|
|
66808
|
+
/** Optional progress treatment for an active pipeline run. Omitted currently means orbit. */
|
|
66809
|
+
running_animation: runningAnimationSchema.optional(),
|
|
66784
66810
|
/** A deliberate override only. Adapters derive links; hand-written ones drift. */
|
|
66785
66811
|
link: external_exports.url().optional(),
|
|
66786
66812
|
/** Source-agnostic endpoint used by the http-value signal. */
|
|
@@ -66889,6 +66915,10 @@ var pipelineStatusSchema = external_exports.object({
|
|
|
66889
66915
|
branch: external_exports.string().min(1).optional(),
|
|
66890
66916
|
/** Elapsed execution time, supplied only after the upstream run has completed. */
|
|
66891
66917
|
durationMs: external_exports.number().int().nonnegative().optional(),
|
|
66918
|
+
/** When an active run began, so the client can advance its elapsed display between polls. */
|
|
66919
|
+
runStartedAt: external_exports.iso.datetime().optional(),
|
|
66920
|
+
/** Advisory median duration from recent completed runs from the same source response. */
|
|
66921
|
+
estimatedDurationMs: external_exports.number().int().positive().optional(),
|
|
66892
66922
|
/** When this workflow run was last updated by its source, distinct from our observation time. */
|
|
66893
66923
|
sourceUpdatedAt: external_exports.iso.datetime().optional()
|
|
66894
66924
|
});
|
package/package.json
CHANGED
|
@@ -1,3 +0,0 @@
|
|
|
1
|
-
import{z as e}from"zod";import{StrictMode as t,useEffect as n,useRef as r,useState as i,useSyncExternalStore as a}from"react";import{createRoot as o}from"react-dom/client";import{jsx as s,jsxs as c}from"react/jsx-runtime";(function(){let e=document.createElement(`link`).relList;if(e&&e.supports&&e.supports(`modulepreload`))return;for(let e of document.querySelectorAll(`link[rel="modulepreload"]`))n(e);new MutationObserver(e=>{for(let t of e)if(t.type===`childList`)for(let e of t.addedNodes)e.tagName===`LINK`&&e.rel===`modulepreload`&&n(e)}).observe(document,{childList:!0,subtree:!0});function t(e){let t={};return e.integrity&&(t.integrity=e.integrity),e.referrerPolicy&&(t.referrerPolicy=e.referrerPolicy),t.credentials=e.crossOrigin===`use-credentials`?`include`:e.crossOrigin===`anonymous`?`omit`:`same-origin`,t}function n(e){if(e.ep)return;e.ep=!0;let n=t(e);fetch(e.href,n)}})();var l=/^(\d+)(ms|s|m|h)$/,u={ms:1,s:1e3,m:6e4,h:36e5};function d(e){let t=l.exec(e);if(!t)return null;let[,n,r]=t;if(n===void 0||r===void 0)return null;let i=Number(n);return i<=0?null:i*u[r]}var f=e.string().refine(e=>d(e)!==null,{message:`must be a positive duration like "30s", "5m", or "1h"`}).brand(),ee=e.object({x:e.number().int().min(0),y:e.number().int().min(0),w:e.number().int().min(1).max(12),h:e.number().int().min(1)}),te=e.string().min(1),p=e.looseObject({id:e.string().min(1),type:e.string().min(1),source:e.string().min(1).optional(),display:te.optional(),position:ee.optional(),refresh:f.optional(),link:e.url().optional(),url:e.url().optional(),json_path:e.string().regex(/^\$(?:\.[A-Za-z_][A-Za-z0-9_]*|\[\d+\])*$/,`must be a simple JSON path`).optional()}),m=e.looseObject({type:e.string().min(1),token_env:e.string().min(1).optional()}),h=e.object({refresh:f.optional(),panels:e.array(p).min(1).superRefine((e,t)=>{let n=new Map;e.forEach((e,r)=>{let i=n.get(e.id);if(i===void 0){n.set(e.id,r);return}t.addIssue({code:`custom`,path:[r,`id`],message:`duplicate panel id "${e.id}" (already used by panel at index ${i})`})})})}),ne=e.object({issuer:e.url(),client_id:e.string().min(1).optional(),allow:e.object({groups:e.array(e.string().min(1)).optional(),subjects:e.array(e.string().min(1)).optional()}).optional()});e.object({sources:e.record(e.string().min(1),m).default({}),boards:e.record(e.string().min(1),h),auth:ne.optional()});function g(e){let t=e.panelOverrideMillis??e.boardDefaultMillis;return Math.max(t,e.adapterFloorMillis)}var _=e.object({assetPath:e.string().min(1),proxyPath:e.string().min(1),board:e.string().min(1),clientVersion:e.string().min(1),auth:e.object({issuer:e.string().min(1),clientId:e.string().min(1).optional()}).optional()}),re=_.pick({assetPath:!0,clientVersion:!0});function ie(t=globalThis.window?.env){let n=_.safeParse(t);if(!n.success)throw Error(`window.env is missing or invalid \u2014 the server did not inject usable configuration.
|
|
2
|
-
${e.prettifyError(n.error)}`);return n.data}var v=e.enum([`unreachable`,`unauthorized`,`not-found`,`no-runs`,`upstream-error`]),y=e.object({kind:v,message:e.string()}),b=e.discriminatedUnion(`state`,[e.object({panelId:e.string().min(1),state:e.literal(`ok`),observedAt:e.iso.datetime(),link:e.url().nullable(),signal:e.unknown()}),e.object({panelId:e.string().min(1),state:e.literal(`error`),observedAt:e.iso.datetime(),link:e.url().nullable(),error:y})]),x=e.object({type:e.literal(`pipeline-status`),status:e.enum([`passed`,`failed`,`running`,`cancelled`,`unknown`]),rawStatus:e.string(),name:e.string().min(1),branch:e.string().min(1).optional(),durationMs:e.number().int().nonnegative().optional(),sourceUpdatedAt:e.iso.datetime().optional()}),S=e.object({label:e.string().min(1),status:x.shape.status,detail:e.string().min(1),link:e.url().nullable()}),C=e.object({type:e.literal(`pull-request-health`),status:x.shape.status,summary:e.string().min(1),workflows:e.array(S),pullRequests:e.array(S)}),ae=e.object({type:e.literal(`http-value`),value:e.union([e.string(),e.number(),e.boolean()])}),w={diagnostics:`_diagnostics_1pu1f_1`,button:`_button_1pu1f_5`,area:`_area_1pu1f_14`,actions:`_actions_1pu1f_31`};function oe({log:e}){let[t,n]=i(!1),r=a(e.subscribe,e.count,e.count);return c(`section`,{className:w.diagnostics,children:[c(`button`,{className:w.button,type:`button`,"aria-expanded":t,onClick:()=>n(!t),children:[`Diagnostics (`,r,`)`]}),t&&c(`div`,{className:w.area,children:[c(`p`,{children:[r,` retained browser-local events. They are never uploaded.`]}),c(`div`,{className:w.actions,children:[s(`button`,{className:w.button,type:`button`,onClick:()=>{let t=new Blob([JSON.stringify(e.export(),null,2)],{type:`application/json`}),n=URL.createObjectURL(t),r=document.createElement(`a`);r.href=n,r.download=`dashboard-diagnostics-${new Date().toISOString().replaceAll(`:`,`-`)}.json`,r.click(),URL.revokeObjectURL(n)},children:`Download`}),s(`button`,{className:w.button,type:`button`,onClick:()=>{window.confirm(`Clear this browser’s retained dashboard diagnostics?`)&&e.clear()},children:`Clear`})]})]})]})}var T=`ze-great-dashboard.diagnostics.v1`,E=6048e5,D=[`session-start`,`client-update-check`,`client-update-failure`,`client-update-detected`,`board-fetch-start`,`board-fetch-response`,`board-fetch-parse-failure`,`board-fetch-failure`,`panel-fetch-start`,`panel-fetch-response`,`panel-fetch-parse-failure`,`panel-fetch-failure`,`panel-rendered`],O=class{env;storage;now;events=[];listeners=new Set;sessionId=crypto.randomUUID?.()??`${Date.now()}-${Math.random()}`;constructor(e,t=M(),n=()=>new Date){this.env=e,this.storage=t,this.now=n,this.events=this.read(),this.record({kind:`session-start`})}record(e){this.events=A([...this.events,{...e,schemaVersion:1,at:this.now().toISOString(),sessionId:this.sessionId,board:this.env.board}],this.now()),this.persist(),this.notify()}count=()=>this.events.length;clear(){this.events=[];try{this.storage?.removeItem(T)}catch{}this.notify()}subscribe=e=>(this.listeners.add(e),()=>{this.listeners.delete(e)});export=()=>({schemaVersion:1,exportedAt:this.now().toISOString(),client:{version:this.env.clientVersion,assetPath:this.env.assetPath,board:this.env.board,sessionId:this.sessionId},events:this.events});read(){try{let e=this.storage?.getItem(T);if(!e)return[];let t=JSON.parse(e);return t.schemaVersion!==1||!Array.isArray(t.events)||!t.events.every(j)?(this.storage?.removeItem(T),[]):A(t.events.map(e=>({...e,schemaVersion:1})),this.now())}catch{try{this.storage?.removeItem(T)}catch{}return[]}}persist(){try{this.storage?.setItem(T,JSON.stringify({schemaVersion:1,events:this.events}))}catch{}}notify(){for(let e of this.listeners)e()}};function k(e){let t=Object.fromEntries([[`cacheControl`,`cache-control`],[`etag`,`etag`],[`lastModified`,`last-modified`],[`date`,`date`],[`age`,`age`]].flatMap(([t,n])=>{let r=e.get(n);return r?[[t,r]]:[]}));return Object.keys(t).length?t:void 0}function A(e,t){let n=t.valueOf()-E;return e.filter(e=>Number.isFinite(new Date(e.at).valueOf())&&new Date(e.at).valueOf()>=n).slice(-2e3)}function j(e){if(!e||typeof e!=`object`)return!1;let t=e;return(t.schemaVersion===void 0||t.schemaVersion===1)&&typeof t.at==`string`&&Number.isFinite(new Date(t.at).valueOf())&&typeof t.sessionId==`string`&&typeof t.board==`string`&&D.includes(t.kind)}function M(){try{return window.localStorage}catch{return}}function N({value:e,label:t=`As of`}){let n=new Date(e),r=n.toLocaleTimeString([],{hour:`2-digit`,minute:`2-digit`}),i=Date.now()-n.getTime(),a=i>3e5,o=P(i);return c(`p`,{className:`panel__hint panel__observed${a?` panel__observed--stale`:``}`,children:[s(`span`,{"aria-hidden":`true`,children:`◷`}),` `,t,` `,r,` · `,o]})}function P(e){if(e<6e4)return`just now`;let t=Math.floor(e/6e4);return t<60?`${t}m ago`:`${Math.floor(t/60)}h ${t%60}m ago`}function F(e){let t=e.position;if(t)return{"--panel-column":`${t.x+1} / span ${t.w}`,"--panel-row":`${t.y+1} / span ${t.h}`}}function I({panel:e,envelope:t,error:n=!1,children:r}){let i=e.display===`primary`||e.display===`compact`?e.display:`supporting`;return c(`section`,{className:`panel panel--${i}${n?` panel--error`:``}`,style:F(e),"aria-busy":!t||void 0,children:[s(`h2`,{className:`panel__label`,children:e.id}),r,s(L,{panelId:e.id,link:t?.link})]})}function L({panelId:e,link:t}){return t?c(`a`,{className:`panel__link`,href:t,target:`_blank`,rel:`noopener noreferrer`,"aria-label":`View source for ${e} (opens in a new tab)`,children:[`View source `,s(`span`,{"aria-hidden":`true`,children:`↗`})]}):null}function R({panel:e,envelope:t}){if(!t)return s(I,{panel:e,children:s(`p`,{className:`panel__hint`,children:`Loading…`})});if(t.state===`error`)return c(I,{panel:e,envelope:t,error:!0,children:[s(`p`,{className:`panel__status`,children:`⚠ Unable to read`}),s(`p`,{className:`panel__hint`,children:t.error.message}),s(N,{value:t.observedAt})]});let n=ae.safeParse(t.signal);return n.success?c(I,{panel:e,envelope:t,children:[s(`p`,{className:`panel__status`,children:String(n.data.value)}),s(N,{value:t.observedAt})]}):c(I,{panel:e,envelope:t,error:!0,children:[s(`p`,{className:`panel__status`,children:`⚠ Invalid value`}),s(N,{value:t.observedAt})]})}function z({label:e,hint:t,wide:n=!1}){return c(`section`,{className:n?`panel panel--wide`:`panel`,children:[s(`h2`,{className:`panel__label`,children:e}),s(`p`,{className:`panel__hint`,children:t})]})}function B({panel:e,envelope:t}){if(!t)return s(I,{panel:e,children:s(`p`,{className:`panel__hint`,children:`Loading…`})});if(t.state===`error`)return c(I,{panel:e,envelope:t,error:!0,children:[c(`p`,{className:`panel__status`,children:[`⚠ `,t.error.kind===`no-runs`?`No workflow runs`:`Unable to read`]}),s(`p`,{className:`panel__hint`,children:t.error.message}),s(N,{value:t.observedAt})]});let n=x.safeParse(t.signal);if(!n.success)return c(I,{panel:e,envelope:t,error:!0,children:[s(`p`,{className:`panel__status`,children:`⚠ Invalid signal`}),s(N,{value:t.observedAt})]});let r=V(n.data.status);return c(I,{panel:e,envelope:t,children:[c(`p`,{className:`panel__status panel__status--${n.data.status}`,children:[r.glyph,` `,r.label]}),c(`p`,{className:`panel__hint`,children:[n.data.name,` · `,n.data.rawStatus,n.data.branch&&c(`span`,{className:`panel__branch`,title:`Branch: ${n.data.branch}`,children:[s(`span`,{"aria-hidden":`true`,children:` · ⎇ `}),s(`span`,{className:`screen-reader-only`,children:`Branch: `}),n.data.branch]})]}),n.data.status!==`running`&&n.data.durationMs!==void 0&&c(`p`,{className:`panel__hint`,children:[`Took `,se(n.data.durationMs)]}),n.data.sourceUpdatedAt&&s(N,{value:n.data.sourceUpdatedAt,label:`Run updated`}),s(N,{value:t.observedAt})]})}function se(e){let t=Math.floor(e/1e3),n=Math.floor(t/3600),r=Math.floor(t%3600/60),i=t%60;return n>0?`${n}h ${r}m`:r>0?`${r}m ${i}s`:`${i}s`}function V(e){switch(e){case`passed`:return{glyph:`✓`,label:`Passed`};case`failed`:return{glyph:`✕`,label:`Failed`};case`running`:return{glyph:`↻`,label:`Running`};case`cancelled`:return{glyph:`⊘`,label:`Cancelled`};case`unknown`:return{glyph:`?`,label:`Unknown`}}}function H({panel:e,envelope:t}){if(!t)return s(I,{panel:e,children:s(`p`,{className:`panel__hint`,children:`Loading…`})});if(t.state===`error`)return c(I,{panel:e,envelope:t,error:!0,children:[s(`p`,{className:`panel__status`,children:`⚠ Unable to read`}),s(`p`,{className:`panel__hint`,children:t.error.message}),s(N,{value:t.observedAt})]});let n=C.safeParse(t.signal);if(!n.success)return s(I,{panel:e,envelope:t,error:!0,children:s(`p`,{className:`panel__status`,children:`⚠ Invalid signal`})});let r=U(n.data.status);return c(I,{panel:e,envelope:t,children:[c(`p`,{className:`panel__status panel__status--${n.data.status}`,children:[r.glyph,` `,r.label]}),s(`p`,{className:`panel__hint`,children:n.data.summary}),s(N,{value:t.observedAt})]})}function U(e){switch(e){case`passed`:return{glyph:`✓`,label:`Healthy`};case`failed`:return{glyph:`✕`,label:`Failed`};case`running`:return{glyph:`↻`,label:`Running`};case`cancelled`:return{glyph:`⊘`,label:`Cancelled`};case`unknown`:return{glyph:`?`,label:`Unknown`}}}var W=6e4,G=1e4,K=()=>globalThis.window.location.reload();function ce({env:e,diagnostics:t,fetcher:r,reload:i=K}){n(()=>{let n=!1,a=!1,o,s=`${e.proxyPath}/client`,c=async()=>{if(n||a)return;a=!0;let l=new AbortController;o=l;let u=globalThis.setTimeout(()=>l.abort(),G);t.record({kind:`client-update-check`,path:s});try{let a=await(r??globalThis.fetch)(s,{cache:`no-store`,signal:l.signal});if(!a.ok)throw Error(`Client identity returned ${a.status}`);let o=re.safeParse(await a.json());if(!o.success)throw Error(`Client identity response was invalid`);if(n)return;o.data.assetPath!==e.assetPath&&(t.record({kind:`client-update-detected`,path:s,current:{assetPath:e.assetPath,clientVersion:e.clientVersion},next:o.data}),i())}catch(e){!n&&!(e instanceof DOMException&&e.name===`AbortError`)&&t.record({kind:`client-update-failure`,path:s,message:e instanceof Error?e.message:String(e)})}finally{globalThis.clearTimeout(u),a=!1,o===l&&(o=void 0),n||globalThis.setTimeout(()=>void c(),W)}};return c(),()=>{n=!0,o?.abort()}},[t,e.assetPath,e.clientVersion,e.proxyPath,r,i])}function q(e,t){if(t.state===`error`)return{state:t.state,link:t.link};if(e.type===`pipeline-status`){let e=x.safeParse(t.signal);return{state:t.state,status:e.success?e.data.status:void 0,link:t.link}}if(e.type===`pull-request-health`){let e=C.safeParse(t.signal);return{state:t.state,status:e.success?e.data.status:void 0,link:t.link}}return{state:t.state,link:t.link}}function le(e,t,n){if(!e)return!0;let r=q(t,e),i=q(t,n);return r.state!==i.state||r.status!==i.status||r.link!==i.link}function ue({board:e,env:t,diagnostics:a}){let[o,s]=i({}),c=r({});return n(()=>{if(c.current={},s({}),!e)return;let n=!1,r=[];for(let i of e.panels){if(i.type!==`pipeline-status`&&i.type!==`pull-request-health`&&i.type!==`http-value`)continue;let o=!1,l=g({boardDefaultMillis:d(e.refresh??`60s`)??6e4,panelOverrideMillis:i.refresh?d(i.refresh)??void 0:void 0,adapterFloorMillis:0}),u=`${t.proxyPath}/panel/${encodeURIComponent(t.board)}/${encodeURIComponent(i.id)}`,f=()=>{n||o||(o=!0,a.record({kind:`panel-fetch-start`,panelId:i.id,path:u}),fetch(u).then(async e=>{if(a.record({kind:`panel-fetch-response`,panelId:i.id,path:u,status:e.status,cache:k(e.headers)}),e.status!==304)try{return await e.json()}catch(e){throw a.record({kind:`panel-fetch-parse-failure`,panelId:i.id,path:u,message:J(e)}),new Y(e)}}).then(e=>{let t=de(e);if(e!==void 0&&!t&&a.record({kind:`panel-fetch-parse-failure`,panelId:i.id,path:u,message:`Response was not a valid signal envelope.`}),!n&&t){a.record({kind:`panel-fetch-response`,panelId:i.id,path:u,envelope:t});let e=c.current[i.id];le(e,i,t)&&a.record({kind:`panel-rendered`,panelId:i.id,path:u,rendered:q(i,t)}),c.current={...c.current,[i.id]:t},s(c.current)}}).catch(e=>{e instanceof Y||a.record({kind:`panel-fetch-failure`,panelId:i.id,path:u,message:J(e)})}).finally(()=>{o=!1}))};f(),r.push(window.setInterval(f,l))}return()=>{n=!0;for(let e of r)window.clearInterval(e)}},[e,a,t.board,t.proxyPath]),o}function J(e){return e instanceof Error?e.message:String(e)}var Y=class extends Error{constructor(e){super(J(e))}};function de(e){let t=b.safeParse(e);return t.success?t.data:void 0}function fe({env:e}){let[t,a]=i(),[o,l]=i(),u=r(null);u.current||=new O(e);let d=u.current;ce({env:e,diagnostics:d});let f=ue({board:o===e.board?t:void 0,env:e,diagnostics:d});return n(()=>{let t=!1;a(void 0),l(void 0);let n=`${e.proxyPath}/boards/${encodeURIComponent(e.board)}`;return d.record({kind:`board-fetch-start`,path:n}),fetch(n).then(async e=>{if(d.record({kind:`board-fetch-response`,path:n,status:e.status,cache:k(e.headers)}),!e.ok)throw Error(`Board configuration returned ${e.status}`);try{return await e.json()}catch(e){throw d.record({kind:`board-fetch-parse-failure`,path:n,message:X(e)}),new Z(e)}}).then(r=>{if(!t){a(r),l(e.board);let t=Array.isArray(r.panels)?r.panels:[];d.record({kind:`board-fetch-response`,path:n,boardSummary:{panelCount:t.length,panelIds:t.flatMap(e=>typeof e.id==`string`?[e.id]:[])}})}}).catch(r=>{r instanceof Z||d.record({kind:`board-fetch-failure`,path:n,message:X(r)}),t||(a({panels:[]}),l(e.board))}),()=>{t=!0}},[d,e.board,e.proxyPath]),c(`div`,{className:`board`,children:[c(`header`,{className:`board__header`,children:[s(`h1`,{className:`board__title`,children:e.board}),c(`dl`,{className:`board__meta`,children:[c(`div`,{children:[s(`dt`,{children:`client`}),s(`dd`,{children:e.clientVersion})]}),c(`div`,{children:[s(`dt`,{children:`assets`}),s(`dd`,{children:e.assetPath})]})]})]}),c(`main`,{className:`board__grid`,children:[!t&&s(z,{label:`board`,hint:`Loading configuration…`,wide:!0}),t?.panels.map(e=>e.type===`pipeline-status`?s(B,{panel:e,envelope:f[e.id]},e.id):e.type===`pull-request-health`?s(H,{panel:e,envelope:f[e.id]},e.id):e.type===`http-value`?s(R,{panel:e,envelope:f[e.id]},e.id):s(z,{label:e.type,hint:`Not wired yet`,wide:!0},e.id))]}),c(`footer`,{className:`board__footer`,children:[s(`span`,{children:`Signals are read live from their configured authorities.`}),s(oe,{log:d})]})]})}function X(e){return e instanceof Error?e.message:String(e)}var Z=class extends Error{constructor(e){super(X(e))}};function pe({message:e}){return c(`div`,{className:`config-error`,role:`alert`,children:[s(`h1`,{children:`⚠️ Dashboard misconfigured`}),s(`p`,{children:`The page loaded, but the server did not hand it usable configuration.`}),s(`pre`,{children:e})]})}var Q=document.getElementById(`root`);if(!Q)throw Error(`No #root element in the document — the template is not the one we expect.`);var $=o(Q);try{$.render(s(t,{children:s(fe,{env:ie()})}))}catch(e){$.render(s(pe,{message:e instanceof Error?e.message:String(e)}))}
|
|
3
|
-
//# sourceMappingURL=index-BWGv4Ybw.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index-BWGv4Ybw.js","names":[],"sources":["../../../shared/dist/index.js","../../src/Diagnostics.module.css","../../src/Diagnostics.tsx","../../src/diagnostics.ts","../../src/ObservedAt.tsx","../../src/panel-layout.ts","../../src/PanelFrame.tsx","../../src/HttpValuePanel.tsx","../../src/PanelPlaceholder.tsx","../../src/PipelinePanel.tsx","../../src/PullRequestHealthPanel.tsx","../../src/useClientUpdate.ts","../../src/panel-diagnostics.ts","../../src/usePanelSignals.ts","../../src/App.tsx","../../src/ConfigError.tsx","../../src/main.tsx"],"sourcesContent":["// packages/shared/src/board-config.ts\nimport { z as z2 } from \"zod\";\n\n// packages/shared/src/duration.ts\nimport { z } from \"zod\";\nvar DURATION_PATTERN = /^(\\d+)(ms|s|m|h)$/;\nvar UNIT_MILLIS = {\n ms: 1,\n s: 1e3,\n m: 6e4,\n h: 36e5\n};\nfunction parseDuration(value) {\n const match = DURATION_PATTERN.exec(value);\n if (!match) return null;\n const [, rawAmount, rawUnit] = match;\n if (rawAmount === void 0 || rawUnit === void 0) return null;\n const amount = Number(rawAmount);\n if (amount <= 0) return null;\n return amount * UNIT_MILLIS[rawUnit];\n}\nvar durationSchema = z.string().refine((value) => parseDuration(value) !== null, {\n message: 'must be a positive duration like \"30s\", \"5m\", or \"1h\"'\n}).brand();\n\n// packages/shared/src/board-config.ts\nvar positionSchema = z2.object({\n x: z2.number().int().min(0),\n y: z2.number().int().min(0),\n w: z2.number().int().min(1).max(12),\n h: z2.number().int().min(1)\n});\nvar panelDisplayRoles = [\"primary\", \"supporting\", \"compact\"];\nvar panelDisplaySchema = z2.string().min(1);\nvar panelSchema = z2.looseObject({\n id: z2.string().min(1),\n type: z2.string().min(1),\n source: z2.string().min(1).optional(),\n /** Semantic visual weight; position still controls the panel's explicit grid placement. */\n display: panelDisplaySchema.optional(),\n /** Advisory in v1 — a panel without a position renders in config order rather than not at all. */\n position: positionSchema.optional(),\n refresh: durationSchema.optional(),\n /** A deliberate override only. Adapters derive links; hand-written ones drift. */\n link: z2.url().optional(),\n /** Source-agnostic endpoint used by the http-value signal. */\n url: z2.url().optional(),\n /** Small, deliberate JSON path subset: $.version, $.deployment.version, or $.response.docs[0].latestVersion. */\n json_path: z2.string().regex(/^\\$(?:\\.[A-Za-z_][A-Za-z0-9_]*|\\[\\d+\\])*$/, \"must be a simple JSON path\").optional()\n});\nvar sourceSchema = z2.looseObject({\n type: z2.string().min(1),\n /** Credentials are never in the config — only the name of the env var holding one. */\n token_env: z2.string().min(1).optional()\n});\nvar boardSchema = z2.object({\n refresh: durationSchema.optional(),\n panels: z2.array(panelSchema).min(1).superRefine((panels, ctx) => {\n const seen = /* @__PURE__ */ new Map();\n panels.forEach((panel, index) => {\n const firstIndex = seen.get(panel.id);\n if (firstIndex === void 0) {\n seen.set(panel.id, index);\n return;\n }\n ctx.addIssue({\n code: \"custom\",\n path: [index, \"id\"],\n message: `duplicate panel id \"${panel.id}\" (already used by panel at index ${firstIndex})`\n });\n });\n })\n});\nvar authSchema = z2.object({\n issuer: z2.url(),\n /** Absent in gateway mode — the gateway does the flow, the proxy still validates. */\n client_id: z2.string().min(1).optional(),\n allow: z2.object({\n groups: z2.array(z2.string().min(1)).optional(),\n subjects: z2.array(z2.string().min(1)).optional()\n }).optional()\n});\nvar boardConfigSchema = z2.object({\n sources: z2.record(z2.string().min(1), sourceSchema).default({}),\n boards: z2.record(z2.string().min(1), boardSchema),\n auth: authSchema.optional()\n});\nfunction resolveRefreshMillis(args) {\n const requested = args.panelOverrideMillis ?? args.boardDefaultMillis;\n return Math.max(requested, args.adapterFloorMillis);\n}\n\n// packages/shared/src/client-env.ts\nimport { z as z3 } from \"zod\";\nvar clientEnvSchema = z3.object({\n /** Where the immutable client assets live. The one variable that repoints the whole client. */\n assetPath: z3.string().min(1),\n /** Same-origin path the proxy is mounted at, so there is no CORS and no cookie problem. */\n proxyPath: z3.string().min(1),\n /** Which board this is, resolved server-side so the client parses no URLs. */\n board: z3.string().min(1),\n /** The client version being served, so two published versions are visibly distinguishable. */\n clientVersion: z3.string().min(1),\n /** Omitted entirely when unauthenticated — presence is what turns auth on. */\n auth: z3.object({\n issuer: z3.string().min(1),\n clientId: z3.string().min(1).optional()\n }).optional()\n});\nvar clientIdentitySchema = clientEnvSchema.pick({ assetPath: true, clientVersion: true });\nfunction readClientEnv(source = globalThis.window?.env) {\n const result = clientEnvSchema.safeParse(source);\n if (!result.success) {\n throw new Error(\n `window.env is missing or invalid \\u2014 the server did not inject usable configuration.\n${z3.prettifyError(result.error)}`\n );\n }\n return result.data;\n}\n\n// packages/shared/src/envelope.ts\nimport { z as z4 } from \"zod\";\nvar errorKindSchema = z4.enum([\n \"unreachable\",\n \"unauthorized\",\n \"not-found\",\n \"no-runs\",\n \"upstream-error\"\n]);\nvar envelopeErrorSchema = z4.object({\n kind: errorKindSchema,\n message: z4.string()\n});\nvar envelopeSchema = z4.discriminatedUnion(\"state\", [\n z4.object({\n panelId: z4.string().min(1),\n state: z4.literal(\"ok\"),\n /** From the upstream response `Date`. A cached value must never be shown without its age. */\n observedAt: z4.iso.datetime(),\n /** Adapter-derived. The authority for this panel; the dashboard itself asserts nothing. */\n link: z4.url().nullable(),\n signal: z4.unknown()\n }),\n z4.object({\n panelId: z4.string().min(1),\n state: z4.literal(\"error\"),\n /**\n * Populated even on error: knowing *when* a failure was observed is the difference between\n * \"broken just now\" and \"broken all morning\", and a panel that can't reach its source is\n * exactly when a viewer most wants to click through.\n */\n observedAt: z4.iso.datetime(),\n link: z4.url().nullable(),\n error: envelopeErrorSchema\n })\n]);\nvar pipelineStatusSchema = z4.object({\n type: z4.literal(\"pipeline-status\"),\n status: z4.enum([\"passed\", \"failed\", \"running\", \"cancelled\", \"unknown\"]),\n /** The source's unmodified status/result vocabulary, for an honest display. */\n rawStatus: z4.string(),\n name: z4.string().min(1),\n /** The branch represented by this status, when the upstream supplies or filters by one. */\n branch: z4.string().min(1).optional(),\n /** Elapsed execution time, supplied only after the upstream run has completed. */\n durationMs: z4.number().int().nonnegative().optional(),\n /** When this workflow run was last updated by its source, distinct from our observation time. */\n sourceUpdatedAt: z4.iso.datetime().optional()\n});\nvar pullRequestHealthItemSchema = z4.object({\n label: z4.string().min(1),\n status: pipelineStatusSchema.shape.status,\n detail: z4.string().min(1),\n link: z4.url().nullable()\n});\nvar pullRequestHealthSchema = z4.object({\n type: z4.literal(\"pull-request-health\"),\n status: pipelineStatusSchema.shape.status,\n summary: z4.string().min(1),\n workflows: z4.array(pullRequestHealthItemSchema),\n pullRequests: z4.array(pullRequestHealthItemSchema)\n});\nvar httpValueSchema = z4.object({\n type: z4.literal(\"http-value\"),\n value: z4.union([z4.string(), z4.number(), z4.boolean()])\n});\nexport {\n authSchema,\n boardConfigSchema,\n boardSchema,\n clientEnvSchema,\n clientIdentitySchema,\n durationSchema,\n envelopeSchema,\n errorKindSchema,\n httpValueSchema,\n panelDisplayRoles,\n panelDisplaySchema,\n panelSchema,\n parseDuration,\n pipelineStatusSchema,\n positionSchema,\n pullRequestHealthSchema,\n readClientEnv,\n resolveRefreshMillis,\n sourceSchema\n};\n",".diagnostics {\n position: relative;\n}\n\n.button {\n border: 1px solid var(--edge);\n border-radius: 0.25rem;\n background: var(--surface-raised);\n color: var(--ink-secondary);\n font: inherit;\n padding: 0.3em 0.55em;\n}\n\n.area {\n position: absolute;\n z-index: 1;\n right: 0;\n bottom: calc(100% + 0.5rem);\n width: min(24rem, 90vw);\n padding: 0.75rem;\n border: 1px solid var(--edge);\n border-radius: var(--radius);\n background: var(--surface-raised);\n box-shadow: 0 0.5rem 1.5rem #0008;\n}\n\n.area p {\n margin: 0 0 0.5rem;\n}\n\n.actions {\n display: flex;\n gap: 0.5rem;\n}\n","import { useState, useSyncExternalStore } from 'react'\nimport styles from './Diagnostics.module.css'\nimport type { BrowserDiagnosticStore } from './diagnostics.ts'\n\nexport function Diagnostics({ log }: { log: BrowserDiagnosticStore }) {\n const [open, setOpen] = useState(false)\n const count = useSyncExternalStore(log.subscribe, log.count, log.count)\n const download = () => {\n const blob = new Blob([JSON.stringify(log.export(), null, 2)], { type: 'application/json' })\n const url = URL.createObjectURL(blob)\n const link = document.createElement('a')\n link.href = url\n link.download = `dashboard-diagnostics-${new Date().toISOString().replaceAll(':', '-')}.json`\n link.click()\n URL.revokeObjectURL(url)\n }\n const clear = () => {\n if (!window.confirm('Clear this browser’s retained dashboard diagnostics?')) return\n log.clear()\n }\n\n return (\n <section className={styles.diagnostics}>\n <button\n className={styles.button}\n type=\"button\"\n aria-expanded={open}\n onClick={() => setOpen(!open)}\n >\n Diagnostics ({count})\n </button>\n {open && (\n <div className={styles.area}>\n <p>{count} retained browser-local events. They are never uploaded.</p>\n <div className={styles.actions}>\n <button className={styles.button} type=\"button\" onClick={download}>\n Download\n </button>\n <button className={styles.button} type=\"button\" onClick={clear}>\n Clear\n </button>\n </div>\n </div>\n )}\n </section>\n )\n}\n","import type { ClientEnv, Envelope } from '@ze-great-dashboard/shared'\n\nconst storageKey = 'ze-great-dashboard.diagnostics.v1'\nexport const diagnosticsSchemaVersion = 1\nconst maximumEvents = 2_000\nconst maximumAgeMillis = 7 * 24 * 60 * 60 * 1_000\nconst diagnosticKinds = [\n 'session-start',\n 'client-update-check',\n 'client-update-failure',\n 'client-update-detected',\n 'board-fetch-start',\n 'board-fetch-response',\n 'board-fetch-parse-failure',\n 'board-fetch-failure',\n 'panel-fetch-start',\n 'panel-fetch-response',\n 'panel-fetch-parse-failure',\n 'panel-fetch-failure',\n 'panel-rendered',\n] as const\n\nexport type CacheMetadata = Partial<\n Record<'cacheControl' | 'etag' | 'lastModified' | 'date' | 'age', string>\n>\n\ntype EventMetadata = {\n schemaVersion: typeof diagnosticsSchemaVersion\n at: string\n sessionId: string\n board: string\n}\n\nexport type RenderedPanelDiagnostic = {\n state: Envelope['state']\n status?: string\n link: string | null\n}\n\nexport type DiagnosticEventInput =\n | { kind: 'session-start' }\n | { kind: 'client-update-check'; path: string }\n | { kind: 'client-update-failure'; path: string; message: string }\n | {\n kind: 'client-update-detected'\n path: string\n current: { assetPath: string; clientVersion: string }\n next: { assetPath: string; clientVersion: string }\n }\n | { kind: 'board-fetch-start'; path: string }\n | {\n kind: 'board-fetch-response'\n path: string\n status?: number\n cache?: CacheMetadata\n boardSummary?: { panelCount: number; panelIds: string[] }\n }\n | { kind: 'board-fetch-parse-failure'; path: string; message: string }\n | { kind: 'board-fetch-failure'; path: string; message: string }\n | { kind: 'panel-fetch-start'; panelId: string; path: string }\n | {\n kind: 'panel-fetch-response'\n panelId: string\n path: string\n status?: number\n cache?: CacheMetadata\n envelope?: Envelope\n }\n | { kind: 'panel-fetch-parse-failure'; panelId: string; path: string; message: string }\n | { kind: 'panel-fetch-failure'; panelId: string; path: string; message: string }\n | {\n kind: 'panel-rendered'\n panelId: string\n path: string\n rendered: RenderedPanelDiagnostic\n }\n\nexport type DiagnosticEvent = DiagnosticEventInput extends infer Event\n ? Event extends DiagnosticEventInput\n ? Event & EventMetadata\n : never\n : never\n\n/** The only interface client features need in order to emit browser diagnostics. */\nexport interface DiagnosticSink {\n record(event: DiagnosticEventInput): void\n}\n\ntype PersistedDiagnosticEvent = Omit<DiagnosticEvent, 'schemaVersion'> & { schemaVersion?: number }\ntype StoredDiagnostics = { schemaVersion: number; events: PersistedDiagnosticEvent[] }\n\ntype StorageLike = Pick<Storage, 'getItem' | 'setItem' | 'removeItem'>\n\n/** Browser-local diagnostic evidence. It deliberately has no server or shared-contract counterpart. */\nexport class BrowserDiagnosticStore implements DiagnosticSink {\n private events: DiagnosticEvent[] = []\n private readonly listeners = new Set<() => void>()\n private readonly sessionId = crypto.randomUUID?.() ?? `${Date.now()}-${Math.random()}`\n\n constructor(\n private readonly env: ClientEnv,\n private readonly storage: StorageLike | undefined = storageOrUndefined(),\n private readonly now: () => Date = () => new Date(),\n ) {\n this.events = this.read()\n this.record({ kind: 'session-start' })\n }\n\n record(event: DiagnosticEventInput) {\n this.events = prune(\n [\n ...this.events,\n {\n ...event,\n schemaVersion: diagnosticsSchemaVersion,\n at: this.now().toISOString(),\n sessionId: this.sessionId,\n board: this.env.board,\n },\n ],\n this.now(),\n )\n this.persist()\n this.notify()\n }\n\n count = () => {\n return this.events.length\n }\n\n clear() {\n this.events = []\n try {\n this.storage?.removeItem(storageKey)\n } catch {\n // Diagnostics must not interrupt the radiator when browser storage is unavailable.\n }\n this.notify()\n }\n\n subscribe = (listener: () => void) => {\n this.listeners.add(listener)\n return () => {\n this.listeners.delete(listener)\n }\n }\n\n export = () => {\n return {\n schemaVersion: diagnosticsSchemaVersion,\n exportedAt: this.now().toISOString(),\n client: {\n version: this.env.clientVersion,\n assetPath: this.env.assetPath,\n board: this.env.board,\n sessionId: this.sessionId,\n },\n events: this.events,\n }\n }\n\n private read(): DiagnosticEvent[] {\n try {\n const raw = this.storage?.getItem(storageKey)\n if (!raw) return []\n const parsed = JSON.parse(raw) as Partial<StoredDiagnostics>\n if (parsed.schemaVersion !== diagnosticsSchemaVersion || !Array.isArray(parsed.events)) {\n this.storage?.removeItem(storageKey)\n return []\n }\n if (!parsed.events.every(isDiagnosticEvent)) {\n this.storage?.removeItem(storageKey)\n return []\n }\n // v1 retained events predate per-event versions. Their containing store was already v1, so\n // retain them and normalize on the next write rather than discarding viewer evidence.\n return prune(\n parsed.events.map(\n (event) => ({ ...event, schemaVersion: diagnosticsSchemaVersion }) as DiagnosticEvent,\n ),\n this.now(),\n )\n } catch {\n try {\n this.storage?.removeItem(storageKey)\n } catch {\n // Storage can fail on both reads and writes (for example, private browsing policies).\n }\n return []\n }\n }\n\n private persist() {\n try {\n this.storage?.setItem(\n storageKey,\n JSON.stringify({ schemaVersion: diagnosticsSchemaVersion, events: this.events }),\n )\n } catch {\n // Keep the in-memory record for this page, but never make diagnostics a rendering failure.\n }\n }\n\n private notify() {\n for (const listener of this.listeners) listener()\n }\n}\n\nexport function cacheMetadata(headers: Headers): CacheMetadata | undefined {\n const entries = [\n ['cacheControl', 'cache-control'],\n ['etag', 'etag'],\n ['lastModified', 'last-modified'],\n ['date', 'date'],\n ['age', 'age'],\n ] as const\n const metadata = Object.fromEntries(\n entries.flatMap(([key, header]) => {\n const value = headers.get(header)\n return value ? [[key, value]] : []\n }),\n ) as CacheMetadata\n return Object.keys(metadata).length ? metadata : undefined\n}\n\nfunction prune(events: DiagnosticEvent[], now: Date) {\n const cutoff = now.valueOf() - maximumAgeMillis\n return events\n .filter(\n (event) =>\n Number.isFinite(new Date(event.at).valueOf()) && new Date(event.at).valueOf() >= cutoff,\n )\n .slice(-maximumEvents)\n}\n\nfunction isDiagnosticEvent(value: unknown): value is PersistedDiagnosticEvent {\n if (!value || typeof value !== 'object') return false\n const event = value as Partial<DiagnosticEvent>\n return (\n (event.schemaVersion === undefined || event.schemaVersion === diagnosticsSchemaVersion) &&\n typeof event.at === 'string' &&\n Number.isFinite(new Date(event.at).valueOf()) &&\n typeof event.sessionId === 'string' &&\n typeof event.board === 'string' &&\n diagnosticKinds.includes(event.kind as (typeof diagnosticKinds)[number])\n )\n}\n\nfunction storageOrUndefined(): StorageLike | undefined {\n try {\n return window.localStorage\n } catch {\n return undefined\n }\n}\n","export function ObservedAt({ value, label = 'As of' }: { value: string; label?: string }) {\n const observed = new Date(value)\n const formatted = observed.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' })\n const age = Date.now() - observed.getTime()\n const stale = age > 5 * 60 * 1000\n const ageText = formatAge(age)\n return (\n <p className={`panel__hint panel__observed${stale ? ' panel__observed--stale' : ''}`}>\n <span aria-hidden=\"true\">◷</span> {label} {formatted} · {ageText}\n </p>\n )\n}\n\nexport function formatAge(milliseconds: number) {\n if (milliseconds < 60_000) return 'just now'\n const minutes = Math.floor(milliseconds / 60_000)\n if (minutes < 60) return `${minutes}m ago`\n const hours = Math.floor(minutes / 60)\n return `${hours}h ${minutes % 60}m ago`\n}\n","import type { Panel } from '@ze-great-dashboard/shared'\nimport type { CSSProperties } from 'react'\n\n/** Convert the advisory board position into CSS grid placement. */\nexport function panelLayout(panel: Panel): CSSProperties | undefined {\n const position = panel.position\n if (!position) return undefined\n\n return {\n '--panel-column': `${position.x + 1} / span ${position.w}`,\n '--panel-row': `${position.y + 1} / span ${position.h}`,\n } as CSSProperties\n}\n","import type { Envelope, Panel } from '@ze-great-dashboard/shared'\nimport type { ReactNode } from 'react'\nimport { panelLayout } from './panel-layout.ts'\n\nexport function PanelFrame({\n panel,\n envelope,\n error = false,\n children,\n}: {\n panel: Panel\n envelope?: Envelope\n error?: boolean\n children: ReactNode\n}) {\n const display =\n panel.display === 'primary' || panel.display === 'compact' ? panel.display : 'supporting'\n return (\n <section\n className={`panel panel--${display}${error ? ' panel--error' : ''}`}\n style={panelLayout(panel)}\n aria-busy={envelope ? undefined : true}\n >\n <h2 className=\"panel__label\">{panel.id}</h2>\n {children}\n <PanelSourceLink panelId={panel.id} link={envelope?.link} />\n </section>\n )\n}\n\nfunction PanelSourceLink({ panelId, link }: { panelId: string; link?: string | null }) {\n if (!link) return null\n\n return (\n <a\n className=\"panel__link\"\n href={link}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n aria-label={`View source for ${panelId} (opens in a new tab)`}\n >\n View source <span aria-hidden=\"true\">↗</span>\n </a>\n )\n}\n","import type { Panel } from '@ze-great-dashboard/shared'\nimport { type Envelope, httpValueSchema } from '@ze-great-dashboard/shared'\nimport { ObservedAt } from './ObservedAt.tsx'\nimport { PanelFrame } from './PanelFrame.tsx'\n\nexport function HttpValuePanel({\n panel,\n envelope,\n}: {\n panel: Panel\n envelope: Envelope | undefined\n}) {\n if (!envelope)\n return (\n <PanelFrame panel={panel}>\n <p className=\"panel__hint\">Loading…</p>\n </PanelFrame>\n )\n if (envelope.state === 'error')\n return (\n <PanelFrame panel={panel} envelope={envelope} error>\n <p className=\"panel__status\">⚠ Unable to read</p>\n <p className=\"panel__hint\">{envelope.error.message}</p>\n <ObservedAt value={envelope.observedAt} />\n </PanelFrame>\n )\n const signal = httpValueSchema.safeParse(envelope.signal)\n if (!signal.success)\n return (\n <PanelFrame panel={panel} envelope={envelope} error>\n <p className=\"panel__status\">⚠ Invalid value</p>\n <ObservedAt value={envelope.observedAt} />\n </PanelFrame>\n )\n return (\n <PanelFrame panel={panel} envelope={envelope}>\n <p className=\"panel__status\">{String(signal.data.value)}</p>\n <ObservedAt value={envelope.observedAt} />\n </PanelFrame>\n )\n}\n","/**\n * A panel-shaped hole, so the grid can be looked at and argued with before any signal exists.\n * Replaced by real panels in Stage 2 — nothing here is meant to survive.\n */\nexport function PanelPlaceholder({\n label,\n hint,\n wide = false,\n}: {\n label: string\n hint: string\n wide?: boolean\n}) {\n return (\n <section className={wide ? 'panel panel--wide' : 'panel'}>\n <h2 className=\"panel__label\">{label}</h2>\n <p className=\"panel__hint\">{hint}</p>\n </section>\n )\n}\n","import { type Envelope, type Panel, pipelineStatusSchema } from '@ze-great-dashboard/shared'\nimport { ObservedAt } from './ObservedAt.tsx'\nimport { PanelFrame } from './PanelFrame.tsx'\n\nexport function PipelinePanel({\n panel,\n envelope,\n}: {\n panel: Panel\n envelope: Envelope | undefined\n}) {\n if (!envelope)\n return (\n <PanelFrame panel={panel}>\n <p className=\"panel__hint\">Loading…</p>\n </PanelFrame>\n )\n if (envelope.state === 'error') {\n return (\n <PanelFrame panel={panel} envelope={envelope} error>\n <p className=\"panel__status\">\n ⚠ {envelope.error.kind === 'no-runs' ? 'No workflow runs' : 'Unable to read'}\n </p>\n <p className=\"panel__hint\">{envelope.error.message}</p>\n <ObservedAt value={envelope.observedAt} />\n </PanelFrame>\n )\n }\n\n const signal = pipelineStatusSchema.safeParse(envelope.signal)\n if (!signal.success)\n return (\n <PanelFrame panel={panel} envelope={envelope} error>\n <p className=\"panel__status\">⚠ Invalid signal</p>\n <ObservedAt value={envelope.observedAt} />\n </PanelFrame>\n )\n const presentation = statusPresentation(signal.data.status)\n return (\n <PanelFrame panel={panel} envelope={envelope}>\n <p className={`panel__status panel__status--${signal.data.status}`}>\n {presentation.glyph} {presentation.label}\n </p>\n <p className=\"panel__hint\">\n {signal.data.name} · {signal.data.rawStatus}\n {signal.data.branch && (\n <span className=\"panel__branch\" title={`Branch: ${signal.data.branch}`}>\n <span aria-hidden=\"true\"> · ⎇ </span>\n <span className=\"screen-reader-only\">Branch: </span>\n {signal.data.branch}\n </span>\n )}\n </p>\n {signal.data.status !== 'running' && signal.data.durationMs !== undefined && (\n <p className=\"panel__hint\">Took {formatDuration(signal.data.durationMs)}</p>\n )}\n {signal.data.sourceUpdatedAt && (\n <ObservedAt value={signal.data.sourceUpdatedAt} label=\"Run updated\" />\n )}\n <ObservedAt value={envelope.observedAt} />\n </PanelFrame>\n )\n}\n\nfunction formatDuration(durationMs: number) {\n const totalSeconds = Math.floor(durationMs / 1_000)\n const hours = Math.floor(totalSeconds / 3_600)\n const minutes = Math.floor((totalSeconds % 3_600) / 60)\n const seconds = totalSeconds % 60\n\n if (hours > 0) return `${hours}h ${minutes}m`\n if (minutes > 0) return `${minutes}m ${seconds}s`\n return `${seconds}s`\n}\n\nfunction statusPresentation(status: 'passed' | 'failed' | 'running' | 'cancelled' | 'unknown') {\n switch (status) {\n case 'passed':\n return { glyph: '✓', label: 'Passed' }\n case 'failed':\n return { glyph: '✕', label: 'Failed' }\n case 'running':\n return { glyph: '↻', label: 'Running' }\n case 'cancelled':\n return { glyph: '⊘', label: 'Cancelled' }\n case 'unknown':\n return { glyph: '?', label: 'Unknown' }\n }\n}\n","import { type Envelope, type Panel, pullRequestHealthSchema } from '@ze-great-dashboard/shared'\nimport { ObservedAt } from './ObservedAt.tsx'\nimport { PanelFrame } from './PanelFrame.tsx'\n\nexport function PullRequestHealthPanel({\n panel,\n envelope,\n}: {\n panel: Panel\n envelope: Envelope | undefined\n}) {\n if (!envelope)\n return (\n <PanelFrame panel={panel}>\n <p className=\"panel__hint\">Loading…</p>\n </PanelFrame>\n )\n if (envelope.state === 'error')\n return (\n <PanelFrame panel={panel} envelope={envelope} error>\n <p className=\"panel__status\">⚠ Unable to read</p>\n <p className=\"panel__hint\">{envelope.error.message}</p>\n <ObservedAt value={envelope.observedAt} />\n </PanelFrame>\n )\n const signal = pullRequestHealthSchema.safeParse(envelope.signal)\n if (!signal.success)\n return (\n <PanelFrame panel={panel} envelope={envelope} error>\n <p className=\"panel__status\">⚠ Invalid signal</p>\n </PanelFrame>\n )\n const presentation = statusPresentation(signal.data.status)\n return (\n <PanelFrame panel={panel} envelope={envelope}>\n <p className={`panel__status panel__status--${signal.data.status}`}>\n {presentation.glyph} {presentation.label}\n </p>\n <p className=\"panel__hint\">{signal.data.summary}</p>\n <ObservedAt value={envelope.observedAt} />\n </PanelFrame>\n )\n}\n\nfunction statusPresentation(status: 'passed' | 'failed' | 'running' | 'cancelled' | 'unknown') {\n switch (status) {\n case 'passed':\n return { glyph: '✓', label: 'Healthy' }\n case 'failed':\n return { glyph: '✕', label: 'Failed' }\n case 'running':\n return { glyph: '↻', label: 'Running' }\n case 'cancelled':\n return { glyph: '⊘', label: 'Cancelled' }\n case 'unknown':\n return { glyph: '?', label: 'Unknown' }\n }\n}\n","import { type ClientEnv, clientIdentitySchema } from '@ze-great-dashboard/shared'\nimport { useEffect } from 'react'\nimport type { DiagnosticSink } from './diagnostics.ts'\n\nconst clientUpdateIntervalMillis = 60_000\nconst clientUpdateTimeoutMillis = 10_000\nconst defaultReload = () => globalThis.window.location.reload()\n\nexport function useClientUpdate({\n env,\n diagnostics,\n fetcher,\n reload = defaultReload,\n}: {\n env: ClientEnv\n diagnostics: DiagnosticSink\n fetcher?: typeof fetch\n reload?: () => void\n}) {\n useEffect(() => {\n let cancelled = false\n let inFlight = false\n let activeController: AbortController | undefined\n const path = `${env.proxyPath}/client`\n\n const check = async () => {\n if (cancelled || inFlight) return\n inFlight = true\n const controller = new AbortController()\n activeController = controller\n const timeout = globalThis.setTimeout(() => controller.abort(), clientUpdateTimeoutMillis)\n diagnostics.record({ kind: 'client-update-check', path })\n try {\n const response = await (fetcher ?? globalThis.fetch)(path, {\n cache: 'no-store',\n signal: controller.signal,\n })\n if (!response.ok) throw new Error(`Client identity returned ${response.status}`)\n const parsed = clientIdentitySchema.safeParse(await response.json())\n if (!parsed.success) throw new Error('Client identity response was invalid')\n if (cancelled) return\n // assetPath is the server's immutable deployment selector. clientVersion is a label and\n // can change independently without changing the code the browser should load.\n if (parsed.data.assetPath !== env.assetPath) {\n diagnostics.record({\n kind: 'client-update-detected',\n path,\n current: { assetPath: env.assetPath, clientVersion: env.clientVersion },\n next: parsed.data,\n })\n reload()\n }\n } catch (error) {\n if (!cancelled && !(error instanceof DOMException && error.name === 'AbortError')) {\n diagnostics.record({\n kind: 'client-update-failure',\n path,\n message: error instanceof Error ? error.message : String(error),\n })\n }\n } finally {\n globalThis.clearTimeout(timeout)\n inFlight = false\n if (activeController === controller) activeController = undefined\n if (!cancelled) globalThis.setTimeout(() => void check(), clientUpdateIntervalMillis)\n }\n }\n\n void check()\n return () => {\n cancelled = true\n activeController?.abort()\n }\n }, [diagnostics, env.assetPath, env.clientVersion, env.proxyPath, fetcher, reload])\n}\n","import {\n type Envelope,\n type Panel,\n pipelineStatusSchema,\n pullRequestHealthSchema,\n} from '@ze-great-dashboard/shared'\nimport type { RenderedPanelDiagnostic } from './diagnostics.ts'\n\n/**\n * The compact public fact a viewer saw. Keep new panel projections here beside their\n * presentation boundary; this is intentionally not a source or server event contract.\n */\nexport function projectPanelDiagnostic(panel: Panel, envelope: Envelope): RenderedPanelDiagnostic {\n if (envelope.state === 'error') return { state: envelope.state, link: envelope.link }\n\n if (panel.type === 'pipeline-status') {\n const signal = pipelineStatusSchema.safeParse(envelope.signal)\n return {\n state: envelope.state,\n status: signal.success ? signal.data.status : undefined,\n link: envelope.link,\n }\n }\n\n if (panel.type === 'pull-request-health') {\n const signal = pullRequestHealthSchema.safeParse(envelope.signal)\n return {\n state: envelope.state,\n status: signal.success ? signal.data.status : undefined,\n link: envelope.link,\n }\n }\n\n return { state: envelope.state, link: envelope.link }\n}\n\nexport function panelDiagnosticChanged(\n previous: Envelope | undefined,\n panel: Panel,\n next: Envelope,\n) {\n if (!previous) return true\n const before = projectPanelDiagnostic(panel, previous)\n const after = projectPanelDiagnostic(panel, next)\n return (\n before.state !== after.state || before.status !== after.status || before.link !== after.link\n )\n}\n","import {\n type Board,\n type ClientEnv,\n type Envelope,\n envelopeSchema,\n parseDuration,\n resolveRefreshMillis,\n} from '@ze-great-dashboard/shared'\nimport { useEffect, useRef, useState } from 'react'\nimport { cacheMetadata, type DiagnosticSink } from './diagnostics.ts'\nimport { panelDiagnosticChanged, projectPanelDiagnostic } from './panel-diagnostics.ts'\n\nexport function usePanelSignals({\n board,\n env,\n diagnostics,\n}: {\n board: Board | undefined\n env: ClientEnv\n diagnostics: DiagnosticSink\n}) {\n const [signals, setSignals] = useState<Record<string, Envelope | undefined>>({})\n const signalsRef = useRef<Record<string, Envelope | undefined>>({})\n\n useEffect(() => {\n signalsRef.current = {}\n setSignals({})\n if (!board) return\n\n let cancelled = false\n const timers: number[] = []\n for (const panel of board.panels) {\n if (\n panel.type !== 'pipeline-status' &&\n panel.type !== 'pull-request-health' &&\n panel.type !== 'http-value'\n )\n continue\n let inFlight = false\n const refreshMillis = resolveRefreshMillis({\n boardDefaultMillis: parseDuration(board.refresh ?? '60s') ?? 60_000,\n panelOverrideMillis: panel.refresh\n ? (parseDuration(panel.refresh) ?? undefined)\n : undefined,\n adapterFloorMillis: 0,\n })\n const path = `${env.proxyPath}/panel/${encodeURIComponent(env.board)}/${encodeURIComponent(panel.id)}`\n const refresh = () => {\n if (cancelled || inFlight) return\n inFlight = true\n diagnostics.record({ kind: 'panel-fetch-start', panelId: panel.id, path })\n fetch(path)\n .then(async (response) => {\n diagnostics.record({\n kind: 'panel-fetch-response',\n panelId: panel.id,\n path,\n status: response.status,\n cache: cacheMetadata(response.headers),\n })\n if (response.status === 304) return undefined\n try {\n return await response.json()\n } catch (error) {\n diagnostics.record({\n kind: 'panel-fetch-parse-failure',\n panelId: panel.id,\n path,\n message: errorMessage(error),\n })\n throw new DiagnosticParseFailure(error)\n }\n })\n .then((value: unknown) => {\n const envelope = parseEnvelope(value)\n if (value !== undefined && !envelope) {\n diagnostics.record({\n kind: 'panel-fetch-parse-failure',\n panelId: panel.id,\n path,\n message: 'Response was not a valid signal envelope.',\n })\n }\n if (!cancelled && envelope) {\n diagnostics.record({\n kind: 'panel-fetch-response',\n panelId: panel.id,\n path,\n envelope,\n })\n const previous = signalsRef.current[panel.id]\n if (panelDiagnosticChanged(previous, panel, envelope)) {\n diagnostics.record({\n kind: 'panel-rendered',\n panelId: panel.id,\n path,\n rendered: projectPanelDiagnostic(panel, envelope),\n })\n }\n signalsRef.current = { ...signalsRef.current, [panel.id]: envelope }\n setSignals(signalsRef.current)\n }\n })\n .catch((error) => {\n if (!(error instanceof DiagnosticParseFailure)) {\n diagnostics.record({\n kind: 'panel-fetch-failure',\n panelId: panel.id,\n path,\n message: errorMessage(error),\n })\n }\n })\n .finally(() => {\n inFlight = false\n })\n }\n refresh()\n timers.push(window.setInterval(refresh, refreshMillis))\n }\n return () => {\n cancelled = true\n for (const timer of timers) window.clearInterval(timer)\n }\n }, [board, diagnostics, env.board, env.proxyPath])\n\n return signals\n}\n\nfunction errorMessage(error: unknown) {\n return error instanceof Error ? error.message : String(error)\n}\n\nclass DiagnosticParseFailure extends Error {\n constructor(error: unknown) {\n super(errorMessage(error))\n }\n}\n\nfunction parseEnvelope(value: unknown): Envelope | undefined {\n const result = envelopeSchema.safeParse(value)\n return result.success ? result.data : undefined\n}\n","import type { Board, ClientEnv } from '@ze-great-dashboard/shared'\nimport { useEffect, useRef, useState } from 'react'\nimport { Diagnostics } from './Diagnostics.tsx'\nimport { BrowserDiagnosticStore, cacheMetadata } from './diagnostics.ts'\nimport { HttpValuePanel } from './HttpValuePanel.tsx'\nimport { PanelPlaceholder } from './PanelPlaceholder.tsx'\nimport { PipelinePanel } from './PipelinePanel.tsx'\nimport { PullRequestHealthPanel } from './PullRequestHealthPanel.tsx'\nimport { useClientUpdate } from './useClientUpdate.ts'\nimport { usePanelSignals } from './usePanelSignals.ts'\n\n/**\n * The board shell.\n *\n * Stage 1 has no data: there is no proxy endpoint to poll yet. What this proves is the plumbing —\n * that the client was handed its configuration by the server and knows which version of itself it\n * is. The version readout is what makes two published versions visibly different, which is the\n * whole point of the Stage 1 exit criterion.\n */\nexport function App({ env }: { env: ClientEnv }) {\n const [board, setBoard] = useState<Board>()\n const [loadedBoardName, setLoadedBoardName] = useState<string>()\n const diagnosticsRef = useRef<BrowserDiagnosticStore | null>(null)\n if (!diagnosticsRef.current) diagnosticsRef.current = new BrowserDiagnosticStore(env)\n const diagnostics = diagnosticsRef.current\n useClientUpdate({ env, diagnostics })\n const signals = usePanelSignals({\n board: loadedBoardName === env.board ? board : undefined,\n env,\n diagnostics,\n })\n\n useEffect(() => {\n let cancelled = false\n setBoard(undefined)\n setLoadedBoardName(undefined)\n const path = `${env.proxyPath}/boards/${encodeURIComponent(env.board)}`\n diagnostics.record({ kind: 'board-fetch-start', path })\n fetch(path)\n .then(async (response) => {\n diagnostics.record({\n kind: 'board-fetch-response',\n path,\n status: response.status,\n cache: cacheMetadata(response.headers),\n })\n if (!response.ok) throw new Error(`Board configuration returned ${response.status}`)\n try {\n return await response.json()\n } catch (error) {\n diagnostics.record({\n kind: 'board-fetch-parse-failure',\n path,\n message: errorMessage(error),\n })\n throw new DiagnosticParseFailure(error)\n }\n })\n .then((value: unknown) => {\n if (!cancelled) {\n setBoard(value as Board)\n setLoadedBoardName(env.board)\n const panels = Array.isArray((value as { panels?: unknown }).panels)\n ? (value as { panels: Array<{ id?: unknown }> }).panels\n : []\n diagnostics.record({\n kind: 'board-fetch-response',\n path,\n boardSummary: {\n panelCount: panels.length,\n panelIds: panels.flatMap((panel) => (typeof panel.id === 'string' ? [panel.id] : [])),\n },\n })\n }\n })\n .catch((error) => {\n if (!(error instanceof DiagnosticParseFailure)) {\n diagnostics.record({ kind: 'board-fetch-failure', path, message: errorMessage(error) })\n }\n if (!cancelled) {\n setBoard({ panels: [] })\n setLoadedBoardName(env.board)\n }\n })\n return () => {\n cancelled = true\n }\n }, [diagnostics, env.board, env.proxyPath])\n\n return (\n <div className=\"board\">\n <header className=\"board__header\">\n <h1 className=\"board__title\">{env.board}</h1>\n <dl className=\"board__meta\">\n <div>\n <dt>client</dt>\n <dd>{env.clientVersion}</dd>\n </div>\n <div>\n <dt>assets</dt>\n <dd>{env.assetPath}</dd>\n </div>\n </dl>\n </header>\n\n <main className=\"board__grid\">\n {!board && <PanelPlaceholder label=\"board\" hint=\"Loading configuration…\" wide />}\n {board?.panels.map((panel) =>\n panel.type === 'pipeline-status' ? (\n <PipelinePanel key={panel.id} panel={panel} envelope={signals[panel.id]} />\n ) : panel.type === 'pull-request-health' ? (\n <PullRequestHealthPanel key={panel.id} panel={panel} envelope={signals[panel.id]} />\n ) : panel.type === 'http-value' ? (\n <HttpValuePanel key={panel.id} panel={panel} envelope={signals[panel.id]} />\n ) : (\n <PanelPlaceholder key={panel.id} label={panel.type} hint=\"Not wired yet\" wide />\n ),\n )}\n </main>\n\n <footer className=\"board__footer\">\n <span>Signals are read live from their configured authorities.</span>\n <Diagnostics log={diagnostics} />\n </footer>\n </div>\n )\n}\n\nfunction errorMessage(error: unknown) {\n return error instanceof Error ? error.message : String(error)\n}\n\nclass DiagnosticParseFailure extends Error {\n constructor(error: unknown) {\n super(errorMessage(error))\n }\n}\n","export function ConfigError({ message }: { message: string }) {\n return (\n <div className=\"config-error\" role=\"alert\">\n <h1>⚠️ Dashboard misconfigured</h1>\n <p>The page loaded, but the server did not hand it usable configuration.</p>\n <pre>{message}</pre>\n </div>\n )\n}\n","import { readClientEnv } from '@ze-great-dashboard/shared'\nimport { StrictMode } from 'react'\nimport { createRoot } from 'react-dom/client'\nimport { App } from './App.tsx'\nimport { ConfigError } from './ConfigError.tsx'\nimport './styles.css'\n\nconst container = document.getElementById('root')\nif (!container) {\n throw new Error('No #root element in the document — the template is not the one we expect.')\n}\n\nconst root = createRoot(container)\n\ntry {\n root.render(\n <StrictMode>\n <App env={readClientEnv()} />\n </StrictMode>,\n )\n} catch (error) {\n // A radiator that fails silently is worse than one that says what's wrong. If configuration\n // never arrived, say so on screen rather than rendering an empty board.\n root.render(<ConfigError message={error instanceof Error ? error.message : String(error)} />)\n}\n"],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
._diagnostics_1pu1f_1{position:relative}._button_1pu1f_5{border:1px solid var(--edge);background:var(--surface-raised);color:var(--ink-secondary);font:inherit;border-radius:.25rem;padding:.3em .55em}._area_1pu1f_14{z-index:1;border:1px solid var(--edge);border-radius:var(--radius);background:var(--surface-raised);width:min(24rem,90vw);padding:.75rem;position:absolute;bottom:calc(100% + .5rem);right:0;box-shadow:0 .5rem 1.5rem #0008}._area_1pu1f_14 p{margin:0 0 .5rem}._actions_1pu1f_31{gap:.5rem;display:flex}:root{--surface:#12140f;--surface-raised:#1a1a19;--ink-primary:#fff;--ink-secondary:#c3c2b7;--ink-muted:#898781;--edge:#2f312b;--status-good:#0ca30c;--status-warning:#fab219;--status-serious:#ec835a;--status-critical:#d03b3b;--gap:1rem;--radius:.5rem;--lightningcss-light: ;--lightningcss-dark:initial;color-scheme:dark}*{box-sizing:border-box}.screen-reader-only{clip:rect(0, 0, 0, 0);white-space:nowrap;border:0;width:1px;height:1px;margin:-1px;padding:0;position:absolute;overflow:hidden}html,body{height:100%;margin:0}body{background:var(--surface);color:var(--ink-primary);font-family:ui-sans-serif,system-ui,-apple-system,Segoe UI,Helvetica,Arial,sans-serif;font-size:clamp(16px,1.1vw + .5rem,28px);line-height:1.4;overflow-x:hidden}.board{gap:var(--gap);height:100dvh;min-height:0;padding:var(--gap);flex-direction:column;display:flex;overflow:hidden auto}.board__header{justify-content:space-between;align-items:baseline;gap:var(--gap);border-bottom:1px solid var(--edge);padding-bottom:var(--gap);flex-wrap:wrap;flex:none;display:flex}.board__title{letter-spacing:-.01em;margin:0;font-size:1.75em;font-weight:650}.board__meta{gap:calc(var(--gap) * 1.5);flex-wrap:wrap;margin:0;font-size:.7em;display:flex}.board__meta div{flex-direction:column;display:flex}.board__meta dt{color:var(--ink-muted);text-transform:uppercase;letter-spacing:.08em;font-size:.8em}.board__meta dd{color:var(--ink-secondary);overflow-wrap:anywhere;margin:0;font-family:ui-monospace,SFMono-Regular,Menlo,monospace}.board__grid{gap:var(--gap);flex:1;grid-template-rows:repeat(12,minmax(0,1fr));grid-template-columns:repeat(12,1fr);grid-auto-rows:minmax(0,1fr);align-content:stretch;min-height:0;display:grid}.panel{grid-column:var(--panel-column,span 6);grid-row:var(--panel-row,auto);min-width:0;min-height:0;padding:var(--gap);border:1px solid var(--edge);border-radius:var(--radius);background:var(--surface-raised);flex-direction:column;justify-content:center;gap:.25em;line-height:1.2;display:flex;overflow:visible}.panel--wide{grid-column:span 12}.panel__label{color:var(--ink-secondary);margin:0;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:1em;font-weight:600}.panel__hint{color:var(--ink-muted);margin:0;font-size:.75em}.panel__branch{white-space:nowrap;font-family:ui-monospace,SFMono-Regular,Menlo,monospace}.panel__observed{align-items:center;gap:.35em;display:flex}.panel__observed--stale{color:var(--status-warning)}.panel__status{margin:0;font-size:1.35em;font-weight:650}.panel__status--passed{color:var(--status-good)}.panel__status--failed{color:var(--status-critical)}.panel__status--running{color:var(--status-warning)}.panel__status--cancelled,.panel__status--unknown{color:var(--ink-secondary)}.panel--error{border-color:var(--status-serious)}.panel__link{color:var(--ink-secondary);text-underline-offset:.18em;align-self:flex-start;margin-top:.2em;font-size:.75em;font-weight:600}.panel__link:hover{color:var(--ink-primary)}.panel--primary .panel__status{font-size:1.35em}.panel--primary{gap:.1em;padding:.65em}.panel--primary .panel__hint,.panel--primary .panel__observed,.panel--primary .panel__link{font-size:.65em}.panel--compact{gap:0;min-height:3.5em;padding:.2em;line-height:1.05}.panel--compact .panel__label{font-size:.8em}.panel--compact .panel__status{font-size:1.1em}.panel--compact .panel__hint,.panel--compact .panel__observed,.panel--compact .panel__link{font-size:.65em}.panel--compact .panel__link{margin-top:0}.board__footer{color:var(--ink-muted);flex-wrap:wrap;flex:none;justify-content:space-between;align-items:center;gap:.5rem;font-size:.75em;display:flex}.config-error{max-width:60ch;color:var(--ink-primary);margin:0 auto;padding:2rem}.config-error pre{border-radius:var(--radius);border:1px solid var(--status-critical);background:var(--surface-raised);color:var(--ink-secondary);white-space:pre-wrap;overflow-wrap:anywhere;padding:1rem;font-size:.75em}@media (width<=60rem){.board{height:auto;min-height:100dvh;overflow:visible}.board__grid{flex:none;grid-template-columns:1fr;grid-auto-rows:auto;min-height:auto}.panel{grid-area:auto/1/auto/-1;min-height:6em}}
|