1import{a as $,b as be}from"./chunk-EL4L6KN3.js";import{b as re,c as ae,d as oe,e as le,f as se,g as de,i as ce,j as me,k as pe,n as ue}from"./chunk-DPTG64K7.js";import{e as te,f as ne}from"./chunk-74MORUE4.js";import{a as ie}from"./chunk-JCVJLOON.js";import"./chunk-QJMW5YLP.js";import{$b as ee,Ba as O,Ga as Q,Gb as K,Ib as Z,Lb as N,Pb as G,Qa as P,Ra as b,Sa as g,U as x,Ua as k,V as f,Va as y,W as w,Wa as S,X as V,Xa as n,Ya as r,Za as _,Zb as X,bb as E,db as p,fa as m,fb as c,ga as j,kb as W,lb as J,nb as I,ob as D,pb as L,qb as l,ra as U,rb as u,sb as v,tb as R,ua as o,ub as q,vb as Y}from"./chunk-HHMCHBUK.js";var fe=["sourceChart"],_e=["growthChart"],B=(a,t)=>t.value,he=(a,t)=>t.provider,ve=(a,t)=>t.host,xe=(a,t)=>t.id,Se=(a,t)=>t.target;function Ce(a,t){if(a&1&&(n(0,"div",10),l(1),r()),a&2){let e=c();o(),u(e.error())}}function Ee(a,t){if(a&1&&(n(0,"div",11)(1,"div",67)(2,"div",68),l(3,"TOTAL USERS"),r(),n(4,"div",69),l(5),r()(),n(6,"div",67)(7,"div",68),l(8,"NEW (7D)"),r(),n(9,"div",70),l(10),r()(),n(11,"div",67)(12,"div",68),l(13,"PRODUCTS"),r(),n(14,"div",69),l(15),r()(),n(16,"div",67)(17,"div",68),l(18,"UNIQUE URLS"),r(),n(19,"div",69),l(20),r()(),n(21,"div",71)(22,"div",72),l(23,"ON SALE NOW"),r(),n(24,"div",73),l(25),r()()()),a&2){let e=t;o(5),u(e.total_users),o(5),v("+",e.new_users_week),o(5),u(e.total_products),o(5),u(e.unique_urls),o(5),u(e.on_sale)}}function ke(a,t){if(a&1&&(n(0,"div",67)(1,"div",74)(2,"div",17),l(3),r(),n(4,"div",34),l(5),r()(),n(6,"div",75)(7,"div",69),l(8),r(),n(9,"div",34),l(10),r()(),n(11,"div",76),_(12,"div",77),r(),n(13,"div",78),l(14),r()()),a&2){let e=t.$implicit,i=c(2);o(3),u(i.quotaLabel(e.provider)),o(2),u(i.quotaResetIn(e.reset_at)),o(2),L(i.quotaSeverityClass(e)),o(),v(" ",i.quotaPercent(e),"% "),o(2),R("used \xB7 ",e.remaining," of ",e.limit_total," left"),o(2),L(i.quotaSeverityClass(e)),I("width",i.quotaPercent(e),"%")("background","currentColor"),o(2),v("updated ",i.formatRelative(e.updated_at))}}function ye(a,t){if(a&1&&(n(0,"div",12),k(1,ke,15,14,"div",67,he),r()),a&2){let e=c();o(),y(e.quota())}}function we(a,t){a&1&&(n(0,"span",79),l(1,"attention"),r())}function Ae(a,t){a&1&&(n(0,"span",80),l(1,"healthy"),r())}function Te(a,t){if(a&1&&(n(0,"span",34),l(1),r(),b(2,we,2,0,"span",79)(3,Ae,2,0,"span",80)),a&2){let e=t;o(),v("\xB7 ",e.total_24h," in 24h"),o(),g(e.total_24h>0?2:3)}}function Me(a,t){if(a&1){let e=E();n(0,"button",81),p("click",function(){let s=x(e).$implicit,d=c();return f(d.setScrapeErrorSince(s.value))}),l(1),r()}if(a&2){let e=t.$implicit,i=c();D("seg-active",i.scrapeErrorSince()===e.value),o(),v(" ",e.label," ")}}function Ie(a,t){if(a&1&&(n(0,"option",26),l(1),r()),a&2){let e=t.$implicit;S("value",e.value),o(),u(e.label)}}function De(a,t){if(a&1){let e=E();n(0,"button",82),p("click",function(){x(e);let s=c();return f(s.clearScrapeErrorHost())}
1),l(1),n(2,"span",83),l(3,"\xD7"),r()()}if(a&2){let e=c();o(),v(" host: ",e.scrapeErrorHost()," ")}}function Fe(a,t){if(a&1){let e=E();n(0,"button",84),p("click",function(){x(e);let s=c();return f(s.deleteAllScrapeErrors())}),w(),n(1,"svg",85),_(2,"path",86),r(),l(3),r()}if(a&2){let e=c();S("disabled",e.scrapeErrorDeleting()),o(3),v(" Delete all (",e.scrapeErrorsTotal(),") ")}}function Ve(a,t){if(a&1){let e=E();n(0,"button",90),p("click",function(){let s=x(e).$implicit,d=c(3);return f(d.filterByHost(s.host))}),n(1,"span",91),l(2),r(),n(3,"span",92),l(4),r()()}if(a&2){let e=t.$implicit;o(2),u(e.host),o(2),u(e.count)}}function Ne(a,t){if(a&1&&(n(0,"div",87)(1,"div",4),l(2,"BY HOST"),r(),n(3,"div",88),k(4,Ve,5,2,"button",89,ve),r()()),a&2){let e=c();o(4),y(e.byHost)}}function Pe(a,t){a&1&&b(0,Ne,6,0,"div",87),a&2&&g(t.byHost.length>0?0:-1)}function Le(a,t){a&1&&(n(0,"div",30),_(1,"span",93),r())}function Re(a,t){a&1&&(n(0,"div",31),l(1,"No scrape errors in this window."),r())}function $e(a,t){if(a&1){let e=E();n(0,"div",94)(1,"div",100),l(2),r(),n(3,"div",33)(4,"button",101),p("click",function(){x(e);let s=c(2);return f(s.clearScrapeErrorSelection())}),l(5," Clear "),r(),n(6,"button",102),p("click",function(){x(e);let s=c(2);return f(s.deleteSelectedScrapeErrors())}),w(),n(7,"svg",85),_(8,"path",86),r(),l(9),r()()()}if(a&2){let e=c(2);o(2),v(" ",e.selectedScrapeErrorIds().size," selected "),o(4),S("disabled",e.scrapeErrorDeleting()),o(3),v(" ",e.scrapeErrorDeleting()?"Deleting\u2026":"Delete"," ")}}function Be(a,t){if(a&1&&(n(0,"tr")(1,"td",114)(2,"div",115)(3,"div",4),l(4,"FULL MESSAGE"),r(),n(5,"pre",116),l(6),r()()()()),a&2){let e=c().$implicit;o(6),u(e.message)}}function He(a,t){if(a&1){let e=E();n(0,"tr",103),p("click",function(){let s=x(e).$implicit,d=c(2);return f(d.toggleScrapeError(s.id))}),n(1,"td",104),p("click",function(s){return s.stopPropagation()}),n(2,"input",105),p("change",function(s){let d=x(e).$implicit,h=c(2);return f(h.toggleScrapeErrorSelection(d.id,s))}),r()(),n(3,"td",106),l(4),r(),n(5,"td",34),l(6),r(),n(7,"td",107)(8,"span",108),l(9),r()(),n(10,"td",109)(11,"div",110),l(12),r(),n(13,"div",111),l(14),r()(),n(15,"td",112)(16,"a",113),p("click",function(s){return s.stopPropagation()}),l(17),r()()(),b(18,Be,7,1,"tr")}if(a&2){let e=t.$implicit,i=c(2);o(2),S("checked",i.selectedScrapeErrorIds().has(e.id)),P("aria-label","Select row "+e.id),o(2),u(i.formatRelative(e.created_at)),o(2),u(e.host||"\u2014"),o(3),u(e.source||"\u2014"),o(3),u(e.error_type||"Error"),o(2),u(e.message),o(2),S("href",e.url,U),o(),u(e.url),o(),g(i.expandedScrapeErrorId()===e.id?18:-1)}}function je(a,t){if(a&1){let e=E();n(0,"div",99)(1,"div",34),l(2),r(),n(3,"div",117)(4,"button",118),p("click",function(){x(e);let s=c(2);return f(s.goToScrapeErrorPage(s.scrapeErrorPage()-1))}),w(),n(5,"svg",85),_(6,"path",119),r()(),V(),n(7,"div",120),l(8),r(),n(9,"button",121),p("click",function(){x(e);let s=c(2);return f(s.goToScrapeErrorPage(s.scrapeErrorPage()+1))}),w(),n(10,"svg",85),_(11,"path",122),r()()()()}if(a&2){let e=c(2);o(2),q(" Showing ",(e.scrapeErrorPage()-1)*e.scrapeErrorPageSize+1,"\u2013",(e.scrapeErrorPage()-1)*e.scrapeErrorPageSize+e.scrapeErrors().length," of ",e.scrapeErrorsTotal()," "),o(2),S("disabled",e.scrapeErrorPage()<=1||e.scrapeErrorsLoading()),o(4),R(" ",e.scrapeErrorPage()," / ",e.scrapeErrorTotalPages()," "),o(),S("disabled",e.scrapeErrorPage()>=e.scrapeErrorTotalPages()||e.scrapeErrorsLoading())}}function Oe(a,t){if(a&1){let e=E();b(0,$e,10,3,"div",94),n(1,"div",95)(2,"table",96)(3,"thead")(4,"tr",17)(5,"th",97)(6,"input",98),p("change",function(){x(e);let s=c();return f(s.toggleAllScrapeErrorSelection())}),r()(),n(7,"th"),l(8,"WHEN"),r(),n(9,"th"),l(10,"HOST"),r(),n(11,"th"),l(12,"SOURCE"),r(),n(13,"th"),l(14,"ERROR"),r(),n(15,"th"),l(16,"URL"),r()()(),n(17,"tbody"),k(18,He,19,10,null,null,xe),r()()(),b(20,je,12,7,"div",99)}if(a&2){let e=c();g(e.selectedScrapeErrorIds().size>0?0:-1),o(6),S("checked",e.allScrapeErrorsSelected()),o(12),y(e.scrapeErrors()),o(2),g(e.scrapeErrorTotalPages()>1?20:-1)}}function qe(a,t){if(a&1&&(n(0,"div",36),l(1),r()),a&2){let e=c();o(),u(e.broadcastError())}}function Ge(a,t){if(a&1&&(n(0,"li"),l(1),r()),a&2){let e=t.$implicit;o(),q("",e.channel," \xB7 ",e.target," \u2014 ",e.error)}}function ze(a,t){if(a&1&&(n(0,"details",123)(1,"summary",124),l(2),r(),n(3,"ul",125),k(4,Ge,2,3,"li",null,Se),r()()),a&2){let e=c();o(2),R("show ",e.errors.length," error",e.errors.length>
11?"s":""),o(2),y(e.errors)}}function Ue(a,t){if(a&1&&(n(0,"div",37),l(1),b(2,ze,6,2,"details",123),r()),a&2){let e=t;o(),Y(" Sent email ",e.sent.email,"",e.failed.email>0?" (\xB7 "+e.failed.email+" failed)":"",", Telegram ",e.sent.telegram,"",e.failed.telegram>0?" (\xB7 "+e.failed.telegram+" failed)":"",". "),o(),g(e.errors.length>0?2:-1)}}function Qe(a,t){if(a&1){let e=E();n(0,"div")(1,"label",38),l(2,"EMAIL SUBJECT"),r(),n(3,"input",126),p("ngModelChange",function(s){x(e);let d=c();return f(d.broadcastSubject.set(s))}),r()()}if(a&2){let e=c();o(3),S("ngModel",e.broadcastSubject())}}function We(a,t){a&1&&(_(0,"span",127),l(1," Sending\u2026 "))}function Je(a,t){a&1&&l(0," Send broadcast ")}function Ye(a,t){if(a&1){let e=E();n(0,"button",81),p("click",function(){let s=x(e).$implicit,d=c();return f(d.feedbackFilter.set(s.value))}),l(1),n(2,"span",128),l(3),r()()}if(a&2){let e=t.$implicit,i=c();D("seg-active",i.feedbackFilter()===e.value),o(),v(" ",e.label," "),o(2),u(i.feedbackCounts()[e.value]||0)}}function Ke(a,t){a&1&&(n(0,"div",30),_(1,"span",93),r())}function Ze(a,t){a&1&&(n(0,"div",51),l(1,"No feedback in this bucket."),r())}function Xe(a,t){if(a&1&&l(0),a&2){let e=c().$implicit;v(" \xB7 ",e.submitter_user_email||e.submitter_email," ")}}function et(a,t){if(a&1&&(n(0,"option",26),l(1),r()),a&2){let e=t.$implicit;S("value",e.value),o(),u(e.label)}}function tt(a,t){if(a&1){let e=E();n(0,"div",143)(1,"div",144)(2,"div",4),l(3,"DESCRIPTION"),r(),n(4,"p",145),l(5),r()(),n(6,"div")(7,"label",38),l(8,"ADMIN NOTES"),r(),n(9,"textarea",146),p("ngModelChange",function(s){x(e);let d=c().$implicit,h=c(2);return f(h.onFeedbackNoteInput(d.id,s))}),r(),n(10,"div",147)(11,"button",148),p("click",function(){x(e);let s=c().$implicit,d=c(2);return f(d.saveFeedbackNotes(s.id))}),l(12,"Save note"),r()()()()}if(a&2){let e=c().$implicit,i=c(2);o(5),u(e.description),o(4),S("ngModel",i.feedbackNoteValue(e))}}function nt(a,t){if(a&1){let e=E();n(0,"div",130)(1,"div",131),p("click",function(){let s=x(e).$implicit,d=c(2);return f(d.toggleFeedback(s.id))}),n(2,"div",132),l(3),r(),n(4,"div",133)(5,"div",16)(6,"span",134),l(7),r(),n(8,"span",135),l(9),r()(),n(10,"div",136),l(11),b(12,Xe,1,1),l(13),K(14,"date"),r()(),n(15,"select",137),p("ngModelChange",function(s){let d=x(e).$implicit,h=c(2);return f(h.updateFeedbackStatus(d.id,s))})("click",function(s){return s.stopPropagation()}),k(16,et,2,2,"option",26,B),r(),n(18,"span",138),l(19),r(),n(20,"button",139),p("click",function(s){let d=x(e).$implicit,h=c(2);return s.stopPropagation(),f(h.deleteFeedback(d.id))}),w(),n(21,"svg",140),_(22,"path",141),r()(),n(23,"svg",142),_(24,"path",19),r()(),b(25,tt,13,2,"div",143),r()}if(a&2){let e=t.$implicit,i=t.$index,s=c(2);D("border-t",i>0)("border-base-300",i>0),o(3),v(" ",s.initials(e.submitter_name)," "),o(4),u(e.title),o(2),u(e.category),o(2),v(" ",e.submitter_name||"Anonymous"," "),o(),g(e.submitter_user_email||e.submitter_email?12:-1),o(),v(" \xB7 ",Z(14,17,e.created_at,"MMM d, HH:mm")," "),o(2),S("ngModel",e.status),o(),y(s.feedbackStatusOptions),o(2),L(s.feedbackStatusClass(e.status)),o(),v(" ",s.feedbackStatusLabel(e.status)," "),o(4),D("rotate-180",s.expandedFeedbackId()===e.id),o(2),g(s.expandedFeedbackId()===e.id?25:-1)}}function it(a,t){if(a&1&&(n(0,"div"),k(1,nt,26,20,"div",129,xe),r()),a&2){let e=c();o(),y(e.filteredFeedback())}}$.register(...be);var ge=class a{constructor(t,e){this.api=t;this.router=e;j(()=>{let i=this.sourceChart(),s=this.sources();i&&s.length&&this.renderSourcePie(i.nativeElement,s)}),j(()=>{let i=this.growthChart(),s=this.growth();i&&s&&this.renderGrowthLine(i.nativeElement,s)})}stats=m(null);quota=m([]);sources=m([]);growth=m(null);loading=m(!0);error=m(null);feedback=m([]);feedbackLoading=m(!1);feedbackFilter=m("all");expandedFeedbackId=m(null);feedbackNoteDrafts=new Map;feedbackStatusOptions=[{value:"new",label:"New"},{value:"planned",label:"Planned"},{value:"in_progress",label:"In progress"},{value:"testing",label:"Testing"},{value:"done",label:"Done"},{value:"wont_fix",label:"Won't fix"}];feedbackFilterOptions=[{value:"all",label:"All"},{value:"new",label:"New"},{value:"planned",label:"Planned"},{value:"in_progress",label:"In progress"},{value:"testing",label:"Testing"},{value:"done",label:"Done"}];feedbackCounts=N(()=>{let t={new:0,planned:0,in_progress:0,testing:0,done:0,wont_fix:0,all:0};for(let e of this.feedback())t[e.status]=(t[e.status]||0)+1,t.all++;return t});
1filteredFeedback=N(()=>{let t=this.feedbackFilter();return t==="all"?this.feedback():this.feedback().filter(e=>e.status===t)});scrapeErrors=m([]);scrapeErrorStats=m(null);scrapeErrorsLoading=m(!1);scrapeErrorsLoaded=!1;scrapeErrorsTotal=m(0);scrapeErrorSince=m("7d");scrapeErrorHost=m("");scrapeErrorSource=m("");expandedScrapeErrorId=m(null);selectedScrapeErrorIds=m(new Set);scrapeErrorDeleting=m(!1);scrapeErrorPage=m(1);scrapeErrorPageSize=10;allScrapeErrorsSelected=N(()=>{let t=this.scrapeErrors(),e=this.selectedScrapeErrorIds();return t.length>0&&t.every(i=>e.has(i.id))});scrapeErrorTotalPages=N(()=>Math.max(1,Math.ceil(this.scrapeErrorsTotal()/this.scrapeErrorPageSize)));scrapeErrorSinceOptions=[{value:"24h",label:"Last 24h"},{value:"7d",label:"Last 7 days"},{value:"30d",label:"Last 30 days"}];scrapeErrorSourceOptions=[{value:"",label:"All sources"},{value:"cron",label:"Cron"},{value:"add",label:"Add product"},{value:"refresh",label:"Manual refresh"}];broadcastSubject=m("");broadcastBody=m("");broadcastChannelEmail=m(!0);broadcastChannelTelegram=m(!0);broadcastSending=m(!1);broadcastResult=m(null);broadcastError=m(null);showConfirm=m(!1);confirmMessage=m("");confirmCallback=null;sourceChart=G("sourceChart");growthChart=G("growthChart");sourceChartInstance=null;growthChartInstance=null;ngOnInit(){this.api.getAdminStats().subscribe({next:t=>this.stats.set(t)}),this.api.getAdminQuota().subscribe({next:t=>this.quota.set(t.rows)}),this.api.getAdminSourceBreakdown().subscribe({next:t=>this.sources.set(t)}),this.api.getAdminGrowth(30).subscribe({next:t=>this.growth.set(t)}),this.api.getAdminScrapeErrorStats(7).subscribe({next:t=>this.scrapeErrorStats.set(t)}),this.loadFeedback()}onScrapeErrorsToggle(t){t.target.open===!0&&!this.scrapeErrorsLoaded&&(this.loadScrapeErrors(),this.scrapeErrorsLoaded=!0)}loadScrapeErrors(){this.scrapeErrorsLoading.set(!0);let t=(this.scrapeErrorPage()-1)*this.scrapeErrorPageSize;this.api.getAdminScrapeErrors({limit:this.scrapeErrorPageSize,offset:t,since:this.scrapeErrorSince()||void 0,host:this.scrapeErrorHost()||void 0,source:this.scrapeErrorSource()||void 0}).subscribe({next:e=>{this.scrapeErrors.set(e.rows),this.scrapeErrorsTotal.set(e.total),this.scrapeErrorsLoading.set(!1);let i=this.scrapeErrorTotalPages();this.scrapeErrorPage()>i&&(this.scrapeErrorPage.set(i),this.loadScrapeErrors())},error:()=>this.scrapeErrorsLoading.set(!1)}),this.api.getAdminScrapeErrorStats(this.scrapeErrorSince()==="24h"?1:this.scrapeErrorSince()==="30d"?30:7).subscribe({next:e=>this.scrapeErrorStats.set(e)})}setScrapeErrorSince(t){this.scrapeErrorSince.set(t),this.scrapeErrorPage.set(1),this.loadScrapeErrors()}setScrapeErrorSource(t){this.scrapeErrorSource.set(t),this.scrapeErrorPage.set(1),this.loadScrapeErrors()}clearScrapeErrorHost(){this.scrapeErrorHost.set(""),this.scrapeErrorPage.set(1),this.loadScrapeErrors()}filterByHost(t){this.scrapeErrorHost.set(t),this.scrapeErrorPage.set(1),this.loadScrapeErrors()}goToScrapeErrorPage(t){let e=Math.max(1,Math.min(t,this.scrapeErrorTotalPages()));e!==this.scrapeErrorPage()&&(this.scrapeErrorPage.set(e),this.expandedScrapeErrorId.set(null),this.loadScrapeErrors())}toggleScrapeError(t){this.expandedScrapeErrorId.set(this.expandedScrapeErrorId()===t?null:t)}clearScrapeErrorSelection(){this.selectedScrapeErrorIds.set(new Set)}toggleScrapeErrorSelection(t,e){e.stopPropagation();let i=new Set(this.selectedScrapeErrorIds());i.has(t)?i.delete(t):i.add(t),this.selectedScrapeErrorIds.set(i)}toggleAllScrapeErrorSelection(){let t=this.scrapeErrors();this.allScrapeErrorsSelected()?this.selectedScrapeErrorIds.set(new Set):this.selectedScrapeErrorIds.set(new Set(t.map(e=>e.id)))}deleteAllScrapeErrors(){let t=this.scrapeErrorsTotal();if(t===0)return;let i=!!(this.scrapeErrorHost()||this.scrapeErrorSource()||this.scrapeErrorSince()!=="7d")?`Delete all ${t} scrape errors matching the current filter?`:`Delete all ${t} scrape errors in the last 7 days?`;this.askConfirm(i,()=>{this.scrapeErrorDeleting.set(!0),this.api.deleteAllAdminScrapeErrors({since:this.scrapeErrorSince()||void 0,host:this.scrapeErrorHost()||void 0,source:this.scrapeErrorSource()||void 0}).subscribe({next:()=>{this.selectedScrapeErrorIds.set(new Set),this.scrapeErrorPage.set(1),this.scrapeErrorDeleting.set(!1),this.loadScrapeErrors()},error:()=>this.scrapeErrorDeleting.set(!1)})})}deleteSelectedScrapeErrors(){let t=Array.from(this.selectedScrapeErrorIds());t.length!==0&&this.askConfirm(`Delete ${t.length} scrape error${t.length===1?"":"s"}?`,()=>{this.scrapeErrorDeleting.set(!0),this.api.deleteAdminScrapeErrors(t).subscribe({next:()=>{this.selectedScrapeErrorIds.set(new Set),this.scrapeErrorDeleting.set(!1),this.loadScrapeErrors()},error:()=>this.scrapeErrorDeleting.set(!1)})})}loadFeedback(){this.feedbackLoading.set(!0),this.api.getAdminFeedback().subscribe({next:t=>{this.feedback.set(t),this.feedbackLoading.set(!1)},error:()=>this.feedbackLoading.set(!1)})}toggleFeedback(t){this.expandedFeedbackId.set(this.expandedFeedbackId()===t?null:t)}updateFeedbackStatus(t,e){this.api.updateAdminFeedback(t,{status:e}).subscribe({next:i=>{this.feedback.set(this.feedback().map(s=>s.id===t?i:s))}})}saveFeedbackNotes(t){let e=this.feedbackNoteDrafts.get(t)??"";this.api.updateAdminFeedback(t,{admin_notes:e}).subscribe({next:i=>{this.feedback.set(this.feedback().map(s=>s.id===t?i:s)),this.feedbackNoteDrafts.delete(t)}})}onFeedbackNoteInput(t,e){this.feedbackNoteDrafts.set(t,e)}feedbackNoteValue(t){return this.feedbackNoteDrafts.has(t.id)?this.feedbackNoteDrafts.get(t.id):t.admin_notes||""}deleteFeedback(t){this.askConfirm("Delete this feedback? This cannot be undone.",()=>{this.api.deleteAdminFeedback(t).subscribe({next:()=>this.feedback.set(this.feedback().filter(e=>e.id!==t))})})}sendBroadcast(){let t=this.broadcastBody().trim(),e=this.broadcastSubject().trim(),i=[];if(this.broadcastChannelEmail()&&i.push("email"),this.broadcastChannelTelegram()&&i.push("telegram"),!t){this.broadcastError.set("Message body is required");return}if(i.length===0){this.broadcastError.set("Select at least one channel");return}if(i.includes("email")&&!e){this.broadcastError.set("Subject is required for email");return}let s=i.map(d=>d==="email"?"every email channel":"every Telegram chat").join(" and ");this.askConfirm(`Send this message to ${s}? This cannot be undone.`,()=>{this.broadcastSending.set(!0),this.broadcastError.set(null),this.broadcastResult.set(null),this.api.sendAdminBroadcast({body:t,subject:e||void 0,channels:i}).subscribe({next:d=>{this.broadcastSending.set(!1),this.broadcastResult.set(d),d.failed.email===0&&d.failed.telegram===0&&(this.broadcastBody.set(""),this.broadcastSubject.set(""))},error:d=>{this.broadcastSending.set(!1),this.broadcastError.set(d.error?.error||"Failed to send broadcast")}})})}askConfirm(t,e){this.confirmMessage.set(t),this.confirmCallback=e,this.showConfirm.set(!0)}confirmAccept(){this.showConfirm.set(!1),this.confirmCallback?.(),this.confirmCallback=null}confirmReject(){this.showConfirm.set(!1),this.confirmCallback=null}feedbackStatusClass(t){switch(t){case"new":return"bg-gold-soft text-gold";case"planned":return"bg-sky-soft text-sky";case"in_progress":return"bg-mint-soft text-mint";case"testing":return"bg-rose-soft text-rose";case"done":return"bg-rise-soft text-rise";case"wont_fix":return"bg-surface-alt text-ink-muted"}}feedbackStatusLabel(t){return this.feedbackStatusOptions.find(e=>e.value===t)?.label||t}initials(t){if(!t)return"?";
1let e=t.trim().split(/\s+/).filter(Boolean);return e.length===0?"?":e.length===1?e[0].charAt(0).toUpperCase():(e[0].charAt(0)+e[e.length-1].charAt(0)).toUpperCase()}readVar(t,e){try{return getComputedStyle(document.documentElement).getPropertyValue(t).trim()||e}catch{return e}}quotaLabel(t){return t==="rapidapi:real-time-amazon-data"?"RapidAPI \u2014 Amazon":t}quotaPercent(t){if(!t.limit_total||t.remaining==null)return 0;let e=t.limit_total-t.remaining;return Math.max(0,Math.min(100,Math.round(e/t.limit_total*100)))}quotaResetIn(t){if(!t)return"\u2014";let e=new Date(t).getTime()-Date.now();if(e<=0)return"resetting";let i=Math.floor(e/36e5);return i<24?`resets in ${i}h`:`resets in ${Math.floor(i/24)}d`}quotaSeverityClass(t){let e=this.quotaPercent(t);return e>=90?"text-rose":e>=70?"text-gold":"text-mint"}formatRelative(t){if(!t)return"never";let e=new Date(t),i=Date.now()-e.getTime(),s=Math.floor(i/6e4);if(s<1)return"just now";if(s<60)return`${s}m ago`;let d=Math.floor(s/60);if(d<24)return`${d}h ago`;let h=Math.floor(d/24);return h<30?`${h}d ago`:e.toLocaleDateString(void 0,{month:"short",day:"numeric"})}renderSourcePie(t,e){this.sourceChartInstance&&this.sourceChartInstance.destroy();let i=this.readVar("--pw-mint","#00c277"),s=this.readVar("--pw-gold","#d4a24a"),d=this.readVar("--pw-sky","#6b9dd0"),h=this.readVar("--pw-rose","#e87872"),A=this.readVar("--pw-ink-soft","#5b5a55"),T=this.readVar("--pw-ink-muted","#8e8d86"),F=[i,d,s,h,A,T];this.sourceChartInstance=new $(t,{type:"doughnut",data:{labels:e.map(M=>M.source),datasets:[{data:e.map(M=>M.count),backgroundColor:e.map((M,H)=>F[H%F.length]),borderWidth:0}]},options:{responsive:!0,maintainAspectRatio:!1,plugins:{legend:{position:"right",labels:{font:{size:12,family:"Geist"},padding:12,color:A}}}}})}renderGrowthLine(t,e){this.growthChartInstance&&this.growthChartInstance.destroy();let i=this.readVar("--pw-mint","#00c277"),s=this.readVar("--pw-sky","#6b9dd0"),d=this.readVar("--pw-ink-soft","#5b5a55"),h=this.readVar("--pw-ink-muted","#8e8d86"),A=this.readVar("--pw-border-soft","#efebe2"),T=[],F=new Date;for(let C=e.days-1;C>=0;C--){let z=new Date(F);z.setDate(F.getDate()-C),T.push(z.toISOString().slice(0,10))}let M=new Map(e.users.map(C=>[C.day.slice(0,10),C.count])),H=new Map(e.products.map(C=>[C.day.slice(0,10),C.count]));this.growthChartInstance=new $(t,{type:"line",data:{labels:T,datasets:[{label:"New users",data:T.map(C=>M.get(C)||0),borderColor:s,backgroundColor:`${s}22`,fill:!0,tension:.3,pointRadius:2,borderWidth:2},{label:"New products",data:T.map(C=>H.get(C)||0),borderColor:i,backgroundColor:`${i}22`,fill:!0,tension:.3,pointRadius:2,borderWidth:2}]},options:{responsive:!0,maintainAspectRatio:!1,plugins:{legend:{position:"top",align:"end",labels:{font:{size:11,family:"Geist"},color:d}}},scales:{x:{grid:{display:!1},ticks:{maxTicksLimit:10,font:{size:10,family:"JetBrains Mono"},color:h}},y:{beginAtZero:!0,grid:{color:A},ticks:{precision:0,font:{size:10,family:"JetBrains Mono"},color:h}}}}})}static \u0275fac=function(e){return new(e||a)(O(ie),O(te))};static \u0275cmp=Q({type:a,selectors:[["app-admin"]],viewQuery:function(e,i){e&1&&W(i.sourceChart,fe,5)(i.growthChart,_e,5),e&2&&J(2)},decls:122,vars:30,consts:[["growthChart",""],["sourceChart",""],[1,"container","py-12"],[1,"animate-fadeIn","mb-8"],[1,"label-caps","mb-2"],[1,"serif-display","text-[44px]","leading-[1]","mb-2"],[1,"italic","text-mint"],[1,"text-[15px]","text-ink-soft"],[1,"mt-3","flex","flex-wrap","gap-2"],["routerLink","/admin/changelog",1,"btn","btn-ghost","btn-sm","rounded-full"],[1,"mb-6","px-4","py-3","rounded-xl","bg-rose-soft","text-rose","text-sm"],[1,"grid","grid-cols-2","lg:grid-cols-5","gap-3","mb-8"],[1,"grid","grid-cols-1","md:grid-cols-2","gap-3","mb-8"],[1,"bg-base-100","rounded-2xl","border","border-base-300","overflow-hidden","mb-6"],[1,"group",3,"toggle"],[1,"px-6","py-5","cursor-pointer","list-none","flex","justify-between","items-center","bg-surface-alt"],[1,"flex","items-center","gap-2","flex-wrap"],[1,"label-caps"],["viewBox","0 0 14 14","fill","none","stroke","currentColor","stroke-width","1.8","stroke-linecap","round","stroke-linejoin","round",1,"w-4","h-4","text-ink-soft","transition-transform","group-open:rotate-180"],["d","M2 5l5 5 5-5"],[1,"p-6"],[1,"flex","flex-wrap","items-center","gap-2","mb-4"],[1,"seg"],["type","button",3,"seg-active"],[1,"relative"],[1,"appearance-none","pl-3","pr-8","py-1.5","rounded-full","bg-surface-alt","border","border-base-300","text-[12px]","font-mono","cursor-pointer",3,"ngModelChange","ngModel"],[3,"value"],["viewBox","0 0 14 14","fill","none","stroke","currentColor","stroke-width","1.8","stroke-linecap","round","stroke-linejoin","round",1,"absolute","right-3","to
1p-1/2","-translate-y-1/2","w-3","h-3","text-ink-soft","pointer-events-none"],[1,"inline-flex","items-center","gap-1","px-2.5","py-1","rounded-full","bg-rose-soft","text-rose","text-[11px]","font-mono"],["type","button",1,"ml-auto","inline-flex","items-center","gap-1.5","px-3","py-1","rounded-full","bg-rose-soft","text-rose","text-[11px]","font-mono","hover:brightness-95","disabled:opacity-50","disabled:cursor-not-allowed",3,"disabled"],[1,"text-center","py-10","text-ink-muted"],[1,"text-center","py-10","text-ink-muted","italic"],[1,"group"],[1,"flex","items-center","gap-2"],[1,"font-mono","text-[11px]","text-ink-muted"],[1,"p-6","space-y-4"],[1,"px-4","py-3","rounded-xl","bg-rose-soft","text-rose","text-[13px]"],[1,"px-4","py-3","rounded-xl","bg-mint-soft","text-mint-ink","text-[13px]"],[1,"label-caps","block","mb-2"],[1,"flex","gap-5","flex-wrap"],[1,"inline-flex","items-center","gap-2.5"],["type","button",1,"relative","shrink-0",2,"width","44px","height","24px","border-radius","999px","transition","background 200ms ease",3,"click"],[2,"position","absolute","top","2px","width","20px","height","20px","border-radius","50%","background","var(--bg-elev)","transition","left 200ms ease","box-shadow","0 1px 3px rgba(0,0,0,0.2)"],[1,"text-[13px]"],["placeholder",`<b>Heads up!</b> We just added ... 2 3Supports HTML: <b>, <i>, <u>, <a href>, <br>, <code>.`,1,"input","w-full","min-h-[140px]","resize-y","text-[13px]","font-mono",3,"ngModelChange","ngModel"],[1,"text-[11px]","text-ink-muted","mt-1","font-mono"],[1,"flex","justify-end"],[1,"btn","btn-primary","rounded-full",3,"click","disabled"],[1,"bg-base-100","rounded-2xl","border","border-base-300","overflow-hidden","mt-8"],[1,"px-6","py-4","border-b","border-base-300","flex","items-center","gap-3","bg-surface-alt","flex-wrap"],[1,"flex-1"],[1,"text-center","py-14","text-ink-muted","italic"],[1,"modal"],[1,"modal-box","w-80","rounded-[24px]","border","border-base-300","animate-popIn"],[1,"label-caps","mb-1",2,"color","var(--pw-rose)"],[1,"serif-display","text-[26px]","leading-tight"],[1,"py-3","text-sm","text-ink-soft"],[1,"modal-action"],[1,"btn","btn-ghost","rounded-full",3,"click"],[1,"btn","btn-error","rounded-full",3,"click"],["method","dialog",1,"modal-backdrop"],[3,"click"],[1,"grid","grid-cols-1","lg:grid-cols-3","gap-4","mt-8"],[1,"lg:col-span-2","p-5","rounded-2xl","bg-base-100","border","border-base-300"],[1,"label-caps","mb-4"],[1,"relative","h-64"],[1,"p-5","rounded-2xl","bg-base-100","border","border-base-300"],[1,"p-4","rounded-2xl","bg-base-100","border","border-base-300"],[1,"label-caps","mb-1.5"],[1,"serif-display","text-[32px]","leading-none"],[1,"serif-display","text-[32px]","leading-none","text-mint"],[1,"p-4","rounded-2xl","bg-rose-soft","border","border-base-300","col-span-2","lg:col-span-1"],[1,"label-caps","mb-1.5",2,"color","var(--pw-rose)"],[1,"serif-display","text-[32px]","leading-none","text-rose"],[1,"flex","items-baseline","justify-between","mb-2"],[1,"flex","items-baseline","gap-2","mb-2"],[1,"h-1.5","rounded-full","bg-surface-alt","overflow-hidden"],[1,"h-full","transition-all"],[1,"font-mono","text-[10px]","text-ink-muted","mt-2"],[1,"inline-flex","px-2","py-[2px]","rounded-md","bg-rose-soft","text-rose","text-[10px]","font-mono","font-medium"],[1,"inline-flex","px-2","py-[2px]","rounded-md","bg-mint-soft","text-mint-ink","text-[10px]","font-mono","font-medium"],["type","button",3,"click"],[1,"inline-flex","items-center","gap-1","px-2.5","py-1","rounded-full","bg-rose-soft","text-rose","text-[11px]","font-mono",3,"click"],[1,"ml-1"],["type","button",1,"ml-auto","inline-flex","items-center","gap-1.5","px-3","py-1","rounded-full","bg-rose-soft","text-rose","text-[11px]","font-mono","hover:brightness-95","disabled:opacity-50","disabled:cursor-not-allowed",3,"click","disabled"],["viewBox","0 0 14 14","fill","none","stroke","currentColor","stroke-width","1.8","stroke-linecap","round","stroke-linejoin","round",1,"w-3","h-3"],["d","M2 4h10M5 4V2.5h4V4M3.5 4l.5 8h6l.5-8M6 7v3M8 7v3"],[1,"mb-4"],[1,"flex","flex-wrap","gap-2"],[1,"inline-flex","items-center","gap-2","px-3","py-1.5","rounded-full","border","border-base-300","bg-surface-alt","hover:bg-base-200","transition-colors","text-[12px]"],[1,"inline-flex","items-center","gap-2","px-3","py-1.5","rounded-full","border","border-base-300","bg-surface-alt","hover:bg-base-200","transition-colors","text-[12px]",3,"click"],[1,"font-mono"],[1,"inline-flex","px-1.5","py-[1px]","rounded-md","text-[10px]","font-mono",2,"background","var(--drop)","color","#fff"],[1,"loading","loading-spinner","loading-md"],[1,"flex","items-center","justify-between","gap-3","mb-3","px-4","py-2.5","rounded-xl","bg-surface-alt","border","border-base-300"],[1,"overflow-x-auto"],[1,"table"],[1,"w-10"],["type","checkbox","aria-label","Select all",1,"w-4","h-4","cursor-pointer","align-middle","accent-rose-700",2,"accent-color","var(--drop)",3,"change","checked"],[1,"flex","items-center","justify-between","mt-4","gap-3"],[1,"text-[12px]","font-mono","text-ink-soft"],["type","button",1,"px-3","py-1.5","rounded-full","text-[12px]","text-ink-soft","hover:text-base-content",3,"click"],["type","button",1,"inline-flex","items-center","gap-1.5","px-4","py-1.5","rounded-full","text-[12px]","font-medium","bg-rose-soft","text-rose","hover:brightness-95","disabled:opacity-50","disabled:cursor-not-allowed",3,"click","disabled"],[1,"hover:bg-surface-alt","cursor-pointer","transition-colors",3,"click"],[1,"w-10",3,"click"],["type","checkbox",1,"w-4","h-4","cursor-pointer","align-middle",2,"accent-color","var(--drop)",3,"change","checked"],[1,"text-[12px]","text-ink-soft","whitespace-nowrap"],[1,"font-mono","text-[11px]"],[1,"inline-flex","px-2","py-[2px]","rounded-md","bg-surface-alt","text-ink-soft","text-[10px]"],[1,"text-[12px]","max-w-md"],[1,"font-mono","text-[10px]","text-ink-muted"],[1,"text-rose","truncate"],[1,"font-mono","text-[11px]","text-ink-muted","max-w-xs","truncate"],["target","_blank","rel","noopener",1,"hover:text-ink",3,"click","href"],["colspan","6",1,"bg-surface-alt"],[1,"p-4"],[1,"text-[11px]","whitespace-pre-wrap","break-words","text-ink-soft","font-mono"],[1,"flex","items-center","gap-1.5"],["type","button","aria-label","Previous page",1,"inline-flex","items-center","justify-center","w-7","h-7","rounded-full","border","border-base-300","bg-surface-alt","text-ink-soft","hover:text-base-content","disabled:opacity-40","disabled:cursor-not-allowed",3,"click","disabled"],["d","M9 2l-4 5 4 5"],[1,"font-mono","text-[11px]","text-ink-soft","px-2","min-w-[60px]","text-center"],["type","button","aria-label","Next page",1,"inline-flex","items-center","justify-center","w-7","h-7","rounded-full","border","border-base-300","bg-surface-alt","text-ink-soft","hover:text-base-content","disabled:opacity-40","disabled:cursor-not-allowed",3,"click","disabled"],["d","M5 2l4 5-4 5"],[1,"mt-2"],[1,"curs
3or-pointer","text-[11px]","font-mono","text-rose"],[1,"mt-2","space-y-1","font-mono","text-[11px]"],["type","text","placeholder","Short subject line (required for email)",1,"input","w-full","text-[14px]",3,"ngModelChange","ngModel"],[1,"loading","loading-spinner","loading-xs"],[1,"font-mono","text-[10px]","opacity-60","ml-1"],[1,"px-6","py-4",3,"border-t","border-base-300"],[1,"px-6","py-4"],[1,"flex","items-start","gap-3","cursor-pointer",3,"click"],[1,"w-9","h-9","rounded-full","shrink-0","bg-surface-alt","flex","items-center","justify-center","text-ink-soft","text-[12px]","font-semibold","uppercase","tracking-wide"],[1,"flex-1","min-w-0"],[1,"text-[14px]","font-medium"],[1,"label-caps","text-[10px]"],[1,"font-mono","text-[11px]","text-ink-muted","mt-0.5"],[1,"select","select-xs","select-bordered","rounded-md","font-ui",3,"ngModelChange","click","ngModel"],[1,"inline-flex","items-center","px-2","py-[3px]","rounded-md","text-[11px]","font-mono","font-medium","whitespace-nowrap"],["title","Delete",1,"w-6","h-6","rounded-lg","bg-surface-alt","flex","items-center","justify-center","text-ink-soft","hover:text-rose","hover:bg-rose-soft","shrink-0",3,"click"],["viewBox","0 0 16 16","fill","none","stroke","currentColor","stroke-width","1.6","stroke-linecap","round","stroke-linejoin","round",1,"w-3","h-3"],["d","M2.5 4h11M6 4V2.5h4V4M4 4l.5 9h7L12 4"],["viewBox","0 0 14 14","fill","none","stroke","currentColor","stroke-width","1.8","stroke-linecap","round","stroke-linejoin","round",1,"w-4","h-4","text-ink-soft","shrink-0","transition-transform","mt-1"],[1,"mt-4","pl-12","animate-fadeIn"],[1,"p-4","rounded-xl","bg-surface-alt","mb-3"],[1,"text-[13px]","text-base-content","leading-relaxed","whitespace-pre-wrap"],["placeholder","Private to-do notes, links, estimates\u2026",1,"input","min-h-[80px]","resize-y","text-[13px]",3,"ngModelChange","ngModel"],[1,"flex","justify-end","mt-2"],[1,"btn","btn-primary","btn-sm","rounded-full",3,"click"]],template:function(e,i){if(e&1&&(n(0,"div",2)(1,"div",3)(2,"div",4),l(3,"ADMIN"),r(),n(4,"h1",5),l(5," Everything, "),n(6,"span",6),l(7,"visible."),r()(),n(8,"p",7),l(9,"Aggregate stats and operations."),r(),n(10,"div",8)(11,"a",9),l(12,"Manage changelog \u2192"),r()()(),b(13,Ce,2,1,"div",10),b(14,Ee,26,5,"div",11),b(15,ye,3,0,"div",12),n(16,"div",13)(17,"details",14),p("toggle",function(d){return i.onScrapeErrorsToggle(d)}),n(18,"summary",15)(19,"div",16)(20,"div",17),l(21,"FAILED SCRAPES"),r(),b(22,Te,4,2),r(),w(),n(23,"svg",18),_(24,"path",19),r()(),V(),n(25,"div",20)(26,"div",21)(27,"div",22),k(28,Me,2,3,"button",23,B),r(),n(30,"div",24)(31,"select",25),p("ngModelChange",function(d){return i.setScrapeErrorSource(d)}),k(32,Ie,2,2,"option",26,B),r(),w(),n(34,"svg",27),_(35,"path",19),r()(),b(36,De,4,1,"button",28),b(37,Fe,4,2,"button",29),r(),b(38,Pe,1,1),b(39,Le,2,0,"div",30)(40,Re,2,0,"div",31)(41,Oe,21,3),r()()(),V(),n(42,"div",13)(43,"details",32)(44,"summary",15)(45,"div",33)(46,"div",17),l(47,"BROADCAST"),r(),n(48,"span",34),l(49,"\xB7 send to all users"),r()(),w(),n(50,"svg",18),_(51,"path",19),r()(),V(),n(52,"div",35),b(53,qe,2,1,"div",36),b(54,Ue,3,5,"div",37),n(55,"div")(56,"label",38),l(57,"CHANNELS"),r(),n(58,"div",39)(59,"div",40)(60,"button",41),p("click",function(){return i.broadcastChannelEmail.set(!i.broadcastChannelEmail())}),_(61,"span",42),r(),n(62,"span",43),l(63,"Email"),r()(),n(64,"div",40)(65,"button",41),p("click",function(){return i.broadcastChannelTelegram.set(!i.broadcastChannelTelegram())}),_(66,"span",42),r(),n(67,"span",43),l(68,"Telegram"),r()()()(),b(69,Qe,4,1,"div"),n(70,"div")(71,"label",38),l(72,"MESSAGE (HTML)"),r(),n(73,"textarea",44),p("ngModelChange",function(d){return i.broadcastBody.set(d)}),r(),n(74,"p",45),l(75," Sent as HTML to email, parsed as Telegram HTML (b/i/u/s/a/code/pre/br) to Telegram. "),r()(),n(76,"div",46)(77,"button",47),p("click",function(){return i.sendBroadcast()}),b(78,We,2,0)(79,Je,1,0),r()()()()(),n(80,"div",48)(81,"div",49)(82,"div",17),l(83,"FEEDBACK"),r(),n(84,"span",34),l(85),r(),_(86,"div",50),n(87,"div",22),k(88,Ye,4,4,"button",23,B),r()(),b(90,Ke,2,0,"div",30)(91,Ze,2,0,"div",51)(92,it,3,0,"div"),r(),n(93,"dialog",52)(94,"div",53)(95,"div",54),l(96,"CONFIRM"),r(),n(97,"h3",55),l(98,"Are you sure?"),r(),n(99,"p",56),l(100),r(),n(101,"div",57)(102,"button",58),p("click",function(){return i.confirmReject()}),l(103,"Cancel"),r(),n(104,"button",59),p("click",function(){return i.confirmAccept()}),l(105,"Confirm"),r()()(),n(106,"form",60)(107,"button",61),p("click",function(){return i.confirmReject()}),l(108,"close"),r()()(),n(109,"div",62)(110,"div",63)(111,"div",64),l(112,"GROWTH \u2014 LAST 30 DAYS"),r(),n(113,"div",65),_(114,"canvas",null,0),r()(),n(116,"div",66)(117,"div",64),l(118,"SOURCES"),r(),n(119,"div",65),_(120,"canvas",null,1),r()()()()),e&2){let s,d,h,A;o(13),g(i.error()?13:-1),o(),g((s=i.stats())?14:-1,s),o(),g(i.quota().length>0?15:-1),o(7),g((d=i.scrapeErrorStats())?22:-1,d),o(6),y(i.scrapeErrorSinceOptions),o(3),S("ngModel",i.scrapeErrorSource()),o(),y(i.scrapeErrorSourceOptions),o(4),g(i.scrapeErrorHost()?36:-1),o(),g(i.scrapeErrorsTotal()>0?37:-1),o(),g((h=i.scrapeErrorStats())?38:-1,h),o(),g(i.scrapeErrorsLoading()?39:i.scrapeErrors().length===0?40:41),o(14),g(i.broadcastError()?53:-1),o(),g((A=i.broadcastResult())?54:-1,A),o(6),I("background",i.broadcastChannelEmail()?"var(--accent)":"var(--border)"),P("aria-pressed",i.broadcastChannelEmail()),o(),I("left",i.broadcastChannelEmail()?22:2,"px"),o(4),I("background",i.broadcastChannelTelegram()?"var(--accent)":"var(--border)"),P("aria-pressed",i.broadcastChannelTelegram()),o(),I("left",i.broadcastChannelTelegram()?22:2,"px"),o(3),g(i.broadcastChannelEmail()?69:-1),o(4),S("ngModel",i.broadcastBody()),o(4),S("disabled",i.broadcastSending()),o(),g(i.broadcastSending()?78:79),o(7),v("\xB7 ",i.feedback().length),o(3),y(i.feedbackFilterOptions),o(2),g(i.feedbackLoading()?90:i.filteredFeedback().length===0?91:92),o(3),D("modal-open",i.showConfirm()),o(7),u(i.confirmMessage())}}
3,dependencies:[ee,ue,de,me,pe,re,ce,ae,oe,se,le,ne,X],styles:['@charset "UTF-8";']})};export{ge as AdminComponent};
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.