git-history-ui 5.1.1 → 5.2.0
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/CHANGELOG.md +16 -0
- package/build/frontend/{chunk-T5NR37IK.js → chunk-3HQI3U5H.js} +1 -1
- package/build/frontend/chunk-5ISCQDR6.js +1 -0
- package/build/frontend/{chunk-AS5GIWPS.js → chunk-6SY2IWCO.js} +1 -1
- package/build/frontend/{chunk-EAY7RGLT.js → chunk-KINVHBDC.js} +1 -1
- package/build/frontend/index.html +2 -2
- package/build/frontend/main-MVJO42GL.js +1 -0
- package/build/frontend/{styles-VRDIEW7E.css → styles-YVI22YLY.css} +1 -1
- package/dist/backend/aggregations.d.ts.map +1 -1
- package/dist/backend/aggregations.js.map +1 -1
- package/dist/backend/breakage.d.ts +1 -1
- package/dist/backend/breakage.d.ts.map +1 -1
- package/dist/backend/breakage.js +2 -1
- package/dist/backend/breakage.js.map +1 -1
- package/dist/backend/cache/sqliteIndex.d.ts +13 -0
- package/dist/backend/cache/sqliteIndex.d.ts.map +1 -1
- package/dist/backend/cache/sqliteIndex.js +68 -5
- package/dist/backend/cache/sqliteIndex.js.map +1 -1
- package/dist/backend/gitService.d.ts +2 -0
- package/dist/backend/gitService.d.ts.map +1 -1
- package/dist/backend/gitService.js +44 -16
- package/dist/backend/gitService.js.map +1 -1
- package/dist/backend/search/datePhrase.d.ts.map +1 -1
- package/dist/backend/search/datePhrase.js +6 -2
- package/dist/backend/search/datePhrase.js.map +1 -1
- package/dist/backend/server.d.ts +2 -0
- package/dist/backend/server.d.ts.map +1 -1
- package/dist/backend/server.js +209 -65
- package/dist/backend/server.js.map +1 -1
- package/dist/cli.js +3 -1
- package/dist/cli.js.map +1 -1
- package/package.json +2 -2
- package/build/frontend/chunk-HSZFTFM3.js +0 -1
- package/build/frontend/main-TYWZN6ZP.js +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,22 @@ this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
|
|
|
6
6
|
|
|
7
7
|
## [Unreleased]
|
|
8
8
|
|
|
9
|
+
## [5.2.0] - 2026-06-27
|
|
10
|
+
|
|
11
|
+
### Added
|
|
12
|
+
|
|
13
|
+
- Added optional SQLite-backed Git intelligence index endpoints and frontend status controls for build, rebuild, cancel, and progress visibility.
|
|
14
|
+
- Added broad server validation and security edge-case test coverage for malformed input, unsafe paths, and boundary conditions.
|
|
15
|
+
|
|
16
|
+
### Changed
|
|
17
|
+
|
|
18
|
+
- Hardened server request validation, git parsing, repository path handling, and index/cache behavior for safer local operation.
|
|
19
|
+
- Improved frontend robustness across command palette, grouped lists, blame, shortcuts, and Angular startup configuration.
|
|
20
|
+
|
|
21
|
+
### Fixed
|
|
22
|
+
|
|
23
|
+
- Mocked index-status dependencies in app deep-link specs so frontend tests cover the new root status component reliably.
|
|
24
|
+
|
|
9
25
|
## [5.1.1] - 2026-06-10
|
|
10
26
|
|
|
11
27
|
### Changed
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{b as J,c as K,e as Q,f as X,g as Z,h as ee}from"./chunk-HHK3LJFN.js";import{a as te}from"./chunk-HSZFTFM3.js";import{a as ie}from"./chunk-5K2HNBK3.js";import{$a as B,Ab as T,Bb as b,Jb as G,Kb as A,Mb as d,Nb as v,Oa as V,Ob as z,Sa as p,X as U,aa as E,e as P,eb as _,ec as H,fa as O,ga as k,nb as D,pa as u,qb as c,rb as o,rc as Y,sb as l,sc as j,tb as L,vc as q,zb as x}from"./chunk-MTI6UKQ3.js";var F=[{id:"aurora",name:"Aurora",stops:["#6d28d9","#7c3aed","#2563eb"],glow:"rgba(236,72,153,0.35)",ink:"#ffffff",inkSoft:"rgba(255,255,255,0.78)",inkFaint:"rgba(255,255,255,0.6)",tile:"rgba(255,255,255,0.08)",line:"rgba(255,255,255,0.14)",accent:"#ffffff"},{id:"sunset",name:"Sunset",stops:["#f97316","#db2777","#7c3aed"],glow:"rgba(250,204,21,0.4)",ink:"#ffffff",inkSoft:"rgba(255,255,255,0.82)",inkFaint:"rgba(255,255,255,0.66)",tile:"rgba(255,255,255,0.12)",line:"rgba(255,255,255,0.18)",accent:"#fde68a"},{id:"forest",name:"Forest",stops:["#064e3b","#047857","#0d9488"],glow:"rgba(163,230,53,0.35)",ink:"#ffffff",inkSoft:"rgba(255,255,255,0.8)",inkFaint:"rgba(255,255,255,0.62)",tile:"rgba(255,255,255,0.1)",line:"rgba(255,255,255,0.16)",accent:"#bbf7d0"},{id:"midnight",name:"Midnight",stops:["#020617","#0f172a","#1e293b"],glow:"rgba(56,189,248,0.3)",ink:"#e2e8f0",inkSoft:"rgba(226,232,240,0.72)",inkFaint:"rgba(148,163,184,0.7)",tile:"rgba(148,163,184,0.12)",line:"rgba(148,163,184,0.18)",accent:"#38bdf8"},{id:"candy",name:"Candy",stops:["#ec4899","#f43f5e","#fb923c"],glow:"rgba(255,255,255,0.4)",ink:"#ffffff",inkSoft:"rgba(255,255,255,0.85)",inkFaint:"rgba(255,255,255,0.7)",tile:"rgba(255,255,255,0.16)",line:"rgba(255,255,255,0.22)",accent:"#ffffff"},{id:"paper",name:"Paper",stops:["#f8fafc","#eef2f7","#dbe2ea"],glow:"rgba(124,58,237,0.18)",ink:"#0f172a",inkSoft:"rgba(15,23,42,0.7)",inkFaint:"rgba(15,23,42,0.5)",tile:"rgba(15,23,42,0.05)",line:"rgba(15,23,42,0.1)",accent:"#7c3aed"}],R=[{id:"classic",name:"Classic",description:"Stats, contributors and highlights"},{id:"minimal",name:"Minimal",description:"One big number, clean and centered"},{id:"bold",name:"Bold",description:"Oversized stat tiles front and center"}],ae=F[0],oe="classic",N=class a{W=1080;H=1350;FONT="ui-sans-serif, system-ui, -apple-system, Segoe UI, sans-serif";toBlob(e,t,i){return P(this,null,function*(){let n=this.render(e,t,i);return yield new Promise((s,r)=>{n.toBlob(m=>m?s(m):r(new Error("Canvas export failed")),"image/png")})})}toDataUrl(e,t,i){return this.render(e,t,i).toDataURL("image/png")}resolvePalette(e){return F.find(t=>t.id===e)??ae}resolveTemplate(e){return R.find(t=>t.id===e)?.id??oe}render(e,t,i){let n=this.resolvePalette(i?.paletteId),s=this.resolveTemplate(i?.template),r=Math.min(2,Math.max(1,window.devicePixelRatio||1)),m=document.createElement("canvas");m.width=this.W*r,m.height=this.H*r;let g=m.getContext("2d");if(!g)throw new Error("2D canvas context unavailable");switch(g.scale(r,r),g.textBaseline="alphabetic",this.drawBackground(g,n),s){case"minimal":this.renderMinimal(g,e,t,n);break;case"bold":this.renderBold(g,e,t,n);break;default:this.renderClassic(g,e,t,n)}return this.drawFooter(g,n,s==="minimal"),m}renderClassic(e,t,i,n){let r=120;e.fillStyle=n.inkSoft,e.font=`600 28px ${this.FONT}`,e.fillText("\u2387 GIT WRAPPED",80,r),r+=86,e.fillStyle=n.ink,e.font=`800 120px ${this.FONT}`,e.fillText(t.label,80,r),r+=52,e.fillStyle=n.inkSoft,e.font=`500 34px ${this.FONT}`,e.fillText(this.truncate(e,i,this.W-160),80,r),r+=70;let m=[[this.formatNumber(t.totalCommits),"commits"],[this.formatNumber(t.totalAuthors),"contributors"],[this.formatNumber(t.totalFilesTouched),"files touched"],[`+${this.formatNumber(t.totalAdditions)}`,"lines added"]],g=(this.W-160-30)/2,f=150;m.forEach(([y,w],h)=>{let I=h%2,W=Math.floor(h/2),S=80+I*(g+30),$=r+W*(f+24);this.roundRect(e,S,$,g,f,24),e.fillStyle=n.tile,e.fill(),e.fillStyle=n.ink,e.font=`800 60px ${this.FONT}`,e.fillText(y,S+32,$+78),e.fillStyle=n.inkFaint,e.font=`500 26px ${this.FONT}`,e.fillText(w,S+32,$+118)}),r+=f*2+24+70,e.fillStyle=n.inkFaint,e.font=`700 24px ${this.FONT}`,e.fillText("TOP CONTRIBUTORS",80,r),r+=44;let C=t.topContributors.slice(0,3),M=C[0]?.commits||1;C.forEach((y,w)=>{e.fillStyle=n.ink,e.font=`600 30px ${this.FONT}`,e.fillText(`${w+1}. ${this.truncate(e,y.author,520)}`,80,r+30),e.fillStyle=n.inkFaint,e.textAlign="right",e.fillText(`${y.commits}`,this.W-80,r+30),e.textAlign="left";let h=r+46;this.roundRect(e,80,h,this.W-160,10,5),e.fillStyle=n.line,e.fill(),this.roundRect(e,80,h,(this.W-160)*(y.commits/M),10,5),e.fillStyle=n.accent,e.fill(),r+=78}),r+=30,this.drawFunStats(e,t,n,80,r)}renderMinimal(e,t,i,n){let s=this.W/2;e.textAlign="center",e.fillStyle=n.inkFaint,e.font=`600 30px ${this.FONT}`,e.fillText("\u2387 GIT WRAPPED",s,360),e.fillStyle=n.ink,e.font=`800 220px ${this.FONT}`,e.fillText(t.label,s,560),e.fillStyle=n.inkSoft,e.font=`500 38px ${this.FONT}`,e.fillText(this.truncate(e,i,this.W-160),s,640),this.roundRect(e,s-60,690,120,8,4),e.fillStyle=n.accent,e.fill();let m=[[this.formatNumber(t.totalCommits),"commits"],[this.formatNumber(t.totalAuthors),"contributors"],[`${t.superlatives.longestStreakDays}d`,"streak"]],g=this.W/3,f=880;m.forEach(([M,y],w)=>{let h=g*w+g/2;e.fillStyle=n.ink,e.font=`800 76px ${this.FONT}`,e.fillText(M,h,f),e.fillStyle=n.inkFaint,e.font=`500 28px ${this.FONT}`,e.fillText(y,h,f+48)});let C=t.topContributors[0];C&&(e.fillStyle=n.inkFaint,e.font=`700 24px ${this.FONT}`,e.fillText("TOP CONTRIBUTOR",s,1080),e.fillStyle=n.ink,e.font=`600 44px ${this.FONT}`,e.fillText(this.truncate(e,C.author,this.W-160),s,1136)),e.textAlign="left"}renderBold(e,t,i,n){let r=130;e.fillStyle=n.inkSoft,e.font=`600 28px ${this.FONT}`,e.fillText("\u2387 GIT WRAPPED",80,r),r+=70,e.fillStyle=n.ink,e.font=`800 84px ${this.FONT}`,e.fillText(t.label,80,r),e.fillStyle=n.inkSoft,e.font=`500 30px ${this.FONT}`,e.fillText(this.truncate(e,i,this.W-160),80,r+44),r+=110;let m=[[this.formatNumber(t.totalCommits),"commits"],[this.formatNumber(t.totalAuthors),"contributors"],[`+${this.formatNumber(t.totalAdditions)}`,"lines added"],[`${t.nightOwlPercent}%`,"night-owl commits"]],g=28,f=(this.W-160-g)/2,C=340;m.forEach(([M,y],w)=>{let h=w%2,I=Math.floor(w/2),W=80+h*(f+g),S=r+I*(C+g);this.roundRect(e,W,S,f,C,32),e.fillStyle=n.tile,e.fill(),e.fillStyle=n.accent,this.roundRect(e,W+36,S+40,56,8,4),e.fill(),e.fillStyle=n.ink,e.font=`800 110px ${this.FONT}`,e.fillText(this.truncate(e,M,f-72),W+36,S+200),e.fillStyle=n.inkFaint,e.font=`500 30px ${this.FONT}`,e.fillText(this.truncate(e,y,f-72),W+36,S+256)})}drawFunStats(e,t,i,n,s){let r=s,m=[["\u{1F319}",`${t.nightOwlPercent}% night-owl commits`],["\u{1F6CB}\uFE0F",`${t.weekendWarriorPercent}% on weekends`],["\u{1F525}",`${t.superlatives.longestStreakDays}-day longest streak`]];t.superlatives.busiestHour&&m.push(["\u23F0",`peak hour ${String(t.superlatives.busiestHour.hour).padStart(2,"0")}:00`]),e.font=`500 30px ${this.FONT}`,m.forEach(([g,f])=>{e.fillStyle=i.ink,e.fillText(g,n,r+30),e.fillStyle=i.inkSoft,e.fillText(f,n+56,r+30),r+=56})}drawFooter(e,t,i){e.fillStyle=t.inkFaint,e.font=`500 24px ${this.FONT}`;let n="made with git-history-ui \xB7 npx git-history-ui";i?(e.textAlign="center",e.fillText(n,this.W/2,this.H-70),e.textAlign="left"):e.fillText(n,80,this.H-70)}drawBackground(e,t){let i=e.createLinearGradient(0,0,this.W,this.H);i.addColorStop(0,t.stops[0]),i.addColorStop(.5,t.stops[1]),i.addColorStop(1,t.stops[2]),e.fillStyle=i,e.fillRect(0,0,this.W,this.H);let n=e.createRadialGradient(this.W*.85,120,0,this.W*.85,120,520);n.addColorStop(0,t.glow),n.addColorStop(1,"rgba(0,0,0,0)"),e.fillStyle=n,e.fillRect(0,0,this.W,this.H)}roundRect(e,t,i,n,s,r){let m=Math.min(r,n/2,s/2);e.beginPath(),e.moveTo(t+m,i),e.arcTo(t+n,i,t+n,i+s,m),e.arcTo(t+n,i+s,t,i+s,m),e.arcTo(t,i+s,t,i,m),e.arcTo(t,i,t+n,i,m),e.closePath()}truncate(e,t,i){if(e.measureText(t).width<=i)return t;let n=t;for(;n.length>1&&e.measureText(`${n}\u2026`).width>i;)n=n.slice(0,-1);return`${n}\u2026`}formatNumber(e){return e>=1e6?`${(e/1e6).toFixed(1)}M`:e>=1e4?`${(e/1e3).toFixed(0)}k`:e>=1e3?`${(e/1e3).toFixed(1)}k`:String(e)}static \u0275fac=function(t){return new(t||a)};static \u0275prov=U({token:a,factory:a.\u0275fac,providedIn:"root"})};function le(a,e){if(a&1&&(o(0,"option",12),d(1),l()),a&2){let t=e.$implicit;c("ngValue",t),p(),v(t)}}function se(a,e){if(a&1&&(o(0,"option",13),d(1),l()),a&2){let t=e.$implicit;c("value",t),p(),v(t)}}function de(a,e){a&1&&(o(0,"div",14),d(1,"Computing your year in review\u2026"),l())}function pe(a,e){if(a&1&&(o(0,"div",15),d(1),l()),a&2){let t=e.ngIf;p(),v(t)}}function me(a,e){if(a&1&&L(0,"img",33),a&2){let t=e.ngIf;c("src",t,V)}}function ce(a,e){if(a&1){let t=x();o(0,"button",34),T("click",function(){let n=O(t).$implicit,s=b(2);return k(s.setTemplate(n.id))}),o(1,"span",35),d(2),l(),o(3,"span",36),d(4),l()()}if(a&2){let t=e.$implicit,i=b(2);A("selected",i.template()===t.id),c("title",t.description),D("aria-pressed",i.template()===t.id),p(2),v(t.name),p(2),v(t.description)}}function ge(a,e){if(a&1){let t=x();o(0,"button",37),T("click",function(){let n=O(t).$implicit,s=b(2);return k(s.setPalette(n.id))}),l()}if(a&2){let t=e.$implicit,i=b(2);G("background",i.swatchGradient(t.stops)),A("selected",i.paletteId()===t.id),c("title",t.name),D("aria-pressed",i.paletteId()===t.id)("aria-label",t.name)}}function fe(a,e){if(a&1){let t=x();o(0,"button",30),T("click",function(){O(t);let n=b(2);return k(n.share())}),d(1," \u2197 Share\u2026 "),l()}if(a&2){let t=b(2);c("disabled",t.busy())}}function ue(a,e){if(a&1&&(o(0,"p",38),d(1),l()),a&2){let t=e.ngIf;p(),v(t)}}function he(a,e){if(a&1){let t=x();o(0,"div",16)(1,"div",17),_(2,me,1,1,"img",18),l(),o(3,"aside",19)(4,"div",20)(5,"div",21)(6,"strong"),d(7),l(),o(8,"span"),d(9,"commits"),l()(),o(10,"div",21)(11,"strong"),d(12),l(),o(13,"span"),d(14,"contributors"),l()(),o(15,"div",21)(16,"strong"),d(17),l(),o(18,"span"),d(19,"files"),l()(),o(20,"div",21)(21,"strong"),d(22),l(),o(23,"span"),d(24,"night owl"),l()()(),o(25,"div",22)(26,"p",23),d(27,"Template"),l(),o(28,"div",24),_(29,ce,5,6,"button",25),l(),o(30,"p",23),d(31,"Color scheme"),l(),o(32,"div",26),_(33,ge,1,7,"button",27),l()(),o(34,"button",28),T("click",function(){O(t);let n=b();return k(n.download())}),d(35," \u2B07 Download card (PNG) "),l(),_(36,fe,2,1,"button",29),o(37,"button",30),T("click",function(){O(t);let n=b();return k(n.copy())}),d(38," \u29C9 Copy to clipboard "),l(),_(39,ue,2,1,"p",31),o(40,"p",32),d(41," Everything is computed locally from your git history \u2014 nothing leaves your machine. "),l()()()}if(a&2){let t=e.ngIf,i=b();p(2),c("ngIf",i.previewUrl()),p(5),v(t.totalCommits),p(5),v(t.totalAuthors),p(5),v(t.totalFilesTouched),p(5),z("",t.nightOwlPercent,"%"),p(7),c("ngForOf",i.templates),p(4),c("ngForOf",i.palettes),p(),c("disabled",i.busy()),p(2),c("ngIf",i.canShare()),p(),c("disabled",i.busy()),p(2),c("ngIf",i.status())}}var ne=class a{insightsApi=E(ie);renderer=E(N);git=E(te);stats=u(null);loading=u(!1);error=u(null);busy=u(!1);status=u(null);previewUrl=u(null);authors=u([]);year=u(new Date().getFullYear());author=u("");template=u("classic");paletteId=u(F[0].id);templates=R;palettes=F;years=H(()=>{let e=new Date().getFullYear(),t=[];for(let i=e;i>=e-9;i--)t.push(i);return t});constructor(){this.git.getAuthors().subscribe({next:e=>this.authors.set(e),error:()=>this.authors.set([])}),this.load()}canShare(){return typeof navigator<"u"&&typeof navigator.canShare=="function"}setYear(e){this.year.set(Number(e)),this.load()}setAuthor(e){this.author.set(e??""),this.load()}setTemplate(e){this.template.set(e);let t=this.stats();t&&this.refreshPreview(t)}setPalette(e){this.paletteId.set(e);let t=this.stats();t&&this.refreshPreview(t)}swatchGradient(e){return`linear-gradient(135deg, ${e[0]}, ${e[1]} 50%, ${e[2]})`}cardOptions(){return{template:this.template(),paletteId:this.paletteId()}}repoName(){let e=(document.title||"").replace(/\s*[-–|·].*$/,"").trim();return e&&e.toLowerCase()!=="git history"?e:"this repository"}load(){this.loading.set(!0),this.error.set(null),this.status.set(null),this.insightsApi.wrapped({year:this.year(),author:this.author().trim()||void 0}).subscribe({next:e=>{this.stats.set(e),this.loading.set(!1),this.refreshPreview(e)},error:e=>{this.error.set(e?.error?.error??"Failed to compute Git Wrapped"),this.loading.set(!1)}})}refreshPreview(e){try{this.previewUrl.set(this.renderer.toDataUrl(e,this.repoName(),this.cardOptions()))}catch{this.previewUrl.set(null)}}fileName(){return`git-wrapped-${this.year()}-${this.template()}-${this.paletteId()}.png`}download(){return P(this,null,function*(){let e=this.stats();if(e){this.busy.set(!0),this.status.set(null);try{let t=yield this.renderer.toBlob(e,this.repoName(),this.cardOptions()),i=URL.createObjectURL(t),n=document.createElement("a");n.href=i,n.download=this.fileName(),n.click(),URL.revokeObjectURL(i),this.status.set("Saved your card.")}catch{this.status.set("Could not generate the image.")}finally{this.busy.set(!1)}}})}share(){return P(this,null,function*(){let e=this.stats();if(e){this.busy.set(!0),this.status.set(null);try{let t=yield this.renderer.toBlob(e,this.repoName(),this.cardOptions()),i=new File([t],this.fileName(),{type:"image/png"});navigator.canShare?.({files:[i]})?(yield navigator.share({files:[i],title:`Git Wrapped ${this.year()}`,text:`My Git Wrapped for ${this.year()} \u{1F381}`}),this.status.set("Shared.")):yield this.download()}catch(t){t?.name!=="AbortError"&&this.status.set("Sharing was not available; try downloading instead.")}finally{this.busy.set(!1)}}})}copy(){return P(this,null,function*(){let e=this.stats();if(e){this.busy.set(!0),this.status.set(null);try{let t=yield this.renderer.toBlob(e,this.repoName(),this.cardOptions());typeof ClipboardItem<"u"&&navigator.clipboard?.write?(yield navigator.clipboard.write([new ClipboardItem({"image/png":t})]),this.status.set("Copied to clipboard.")):yield this.download()}catch{this.status.set("Clipboard not available; downloaded instead."),yield this.download()}finally{this.busy.set(!1)}}})}static \u0275fac=function(t){return new(t||a)};static \u0275cmp=B({type:a,selectors:[["app-wrapped"]],decls:23,vars:7,consts:[[1,"page"],[1,"head"],[1,"eyebrow"],[1,"controls"],[1,"field"],[3,"ngModelChange","ngModel"],[3,"ngValue",4,"ngFor","ngForOf"],["value",""],[3,"value",4,"ngFor","ngForOf"],["class","empty",4,"ngIf"],["class","empty error",4,"ngIf"],["class","layout",4,"ngIf"],[3,"ngValue"],[3,"value"],[1,"empty"],[1,"empty","error"],[1,"layout"],[1,"preview-wrap"],["alt","Git Wrapped card preview",3,"src",4,"ngIf"],[1,"actions"],[1,"stat-grid"],[1,"mini"],[1,"customize"],[1,"section-label"],[1,"template-grid"],["type","button","class","template-chip",3,"selected","title","click",4,"ngFor","ngForOf"],[1,"palette-grid"],["type","button","class","swatch",3,"selected","title","background","click",4,"ngFor","ngForOf"],["type","button",1,"primary",3,"click","disabled"],["class","ghost","type","button",3,"disabled","click",4,"ngIf"],["type","button",1,"ghost",3,"click","disabled"],["class","note",4,"ngIf"],[1,"hint"],["alt","Git Wrapped card preview",3,"src"],["type","button",1,"template-chip",3,"click","title"],[1,"t-name"],[1,"t-desc"],["type","button",1,"swatch",3,"click","title"],[1,"note"]],template:function(t,i){t&1&&(o(0,"div",0)(1,"header",1)(2,"div")(3,"p",2),d(4,"Year in review"),l(),o(5,"h2"),d(6,"Git Wrapped"),l()(),o(7,"div",3)(8,"label",4)(9,"span"),d(10,"Year"),l(),o(11,"select",5),T("ngModelChange",function(s){return i.setYear(s)}),_(12,le,2,2,"option",6),l()(),o(13,"label",4)(14,"span"),d(15,"Author"),l(),o(16,"select",5),T("ngModelChange",function(s){return i.setAuthor(s)}),o(17,"option",7),d(18,"All contributors"),l(),_(19,se,2,2,"option",8),l()()()(),_(20,de,2,0,"div",9)(21,pe,2,1,"div",10)(22,he,42,11,"div",11),l()),t&2&&(p(11),c("ngModel",i.year()),p(),c("ngForOf",i.years()),p(4),c("ngModel",i.author()),p(3),c("ngForOf",i.authors()),p(),c("ngIf",i.loading()),p(),c("ngIf",i.error()),p(),c("ngIf",i.stats()))},dependencies:[q,Y,j,ee,X,Z,Q,J,K],styles:["[_nghost-%COMP%]{display:block;flex:1;min-height:0;overflow-y:auto}.page[_ngcontent-%COMP%]{padding:1.1rem 1.25rem 1.4rem;max-width:1100px;margin:0 auto}.head[_ngcontent-%COMP%]{display:flex;align-items:flex-end;justify-content:space-between;gap:1rem;flex-wrap:wrap;margin-bottom:1.25rem}.eyebrow[_ngcontent-%COMP%]{margin:0 0 .2rem;color:var(--accent);font-size:11px;font-weight:700;letter-spacing:.08em;text-transform:uppercase}.head[_ngcontent-%COMP%] h2[_ngcontent-%COMP%]{margin:0;font-size:clamp(20px,2vw,28px);letter-spacing:-.03em}.controls[_ngcontent-%COMP%]{display:flex;gap:.75rem;flex-wrap:wrap}.field[_ngcontent-%COMP%]{display:flex;flex-direction:column;gap:.25rem;font-size:11px;color:var(--fg-muted);text-transform:uppercase;letter-spacing:.05em}.field[_ngcontent-%COMP%] select[_ngcontent-%COMP%], .field[_ngcontent-%COMP%] input[_ngcontent-%COMP%]{padding:.45rem .6rem;border:1px solid var(--border-soft);border-radius:var(--radius-md);background:var(--bg-panel);color:var(--fg-primary);font-size:13px;text-transform:none;letter-spacing:normal}.empty[_ngcontent-%COMP%]{padding:2rem;color:var(--fg-muted);text-align:center}.empty.error[_ngcontent-%COMP%]{color:var(--danger)}.layout[_ngcontent-%COMP%]{display:grid;grid-template-columns:minmax(0,1fr) 320px;gap:1.5rem;align-items:start}.preview-wrap[_ngcontent-%COMP%]{background:var(--bg-panel);border:1px solid var(--border-soft);border-radius:var(--radius-lg);padding:1rem;box-shadow:var(--shadow-sm);display:flex;justify-content:center}.preview-wrap[_ngcontent-%COMP%] img[_ngcontent-%COMP%]{width:100%;max-width:420px;height:auto;border-radius:16px;box-shadow:var(--shadow-md)}.actions[_ngcontent-%COMP%]{display:flex;flex-direction:column;gap:.6rem;position:sticky;top:1rem}.stat-grid[_ngcontent-%COMP%]{display:grid;grid-template-columns:1fr 1fr;gap:.5rem;margin-bottom:.5rem}.mini[_ngcontent-%COMP%]{display:flex;flex-direction:column;padding:.6rem .75rem;background:var(--bg-panel);border:1px solid var(--border-soft);border-radius:var(--radius-md)}.mini[_ngcontent-%COMP%] strong[_ngcontent-%COMP%]{font-size:22px;letter-spacing:-.03em}.mini[_ngcontent-%COMP%] span[_ngcontent-%COMP%]{color:var(--fg-muted);font-size:11px;text-transform:uppercase;letter-spacing:.04em}button[_ngcontent-%COMP%]{padding:.65rem .9rem;border-radius:var(--radius-md);font-size:13px;font-weight:600;cursor:pointer;border:1px solid var(--border-soft)}button[_ngcontent-%COMP%]:disabled{opacity:.55;cursor:not-allowed}.primary[_ngcontent-%COMP%]{background:var(--accent);color:#fff;border-color:transparent}.ghost[_ngcontent-%COMP%]{background:var(--bg-panel);color:var(--fg-primary)}.note[_ngcontent-%COMP%]{margin:.25rem 0 0;font-size:12px;color:var(--accent)}.hint[_ngcontent-%COMP%]{margin:.5rem 0 0;font-size:11px;color:var(--fg-muted);line-height:1.5}@media (max-width: 820px){.layout[_ngcontent-%COMP%]{grid-template-columns:1fr}.actions[_ngcontent-%COMP%]{position:static}}"],changeDetection:0})};export{ne as WrappedComponent};
|
|
1
|
+
import{b as J,c as K,e as Q,f as X,g as Z,h as ee}from"./chunk-HHK3LJFN.js";import{a as te}from"./chunk-5ISCQDR6.js";import{a as ie}from"./chunk-5K2HNBK3.js";import{$a as B,Ab as T,Bb as b,Jb as G,Kb as A,Mb as d,Nb as v,Oa as V,Ob as z,Sa as p,X as U,aa as E,e as P,eb as _,ec as H,fa as O,ga as k,nb as D,pa as u,qb as c,rb as o,rc as Y,sb as l,sc as j,tb as L,vc as q,zb as x}from"./chunk-MTI6UKQ3.js";var F=[{id:"aurora",name:"Aurora",stops:["#6d28d9","#7c3aed","#2563eb"],glow:"rgba(236,72,153,0.35)",ink:"#ffffff",inkSoft:"rgba(255,255,255,0.78)",inkFaint:"rgba(255,255,255,0.6)",tile:"rgba(255,255,255,0.08)",line:"rgba(255,255,255,0.14)",accent:"#ffffff"},{id:"sunset",name:"Sunset",stops:["#f97316","#db2777","#7c3aed"],glow:"rgba(250,204,21,0.4)",ink:"#ffffff",inkSoft:"rgba(255,255,255,0.82)",inkFaint:"rgba(255,255,255,0.66)",tile:"rgba(255,255,255,0.12)",line:"rgba(255,255,255,0.18)",accent:"#fde68a"},{id:"forest",name:"Forest",stops:["#064e3b","#047857","#0d9488"],glow:"rgba(163,230,53,0.35)",ink:"#ffffff",inkSoft:"rgba(255,255,255,0.8)",inkFaint:"rgba(255,255,255,0.62)",tile:"rgba(255,255,255,0.1)",line:"rgba(255,255,255,0.16)",accent:"#bbf7d0"},{id:"midnight",name:"Midnight",stops:["#020617","#0f172a","#1e293b"],glow:"rgba(56,189,248,0.3)",ink:"#e2e8f0",inkSoft:"rgba(226,232,240,0.72)",inkFaint:"rgba(148,163,184,0.7)",tile:"rgba(148,163,184,0.12)",line:"rgba(148,163,184,0.18)",accent:"#38bdf8"},{id:"candy",name:"Candy",stops:["#ec4899","#f43f5e","#fb923c"],glow:"rgba(255,255,255,0.4)",ink:"#ffffff",inkSoft:"rgba(255,255,255,0.85)",inkFaint:"rgba(255,255,255,0.7)",tile:"rgba(255,255,255,0.16)",line:"rgba(255,255,255,0.22)",accent:"#ffffff"},{id:"paper",name:"Paper",stops:["#f8fafc","#eef2f7","#dbe2ea"],glow:"rgba(124,58,237,0.18)",ink:"#0f172a",inkSoft:"rgba(15,23,42,0.7)",inkFaint:"rgba(15,23,42,0.5)",tile:"rgba(15,23,42,0.05)",line:"rgba(15,23,42,0.1)",accent:"#7c3aed"}],R=[{id:"classic",name:"Classic",description:"Stats, contributors and highlights"},{id:"minimal",name:"Minimal",description:"One big number, clean and centered"},{id:"bold",name:"Bold",description:"Oversized stat tiles front and center"}],ae=F[0],oe="classic",N=class a{W=1080;H=1350;FONT="ui-sans-serif, system-ui, -apple-system, Segoe UI, sans-serif";toBlob(e,t,i){return P(this,null,function*(){let n=this.render(e,t,i);return yield new Promise((s,r)=>{n.toBlob(m=>m?s(m):r(new Error("Canvas export failed")),"image/png")})})}toDataUrl(e,t,i){return this.render(e,t,i).toDataURL("image/png")}resolvePalette(e){return F.find(t=>t.id===e)??ae}resolveTemplate(e){return R.find(t=>t.id===e)?.id??oe}render(e,t,i){let n=this.resolvePalette(i?.paletteId),s=this.resolveTemplate(i?.template),r=Math.min(2,Math.max(1,window.devicePixelRatio||1)),m=document.createElement("canvas");m.width=this.W*r,m.height=this.H*r;let g=m.getContext("2d");if(!g)throw new Error("2D canvas context unavailable");switch(g.scale(r,r),g.textBaseline="alphabetic",this.drawBackground(g,n),s){case"minimal":this.renderMinimal(g,e,t,n);break;case"bold":this.renderBold(g,e,t,n);break;default:this.renderClassic(g,e,t,n)}return this.drawFooter(g,n,s==="minimal"),m}renderClassic(e,t,i,n){let r=120;e.fillStyle=n.inkSoft,e.font=`600 28px ${this.FONT}`,e.fillText("\u2387 GIT WRAPPED",80,r),r+=86,e.fillStyle=n.ink,e.font=`800 120px ${this.FONT}`,e.fillText(t.label,80,r),r+=52,e.fillStyle=n.inkSoft,e.font=`500 34px ${this.FONT}`,e.fillText(this.truncate(e,i,this.W-160),80,r),r+=70;let m=[[this.formatNumber(t.totalCommits),"commits"],[this.formatNumber(t.totalAuthors),"contributors"],[this.formatNumber(t.totalFilesTouched),"files touched"],[`+${this.formatNumber(t.totalAdditions)}`,"lines added"]],g=(this.W-160-30)/2,f=150;m.forEach(([y,w],h)=>{let I=h%2,W=Math.floor(h/2),S=80+I*(g+30),$=r+W*(f+24);this.roundRect(e,S,$,g,f,24),e.fillStyle=n.tile,e.fill(),e.fillStyle=n.ink,e.font=`800 60px ${this.FONT}`,e.fillText(y,S+32,$+78),e.fillStyle=n.inkFaint,e.font=`500 26px ${this.FONT}`,e.fillText(w,S+32,$+118)}),r+=f*2+24+70,e.fillStyle=n.inkFaint,e.font=`700 24px ${this.FONT}`,e.fillText("TOP CONTRIBUTORS",80,r),r+=44;let C=t.topContributors.slice(0,3),M=C[0]?.commits||1;C.forEach((y,w)=>{e.fillStyle=n.ink,e.font=`600 30px ${this.FONT}`,e.fillText(`${w+1}. ${this.truncate(e,y.author,520)}`,80,r+30),e.fillStyle=n.inkFaint,e.textAlign="right",e.fillText(`${y.commits}`,this.W-80,r+30),e.textAlign="left";let h=r+46;this.roundRect(e,80,h,this.W-160,10,5),e.fillStyle=n.line,e.fill(),this.roundRect(e,80,h,(this.W-160)*(y.commits/M),10,5),e.fillStyle=n.accent,e.fill(),r+=78}),r+=30,this.drawFunStats(e,t,n,80,r)}renderMinimal(e,t,i,n){let s=this.W/2;e.textAlign="center",e.fillStyle=n.inkFaint,e.font=`600 30px ${this.FONT}`,e.fillText("\u2387 GIT WRAPPED",s,360),e.fillStyle=n.ink,e.font=`800 220px ${this.FONT}`,e.fillText(t.label,s,560),e.fillStyle=n.inkSoft,e.font=`500 38px ${this.FONT}`,e.fillText(this.truncate(e,i,this.W-160),s,640),this.roundRect(e,s-60,690,120,8,4),e.fillStyle=n.accent,e.fill();let m=[[this.formatNumber(t.totalCommits),"commits"],[this.formatNumber(t.totalAuthors),"contributors"],[`${t.superlatives.longestStreakDays}d`,"streak"]],g=this.W/3,f=880;m.forEach(([M,y],w)=>{let h=g*w+g/2;e.fillStyle=n.ink,e.font=`800 76px ${this.FONT}`,e.fillText(M,h,f),e.fillStyle=n.inkFaint,e.font=`500 28px ${this.FONT}`,e.fillText(y,h,f+48)});let C=t.topContributors[0];C&&(e.fillStyle=n.inkFaint,e.font=`700 24px ${this.FONT}`,e.fillText("TOP CONTRIBUTOR",s,1080),e.fillStyle=n.ink,e.font=`600 44px ${this.FONT}`,e.fillText(this.truncate(e,C.author,this.W-160),s,1136)),e.textAlign="left"}renderBold(e,t,i,n){let r=130;e.fillStyle=n.inkSoft,e.font=`600 28px ${this.FONT}`,e.fillText("\u2387 GIT WRAPPED",80,r),r+=70,e.fillStyle=n.ink,e.font=`800 84px ${this.FONT}`,e.fillText(t.label,80,r),e.fillStyle=n.inkSoft,e.font=`500 30px ${this.FONT}`,e.fillText(this.truncate(e,i,this.W-160),80,r+44),r+=110;let m=[[this.formatNumber(t.totalCommits),"commits"],[this.formatNumber(t.totalAuthors),"contributors"],[`+${this.formatNumber(t.totalAdditions)}`,"lines added"],[`${t.nightOwlPercent}%`,"night-owl commits"]],g=28,f=(this.W-160-g)/2,C=340;m.forEach(([M,y],w)=>{let h=w%2,I=Math.floor(w/2),W=80+h*(f+g),S=r+I*(C+g);this.roundRect(e,W,S,f,C,32),e.fillStyle=n.tile,e.fill(),e.fillStyle=n.accent,this.roundRect(e,W+36,S+40,56,8,4),e.fill(),e.fillStyle=n.ink,e.font=`800 110px ${this.FONT}`,e.fillText(this.truncate(e,M,f-72),W+36,S+200),e.fillStyle=n.inkFaint,e.font=`500 30px ${this.FONT}`,e.fillText(this.truncate(e,y,f-72),W+36,S+256)})}drawFunStats(e,t,i,n,s){let r=s,m=[["\u{1F319}",`${t.nightOwlPercent}% night-owl commits`],["\u{1F6CB}\uFE0F",`${t.weekendWarriorPercent}% on weekends`],["\u{1F525}",`${t.superlatives.longestStreakDays}-day longest streak`]];t.superlatives.busiestHour&&m.push(["\u23F0",`peak hour ${String(t.superlatives.busiestHour.hour).padStart(2,"0")}:00`]),e.font=`500 30px ${this.FONT}`,m.forEach(([g,f])=>{e.fillStyle=i.ink,e.fillText(g,n,r+30),e.fillStyle=i.inkSoft,e.fillText(f,n+56,r+30),r+=56})}drawFooter(e,t,i){e.fillStyle=t.inkFaint,e.font=`500 24px ${this.FONT}`;let n="made with git-history-ui \xB7 npx git-history-ui";i?(e.textAlign="center",e.fillText(n,this.W/2,this.H-70),e.textAlign="left"):e.fillText(n,80,this.H-70)}drawBackground(e,t){let i=e.createLinearGradient(0,0,this.W,this.H);i.addColorStop(0,t.stops[0]),i.addColorStop(.5,t.stops[1]),i.addColorStop(1,t.stops[2]),e.fillStyle=i,e.fillRect(0,0,this.W,this.H);let n=e.createRadialGradient(this.W*.85,120,0,this.W*.85,120,520);n.addColorStop(0,t.glow),n.addColorStop(1,"rgba(0,0,0,0)"),e.fillStyle=n,e.fillRect(0,0,this.W,this.H)}roundRect(e,t,i,n,s,r){let m=Math.min(r,n/2,s/2);e.beginPath(),e.moveTo(t+m,i),e.arcTo(t+n,i,t+n,i+s,m),e.arcTo(t+n,i+s,t,i+s,m),e.arcTo(t,i+s,t,i,m),e.arcTo(t,i,t+n,i,m),e.closePath()}truncate(e,t,i){if(e.measureText(t).width<=i)return t;let n=t;for(;n.length>1&&e.measureText(`${n}\u2026`).width>i;)n=n.slice(0,-1);return`${n}\u2026`}formatNumber(e){return e>=1e6?`${(e/1e6).toFixed(1)}M`:e>=1e4?`${(e/1e3).toFixed(0)}k`:e>=1e3?`${(e/1e3).toFixed(1)}k`:String(e)}static \u0275fac=function(t){return new(t||a)};static \u0275prov=U({token:a,factory:a.\u0275fac,providedIn:"root"})};function le(a,e){if(a&1&&(o(0,"option",12),d(1),l()),a&2){let t=e.$implicit;c("ngValue",t),p(),v(t)}}function se(a,e){if(a&1&&(o(0,"option",13),d(1),l()),a&2){let t=e.$implicit;c("value",t),p(),v(t)}}function de(a,e){a&1&&(o(0,"div",14),d(1,"Computing your year in review\u2026"),l())}function pe(a,e){if(a&1&&(o(0,"div",15),d(1),l()),a&2){let t=e.ngIf;p(),v(t)}}function me(a,e){if(a&1&&L(0,"img",33),a&2){let t=e.ngIf;c("src",t,V)}}function ce(a,e){if(a&1){let t=x();o(0,"button",34),T("click",function(){let n=O(t).$implicit,s=b(2);return k(s.setTemplate(n.id))}),o(1,"span",35),d(2),l(),o(3,"span",36),d(4),l()()}if(a&2){let t=e.$implicit,i=b(2);A("selected",i.template()===t.id),c("title",t.description),D("aria-pressed",i.template()===t.id),p(2),v(t.name),p(2),v(t.description)}}function ge(a,e){if(a&1){let t=x();o(0,"button",37),T("click",function(){let n=O(t).$implicit,s=b(2);return k(s.setPalette(n.id))}),l()}if(a&2){let t=e.$implicit,i=b(2);G("background",i.swatchGradient(t.stops)),A("selected",i.paletteId()===t.id),c("title",t.name),D("aria-pressed",i.paletteId()===t.id)("aria-label",t.name)}}function fe(a,e){if(a&1){let t=x();o(0,"button",30),T("click",function(){O(t);let n=b(2);return k(n.share())}),d(1," \u2197 Share\u2026 "),l()}if(a&2){let t=b(2);c("disabled",t.busy())}}function ue(a,e){if(a&1&&(o(0,"p",38),d(1),l()),a&2){let t=e.ngIf;p(),v(t)}}function he(a,e){if(a&1){let t=x();o(0,"div",16)(1,"div",17),_(2,me,1,1,"img",18),l(),o(3,"aside",19)(4,"div",20)(5,"div",21)(6,"strong"),d(7),l(),o(8,"span"),d(9,"commits"),l()(),o(10,"div",21)(11,"strong"),d(12),l(),o(13,"span"),d(14,"contributors"),l()(),o(15,"div",21)(16,"strong"),d(17),l(),o(18,"span"),d(19,"files"),l()(),o(20,"div",21)(21,"strong"),d(22),l(),o(23,"span"),d(24,"night owl"),l()()(),o(25,"div",22)(26,"p",23),d(27,"Template"),l(),o(28,"div",24),_(29,ce,5,6,"button",25),l(),o(30,"p",23),d(31,"Color scheme"),l(),o(32,"div",26),_(33,ge,1,7,"button",27),l()(),o(34,"button",28),T("click",function(){O(t);let n=b();return k(n.download())}),d(35," \u2B07 Download card (PNG) "),l(),_(36,fe,2,1,"button",29),o(37,"button",30),T("click",function(){O(t);let n=b();return k(n.copy())}),d(38," \u29C9 Copy to clipboard "),l(),_(39,ue,2,1,"p",31),o(40,"p",32),d(41," Everything is computed locally from your git history \u2014 nothing leaves your machine. "),l()()()}if(a&2){let t=e.ngIf,i=b();p(2),c("ngIf",i.previewUrl()),p(5),v(t.totalCommits),p(5),v(t.totalAuthors),p(5),v(t.totalFilesTouched),p(5),z("",t.nightOwlPercent,"%"),p(7),c("ngForOf",i.templates),p(4),c("ngForOf",i.palettes),p(),c("disabled",i.busy()),p(2),c("ngIf",i.canShare()),p(),c("disabled",i.busy()),p(2),c("ngIf",i.status())}}var ne=class a{insightsApi=E(ie);renderer=E(N);git=E(te);stats=u(null);loading=u(!1);error=u(null);busy=u(!1);status=u(null);previewUrl=u(null);authors=u([]);year=u(new Date().getFullYear());author=u("");template=u("classic");paletteId=u(F[0].id);templates=R;palettes=F;years=H(()=>{let e=new Date().getFullYear(),t=[];for(let i=e;i>=e-9;i--)t.push(i);return t});constructor(){this.git.getAuthors().subscribe({next:e=>this.authors.set(e),error:()=>this.authors.set([])}),this.load()}canShare(){return typeof navigator<"u"&&typeof navigator.canShare=="function"}setYear(e){this.year.set(Number(e)),this.load()}setAuthor(e){this.author.set(e??""),this.load()}setTemplate(e){this.template.set(e);let t=this.stats();t&&this.refreshPreview(t)}setPalette(e){this.paletteId.set(e);let t=this.stats();t&&this.refreshPreview(t)}swatchGradient(e){return`linear-gradient(135deg, ${e[0]}, ${e[1]} 50%, ${e[2]})`}cardOptions(){return{template:this.template(),paletteId:this.paletteId()}}repoName(){let e=(document.title||"").replace(/\s*[-–|·].*$/,"").trim();return e&&e.toLowerCase()!=="git history"?e:"this repository"}load(){this.loading.set(!0),this.error.set(null),this.status.set(null),this.insightsApi.wrapped({year:this.year(),author:this.author().trim()||void 0}).subscribe({next:e=>{this.stats.set(e),this.loading.set(!1),this.refreshPreview(e)},error:e=>{this.error.set(e?.error?.error??"Failed to compute Git Wrapped"),this.loading.set(!1)}})}refreshPreview(e){try{this.previewUrl.set(this.renderer.toDataUrl(e,this.repoName(),this.cardOptions()))}catch{this.previewUrl.set(null)}}fileName(){return`git-wrapped-${this.year()}-${this.template()}-${this.paletteId()}.png`}download(){return P(this,null,function*(){let e=this.stats();if(e){this.busy.set(!0),this.status.set(null);try{let t=yield this.renderer.toBlob(e,this.repoName(),this.cardOptions()),i=URL.createObjectURL(t),n=document.createElement("a");n.href=i,n.download=this.fileName(),n.click(),URL.revokeObjectURL(i),this.status.set("Saved your card.")}catch{this.status.set("Could not generate the image.")}finally{this.busy.set(!1)}}})}share(){return P(this,null,function*(){let e=this.stats();if(e){this.busy.set(!0),this.status.set(null);try{let t=yield this.renderer.toBlob(e,this.repoName(),this.cardOptions()),i=new File([t],this.fileName(),{type:"image/png"});navigator.canShare?.({files:[i]})?(yield navigator.share({files:[i],title:`Git Wrapped ${this.year()}`,text:`My Git Wrapped for ${this.year()} \u{1F381}`}),this.status.set("Shared.")):yield this.download()}catch(t){t?.name!=="AbortError"&&this.status.set("Sharing was not available; try downloading instead.")}finally{this.busy.set(!1)}}})}copy(){return P(this,null,function*(){let e=this.stats();if(e){this.busy.set(!0),this.status.set(null);try{let t=yield this.renderer.toBlob(e,this.repoName(),this.cardOptions());typeof ClipboardItem<"u"&&navigator.clipboard?.write?(yield navigator.clipboard.write([new ClipboardItem({"image/png":t})]),this.status.set("Copied to clipboard.")):yield this.download()}catch{this.status.set("Clipboard not available; downloaded instead."),yield this.download()}finally{this.busy.set(!1)}}})}static \u0275fac=function(t){return new(t||a)};static \u0275cmp=B({type:a,selectors:[["app-wrapped"]],decls:23,vars:7,consts:[[1,"page"],[1,"head"],[1,"eyebrow"],[1,"controls"],[1,"field"],[3,"ngModelChange","ngModel"],[3,"ngValue",4,"ngFor","ngForOf"],["value",""],[3,"value",4,"ngFor","ngForOf"],["class","empty",4,"ngIf"],["class","empty error",4,"ngIf"],["class","layout",4,"ngIf"],[3,"ngValue"],[3,"value"],[1,"empty"],[1,"empty","error"],[1,"layout"],[1,"preview-wrap"],["alt","Git Wrapped card preview",3,"src",4,"ngIf"],[1,"actions"],[1,"stat-grid"],[1,"mini"],[1,"customize"],[1,"section-label"],[1,"template-grid"],["type","button","class","template-chip",3,"selected","title","click",4,"ngFor","ngForOf"],[1,"palette-grid"],["type","button","class","swatch",3,"selected","title","background","click",4,"ngFor","ngForOf"],["type","button",1,"primary",3,"click","disabled"],["class","ghost","type","button",3,"disabled","click",4,"ngIf"],["type","button",1,"ghost",3,"click","disabled"],["class","note",4,"ngIf"],[1,"hint"],["alt","Git Wrapped card preview",3,"src"],["type","button",1,"template-chip",3,"click","title"],[1,"t-name"],[1,"t-desc"],["type","button",1,"swatch",3,"click","title"],[1,"note"]],template:function(t,i){t&1&&(o(0,"div",0)(1,"header",1)(2,"div")(3,"p",2),d(4,"Year in review"),l(),o(5,"h2"),d(6,"Git Wrapped"),l()(),o(7,"div",3)(8,"label",4)(9,"span"),d(10,"Year"),l(),o(11,"select",5),T("ngModelChange",function(s){return i.setYear(s)}),_(12,le,2,2,"option",6),l()(),o(13,"label",4)(14,"span"),d(15,"Author"),l(),o(16,"select",5),T("ngModelChange",function(s){return i.setAuthor(s)}),o(17,"option",7),d(18,"All contributors"),l(),_(19,se,2,2,"option",8),l()()()(),_(20,de,2,0,"div",9)(21,pe,2,1,"div",10)(22,he,42,11,"div",11),l()),t&2&&(p(11),c("ngModel",i.year()),p(),c("ngForOf",i.years()),p(4),c("ngModel",i.author()),p(3),c("ngForOf",i.authors()),p(),c("ngIf",i.loading()),p(),c("ngIf",i.error()),p(),c("ngIf",i.stats()))},dependencies:[q,Y,j,ee,X,Z,Q,J,K],styles:["[_nghost-%COMP%]{display:block;flex:1;min-height:0;overflow-y:auto}.page[_ngcontent-%COMP%]{padding:1.1rem 1.25rem 1.4rem;max-width:1100px;margin:0 auto}.head[_ngcontent-%COMP%]{display:flex;align-items:flex-end;justify-content:space-between;gap:1rem;flex-wrap:wrap;margin-bottom:1.25rem}.eyebrow[_ngcontent-%COMP%]{margin:0 0 .2rem;color:var(--accent);font-size:11px;font-weight:700;letter-spacing:.08em;text-transform:uppercase}.head[_ngcontent-%COMP%] h2[_ngcontent-%COMP%]{margin:0;font-size:clamp(20px,2vw,28px);letter-spacing:-.03em}.controls[_ngcontent-%COMP%]{display:flex;gap:.75rem;flex-wrap:wrap}.field[_ngcontent-%COMP%]{display:flex;flex-direction:column;gap:.25rem;font-size:11px;color:var(--fg-muted);text-transform:uppercase;letter-spacing:.05em}.field[_ngcontent-%COMP%] select[_ngcontent-%COMP%], .field[_ngcontent-%COMP%] input[_ngcontent-%COMP%]{padding:.45rem .6rem;border:1px solid var(--border-soft);border-radius:var(--radius-md);background:var(--bg-panel);color:var(--fg-primary);font-size:13px;text-transform:none;letter-spacing:normal}.empty[_ngcontent-%COMP%]{padding:2rem;color:var(--fg-muted);text-align:center}.empty.error[_ngcontent-%COMP%]{color:var(--danger)}.layout[_ngcontent-%COMP%]{display:grid;grid-template-columns:minmax(0,1fr) 320px;gap:1.5rem;align-items:start}.preview-wrap[_ngcontent-%COMP%]{background:var(--bg-panel);border:1px solid var(--border-soft);border-radius:var(--radius-lg);padding:1rem;box-shadow:var(--shadow-sm);display:flex;justify-content:center}.preview-wrap[_ngcontent-%COMP%] img[_ngcontent-%COMP%]{width:100%;max-width:420px;height:auto;border-radius:16px;box-shadow:var(--shadow-md)}.actions[_ngcontent-%COMP%]{display:flex;flex-direction:column;gap:.6rem;position:sticky;top:1rem}.stat-grid[_ngcontent-%COMP%]{display:grid;grid-template-columns:1fr 1fr;gap:.5rem;margin-bottom:.5rem}.mini[_ngcontent-%COMP%]{display:flex;flex-direction:column;padding:.6rem .75rem;background:var(--bg-panel);border:1px solid var(--border-soft);border-radius:var(--radius-md)}.mini[_ngcontent-%COMP%] strong[_ngcontent-%COMP%]{font-size:22px;letter-spacing:-.03em}.mini[_ngcontent-%COMP%] span[_ngcontent-%COMP%]{color:var(--fg-muted);font-size:11px;text-transform:uppercase;letter-spacing:.04em}button[_ngcontent-%COMP%]{padding:.65rem .9rem;border-radius:var(--radius-md);font-size:13px;font-weight:600;cursor:pointer;border:1px solid var(--border-soft)}button[_ngcontent-%COMP%]:disabled{opacity:.55;cursor:not-allowed}.primary[_ngcontent-%COMP%]{background:var(--accent);color:#fff;border-color:transparent}.ghost[_ngcontent-%COMP%]{background:var(--bg-panel);color:var(--fg-primary)}.note[_ngcontent-%COMP%]{margin:.25rem 0 0;font-size:12px;color:var(--accent)}.hint[_ngcontent-%COMP%]{margin:.5rem 0 0;font-size:11px;color:var(--fg-muted);line-height:1.5}@media (max-width: 820px){.layout[_ngcontent-%COMP%]{grid-template-columns:1fr}.actions[_ngcontent-%COMP%]{position:static}}"],changeDetection:0})};export{ne as WrappedComponent};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{Ac as d,Bc as L,Ec as C,Fc as o,X as S,aa as I,h as E}from"./chunk-MTI6UKQ3.js";var $=class a{http=I(L);base="/api";cache=new C(200);getCommits(t={}){let e=new d;for(let[u,s]of Object.entries(t))s!=null&&s!==""&&(e=e.set(u,String(s)));return this.cache.get(`commits:${e.toString()}`,()=>this.http.get(`${this.base}/commits`,{params:e}),o.VOLATILE)}invalidate(){this.cache.clear()}streamCommits(t={}){return new E(e=>{let u=new URL(`${window.location.origin}${this.base}/commits/stream`);for(let[n,i]of Object.entries(t))i!=null&&i!==""&&u.searchParams.set(n,String(i));let s=new EventSource(u.toString()),l=[],m=[],b=Math.max(1,t.page??1),f=w(t.pageSize??100,1,500),p=0,c={},r=0,g=0,h=!1,v=null,O=()=>{r=0,!(!m.length&&!h)&&(m.length&&l.push(...m.splice(0)),e.next({commits:l.slice(),total:h&&p||l.length,page:c.page??b,pageSize:c.pageSize??f,totalPages:c.totalPages??1,hasNext:c.hasNext??!1,hasPrevious:c.hasPrevious??b>1}),h&&(s.close(),e.complete()))},x=()=>{if(!(r||g)){if(m.length>=50||h){r=requestAnimationFrame(O);return}g=window.setTimeout(()=>{g=0,r=requestAnimationFrame(O)},100)}};return s.addEventListener("commit",n=>{l.length+m.length<f&&m.push(JSON.parse(n.data)),x()}),s.addEventListener("done",n=>{let i=JSON.parse(n.data);p=i.total??l.length+m.length,c=i,h=!0,x()}),s.addEventListener("error",n=>{s.close(),r&&cancelAnimationFrame(r),v=this.getCommits(t).subscribe({next:i=>e.next(i),error:i=>e.error(P(n)?M(n):i),complete:()=>e.complete()})}),()=>{s.close(),r&&cancelAnimationFrame(r),g&&window.clearTimeout(g),v?.unsubscribe()}})}getCommit(t){return this.cache.get(`commit:${t}`,()=>this.http.get(`${this.base}/commit/${t}`),o.IMMUTABLE)}getDiff(t){return this.cache.get(`diff:${t}`,()=>this.http.get(`${this.base}/diff/${t}`),o.IMMUTABLE)}getBlame(t){let e=new d().set("file",t);return this.cache.get(`blame:${t}`,()=>this.http.get(`${this.base}/blame`,{params:e}),o.VOLATILE)}getTags(){return this.cache.get("tags",()=>this.http.get(`${this.base}/tags`),o.VOLATILE)}getBranches(){return this.cache.get("branches",()=>this.http.get(`${this.base}/branches`),o.VOLATILE)}getAuthors(){return this.cache.get("authors",()=>this.http.get(`${this.base}/authors`),o.VOLATILE)}getIndexStatus(){return this.http.get(`${this.base}/index/status`)}buildIndex(t=!1){let e=t?new d().set("wait","true"):void 0;return this.http.post(`${this.base}/index/build`,{},{params:e})}rebuildIndex(){return this.http.post(`${this.base}/index/rebuild`,{})}cancelIndexBuild(){return this.http.post(`${this.base}/index/cancel`,{})}static \u0275fac=function(e){return new(e||a)};static \u0275prov=S({token:a,factory:a.\u0275fac,providedIn:"root"})};function w(a,t,e){return Math.max(t,Math.min(e,a))}function P(a){return a instanceof MessageEvent&&typeof a.data=="string"&&a.data.length>0}function M(a){if(a instanceof MessageEvent&&typeof a.data=="string"&&a.data)try{let t=JSON.parse(a.data),e=t.message||t.error;if(e)return new Error(e)}catch{return new Error(a.data)}return new Error("Failed to load commits.")}export{$ as a};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{a as G}from"./chunk-VDZMKPJL.js";import{c as A,e as q}from"./chunk-Q72JIHF2.js";import{a as w}from"./chunk-HSZFTFM3.js";import{a as U}from"./chunk-5K2HNBK3.js";import{$a as M,$b as k,Ab as f,Bb as d,Jb as V,Kb as b,Mb as a,Nb as c,Ob as u,Pb as T,Qb as H,Rb as $,Sa as r,Yb as y,a as D,aa as C,b as z,eb as m,ec as O,fa as v,fc as R,ga as x,nb as F,pa as g,qb as s,rb as i,rc as P,sb as n,sc as S,tb as B,uc as j,vc as I,xb as N,yb as L,zb as h}from"./chunk-MTI6UKQ3.js";function Y(t,o){t&1&&(i(0,"div",3),a(1,"Loading blame\u2026"),n())}function Z(t,o){if(t&1&&(i(0,"div",4),a(1),n()),t&2){let e=o.ngIf;r(),c(e)}}function ee(t,o){t&1&&(i(0,"div",3),a(1," No blame data (file may be binary or freshly created). "),n())}function te(t,o){if(t&1){let e=h();i(0,"div",7)(1,"div",8)(2,"code",9),f("click",function(){let p=v(e).$implicit,_=d(2);return x(_.onSelectCommit(p.hash))}),a(3),n(),i(4,"span",10),a(5),n(),i(6,"span",11),a(7),n()(),i(8,"span",12),a(9),n(),i(10,"pre",13),a(11),n()()}if(t&2){let e=o.$implicit,l=d(2);r(),b("invisible",!e.isFirstOfBlock),r(2),c(e.hash.slice(0,7)),r(2),c(e.author),r(2),c(l.shortDate(e.date)),r(2),c(e.line),r(2),c(e.content)}}function ne(t,o){if(t&1&&(i(0,"div",5),m(1,te,12,7,"div",6),n()),t&2){let e=d();r(),s("ngForOf",e.rows())("ngForTrackBy",e.trackByLine)}}var E=class t{gitService=C(w);set file(o){this._file=o,o?this.load(o):this.lines.set([])}get file(){return this._file}_file=null;onCommitClick=null;lines=g([]);loading=g(!1);error=g(null);rows=O(()=>{let o=[],e="";for(let l of this.lines())o.push(z(D({},l),{isFirstOfBlock:l.hash!==e})),e=l.hash;return o});trackByLine(o,e){return e.line}shortDate(o){return(o||"").slice(0,10)}onSelectCommit(o){this.onCommitClick&&this.onCommitClick(o)}load(o){this.loading.set(!0),this.error.set(null),this.gitService.getBlame(o).subscribe({next:e=>{this.lines.set(e),this.loading.set(!1)},error:e=>{this.error.set(e?.error?.error??"Failed to load blame"),this.loading.set(!1)}})}static \u0275fac=function(e){return new(e||t)};static \u0275cmp=M({type:t,selectors:[["app-blame"]],inputs:{file:"file",onCommitClick:"onCommitClick"},decls:4,vars:4,consts:[["class","empty",4,"ngIf"],["class","empty error",4,"ngIf"],["class","blame",4,"ngIf"],[1,"empty"],[1,"empty","error"],[1,"blame"],["class","row",4,"ngFor","ngForOf","ngForTrackBy"],[1,"row"],[1,"meta"],[1,"hash",3,"click"],[1,"author"],[1,"date"],[1,"line-no"],[1,"code"]],template:function(e,l){e&1&&m(0,Y,2,0,"div",0)(1,Z,2,1,"div",1)(2,ee,2,0,"div",0)(3,ne,2,2,"div",2),e&2&&(s("ngIf",l.loading()),r(),s("ngIf",l.error()),r(),s("ngIf",!l.loading()&&!l.error()&&l.rows().length===0&&l.file),r(),s("ngIf",l.rows().length>0))},dependencies:[I,P,S],styles:["[_nghost-%COMP%]{display:block;font-family:var(--font-mono, monospace);font-size:12.5px}.empty[_ngcontent-%COMP%]{padding:1.5rem;color:var(--fg-muted);text-align:center}.empty.error[_ngcontent-%COMP%]{color:var(--danger)}.blame[_ngcontent-%COMP%]{display:block;background:var(--bg-surface);border:1px solid var(--border-soft);border-radius:var(--radius-md);overflow:auto;max-height:70vh}.row[_ngcontent-%COMP%]{display:grid;grid-template-columns:220px 50px 1fr;align-items:center;gap:.5rem;padding:0 .5rem;border-bottom:1px solid color-mix(in oklab,var(--border-soft) 50%,transparent)}.row[_ngcontent-%COMP%]:hover{background:var(--bg-elevated)}.meta[_ngcontent-%COMP%]{display:flex;gap:.5rem;align-items:center;font-size:11px;color:var(--fg-muted);padding:.15rem 0;border-right:1px solid var(--border-soft)}.meta.invisible[_ngcontent-%COMP%] > *[_ngcontent-%COMP%]{visibility:hidden}.hash[_ngcontent-%COMP%]{color:var(--accent);cursor:pointer;text-decoration:none}.hash[_ngcontent-%COMP%]:hover{text-decoration:underline}.author[_ngcontent-%COMP%]{max-width:100px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.date[_ngcontent-%COMP%]{color:var(--fg-subtle)}.line-no[_ngcontent-%COMP%]{color:var(--fg-subtle);text-align:right;font-variant-numeric:tabular-nums;font-size:11px}.code[_ngcontent-%COMP%]{margin:0;padding:.15rem 0;white-space:pre;overflow-x:auto;color:var(--fg-primary)}"],changeDetection:0})};function ie(t,o){if(t&1&&(i(0,"div",11)(1,"span"),a(2),n(),i(3,"span"),a(4,"\xB7"),n(),i(5,"span"),a(6),n(),i(7,"span"),a(8,"\xB7"),n(),i(9,"span"),a(10),y(11,"slice"),n(),i(12,"span"),a(13,"\xB7"),n(),i(14,"span"),a(15),y(16,"slice"),n()()),t&2){let e=o.ngIf;r(2),u("",e.totalCommits," commits"),r(4),u("",e.contributors.length," contributors"),r(4),u("first: ",k(11,4,e.firstSeen,0,10)),r(5),u("last: ",k(16,8,e.lastTouched,0,10))}}function oe(t,o){t&1&&(i(0,"div",17),a(1,"Loading commits\u2026"),n())}function re(t,o){if(t&1&&(i(0,"div",18),a(1),n()),t&2){let e=o.ngIf;r(),c(e)}}function ae(t,o){if(t&1){let e=h();i(0,"li",19),f("click",function(){let p=v(e).$implicit,_=d(2);return x(_.onSelectCommit(p.hash))}),i(1,"code",20),a(2),n(),i(3,"div",21)(4,"span",22),a(5),n(),i(6,"span",23),a(7),y(8,"slice"),n()()()}if(t&2){let e=o.$implicit,l=d(2);b("selected",e.hash===l.state.selectedHash()),r(2),c(e.shortHash),r(3),c(e.subject),r(2),T("",e.author," \xB7 ",k(8,6,e.date,0,10))}}function le(t,o){if(t&1&&(i(0,"section",12),m(1,oe,2,0,"div",13)(2,re,2,1,"div",14),i(3,"ul",15),m(4,ae,9,10,"li",16),n()()),t&2){let e=d();r(),s("ngIf",e.loading()),r(),s("ngIf",e.error()),r(2),s("ngForOf",e.commits())}}function se(t,o){if(t&1&&(i(0,"section",24),B(1,"app-blame",25),n()),t&2){let e=d();r(),s("file",e.filePath())("onCommitClick",e.onSelectCommit.bind(e))}}function ce(t,o){t&1&&(i(0,"div",17),a(1,"Analyzing breakage history\u2026"),n())}function me(t,o){if(t&1&&(i(0,"div",18),a(1),n()),t&2){let e=o.ngIf;r(),c(e)}}function de(t,o){t&1&&(i(0,"span"),a(1,"\xB7"),n())}function pe(t,o){if(t&1&&(i(0,"span")(1,"strong"),a(2),n(),a(3),n()),t&2){let e=d().ngIf;r(2),c(e.suspects.length),r(),u(" suspect",e.suspects.length===1?"":"s")}}function ge(t,o){t&1&&(i(0,"div",46),a(1," No prior change is strongly correlated with a recent fix. "),n())}function _e(t,o){if(t&1&&(i(0,"li"),a(1),n()),t&2){let e=o.$implicit;r(),c(e)}}function fe(t,o){t&1&&(i(0,"span"),a(1,", "),n())}function ue(t,o){if(t&1){let e=h();i(0,"a",57),f("click",function(p){let _=v(e).$implicit,K=d(6);return p.stopPropagation(),x(K.onSelectCommit(_.hash))}),i(1,"code"),a(2),n(),m(3,fe,2,0,"span",27),n()}if(t&2){let e=o.$implicit,l=o.last;r(2),c(e.shortHash),r(),s("ngIf",!l)}}function ve(t,o){if(t&1&&(i(0,"div",55),a(1),m(2,ue,4,2,"a",56),n()),t&2){let e=d().$implicit;r(),u(" Linked fix",e.linkedFixes.length===1?"":"es",": "),r(),s("ngForOf",e.linkedFixes)}}function xe(t,o){if(t&1){let e=h();i(0,"li",49),f("click",function(){let p=v(e).$implicit,_=d(4);return x(_.onSelectCommit(p.hash))}),i(1,"div",50)(2,"code",20),a(3),n(),i(4,"span",51),a(5),n(),i(6,"span",22),a(7),n()(),i(8,"div",23),a(9),y(10,"slice"),n(),i(11,"ul",52),m(12,_e,2,1,"li",53),n(),m(13,ve,3,2,"div",54),n()}if(t&2){let e=o.$implicit;r(3),c(e.shortHash),r(),F("data-strong",e.score>=8?"true":"false"),r(),c(e.score),r(2),c(e.subject),r(2),H(" ",e.author," \xB7 ",k(10,9,e.date,0,10)," \xB7 ",e.churn," lines changed "),r(3),s("ngForOf",e.reasons),r(),s("ngIf",e.linkedFixes.length)}}function he(t,o){if(t&1&&(i(0,"ol",47),m(1,xe,14,13,"li",48),n()),t&2){let e=d().ngIf;r(),s("ngForOf",e.suspects)}}function be(t,o){t&1&&(i(0,"div",46),a(1," No fix/revert commits matched recent history. "),n())}function Ce(t,o){t&1&&(i(0,"span",62),a(1,"revert"),n())}function ye(t,o){t&1&&(i(0,"span",63),a(1,"fix"),n())}function ke(t,o){if(t&1){let e=h();i(0,"li",19),f("click",function(){let p=v(e).$implicit,_=d(4);return x(_.onSelectCommit(p.hash))}),i(1,"code",20),a(2),n(),i(3,"div",21)(4,"span",22),m(5,Ce,2,0,"span",60)(6,ye,2,0,"span",61),a(7),n(),i(8,"span",23),a(9),y(10,"slice"),n()()()}if(t&2){let e=o.$implicit;b("revert",e.isRevert),r(2),c(e.shortHash),r(3),s("ngIf",e.isRevert),r(),s("ngIf",e.isFix),r(),u(" ",e.subject," "),r(2),H("",e.author," \xB7 ",k(10,9,e.date,0,10)," \xB7 ",e.churn," lines")}}function Me(t,o){if(t&1&&(i(0,"ul",58),m(1,ke,11,13,"li",59),n()),t&2){let e=d().ngIf;r(),s("ngForOf",e.fixCommits)}}function Oe(t,o){if(t&1){let e=h();i(0,"li",66),f("click",function(){let p=v(e).$implicit,_=d(4);return x(_.openFile(p.file))}),i(1,"span",67),a(2),n(),i(3,"span",68),a(4),n()()}if(t&2){let e=o.$implicit;r(2),c(e.file),r(2),u("",e.count,"\xD7")}}function Pe(t,o){if(t&1&&(i(0,"article",37)(1,"header",38)(2,"h3"),a(3,"Often changed together"),n(),i(4,"span",39),a(5,"From recent fixes & suspects"),n()(),i(6,"ul",64),m(7,Oe,5,2,"li",65),n()()),t&2){let e=d().ngIf;r(7),s("ngForOf",e.coChangedFiles)}}function Se(t,o){t&1&&(i(0,"span",63),a(1,"fix"),n())}function Ie(t,o){t&1&&(i(0,"span",62),a(1,"revert"),n())}function we(t,o){if(t&1){let e=h();i(0,"li",19),f("click",function(){let p=v(e).$implicit,_=d(3);return x(_.onSelectCommit(p.hash))}),i(1,"code",20),a(2),n(),i(3,"div",21)(4,"span",22),m(5,Se,2,0,"span",61)(6,Ie,2,0,"span",60),a(7),n(),i(8,"span",23),a(9),y(10,"slice"),n()()()}if(t&2){let e=o.$implicit;b("is-fix",e.isFix||e.isRevert),r(2),c(e.shortHash),r(3),s("ngIf",e.isFix),r(),s("ngIf",e.isRevert),r(),u(" ",e.subject," "),r(2),$("",e.author," \xB7 ",k(10,10,e.date,0,10)," \xB7 +",e.additions,"/-",e.deletions)}}function Ee(t,o){if(t&1&&(N(0),i(1,"div",28)(2,"div",29),B(3,"div",30),n(),i(4,"div",31)(5,"span",32),a(6),n(),i(7,"span",33),a(8),n()(),i(9,"p",34),a(10),n(),i(11,"div",35)(12,"span")(13,"strong"),a(14),n(),a(15," recent touches"),n(),i(16,"span"),a(17,"\xB7"),n(),i(18,"span")(19,"strong"),a(20),n(),a(21," fixes/reverts"),n(),m(22,de,2,0,"span",27)(23,pe,4,2,"span",27),n()(),i(24,"div",36)(25,"article",37)(26,"header",38)(27,"h3"),a(28,"Likely culprits"),n(),i(29,"span",39),a(30,"Scored by proximity to fix commits"),n()(),m(31,ge,2,0,"div",40)(32,he,2,1,"ol",41),n(),i(33,"article",37)(34,"header",38)(35,"h3"),a(36,"Fixes & reverts on this file"),n(),i(37,"span",39),a(38),n()(),m(39,be,2,0,"div",40)(40,Me,2,1,"ul",42),n(),m(41,Pe,8,1,"article",43),i(42,"article",37)(43,"header",38)(44,"h3"),a(45,"Recent commits"),n(),i(46,"span",39),a(47),n()(),i(48,"ul",44),m(49,we,11,14,"li",45),n()()(),L()),t&2){let e=o.ngIf,l=d(2);r(),F("data-level",l.riskLevel()),r(2),V("width",e.riskScore,"%"),r(3),u("",e.riskScore,"/100"),r(2),u("",l.riskLevel()," breakage risk"),r(2),c(e.summary),r(4),c(e.commits.length),r(6),c(e.fixCount),r(2),s("ngIf",e.suspects.length),r(),s("ngIf",e.suspects.length),r(8),s("ngIf",!e.suspects.length),r(),s("ngIf",e.suspects.length),r(6),T("",e.fixCount," of ",e.commits.length," recent commits"),r(),s("ngIf",!e.fixCommits.length),r(),s("ngIf",e.fixCommits.length),r(),s("ngIf",e.coChangedFiles.length),r(6),u("Last ",e.commits.length," touches"),r(2),s("ngForOf",e.commits)}}function Fe(t,o){if(t&1&&(i(0,"section",26),m(1,ce,2,0,"div",13)(2,me,2,1,"div",14)(3,Ee,50,19,"ng-container",27),n()),t&2){let e=d();r(),s("ngIf",e.breakageLoading()),r(),s("ngIf",e.breakageError()),r(),s("ngIf",e.breakage())}}var J=class t{route=C(A);router=C(q);git=C(w);insightsApi=C(U);state=C(G);filePath=g("");stats=g(null);commits=g([]);loading=g(!1);error=g(null);tab=g("history");breakage=g(null);breakageLoading=g(!1);breakageError=g(null);riskLevel=O(()=>{let o=this.breakage()?.riskScore??0;return o>=60?"high":o>=30?"moderate":"low"});constructor(){R(()=>{let o=this.route.snapshot.paramMap.get("path")??"",e=decodeURIComponent(o),l=this.route.snapshot.queryParamMap.get("tab");(l==="breakage"||l==="blame"||l==="history")&&this.tab.set(l),this.filePath.set(e),e&&this.load(e)})}onSelectCommit(o){this.state.selectHash(o),this.router.navigate(["/"],{queryParams:{commit:o}})}goBack(){this.router.navigate(["/"])}onSelectBreakageTab(){this.tab.set("breakage"),!this.breakage()&&!this.breakageLoading()&&this.loadBreakage(this.filePath())}openFile(o){o&&this.router.navigate(["/file",encodeURIComponent(o)])}load(o){this.loading.set(!0),this.error.set(null),this.breakage.set(null),this.breakageError.set(null),this.insightsApi.fileStats(o).subscribe({next:e=>this.stats.set(e),error:()=>this.stats.set(null)}),this.git.getCommits({file:o,page:1,pageSize:200}).subscribe({next:e=>{this.commits.set(e.commits),this.loading.set(!1)},error:e=>{this.error.set(e?.error?.error??"Failed to load file history"),this.loading.set(!1)}}),this.tab()==="breakage"&&this.loadBreakage(o)}loadBreakage(o){o&&(this.breakageLoading.set(!0),this.breakageError.set(null),this.insightsApi.breakage(o).subscribe({next:e=>{this.breakage.set(e),this.breakageLoading.set(!1)},error:e=>{this.breakageError.set(e?.error?.error??"Failed to analyze breakage"),this.breakageLoading.set(!1)}}))}static \u0275fac=function(e){return new(e||t)};static \u0275cmp=M({type:t,selectors:[["app-file-history"]],decls:18,vars:11,consts:[[1,"page"],[1,"head"],[1,"btn","btn-ghost",3,"click"],[1,"title-block"],["class","meta",4,"ngIf"],[1,"tabs"],[1,"tab",3,"click"],["title","Heuristic analysis of recent fixes/reverts and likely culprits.",1,"tab",3,"click"],["class","history",4,"ngIf"],["class","blame-tab",4,"ngIf"],["class","breakage","data-testid","breakage-tab",4,"ngIf"],[1,"meta"],[1,"history"],["class","empty",4,"ngIf"],["class","empty error",4,"ngIf"],[1,"commits"],["class","commit",3,"selected","click",4,"ngFor","ngForOf"],[1,"empty"],[1,"empty","error"],[1,"commit",3,"click"],[1,"hash"],[1,"info"],[1,"subject"],[1,"byline"],[1,"blame-tab"],[3,"file","onCommitClick"],["data-testid","breakage-tab",1,"breakage"],[4,"ngIf"],[1,"risk-card"],["aria-hidden","true",1,"risk-meter"],[1,"risk-meter-fill"],[1,"risk-meta"],[1,"risk-score"],[1,"risk-label"],[1,"summary"],[1,"risk-stats"],[1,"cards"],[1,"card"],[1,"card-head"],[1,"hint"],["class","empty inline",4,"ngIf"],["class","suspects",4,"ngIf"],["class","fixes",4,"ngIf"],["class","card",4,"ngIf"],[1,"recent"],["class","commit",3,"is-fix","click",4,"ngFor","ngForOf"],[1,"empty","inline"],[1,"suspects"],["class","suspect",3,"click",4,"ngFor","ngForOf"],[1,"suspect",3,"click"],[1,"suspect-row"],[1,"score"],[1,"reasons"],[4,"ngFor","ngForOf"],["class","linked",4,"ngIf"],[1,"linked"],["class","link",3,"click",4,"ngFor","ngForOf"],[1,"link",3,"click"],[1,"fixes"],["class","commit",3,"revert","click",4,"ngFor","ngForOf"],["class","tag",4,"ngIf"],["class","tag fix",4,"ngIf"],[1,"tag"],[1,"tag","fix"],[1,"cochanged"],[3,"click",4,"ngFor","ngForOf"],[3,"click"],[1,"path"],[1,"count"]],template:function(e,l){e&1&&(i(0,"div",0)(1,"header",1)(2,"button",2),f("click",function(){return l.goBack()}),a(3,"\u2190 Back"),n(),i(4,"div",3)(5,"h2"),a(6),n(),m(7,ie,17,12,"div",4),n()(),i(8,"nav",5)(9,"button",6),f("click",function(){return l.tab.set("history")}),a(10," History "),n(),i(11,"button",6),f("click",function(){return l.tab.set("blame")}),a(12," Blame "),n(),i(13,"button",7),f("click",function(){return l.onSelectBreakageTab()}),a(14," Breakage Analysis "),n()(),m(15,le,5,3,"section",8)(16,se,2,2,"section",9)(17,Fe,4,3,"section",10),n()),e&2&&(r(6),c(l.filePath()),r(),s("ngIf",l.stats()),r(2),b("active",l.tab()==="history"),r(2),b("active",l.tab()==="blame"),r(2),b("active",l.tab()==="breakage"),r(2),s("ngIf",l.tab()==="history"),r(),s("ngIf",l.tab()==="blame"),r(),s("ngIf",l.tab()==="breakage"))},dependencies:[I,P,S,E,j],styles:["[_nghost-%COMP%]{display:block;flex:1;min-height:0;overflow-y:auto}.page[_ngcontent-%COMP%]{padding:1.1rem 1.25rem;max-width:1200px;margin:0 auto}.head[_ngcontent-%COMP%]{display:flex;align-items:center;gap:1rem;margin-bottom:1rem;padding:.9rem 1rem;background:var(--bg-panel);border:1px solid var(--border-soft);border-radius:var(--radius-lg);box-shadow:var(--shadow-sm)}.head[_ngcontent-%COMP%] h2[_ngcontent-%COMP%]{margin:0;font-size:16px;font-family:var(--font-mono, monospace);word-break:break-all}.meta[_ngcontent-%COMP%]{color:var(--fg-muted);font-size:12px;display:flex;gap:.4rem;flex-wrap:wrap;margin-top:.25rem}.tabs[_ngcontent-%COMP%]{display:flex;gap:.5rem;padding:.25rem;border:1px solid var(--border-soft);border-radius:999px;background:var(--bg-panel);margin-bottom:1rem;width:fit-content}.tab[_ngcontent-%COMP%]{background:transparent;border:0;padding:.5rem .75rem;cursor:pointer;color:var(--fg-muted);border-radius:999px;font-size:13px}.tab.active[_ngcontent-%COMP%]{color:var(--accent);background:var(--accent-soft);font-weight:600}.empty[_ngcontent-%COMP%]{padding:1.5rem;color:var(--fg-muted);text-align:center;font-size:13px}.empty.error[_ngcontent-%COMP%]{color:var(--danger)}.commits[_ngcontent-%COMP%]{list-style:none;margin:0;padding:.35rem;background:var(--bg-panel);border:1px solid var(--border-soft);border-radius:var(--radius-lg);box-shadow:var(--shadow-sm)}.commit[_ngcontent-%COMP%]{display:flex;gap:.75rem;align-items:flex-start;padding:.55rem .85rem;border-radius:var(--radius-md);cursor:pointer}.commit[_ngcontent-%COMP%]:hover{background:var(--bg-elevated)}.commit.selected[_ngcontent-%COMP%]{background:color-mix(in oklab,var(--accent) 18%,transparent)}.commit[_ngcontent-%COMP%] .hash[_ngcontent-%COMP%]{font-family:var(--font-mono, monospace);font-size:11px;color:var(--fg-muted);padding-top:2px}.commit[_ngcontent-%COMP%] .info[_ngcontent-%COMP%]{display:flex;flex-direction:column;min-width:0}.commit[_ngcontent-%COMP%] .subject[_ngcontent-%COMP%]{font-size:13px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.commit[_ngcontent-%COMP%] .byline[_ngcontent-%COMP%]{font-size:11px;color:var(--fg-muted);margin-top:2px}.breakage[_ngcontent-%COMP%]{display:flex;flex-direction:column;gap:1rem}.risk-card[_ngcontent-%COMP%]{padding:1rem 1.1rem;border:1px solid var(--border-soft);border-radius:var(--radius-lg);background:var(--bg-panel);box-shadow:var(--shadow-sm);display:flex;flex-direction:column;gap:.55rem}.risk-meter[_ngcontent-%COMP%]{width:100%;height:8px;background:var(--bg-elevated);border-radius:999px;overflow:hidden}.risk-meter-fill[_ngcontent-%COMP%]{height:100%;background:var(--accent);transition:width .3s ease}.risk-card[data-level=high][_ngcontent-%COMP%] .risk-meter-fill[_ngcontent-%COMP%]{background:var(--danger, #dc2626)}.risk-card[data-level=moderate][_ngcontent-%COMP%] .risk-meter-fill[_ngcontent-%COMP%]{background:var(--warning, #d97706)}.risk-card[data-level=low][_ngcontent-%COMP%] .risk-meter-fill[_ngcontent-%COMP%]{background:var(--success, #16a34a)}.risk-meta[_ngcontent-%COMP%]{display:flex;gap:.6rem;align-items:baseline;font-size:13px}.risk-score[_ngcontent-%COMP%]{font-weight:700;font-family:var(--font-mono, monospace)}.risk-label[_ngcontent-%COMP%]{color:var(--fg-muted);text-transform:capitalize}.summary[_ngcontent-%COMP%]{margin:0;font-size:13px;line-height:1.5}.risk-stats[_ngcontent-%COMP%]{display:flex;gap:.4rem;flex-wrap:wrap;font-size:12px;color:var(--fg-muted)}.risk-stats[_ngcontent-%COMP%] strong[_ngcontent-%COMP%]{color:var(--fg);font-weight:600}.cards[_ngcontent-%COMP%]{display:grid;grid-template-columns:repeat(auto-fit,minmax(360px,1fr));gap:1rem}.card[_ngcontent-%COMP%]{background:var(--bg-panel);border:1px solid var(--border-soft);border-radius:var(--radius-lg);box-shadow:var(--shadow-sm);padding:.85rem;display:flex;flex-direction:column;gap:.6rem;min-width:0}.card-head[_ngcontent-%COMP%]{display:flex;justify-content:space-between;align-items:baseline;gap:.5rem}.card-head[_ngcontent-%COMP%] h3[_ngcontent-%COMP%]{margin:0;font-size:13px;font-weight:600}.hint[_ngcontent-%COMP%]{font-size:11px;color:var(--fg-muted)}.empty.inline[_ngcontent-%COMP%]{padding:.75rem;font-size:12px}.suspects[_ngcontent-%COMP%], .fixes[_ngcontent-%COMP%], .recent[_ngcontent-%COMP%], .cochanged[_ngcontent-%COMP%]{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:.4rem}.suspect[_ngcontent-%COMP%]{padding:.55rem .7rem;border:1px solid var(--border-soft);border-radius:var(--radius-md);cursor:pointer;background:var(--bg-elevated)}.suspect[_ngcontent-%COMP%]:hover{border-color:var(--accent)}.suspect-row[_ngcontent-%COMP%]{display:flex;align-items:center;gap:.5rem;min-width:0}.suspect-row[_ngcontent-%COMP%] .subject[_ngcontent-%COMP%]{font-size:13px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;flex:1}.score[_ngcontent-%COMP%]{font-family:var(--font-mono, monospace);font-size:11px;padding:1px 6px;border-radius:999px;background:var(--accent-soft);color:var(--accent);font-weight:700}.score[data-strong=true][_ngcontent-%COMP%]{background:color-mix(in oklab,var(--danger, #dc2626) 18%,transparent);color:var(--danger, #dc2626)}.reasons[_ngcontent-%COMP%]{list-style:none;margin:.35rem 0 0;padding:0;display:flex;flex-wrap:wrap;gap:.3rem}.reasons[_ngcontent-%COMP%] li[_ngcontent-%COMP%]{font-size:11px;color:var(--fg-muted);padding:1px 6px;border-radius:6px;background:var(--bg-panel);border:1px solid var(--border-soft)}.linked[_ngcontent-%COMP%]{margin-top:.35rem;font-size:11px;color:var(--fg-muted)}.linked[_ngcontent-%COMP%] .link[_ngcontent-%COMP%]{cursor:pointer;color:var(--accent)}.linked[_ngcontent-%COMP%] code[_ngcontent-%COMP%]{font-family:var(--font-mono, monospace)}.tag[_ngcontent-%COMP%]{display:inline-block;font-size:10px;text-transform:uppercase;letter-spacing:.04em;padding:1px 5px;border-radius:4px;background:var(--bg-elevated);color:var(--fg-muted);margin-right:.25rem;vertical-align:middle}.tag.fix[_ngcontent-%COMP%]{background:color-mix(in oklab,var(--accent) 18%,transparent);color:var(--accent)}.commit.revert[_ngcontent-%COMP%] .tag[_ngcontent-%COMP%], .commit.is-fix[_ngcontent-%COMP%] .tag.fix[_ngcontent-%COMP%]{font-weight:600}.cochanged[_ngcontent-%COMP%] li[_ngcontent-%COMP%]{display:flex;justify-content:space-between;gap:.5rem;padding:.4rem .6rem;border-radius:var(--radius-md);cursor:pointer;font-size:12px}.cochanged[_ngcontent-%COMP%] li[_ngcontent-%COMP%]:hover{background:var(--bg-elevated)}.cochanged[_ngcontent-%COMP%] .path[_ngcontent-%COMP%]{font-family:var(--font-mono, monospace);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;min-width:0}.cochanged[_ngcontent-%COMP%] .count[_ngcontent-%COMP%]{color:var(--fg-muted);flex-shrink:0}"],changeDetection:0})};export{J as FileHistoryComponent};
|
|
1
|
+
import{a as G}from"./chunk-VDZMKPJL.js";import{c as A,e as q}from"./chunk-Q72JIHF2.js";import{a as w}from"./chunk-5ISCQDR6.js";import{a as U}from"./chunk-5K2HNBK3.js";import{$a as M,$b as k,Ab as f,Bb as d,Jb as V,Kb as b,Mb as a,Nb as c,Ob as u,Pb as T,Qb as H,Rb as $,Sa as r,Yb as y,a as D,aa as C,b as z,eb as m,ec as O,fa as v,fc as R,ga as x,nb as F,pa as g,qb as s,rb as i,rc as P,sb as n,sc as S,tb as B,uc as j,vc as I,xb as N,yb as L,zb as h}from"./chunk-MTI6UKQ3.js";function Y(t,o){t&1&&(i(0,"div",3),a(1,"Loading blame\u2026"),n())}function Z(t,o){if(t&1&&(i(0,"div",4),a(1),n()),t&2){let e=o.ngIf;r(),c(e)}}function ee(t,o){t&1&&(i(0,"div",3),a(1," No blame data (file may be binary or freshly created). "),n())}function te(t,o){if(t&1){let e=h();i(0,"div",7)(1,"div",8)(2,"code",9),f("click",function(){let p=v(e).$implicit,_=d(2);return x(_.onSelectCommit(p.hash))}),a(3),n(),i(4,"span",10),a(5),n(),i(6,"span",11),a(7),n()(),i(8,"span",12),a(9),n(),i(10,"pre",13),a(11),n()()}if(t&2){let e=o.$implicit,l=d(2);r(),b("invisible",!e.isFirstOfBlock),r(2),c(e.hash.slice(0,7)),r(2),c(e.author),r(2),c(l.shortDate(e.date)),r(2),c(e.line),r(2),c(e.content)}}function ne(t,o){if(t&1&&(i(0,"div",5),m(1,te,12,7,"div",6),n()),t&2){let e=d();r(),s("ngForOf",e.rows())("ngForTrackBy",e.trackByLine)}}var E=class t{gitService=C(w);set file(o){this._file=o,o?this.load(o):this.lines.set([])}get file(){return this._file}_file=null;onCommitClick=null;lines=g([]);loading=g(!1);error=g(null);rows=O(()=>{let o=[],e="";for(let l of this.lines())o.push(z(D({},l),{isFirstOfBlock:l.hash!==e})),e=l.hash;return o});trackByLine(o,e){return e.line}shortDate(o){return(o||"").slice(0,10)}onSelectCommit(o){this.onCommitClick&&this.onCommitClick(o)}load(o){this.loading.set(!0),this.error.set(null),this.gitService.getBlame(o).subscribe({next:e=>{this.lines.set(e),this.loading.set(!1)},error:e=>{this.error.set(e?.error?.error??"Failed to load blame"),this.loading.set(!1)}})}static \u0275fac=function(e){return new(e||t)};static \u0275cmp=M({type:t,selectors:[["app-blame"]],inputs:{file:"file",onCommitClick:"onCommitClick"},decls:4,vars:4,consts:[["class","empty",4,"ngIf"],["class","empty error",4,"ngIf"],["class","blame",4,"ngIf"],[1,"empty"],[1,"empty","error"],[1,"blame"],["class","row",4,"ngFor","ngForOf","ngForTrackBy"],[1,"row"],[1,"meta"],[1,"hash",3,"click"],[1,"author"],[1,"date"],[1,"line-no"],[1,"code"]],template:function(e,l){e&1&&m(0,Y,2,0,"div",0)(1,Z,2,1,"div",1)(2,ee,2,0,"div",0)(3,ne,2,2,"div",2),e&2&&(s("ngIf",l.loading()),r(),s("ngIf",l.error()),r(),s("ngIf",!l.loading()&&!l.error()&&l.rows().length===0&&l.file),r(),s("ngIf",l.rows().length>0))},dependencies:[I,P,S],styles:["[_nghost-%COMP%]{display:block;font-family:var(--font-mono, monospace);font-size:12.5px}.empty[_ngcontent-%COMP%]{padding:1.5rem;color:var(--fg-muted);text-align:center}.empty.error[_ngcontent-%COMP%]{color:var(--danger)}.blame[_ngcontent-%COMP%]{display:block;background:var(--bg-surface);border:1px solid var(--border-soft);border-radius:var(--radius-md);overflow:auto;max-height:70vh}.row[_ngcontent-%COMP%]{display:grid;grid-template-columns:220px 50px 1fr;align-items:center;gap:.5rem;padding:0 .5rem;border-bottom:1px solid color-mix(in oklab,var(--border-soft) 50%,transparent)}.row[_ngcontent-%COMP%]:hover{background:var(--bg-elevated)}.meta[_ngcontent-%COMP%]{display:flex;gap:.5rem;align-items:center;font-size:11px;color:var(--fg-muted);padding:.15rem 0;border-right:1px solid var(--border-soft)}.meta.invisible[_ngcontent-%COMP%] > *[_ngcontent-%COMP%]{visibility:hidden}.hash[_ngcontent-%COMP%]{color:var(--accent);cursor:pointer;text-decoration:none}.hash[_ngcontent-%COMP%]:hover{text-decoration:underline}.author[_ngcontent-%COMP%]{max-width:100px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.date[_ngcontent-%COMP%]{color:var(--fg-subtle)}.line-no[_ngcontent-%COMP%]{color:var(--fg-subtle);text-align:right;font-variant-numeric:tabular-nums;font-size:11px}.code[_ngcontent-%COMP%]{margin:0;padding:.15rem 0;white-space:pre;overflow-x:auto;color:var(--fg-primary)}"],changeDetection:0})};function ie(t,o){if(t&1&&(i(0,"div",11)(1,"span"),a(2),n(),i(3,"span"),a(4,"\xB7"),n(),i(5,"span"),a(6),n(),i(7,"span"),a(8,"\xB7"),n(),i(9,"span"),a(10),y(11,"slice"),n(),i(12,"span"),a(13,"\xB7"),n(),i(14,"span"),a(15),y(16,"slice"),n()()),t&2){let e=o.ngIf;r(2),u("",e.totalCommits," commits"),r(4),u("",e.contributors.length," contributors"),r(4),u("first: ",k(11,4,e.firstSeen,0,10)),r(5),u("last: ",k(16,8,e.lastTouched,0,10))}}function oe(t,o){t&1&&(i(0,"div",17),a(1,"Loading commits\u2026"),n())}function re(t,o){if(t&1&&(i(0,"div",18),a(1),n()),t&2){let e=o.ngIf;r(),c(e)}}function ae(t,o){if(t&1){let e=h();i(0,"li",19),f("click",function(){let p=v(e).$implicit,_=d(2);return x(_.onSelectCommit(p.hash))}),i(1,"code",20),a(2),n(),i(3,"div",21)(4,"span",22),a(5),n(),i(6,"span",23),a(7),y(8,"slice"),n()()()}if(t&2){let e=o.$implicit,l=d(2);b("selected",e.hash===l.state.selectedHash()),r(2),c(e.shortHash),r(3),c(e.subject),r(2),T("",e.author," \xB7 ",k(8,6,e.date,0,10))}}function le(t,o){if(t&1&&(i(0,"section",12),m(1,oe,2,0,"div",13)(2,re,2,1,"div",14),i(3,"ul",15),m(4,ae,9,10,"li",16),n()()),t&2){let e=d();r(),s("ngIf",e.loading()),r(),s("ngIf",e.error()),r(2),s("ngForOf",e.commits())}}function se(t,o){if(t&1&&(i(0,"section",24),B(1,"app-blame",25),n()),t&2){let e=d();r(),s("file",e.filePath())("onCommitClick",e.onSelectCommit.bind(e))}}function ce(t,o){t&1&&(i(0,"div",17),a(1,"Analyzing breakage history\u2026"),n())}function me(t,o){if(t&1&&(i(0,"div",18),a(1),n()),t&2){let e=o.ngIf;r(),c(e)}}function de(t,o){t&1&&(i(0,"span"),a(1,"\xB7"),n())}function pe(t,o){if(t&1&&(i(0,"span")(1,"strong"),a(2),n(),a(3),n()),t&2){let e=d().ngIf;r(2),c(e.suspects.length),r(),u(" suspect",e.suspects.length===1?"":"s")}}function ge(t,o){t&1&&(i(0,"div",46),a(1," No prior change is strongly correlated with a recent fix. "),n())}function _e(t,o){if(t&1&&(i(0,"li"),a(1),n()),t&2){let e=o.$implicit;r(),c(e)}}function fe(t,o){t&1&&(i(0,"span"),a(1,", "),n())}function ue(t,o){if(t&1){let e=h();i(0,"a",57),f("click",function(p){let _=v(e).$implicit,K=d(6);return p.stopPropagation(),x(K.onSelectCommit(_.hash))}),i(1,"code"),a(2),n(),m(3,fe,2,0,"span",27),n()}if(t&2){let e=o.$implicit,l=o.last;r(2),c(e.shortHash),r(),s("ngIf",!l)}}function ve(t,o){if(t&1&&(i(0,"div",55),a(1),m(2,ue,4,2,"a",56),n()),t&2){let e=d().$implicit;r(),u(" Linked fix",e.linkedFixes.length===1?"":"es",": "),r(),s("ngForOf",e.linkedFixes)}}function xe(t,o){if(t&1){let e=h();i(0,"li",49),f("click",function(){let p=v(e).$implicit,_=d(4);return x(_.onSelectCommit(p.hash))}),i(1,"div",50)(2,"code",20),a(3),n(),i(4,"span",51),a(5),n(),i(6,"span",22),a(7),n()(),i(8,"div",23),a(9),y(10,"slice"),n(),i(11,"ul",52),m(12,_e,2,1,"li",53),n(),m(13,ve,3,2,"div",54),n()}if(t&2){let e=o.$implicit;r(3),c(e.shortHash),r(),F("data-strong",e.score>=8?"true":"false"),r(),c(e.score),r(2),c(e.subject),r(2),H(" ",e.author," \xB7 ",k(10,9,e.date,0,10)," \xB7 ",e.churn," lines changed "),r(3),s("ngForOf",e.reasons),r(),s("ngIf",e.linkedFixes.length)}}function he(t,o){if(t&1&&(i(0,"ol",47),m(1,xe,14,13,"li",48),n()),t&2){let e=d().ngIf;r(),s("ngForOf",e.suspects)}}function be(t,o){t&1&&(i(0,"div",46),a(1," No fix/revert commits matched recent history. "),n())}function Ce(t,o){t&1&&(i(0,"span",62),a(1,"revert"),n())}function ye(t,o){t&1&&(i(0,"span",63),a(1,"fix"),n())}function ke(t,o){if(t&1){let e=h();i(0,"li",19),f("click",function(){let p=v(e).$implicit,_=d(4);return x(_.onSelectCommit(p.hash))}),i(1,"code",20),a(2),n(),i(3,"div",21)(4,"span",22),m(5,Ce,2,0,"span",60)(6,ye,2,0,"span",61),a(7),n(),i(8,"span",23),a(9),y(10,"slice"),n()()()}if(t&2){let e=o.$implicit;b("revert",e.isRevert),r(2),c(e.shortHash),r(3),s("ngIf",e.isRevert),r(),s("ngIf",e.isFix),r(),u(" ",e.subject," "),r(2),H("",e.author," \xB7 ",k(10,9,e.date,0,10)," \xB7 ",e.churn," lines")}}function Me(t,o){if(t&1&&(i(0,"ul",58),m(1,ke,11,13,"li",59),n()),t&2){let e=d().ngIf;r(),s("ngForOf",e.fixCommits)}}function Oe(t,o){if(t&1){let e=h();i(0,"li",66),f("click",function(){let p=v(e).$implicit,_=d(4);return x(_.openFile(p.file))}),i(1,"span",67),a(2),n(),i(3,"span",68),a(4),n()()}if(t&2){let e=o.$implicit;r(2),c(e.file),r(2),u("",e.count,"\xD7")}}function Pe(t,o){if(t&1&&(i(0,"article",37)(1,"header",38)(2,"h3"),a(3,"Often changed together"),n(),i(4,"span",39),a(5,"From recent fixes & suspects"),n()(),i(6,"ul",64),m(7,Oe,5,2,"li",65),n()()),t&2){let e=d().ngIf;r(7),s("ngForOf",e.coChangedFiles)}}function Se(t,o){t&1&&(i(0,"span",63),a(1,"fix"),n())}function Ie(t,o){t&1&&(i(0,"span",62),a(1,"revert"),n())}function we(t,o){if(t&1){let e=h();i(0,"li",19),f("click",function(){let p=v(e).$implicit,_=d(3);return x(_.onSelectCommit(p.hash))}),i(1,"code",20),a(2),n(),i(3,"div",21)(4,"span",22),m(5,Se,2,0,"span",61)(6,Ie,2,0,"span",60),a(7),n(),i(8,"span",23),a(9),y(10,"slice"),n()()()}if(t&2){let e=o.$implicit;b("is-fix",e.isFix||e.isRevert),r(2),c(e.shortHash),r(3),s("ngIf",e.isFix),r(),s("ngIf",e.isRevert),r(),u(" ",e.subject," "),r(2),$("",e.author," \xB7 ",k(10,10,e.date,0,10)," \xB7 +",e.additions,"/-",e.deletions)}}function Ee(t,o){if(t&1&&(N(0),i(1,"div",28)(2,"div",29),B(3,"div",30),n(),i(4,"div",31)(5,"span",32),a(6),n(),i(7,"span",33),a(8),n()(),i(9,"p",34),a(10),n(),i(11,"div",35)(12,"span")(13,"strong"),a(14),n(),a(15," recent touches"),n(),i(16,"span"),a(17,"\xB7"),n(),i(18,"span")(19,"strong"),a(20),n(),a(21," fixes/reverts"),n(),m(22,de,2,0,"span",27)(23,pe,4,2,"span",27),n()(),i(24,"div",36)(25,"article",37)(26,"header",38)(27,"h3"),a(28,"Likely culprits"),n(),i(29,"span",39),a(30,"Scored by proximity to fix commits"),n()(),m(31,ge,2,0,"div",40)(32,he,2,1,"ol",41),n(),i(33,"article",37)(34,"header",38)(35,"h3"),a(36,"Fixes & reverts on this file"),n(),i(37,"span",39),a(38),n()(),m(39,be,2,0,"div",40)(40,Me,2,1,"ul",42),n(),m(41,Pe,8,1,"article",43),i(42,"article",37)(43,"header",38)(44,"h3"),a(45,"Recent commits"),n(),i(46,"span",39),a(47),n()(),i(48,"ul",44),m(49,we,11,14,"li",45),n()()(),L()),t&2){let e=o.ngIf,l=d(2);r(),F("data-level",l.riskLevel()),r(2),V("width",e.riskScore,"%"),r(3),u("",e.riskScore,"/100"),r(2),u("",l.riskLevel()," breakage risk"),r(2),c(e.summary),r(4),c(e.commits.length),r(6),c(e.fixCount),r(2),s("ngIf",e.suspects.length),r(),s("ngIf",e.suspects.length),r(8),s("ngIf",!e.suspects.length),r(),s("ngIf",e.suspects.length),r(6),T("",e.fixCount," of ",e.commits.length," recent commits"),r(),s("ngIf",!e.fixCommits.length),r(),s("ngIf",e.fixCommits.length),r(),s("ngIf",e.coChangedFiles.length),r(6),u("Last ",e.commits.length," touches"),r(2),s("ngForOf",e.commits)}}function Fe(t,o){if(t&1&&(i(0,"section",26),m(1,ce,2,0,"div",13)(2,me,2,1,"div",14)(3,Ee,50,19,"ng-container",27),n()),t&2){let e=d();r(),s("ngIf",e.breakageLoading()),r(),s("ngIf",e.breakageError()),r(),s("ngIf",e.breakage())}}var J=class t{route=C(A);router=C(q);git=C(w);insightsApi=C(U);state=C(G);filePath=g("");stats=g(null);commits=g([]);loading=g(!1);error=g(null);tab=g("history");breakage=g(null);breakageLoading=g(!1);breakageError=g(null);riskLevel=O(()=>{let o=this.breakage()?.riskScore??0;return o>=60?"high":o>=30?"moderate":"low"});constructor(){R(()=>{let o=this.route.snapshot.paramMap.get("path")??"",e=decodeURIComponent(o),l=this.route.snapshot.queryParamMap.get("tab");(l==="breakage"||l==="blame"||l==="history")&&this.tab.set(l),this.filePath.set(e),e&&this.load(e)})}onSelectCommit(o){this.state.selectHash(o),this.router.navigate(["/"],{queryParams:{commit:o}})}goBack(){this.router.navigate(["/"])}onSelectBreakageTab(){this.tab.set("breakage"),!this.breakage()&&!this.breakageLoading()&&this.loadBreakage(this.filePath())}openFile(o){o&&this.router.navigate(["/file",encodeURIComponent(o)])}load(o){this.loading.set(!0),this.error.set(null),this.breakage.set(null),this.breakageError.set(null),this.insightsApi.fileStats(o).subscribe({next:e=>this.stats.set(e),error:()=>this.stats.set(null)}),this.git.getCommits({file:o,page:1,pageSize:200}).subscribe({next:e=>{this.commits.set(e.commits),this.loading.set(!1)},error:e=>{this.error.set(e?.error?.error??"Failed to load file history"),this.loading.set(!1)}}),this.tab()==="breakage"&&this.loadBreakage(o)}loadBreakage(o){o&&(this.breakageLoading.set(!0),this.breakageError.set(null),this.insightsApi.breakage(o).subscribe({next:e=>{this.breakage.set(e),this.breakageLoading.set(!1)},error:e=>{this.breakageError.set(e?.error?.error??"Failed to analyze breakage"),this.breakageLoading.set(!1)}}))}static \u0275fac=function(e){return new(e||t)};static \u0275cmp=M({type:t,selectors:[["app-file-history"]],decls:18,vars:11,consts:[[1,"page"],[1,"head"],[1,"btn","btn-ghost",3,"click"],[1,"title-block"],["class","meta",4,"ngIf"],[1,"tabs"],[1,"tab",3,"click"],["title","Heuristic analysis of recent fixes/reverts and likely culprits.",1,"tab",3,"click"],["class","history",4,"ngIf"],["class","blame-tab",4,"ngIf"],["class","breakage","data-testid","breakage-tab",4,"ngIf"],[1,"meta"],[1,"history"],["class","empty",4,"ngIf"],["class","empty error",4,"ngIf"],[1,"commits"],["class","commit",3,"selected","click",4,"ngFor","ngForOf"],[1,"empty"],[1,"empty","error"],[1,"commit",3,"click"],[1,"hash"],[1,"info"],[1,"subject"],[1,"byline"],[1,"blame-tab"],[3,"file","onCommitClick"],["data-testid","breakage-tab",1,"breakage"],[4,"ngIf"],[1,"risk-card"],["aria-hidden","true",1,"risk-meter"],[1,"risk-meter-fill"],[1,"risk-meta"],[1,"risk-score"],[1,"risk-label"],[1,"summary"],[1,"risk-stats"],[1,"cards"],[1,"card"],[1,"card-head"],[1,"hint"],["class","empty inline",4,"ngIf"],["class","suspects",4,"ngIf"],["class","fixes",4,"ngIf"],["class","card",4,"ngIf"],[1,"recent"],["class","commit",3,"is-fix","click",4,"ngFor","ngForOf"],[1,"empty","inline"],[1,"suspects"],["class","suspect",3,"click",4,"ngFor","ngForOf"],[1,"suspect",3,"click"],[1,"suspect-row"],[1,"score"],[1,"reasons"],[4,"ngFor","ngForOf"],["class","linked",4,"ngIf"],[1,"linked"],["class","link",3,"click",4,"ngFor","ngForOf"],[1,"link",3,"click"],[1,"fixes"],["class","commit",3,"revert","click",4,"ngFor","ngForOf"],["class","tag",4,"ngIf"],["class","tag fix",4,"ngIf"],[1,"tag"],[1,"tag","fix"],[1,"cochanged"],[3,"click",4,"ngFor","ngForOf"],[3,"click"],[1,"path"],[1,"count"]],template:function(e,l){e&1&&(i(0,"div",0)(1,"header",1)(2,"button",2),f("click",function(){return l.goBack()}),a(3,"\u2190 Back"),n(),i(4,"div",3)(5,"h2"),a(6),n(),m(7,ie,17,12,"div",4),n()(),i(8,"nav",5)(9,"button",6),f("click",function(){return l.tab.set("history")}),a(10," History "),n(),i(11,"button",6),f("click",function(){return l.tab.set("blame")}),a(12," Blame "),n(),i(13,"button",7),f("click",function(){return l.onSelectBreakageTab()}),a(14," Breakage Analysis "),n()(),m(15,le,5,3,"section",8)(16,se,2,2,"section",9)(17,Fe,4,3,"section",10),n()),e&2&&(r(6),c(l.filePath()),r(),s("ngIf",l.stats()),r(2),b("active",l.tab()==="history"),r(2),b("active",l.tab()==="blame"),r(2),b("active",l.tab()==="breakage"),r(2),s("ngIf",l.tab()==="history"),r(),s("ngIf",l.tab()==="blame"),r(),s("ngIf",l.tab()==="breakage"))},dependencies:[I,P,S,E,j],styles:["[_nghost-%COMP%]{display:block;flex:1;min-height:0;overflow-y:auto}.page[_ngcontent-%COMP%]{padding:1.1rem 1.25rem;max-width:1200px;margin:0 auto}.head[_ngcontent-%COMP%]{display:flex;align-items:center;gap:1rem;margin-bottom:1rem;padding:.9rem 1rem;background:var(--bg-panel);border:1px solid var(--border-soft);border-radius:var(--radius-lg);box-shadow:var(--shadow-sm)}.head[_ngcontent-%COMP%] h2[_ngcontent-%COMP%]{margin:0;font-size:16px;font-family:var(--font-mono, monospace);word-break:break-all}.meta[_ngcontent-%COMP%]{color:var(--fg-muted);font-size:12px;display:flex;gap:.4rem;flex-wrap:wrap;margin-top:.25rem}.tabs[_ngcontent-%COMP%]{display:flex;gap:.5rem;padding:.25rem;border:1px solid var(--border-soft);border-radius:999px;background:var(--bg-panel);margin-bottom:1rem;width:fit-content}.tab[_ngcontent-%COMP%]{background:transparent;border:0;padding:.5rem .75rem;cursor:pointer;color:var(--fg-muted);border-radius:999px;font-size:13px}.tab.active[_ngcontent-%COMP%]{color:var(--accent);background:var(--accent-soft);font-weight:600}.empty[_ngcontent-%COMP%]{padding:1.5rem;color:var(--fg-muted);text-align:center;font-size:13px}.empty.error[_ngcontent-%COMP%]{color:var(--danger)}.commits[_ngcontent-%COMP%]{list-style:none;margin:0;padding:.35rem;background:var(--bg-panel);border:1px solid var(--border-soft);border-radius:var(--radius-lg);box-shadow:var(--shadow-sm)}.commit[_ngcontent-%COMP%]{display:flex;gap:.75rem;align-items:flex-start;padding:.55rem .85rem;border-radius:var(--radius-md);cursor:pointer}.commit[_ngcontent-%COMP%]:hover{background:var(--bg-elevated)}.commit.selected[_ngcontent-%COMP%]{background:color-mix(in oklab,var(--accent) 18%,transparent)}.commit[_ngcontent-%COMP%] .hash[_ngcontent-%COMP%]{font-family:var(--font-mono, monospace);font-size:11px;color:var(--fg-muted);padding-top:2px}.commit[_ngcontent-%COMP%] .info[_ngcontent-%COMP%]{display:flex;flex-direction:column;min-width:0}.commit[_ngcontent-%COMP%] .subject[_ngcontent-%COMP%]{font-size:13px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.commit[_ngcontent-%COMP%] .byline[_ngcontent-%COMP%]{font-size:11px;color:var(--fg-muted);margin-top:2px}.breakage[_ngcontent-%COMP%]{display:flex;flex-direction:column;gap:1rem}.risk-card[_ngcontent-%COMP%]{padding:1rem 1.1rem;border:1px solid var(--border-soft);border-radius:var(--radius-lg);background:var(--bg-panel);box-shadow:var(--shadow-sm);display:flex;flex-direction:column;gap:.55rem}.risk-meter[_ngcontent-%COMP%]{width:100%;height:8px;background:var(--bg-elevated);border-radius:999px;overflow:hidden}.risk-meter-fill[_ngcontent-%COMP%]{height:100%;background:var(--accent);transition:width .3s ease}.risk-card[data-level=high][_ngcontent-%COMP%] .risk-meter-fill[_ngcontent-%COMP%]{background:var(--danger, #dc2626)}.risk-card[data-level=moderate][_ngcontent-%COMP%] .risk-meter-fill[_ngcontent-%COMP%]{background:var(--warning, #d97706)}.risk-card[data-level=low][_ngcontent-%COMP%] .risk-meter-fill[_ngcontent-%COMP%]{background:var(--success, #16a34a)}.risk-meta[_ngcontent-%COMP%]{display:flex;gap:.6rem;align-items:baseline;font-size:13px}.risk-score[_ngcontent-%COMP%]{font-weight:700;font-family:var(--font-mono, monospace)}.risk-label[_ngcontent-%COMP%]{color:var(--fg-muted);text-transform:capitalize}.summary[_ngcontent-%COMP%]{margin:0;font-size:13px;line-height:1.5}.risk-stats[_ngcontent-%COMP%]{display:flex;gap:.4rem;flex-wrap:wrap;font-size:12px;color:var(--fg-muted)}.risk-stats[_ngcontent-%COMP%] strong[_ngcontent-%COMP%]{color:var(--fg);font-weight:600}.cards[_ngcontent-%COMP%]{display:grid;grid-template-columns:repeat(auto-fit,minmax(360px,1fr));gap:1rem}.card[_ngcontent-%COMP%]{background:var(--bg-panel);border:1px solid var(--border-soft);border-radius:var(--radius-lg);box-shadow:var(--shadow-sm);padding:.85rem;display:flex;flex-direction:column;gap:.6rem;min-width:0}.card-head[_ngcontent-%COMP%]{display:flex;justify-content:space-between;align-items:baseline;gap:.5rem}.card-head[_ngcontent-%COMP%] h3[_ngcontent-%COMP%]{margin:0;font-size:13px;font-weight:600}.hint[_ngcontent-%COMP%]{font-size:11px;color:var(--fg-muted)}.empty.inline[_ngcontent-%COMP%]{padding:.75rem;font-size:12px}.suspects[_ngcontent-%COMP%], .fixes[_ngcontent-%COMP%], .recent[_ngcontent-%COMP%], .cochanged[_ngcontent-%COMP%]{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:.4rem}.suspect[_ngcontent-%COMP%]{padding:.55rem .7rem;border:1px solid var(--border-soft);border-radius:var(--radius-md);cursor:pointer;background:var(--bg-elevated)}.suspect[_ngcontent-%COMP%]:hover{border-color:var(--accent)}.suspect-row[_ngcontent-%COMP%]{display:flex;align-items:center;gap:.5rem;min-width:0}.suspect-row[_ngcontent-%COMP%] .subject[_ngcontent-%COMP%]{font-size:13px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;flex:1}.score[_ngcontent-%COMP%]{font-family:var(--font-mono, monospace);font-size:11px;padding:1px 6px;border-radius:999px;background:var(--accent-soft);color:var(--accent);font-weight:700}.score[data-strong=true][_ngcontent-%COMP%]{background:color-mix(in oklab,var(--danger, #dc2626) 18%,transparent);color:var(--danger, #dc2626)}.reasons[_ngcontent-%COMP%]{list-style:none;margin:.35rem 0 0;padding:0;display:flex;flex-wrap:wrap;gap:.3rem}.reasons[_ngcontent-%COMP%] li[_ngcontent-%COMP%]{font-size:11px;color:var(--fg-muted);padding:1px 6px;border-radius:6px;background:var(--bg-panel);border:1px solid var(--border-soft)}.linked[_ngcontent-%COMP%]{margin-top:.35rem;font-size:11px;color:var(--fg-muted)}.linked[_ngcontent-%COMP%] .link[_ngcontent-%COMP%]{cursor:pointer;color:var(--accent)}.linked[_ngcontent-%COMP%] code[_ngcontent-%COMP%]{font-family:var(--font-mono, monospace)}.tag[_ngcontent-%COMP%]{display:inline-block;font-size:10px;text-transform:uppercase;letter-spacing:.04em;padding:1px 5px;border-radius:4px;background:var(--bg-elevated);color:var(--fg-muted);margin-right:.25rem;vertical-align:middle}.tag.fix[_ngcontent-%COMP%]{background:color-mix(in oklab,var(--accent) 18%,transparent);color:var(--accent)}.commit.revert[_ngcontent-%COMP%] .tag[_ngcontent-%COMP%], .commit.is-fix[_ngcontent-%COMP%] .tag.fix[_ngcontent-%COMP%]{font-weight:600}.cochanged[_ngcontent-%COMP%] li[_ngcontent-%COMP%]{display:flex;justify-content:space-between;gap:.5rem;padding:.4rem .6rem;border-radius:var(--radius-md);cursor:pointer;font-size:12px}.cochanged[_ngcontent-%COMP%] li[_ngcontent-%COMP%]:hover{background:var(--bg-elevated)}.cochanged[_ngcontent-%COMP%] .path[_ngcontent-%COMP%]{font-family:var(--font-mono, monospace);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;min-width:0}.cochanged[_ngcontent-%COMP%] .count[_ngcontent-%COMP%]{color:var(--fg-muted);flex-shrink:0}"],changeDetection:0})};export{J as FileHistoryComponent};
|