diff --git a/src/scripts/generated/dashboard.ts b/src/scripts/generated/dashboard.ts deleted file mode 100644 index 1a744f5..0000000 --- a/src/scripts/generated/dashboard.ts +++ /dev/null @@ -1,6 +0,0 @@ -// AUTO-GENERATED by scripts/build-client.mjs — do not edit directly. -// Source: src/scripts/client/dashboard.ts -// Run `npm run build:client` to regenerate. - -export const dashboardScript = - '"use strict";(()=>{var y=[],h=[],H=null,D=null,A=null,F=null,b=null,I=null,M=!1,v="title",L="asc",N=new Intl.Collator(void 0,{numeric:!0,sensitivity:"base"});function P(){y=Array.from(document.querySelectorAll(".feed-row")),h=Array.from(document.querySelectorAll(".feed-select")),H=document.getElementById("selected-feed-count"),D=document.getElementById("feed-match-count"),A=document.getElementById("feed-total-count"),F=document.getElementById("bulk-delete-feeds-button"),b=document.getElementById("select-all-feeds"),J(),j(),Z(),R(),E()}function R(){if(!D)return;let e=y.length,t=y.filter(s=>!s.hidden).length,n=(document.getElementById("feed-search")?.value||"").trim();D.textContent=n?"Showing "+t+" of "+e:"Showing "+e}function U(){I&&clearTimeout(I),I=setTimeout(se,120)}function C(e,t){let n="sort"+t.charAt(0).toUpperCase()+t.slice(1);return e.dataset&&e.dataset[n]?e.dataset[n]:""}function _(e){Array.from(e.querySelectorAll("th[data-sort-key]")).forEach(n=>{let s=n.getAttribute("data-sort-key")||"",l=n.querySelector(".sort-indicator"),i=s===v;l&&(l.textContent=i?L==="asc"?"^":"v":""),n.setAttribute("aria-sort",i?L==="asc"?"ascending":"descending":"none")})}function W(e){let t=document.querySelector("table.table-feeds"),n=document.getElementById("feed-table-body");if(!t||!n)return;v===e?L=L==="asc"?"desc":"asc":(v=e,L="asc");let s=L==="asc"?1:-1,l=Array.from(n.querySelectorAll(".feed-row"));l.sort((m,c)=>{let f=C(m,v),u=C(c,v);return s*N.compare(f,u)});let i=document.createDocumentFragment();l.forEach(m=>i.appendChild(m)),n.appendChild(i),_(t)}function j(){let e=document.querySelector("table.table-feeds");e&&(e.querySelectorAll("button.th-button[data-sort-key]").forEach(t=>{t.addEventListener("click",()=>{let n=t.getAttribute("data-sort-key")||"";n&&W(n)})}),_(e))}function J(){let e=document.querySelector("table.table-feeds");if(!e)return;let t="email-to-rss.admin.feedsTable.colWidths",n={title:220,feedId:120,email:160,rss:160,actions:160},s={title:340,feedId:160,email:220,rss:220,actions:200},l=Array.from(e.querySelectorAll("colgroup col")),i={};l.forEach(a=>{let d=a.getAttribute("data-col");d&&(i[d]=a)});try{let a=JSON.parse(localStorage.getItem(t)||"{}");Object.keys(a||{}).forEach(d=>{let o=Number(a[d]);!i[d]||!Number.isFinite(o)||(i[d].style.width=o+"px")})}catch{}let m=()=>{try{let a={};Object.keys(i).forEach(d=>{if(d==="select")return;let o=parseInt(i[d].style.width||"0",10);Number.isFinite(o)&&o>0&&(a[d]=o)}),localStorage.setItem(t,JSON.stringify(a))}catch{}},c=null,f=0,u=0;e.querySelectorAll(".col-resizer").forEach(a=>{a.addEventListener("pointerdown",o=>{o.preventDefault(),o.stopPropagation();let r=a.getAttribute("data-col"),g=r?i[r]:null;if(!r||!g)return;let w=a.closest("th"),T=w?w.getBoundingClientRect().width:parseInt(g.style.width||"0",10)||120;c={key:r,col:g,startX:o.clientX,startWidth:T},document.body.classList.add("is-resizing"),a.setPointerCapture(o.pointerId)}),a.addEventListener("pointermove",o=>{if(!c)return;let r=n[c.key]||120;u=Math.max(r,Math.round(c.startWidth+(o.clientX-c.startX))),!f&&(f=requestAnimationFrame(()=>{c.col.style.width=u+"px",f=0}))});let d=()=>{c&&(c=null,document.body.classList.remove("is-resizing"),m())};a.addEventListener("pointerup",d),a.addEventListener("pointercancel",d),a.addEventListener("dblclick",o=>{o.preventDefault(),o.stopPropagation();let r=a.getAttribute("data-col"),g=r?i[r]:null,w=r?s[r]:null;!r||!g||!w||(g.style.width=w+"px",m())})})}var z="Confirm delete",K="Deleting...",X=4e3;function V(){return new URL(window.location.href).searchParams.get("view")||"list"}function k(e){if(!e)return;e.classList.remove("is-confirming"),e.removeAttribute("data-confirming"),e.disabled=!1;let t=e.dataset.originalLabel||(e.textContent||"").trim()||"Delete";e.innerHTML=t}function G(e,t){if(!e){t&&t();return}let n=e.tagName.toLowerCase()==="li";n&&(e.style.maxHeight=e.getBoundingClientRect().height+"px",e.style.overflow="hidden"),e.classList.add("is-removing"),requestAnimationFrame(()=>{n&&(e.style.maxHeight="0px",e.style.marginTop="0px",e.style.marginBottom="0px",e.style.paddingTop="0px",e.style.paddingBottom="0px")}),window.setTimeout(()=>{e.remove(),t&&t()},240)}async function Y(e,t){let n=await fetch("/admin/feeds/"+encodeURIComponent(e)+"/delete?view="+encodeURIComponent(t),{method:"POST",headers:{Accept:"application/json"},credentials:"same-origin"}),s=await n.json().catch(()=>({}));if(!n.ok){let l=s&&s.error?String(s.error):"Request failed ("+n.status+")";throw new Error(l)}return s}function Q(){y=Array.from(document.querySelectorAll(".feed-row")),h=Array.from(document.querySelectorAll(".feed-select")),A&&(A.textContent=String(y.length)),R(),E()}function Z(){Array.from(document.querySelectorAll(\'button[data-delete-kind="feed"]\')).forEach(t=>{if(t.dataset.deleteReady==="true")return;t.dataset.deleteReady="true";let n=(t.textContent||"").trim()||"Delete";t.dataset.originalLabel=n;let s=!1,l=0,i=!1,m=()=>{s=!0,t.classList.add("is-confirming"),t.setAttribute("data-confirming","true"),t.innerHTML=z,l&&window.clearTimeout(l),l=window.setTimeout(()=>{s=!1,k(t)},X)};t.addEventListener("click",async c=>{if(c.preventDefault(),i)return;if(!s){m();return}l&&window.clearTimeout(l),i=!0,S(t,!0,K);let f=window.showToast?window.showToast("Deleting feed...",{type:"info",loading:!0,duration:0}):null,u=t.getAttribute("data-feed-id")||"",a=t.getAttribute("data-view")||V(),d=t.closest(".feed-row");try{await Y(u,a),f&&f.update?f.update("Feed deleted.",{type:"success",loading:!1,duration:3200}):window.showToast&&window.showToast("Feed deleted.",{type:"success"}),G(d,()=>{Q()})}catch(o){let r=o instanceof Error&&o.message?o.message:"Unknown error";f&&f.update?f.update("Delete failed: "+r,{type:"error",loading:!1}):window.showToast&&window.showToast("Delete failed: "+r,{type:"error"}),S(t,!1),s=!1,k(t)}finally{i=!1,d||(S(t,!1),s=!1,k(t))}}),t.addEventListener("keydown",c=>{c.key==="Escape"&&s&&!i&&(s=!1,l&&window.clearTimeout(l),k(t))})})}function E(){if(!h.length)return;let e=h.filter(t=>t.checked);if(H&&(H.textContent=e.length+" selected"),F&&(F.disabled=e.length===0),b){let t=h.filter(n=>!n.closest("tr")?.hidden);b.checked=t.length>0&&t.every(n=>n.checked)}}function $(e){h.forEach(t=>{t.closest("tr")?.hidden||(t.checked=e)}),E()}function ee(e){h.forEach(t=>{t.closest("tr")?.hidden||(t.checked=e)}),E()}function te(){ee(!0)}function ne(){h.forEach(e=>{e.checked=!1}),E()}function se(){let e=(document.getElementById("feed-search")?.value||"").toLowerCase().trim();y.forEach(t=>{let n=t.getAttribute("data-search")||"";t.hidden=!!e&&!n.includes(e)}),R(),E()}function ie(){let e=h.filter(s=>s.checked).length;if(e===0)return!1;let t=(document.getElementById("feed-search")?.value||"").trim(),n=e>=50&&!t?`\n\nThis is a large delete. Tip: use Search to narrow down spam first.`:"";return confirm("Delete "+e+" selected feed(s)? This disables the feeds immediately. Stored emails are cleaned up best-effort and may take a while."+n)}function S(e,t,n){if(!e)return;if(t){e.dataset.originalLabel||(e.dataset.originalLabel=(e.textContent||"").trim());let l=n||"Working...";e.classList.add("is-loading"),e.disabled=!0,e.innerHTML=\'\'+l;return}let s=e.dataset.originalLabel||(e.textContent||"").trim();e.classList.remove("is-loading"),e.innerHTML=s}function B(e){let t=new Set((e||[]).map(n=>String(n)));t.size!==0&&(y.forEach(n=>{let s=n.querySelector("input.feed-select"),l=s?s.value:"";t.has(l)&&n.remove()}),y=Array.from(document.querySelectorAll(".feed-row")),h=Array.from(document.querySelectorAll(".feed-select")),A&&(A.textContent=String(y.length)))}function oe(e){return e&&e.preventDefault&&e.preventDefault(),re(),!1}async function re(){if(M)return;let e=h.filter(i=>i.checked).map(i=>i.value);if(e.length===0){window.showToast&&window.showToast("No feeds selected.",{type:"info"});return}if(!ie())return;M=!0,S(F,!0,"Deleting...");let t=window.showToast?window.showToast("Deleting "+e.length+" feed(s)...",{type:"info",loading:!0,duration:0}):null,n=10,s=0,l=[];try{for(let m=0;m({})),!f.ok){let r=u&&u.error?String(u.error):"Bulk feed delete failed (HTTP "+f.status+")";throw new Error(r)}let a=Array.isArray(u.deletedFeedIds)?u.deletedFeedIds:c,d=Array.isArray(u.failedFeedIds)?u.failedFeedIds:[],o=Array.isArray(u.failures)?u.failures:[];if(B(a),s+=a.length,t&&t.update){let r=Math.min(m+c.length,e.length);t.update("Deleting... ("+r+" of "+e.length+")",{type:"info"})}if(R(),E(),d.length>0){t&&t.update&&t.update("Retrying "+d.length+" failed feed(s) one-by-one...",{type:"info"});let r=[];for(let g=0;g({})),!T.ok){let q=p&&p.error?String(p.error):"Retry delete failed (HTTP "+T.status+")";throw new Error(q)}let x=Array.isArray(p.deletedFeedIds)?p.deletedFeedIds:[],O=Array.isArray(p.failedFeedIds)?p.failedFeedIds:[];x.includes(w)?(B([w]),s+=1):(O.includes(w),r.push(w))}catch{r.push(w)}t&&t.update&&t.update("Retrying... ("+(g+1)+" of "+d.length+")",{type:"info"})}}if(r.length>0&&(l.push(...r),window.showToast&&o.length>0)){let g=o[0]&&o[0].error?String(o[0].error):"";g&&window.showToast("Some feeds failed to delete: "+g,{type:"error"})}R(),E()}}t&&t.dismiss&&t.dismiss();let i=Array.from(new Set(l.map(m=>String(m)).filter(Boolean)));i.length>0?window.showToast&&window.showToast("Deleted "+s+" feed(s). "+i.length+" failed (still visible).",{type:"error"}):window.showToast&&window.showToast("Deleted "+s+" feed(s).",{type:"success"})}catch(i){t&&t.dismiss&&t.dismiss(),window.showToast&&window.showToast(i instanceof Error&&i.message?i.message:"Bulk feed delete failed.",{type:"error"})}finally{M=!1,S(F,!1),E()}}window.scheduleFeedFilter=U;window.toggleAllFeeds=$;window.selectMatchingFeeds=te;window.clearFeedSelection=ne;window.onBulkFeedDeleteSubmit=oe;document.addEventListener("DOMContentLoaded",()=>{P()});})();\n'; diff --git a/src/scripts/generated/emails-page.ts b/src/scripts/generated/emails-page.ts deleted file mode 100644 index d25c173..0000000 --- a/src/scripts/generated/emails-page.ts +++ /dev/null @@ -1,6 +0,0 @@ -// AUTO-GENERATED by scripts/build-client.mjs — do not edit directly. -// Source: src/scripts/client/emails-page.ts -// Run `npm run build:client` to regenerate. - -export const emailsPageScript = - '"use strict";(()=>{var b=window.__APP_CONFIG__?.feedId??"",g=[],f=[],R=null,_=null,A=null,v=null,C=null,k=null,S=!1,T="receivedAt",p="desc",O=new Intl.Collator(void 0,{numeric:!0,sensitivity:"base"});function q(){g=Array.from(document.querySelectorAll(".email-row")),f=Array.from(document.querySelectorAll(".email-select")),R=document.getElementById("selected-email-count"),_=document.getElementById("email-match-count"),A=document.getElementById("email-total-count"),v=document.getElementById("bulk-delete-emails-button"),C=document.getElementById("select-all-emails"),K(),P(),J(),I(),w()}function I(){if(!_)return;let e=g.length,t=g.filter(i=>!i.hidden).length,n=(document.getElementById("email-search")?.value||"").trim();_.textContent=n?"Showing "+t+" of "+e:"Showing "+e}function x(){k&&clearTimeout(k),k=setTimeout(Y,120)}function H(e,t){let n="sort"+t.charAt(0).toUpperCase()+t.slice(1);return e.dataset&&e.dataset[n]?e.dataset[n]:""}function B(e){Array.from(e.querySelectorAll("th[data-sort-key]")).forEach(t=>{let n=t.getAttribute("data-sort-key")||"",i=t.querySelector(".sort-indicator"),u=n===T;i&&(i.textContent=u?p==="asc"?"^":"v":""),t.setAttribute("aria-sort",u?p==="asc"?"ascending":"descending":"none")})}function N(e){let t=document.querySelector("table.table-emails"),n=t?t.querySelector("tbody"):null;if(!t||!n)return;T===e?p=p==="asc"?"desc":"asc":(T=e,p=e==="receivedAt"?"desc":"asc");let i=p==="asc"?1:-1,u=Array.from(n.querySelectorAll(".email-row"));u.sort((l,r)=>i*O.compare(H(l,T),H(r,T)));let s=document.createDocumentFragment();u.forEach(l=>s.appendChild(l)),n.appendChild(s),B(t)}function P(){let e=document.querySelector("table.table-emails");e&&(e.querySelectorAll("button.th-button[data-sort-key]").forEach(t=>{t.addEventListener("click",()=>{let n=t.getAttribute("data-sort-key");n&&N(n)})}),B(e))}function K(){let e=document.querySelector("table.table-emails");if(!e)return;let t="email-to-rss.admin.emailsTable.colWidths",n={subject:240,receivedAt:180,actions:160},i={subject:520,receivedAt:220,actions:200},u=Array.from(e.querySelectorAll("colgroup col")),s={};u.forEach(o=>{let a=o.getAttribute("data-col");a&&(s[a]=o)});try{let o=JSON.parse(localStorage.getItem(t)||"{}");Object.keys(o||{}).forEach(a=>{let c=Number(o[a]);s[a]&&Number.isFinite(c)&&(s[a].style.width=c+"px")})}catch{}let l=()=>{try{let o={};Object.keys(s).forEach(a=>{if(a==="select")return;let c=parseInt(s[a].style.width||"0",10);Number.isFinite(c)&&c>0&&(o[a]=c)}),localStorage.setItem(t,JSON.stringify(o))}catch{}},r=null,E=0,d=0;e.querySelectorAll(".col-resizer").forEach(o=>{o.addEventListener("pointerdown",c=>{c.preventDefault(),c.stopPropagation();let m=o.getAttribute("data-col"),h=m?s[m]:null;if(!m||!h)return;let y=o.closest("th"),D=y?y.getBoundingClientRect().width:parseInt(h.style.width||"0",10)||200;r={key:m,col:h,startX:c.clientX,startWidth:D},document.body.classList.add("is-resizing"),o.setPointerCapture(c.pointerId)}),o.addEventListener("pointermove",c=>{if(!r)return;let m=n[r.key]||180;d=Math.max(m,Math.round(r.startWidth+(c.clientX-r.startX))),!E&&(E=requestAnimationFrame(()=>{r.col.style.width=d+"px",E=0}))});let a=()=>{r&&(r=null,document.body.classList.remove("is-resizing"),l())};o.addEventListener("pointerup",a),o.addEventListener("pointercancel",a),o.addEventListener("dblclick",c=>{c.preventDefault(),c.stopPropagation();let m=o.getAttribute("data-col"),h=m?s[m]:null,y=m?i[m]:null;!m||!h||!y||(h.style.width=y+"px",l())})})}var F="Confirm delete",U=4e3;function M(e){e&&(e.classList.remove("is-confirming"),e.removeAttribute("data-confirming"),e.disabled=!1,e.textContent=e.dataset.originalLabel||"Delete")}function L(e,t,n){if(e){if(t){e.dataset.originalLabel||(e.dataset.originalLabel=(e.textContent||"").trim()),e.classList.add("is-loading"),e.disabled=!0,e.textContent="";let i=document.createElement("span");i.className="spinner",i.setAttribute("aria-hidden","true"),e.appendChild(i),e.appendChild(document.createTextNode(" "+(n||"Working...")));return}e.classList.remove("is-loading"),e.textContent=e.dataset.originalLabel||(e.textContent||"").trim()}}function W(e,t){if(!e){t&&t();return}e.classList.add("is-removing"),window.setTimeout(()=>{e.remove(),t&&t()},240)}async function j(e,t){let n=await fetch("/admin/emails/"+encodeURIComponent(e)+"/delete?feedId="+encodeURIComponent(t),{method:"POST",headers:{Accept:"application/json"},credentials:"same-origin"}),i=await n.json().catch(()=>({}));if(!n.ok)throw new Error(i&&i.error?String(i.error):"Request failed ("+n.status+")");return i}function z(){g=Array.from(document.querySelectorAll(".email-row")),f=Array.from(document.querySelectorAll(".email-select")),A&&(A.textContent=String(g.length)),I(),w()}function J(){Array.from(document.querySelectorAll(\'button[data-delete-kind="email"]\')).forEach(e=>{if(e.dataset.deleteReady==="true")return;e.dataset.deleteReady="true",e.dataset.originalLabel=(e.textContent||"").trim()||"Delete";let t=!1,n=0,i=!1,u=()=>{t=!0,e.classList.add("is-confirming"),e.setAttribute("data-confirming","true"),e.textContent=F,n&&window.clearTimeout(n),n=window.setTimeout(()=>{t=!1,M(e)},U)};e.addEventListener("click",async s=>{if(s.preventDefault(),i)return;if(!t){u();return}n&&window.clearTimeout(n),i=!0,L(e,!0,"Deleting...");let l=window.showToast?window.showToast("Deleting email...",{type:"info",loading:!0,duration:0}):null,r=e.getAttribute("data-email-key")||"",E=e.getAttribute("data-feed-id")||b,d=e.closest(".email-row");try{await j(r,E),l&&l.update?l.update("Email deleted.",{type:"success",loading:!1,duration:3200}):window.showToast&&window.showToast("Email deleted.",{type:"success"}),W(d,()=>z())}catch(o){let a="Delete failed: "+(o instanceof Error&&o.message?o.message:"Unknown error");l&&l.update?l.update(a,{type:"error",loading:!1}):window.showToast&&window.showToast(a,{type:"error"}),L(e,!1),t=!1,M(e)}finally{i=!1,d||(L(e,!1),t=!1,M(e))}}),e.addEventListener("keydown",s=>{s.key==="Escape"&&t&&!i&&(t=!1,n&&window.clearTimeout(n),M(e))})})}function w(){if(!f.length)return;let e=f.filter(t=>t.checked);if(R&&(R.textContent=e.length+" selected"),v&&(v.disabled=e.length===0),C){let t=f.filter(n=>!n.closest("tr")?.hidden);C.checked=t.length>0&&t.every(n=>n.checked)}}function X(e){f.forEach(t=>{t.closest("tr")?.hidden||(t.checked=e)}),w()}function G(){f.forEach(e=>{e.closest("tr")?.hidden||(e.checked=!0)}),w()}function V(){f.forEach(e=>{e.checked=!1}),w()}function Y(){let e=(document.getElementById("email-search")?.value||"").toLowerCase().trim();g.forEach(t=>{t.hidden=!!e&&!(t.getAttribute("data-search")||"").includes(e)}),I(),w()}function Q(){let e=f.filter(i=>i.checked).length;if(e===0)return!1;let t=(document.getElementById("email-search")?.value||"").trim(),n=e>=200&&!t?`\n\nThis is a large delete. Tip: use Search to narrow down spam first.`:"";return confirm("Delete "+e+" selected email(s)?"+n)}function Z(e){let t=new Set((e||[]).map(n=>String(n)));t.size&&(g.forEach(n=>{let i=n.querySelector("input.email-select");i&&t.has(i.value)&&n.remove()}),g=Array.from(document.querySelectorAll(".email-row")),f=Array.from(document.querySelectorAll(".email-select")),A&&(A.textContent=String(g.length)))}function $(e){return e&&e.preventDefault&&e.preventDefault(),ee(),!1}async function ee(){if(S)return;let e=f.filter(s=>s.checked).map(s=>s.value);if(!e.length){window.showToast&&window.showToast("No emails selected.",{type:"info"});return}if(!Q())return;S=!0,L(v,!0,"Deleting...");let t=window.showToast?window.showToast("Deleting "+e.length+" email(s)...",{type:"info",loading:!0,duration:0}):null,n=50,i=0,u=[];try{let s="/admin/feeds/"+encodeURIComponent(b)+"/emails/bulk-delete";for(let l=0;l({})),!E.ok)throw new Error(d&&d.error?String(d.error):"Bulk email delete failed (HTTP "+E.status+")");let o=Array.isArray(d.deletedEmailKeys)?d.deletedEmailKeys:r;Z(o),i+=o.length,u.push(...Array.isArray(d.failedEmailKeys)?d.failedEmailKeys:[]),t&&t.update&&t.update("Deleting... ("+Math.min(l+r.length,e.length)+" of "+e.length+")",{type:"info"}),I(),w()}t&&t.dismiss&&t.dismiss(),u.length>0?window.showToast&&window.showToast("Deleted "+i+" email(s). "+u.length+" failed (still visible).",{type:"error"}):window.showToast&&window.showToast("Deleted "+i+" email(s).",{type:"success"})}catch(s){t&&t.dismiss&&t.dismiss(),window.showToast&&window.showToast(s instanceof Error&&s.message?s.message:"Bulk email delete failed.",{type:"error"})}finally{S=!1,L(v,!1),w()}}window.scheduleEmailFilter=x;window.toggleAllEmails=X;window.selectMatchingEmails=G;window.clearEmailSelection=V;window.onBulkEmailDeleteSubmit=$;document.addEventListener("DOMContentLoaded",()=>{q()});})();\n';