Dashboard-VPvfYTM4.js 16 KB

123
  1. const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/DashboardCharts-s26_Bnz4.js","assets/react-dom-stZKkA6x.js","assets/theme-DNlqAiGO.js","assets/jsx-runtime-dm82oUI8.js","assets/theme-e1juCvr1.css","assets/grid-DcIFgt5N.js","assets/table-CHt5qwx3.js","assets/useForm-sdDvuRHy.js","assets/StatusPill-Bcw_ne6L.js","assets/index-CBPGvhVC.js","assets/modulepreload-polyfill-Dezn_h7o.js","assets/index-Tu04tXLf.css","assets/row-Cmd9RpeX.js","assets/EmptyState-rI31ioMm.js","assets/analytics-model-BpU8MjWz.js"])))=>i.map(i=>d[i]);
  2. import{a as e,n as t,r as n}from"./react-dom-stZKkA6x.js";import{a as r,r as i,u as a}from"./theme-DNlqAiGO.js";import{i as o,kt as s,n as c,st as l,t as u}from"./jsx-runtime-dm82oUI8.js";import{i as d,o as f}from"./grid-DcIFgt5N.js";import{n as p,r as ee,t as m}from"./StatusPill-Bcw_ne6L.js";import{n as h,t as g}from"./row-Cmd9RpeX.js";import{t as te}from"./segmented-DUpU-ING.js";import{t as _}from"./list-B3SBzx24.js";import{g as v,h as y,l as b,n as x,p as ne,v as re}from"./index-CBPGvhVC.js";import{t as S}from"./EmptyState-rI31ioMm.js";import{t as C}from"./domain-model-BLOrIAIx.js";import{n as ie}from"./analytics-model-BpU8MjWz.js";var w=n((e=>{Object.defineProperty(e,"__esModule",{value:!0}),e.default={icon:{tag:`svg`,attrs:{viewBox:`64 64 896 896`,focusable:`false`},children:[{tag:`path`,attrs:{d:`M869 487.8L491.2 159.9c-2.9-2.5-6.6-3.9-10.5-3.9h-88.5c-7.4 0-10.8 9.2-5.2 14l350.2 304H152c-4.4 0-8 3.6-8 8v60c0 4.4 3.6 8 8 8h585.1L386.9 854c-5.6 4.9-2.2 14 5.2 14h91.5c1.9 0 3.8-.7 5.2-2L869 536.2a32.07 32.07 0 000-48.4z`}}]},name:`arrow-right`,theme:`outlined`}})),T=e(t()),E=e(w());function D(){return D=Object.assign?Object.assign.bind():function(e){for(var t=1;t<arguments.length;t++){var n=arguments[t];for(var r in n)Object.prototype.hasOwnProperty.call(n,r)&&(e[r]=n[r])}return e},D.apply(this,arguments)}var ae=T.forwardRef((e,t)=>T.createElement(a,D({},e,{ref:t,icon:E.default}))),O=e(n((e=>{Object.defineProperty(e,"__esModule",{value:!0}),e.default={icon:{tag:`svg`,attrs:{viewBox:`64 64 896 896`,focusable:`false`},children:[{tag:`path`,attrs:{d:`M512 64C264.6 64 64 264.6 64 512s200.6 448 448 448 448-200.6 448-448S759.4 64 512 64zm0 820c-205.4 0-372-166.6-372-372s166.6-372 372-372 372 166.6 372 372-166.6 372-372 372z`}},{tag:`path`,attrs:{d:`M464 688a48 48 0 1096 0 48 48 0 10-96 0zm24-112h48c4.4 0 8-3.6 8-8V296c0-4.4-3.6-8-8-8h-48c-4.4 0-8 3.6-8 8v272c0 4.4 3.6 8 8 8z`}}]},name:`exclamation-circle`,theme:`outlined`}}))());function k(){return k=Object.assign?Object.assign.bind():function(e){for(var t=1;t<arguments.length;t++){var n=arguments[t];for(var r in n)Object.prototype.hasOwnProperty.call(n,r)&&(e[r]=n[r])}return e},k.apply(this,arguments)}var A=T.forwardRef((e,t)=>T.createElement(a,k({},e,{ref:t,icon:O.default}))),j=u();function M({label:e,value:t,hint:n,tone:r=`default`}){return(0,j.jsxs)(d,{className:`metric-card metric-card--${r}`,children:[(0,j.jsx)(c.Text,{type:`secondary`,children:e}),(0,j.jsx)(c.Title,{level:3,className:`metric-value`,children:t}),n?(0,j.jsx)(c.Text,{type:`secondary`,className:`metric-card__hint`,children:n}):null]})}var N=(0,T.lazy)(()=>v(()=>import(`./DashboardCharts-s26_Bnz4.js`),__vite__mapDeps([0,1,2,3,4,5,6,7,8,9,10,11,12,13,14])));function P(){let{config:e}=x(),{locale:t}=r(),n=ne(),[a,u]=y(),d=z(a.get(`range`)),v=B(a.get(`analysis`)),[C,w]=(0,T.useState)(null),[E,D]=(0,T.useState)(!0),[O,k]=(0,T.useState)(null),[P,L]=(0,T.useState)({}),V=(0,T.useRef)(0),H=t.startsWith(`en`)?se:oe,U=(0,T.useCallback)(async()=>{let e=++V.current;D(!0),k(null);try{let[t,n,r,a,o]=await Promise.allSettled([i.analytics(d),i.domains(),i.smtpCredential(),i.apiTokens(),i.webhookDeliveries({status:`dead`,limit:5})]);if(e!==V.current)return;let s=[t.status===`rejected`?H.dependencyError(H.analyticsDependency,t.reason):``,n.status===`rejected`?H.dependencyError(H.domainsDependency,n.reason):``].filter(Boolean);k(s.length?{range:d,message:s.join(`
  3. `)}:null);let c={};r.status===`rejected`&&(c.smtp=R(r.reason,H.loadFailed)),a.status===`rejected`&&(c.apiTokens=R(a.reason,H.loadFailed)),o.status===`rejected`&&(c.webhooks=R(o.reason,H.loadFailed)),L(c),w(e=>{let i=e?.range===d?e:null,s=t.status===`fulfilled`?t.value.analytics:i?.analytics,c=n.status===`fulfilled`?n.value.domains:e?.domains;return!s||!c?e:{range:d,analytics:s,domains:c,smtpCredential:r.status===`fulfilled`?r.value.credential:e?.smtpCredential,apiTokens:a.status===`fulfilled`?a.value.tokens:e?.apiTokens,failedWebhooks:o.status===`fulfilled`?o.value.deliveries:e?.failedWebhooks}})}catch(t){e===V.current&&k({range:d,message:t instanceof Error?t.message:H.loadFailed})}finally{e===V.current&&D(!1)}},[H,d]);(0,T.useEffect)(()=>(U(),()=>{V.current+=1}),[U]);let W=C?.range===d?C:null,G=O?.range===d?O.message:``,K=(0,T.useMemo)(()=>W?{...W,smtpCredential:P.smtp?void 0:W.smtpCredential,apiTokens:P.apiTokens?void 0:W.apiTokens,failedWebhooks:P.webhooks?void 0:W.failedWebhooks}:null,[W,P.apiTokens,P.smtp,P.webhooks]),q=(0,T.useMemo)(()=>K?I(K,H):[],[H,K]),J=Object.entries(P),Y=J.length>0;function ce(e){let t=new URLSearchParams(a);t.set(`range`,String(e)),u(t)}function le(e){let t=new URLSearchParams(a);e===`delivery`?t.delete(`analysis`):t.set(`analysis`,e),u(t)}if(!W&&!G)return(0,j.jsxs)(o,{direction:`vertical`,size:20,className:`full-width`,"aria-label":H.loading,children:[(0,j.jsx)(l,{active:!0,title:{width:`28%`},paragraph:{rows:2}}),(0,j.jsx)(g,{gutter:[16,16],children:[0,1,2,3].map(e=>(0,j.jsx)(h,{xs:24,sm:12,xl:6,children:(0,j.jsx)(l.Node,{active:!0,style:{width:`100%`}})},e))}),(0,j.jsx)(p,{children:(0,j.jsx)(l,{active:!0,paragraph:{rows:8}})})]});if(G&&!W)return(0,j.jsx)(re,{status:`error`,title:H.loadFailed,subTitle:G,extra:(0,j.jsx)(s,{type:`primary`,onClick:()=>void U(),children:H.retry})});if(!W)return null;let{analytics:X,domains:ue}=W,Z=X.summary,Q=ie(X),$=Number(Z.terminalFailed||Z.failed||0)+Number(Z.deferred||0)+Number(Z.pending||0);return(0,j.jsxs)(o,{direction:`vertical`,size:20,className:`full-width`,children:[e?.usingDefaultAdminPassword?(0,j.jsx)(f,{type:`warning`,showIcon:!0,message:H.defaultPassword,description:H.defaultPasswordDescription}):null,G?(0,j.jsx)(f,{type:`error`,showIcon:!0,message:H.partialFailure,description:G,action:(0,j.jsx)(s,{size:`small`,onClick:()=>void U(),children:H.retry})}):null,J.length?(0,j.jsx)(f,{type:`warning`,showIcon:!0,message:H.dependencyFailureTitle,description:(0,j.jsx)(o,{direction:`vertical`,size:2,children:J.map(([e,t])=>(0,j.jsxs)(c.Text,{children:[H.dependencyLabel(e),`: `,t]},e))}),action:(0,j.jsx)(s,{size:`small`,loading:E,onClick:()=>void U(),children:H.retry})}):null,(0,j.jsx)(ee,{title:H.title,subtitle:H.subtitle,extra:(0,j.jsx)(te,{"aria-label":H.rangeLabel,value:d,onChange:ce,options:[{label:H.last24Hours,value:1},{label:H.last7Days,value:7},{label:H.last30Days,value:30}]})}),(0,j.jsxs)(g,{gutter:[16,16],children:[(0,j.jsx)(h,{xs:24,sm:12,xl:6,children:(0,j.jsx)(M,{label:H.sent,value:Z.total||0,hint:`${Z.recipients||0} ${H.recipients}`})}),(0,j.jsx)(h,{xs:24,sm:12,xl:6,children:(0,j.jsx)(M,{label:H.deliveryRate,value:`${Z.deliveryRate||0}%`,hint:`${Z.delivered||0} ${H.delivered}`})}),(0,j.jsx)(h,{xs:24,sm:12,xl:6,children:(0,j.jsx)(M,{label:H.failuresAndDelays,value:$,tone:$?`danger`:`default`,hint:`${Z.terminalFailed||Z.failed||0} ${H.failed} · ${Z.deferred||0} ${H.deferred}`})}),(0,j.jsx)(h,{xs:24,sm:12,xl:6,children:(0,j.jsx)(M,{label:H.opensAndClicks,value:`${Q.openRate}% / ${Q.clickRate}%`,hint:`${Q.uniqueOpens} ${H.opens} · ${Q.uniqueClicks} ${H.clicks}`})})]}),(0,j.jsx)(p,{title:H.actionNeeded,extra:q.length?(0,j.jsxs)(m,{tone:`warning`,children:[q.length,` `,H.items]}):Y?(0,j.jsx)(m,{tone:`warning`,children:H.statusUnknown}):(0,j.jsx)(m,{tone:`success`,children:H.allClear}),children:q.length?(0,j.jsx)(_,{dataSource:q,renderItem:e=>(0,j.jsx)(_.Item,{actions:e.actions.map(t=>(0,j.jsxs)(s,{type:`link`,onClick:()=>n(t.path),children:[t.label,` `,(0,j.jsx)(ae,{})]},`${e.key}:${t.path}`)),children:(0,j.jsx)(_.Item.Meta,{avatar:(0,j.jsx)(A,{"aria-hidden":!0,style:{color:e.tone===`error`?`#dc2626`:`#d97706`,fontSize:20}}),title:(0,j.jsxs)(o,{wrap:!0,children:[(0,j.jsx)(c.Text,{strong:!0,children:e.title}),(0,j.jsx)(m,{tone:e.tone,children:H.needsAction})]}),description:e.description})})}):Y?(0,j.jsx)(S,{description:H.actionStatusUnknown,icon:(0,j.jsx)(A,{style:{color:`#d97706`}})}):(0,j.jsx)(S,{description:H.noActionNeeded,icon:(0,j.jsx)(b,{style:{color:`#16a34a`}})})}),Z.total?null:(0,j.jsx)(F,{domains:ue,credential:K?.smtpCredential,apiTokens:K?.apiTokens,onNavigate:n,copy:H}),(0,j.jsx)(T.Suspense,{fallback:(0,j.jsx)(p,{children:(0,j.jsx)(l,{active:!0,paragraph:{rows:8}})}),children:(0,j.jsx)(N,{analytics:X,copy:H,activeSection:v,onSectionChange:le})})]})}function F({domains:e,credential:t,apiTokens:n,onNavigate:r,copy:i}){let a=e.length>0,o=e.some(e=>C(e).status===`success`),l=L(t,n),u=[{title:i.addDomain,done:a,unknown:!1,actions:[{path:`/domains`}]},{title:i.configureDns,done:o,unknown:!1,actions:[{path:a?`/domains/${e[0].id}/dns`:`/domains`}]},{title:i.createCredential,done:l===`ready`,unknown:l===`unknown`,actions:[{label:i.smtpEntry,path:`/integrations/smtp`},{label:i.apiKeyEntry,path:`/integrations/api-keys`}]},{title:i.sendTest,done:!1,unknown:!1,actions:[{path:a?`/domains/${e[0].id}/sending`:`/domains`}]}];return(0,j.jsx)(p,{title:i.getReady,extra:(0,j.jsx)(c.Text,{type:`secondary`,children:i.getReadyHint}),children:(0,j.jsx)(_,{dataSource:u,renderItem:(e,t)=>(0,j.jsx)(_.Item,{actions:e.actions.map(n=>(0,j.jsx)(s,{type:t===0&&!e.done?`primary`:`default`,onClick:()=>r(n.path),children:n.label||(e.done?i.review:i.start)},n.path)),children:(0,j.jsx)(_.Item.Meta,{avatar:e.done?(0,j.jsx)(b,{style:{color:`#16a34a`,fontSize:20}}):e.unknown?(0,j.jsx)(m,{tone:`warning`,children:i.statusUnknown}):(0,j.jsx)(m,{tone:`neutral`,children:t+1}),title:(0,j.jsx)(c.Text,{delete:e.done,children:e.title})})})})})}function I(e,t){let n=e.domains.filter(e=>C(e).status!==`success`),r=e.analytics.recentFailures||[],i=[];if(n.length&&i.push({key:`dns`,title:t.dnsNotReady(n.length),description:t.dnsNotReadyHint,tone:`warning`,actions:[{label:t.reviewDomains,path:`/domains?status=error`}]}),r.length&&i.push({key:`failures`,title:t.recentFailures(r.length),description:r[0]?.detail||t.recentFailuresHint,tone:`error`,actions:[{label:t.inspectActivity,path:`/activity?status=failed`}]}),e.failedWebhooks?.length){let n=e.failedWebhooks[0],r=n?.webhookId?`/integrations/webhooks?webhookId=${n.webhookId}&deliveryStatus=dead`:`/integrations/webhooks?deliveryStatus=dead`;i.push({key:`webhooks`,title:t.webhookFailures(e.failedWebhooks.length),description:t.webhookFailuresHint,tone:`error`,actions:[{label:t.reviewWebhooks,path:r}]})}return L(e.smtpCredential,e.apiTokens)===`missing`&&i.push({key:`credential`,title:t.missingCredential,description:t.missingCredentialHint,tone:`warning`,actions:[{label:t.configureSmtp,path:`/integrations/smtp`},{label:t.createApiKey,path:`/integrations/api-keys`}]}),i}function L(e,t){let n=!!e?.passwordSet,r=!!t?.some(e=>e.status===`active`&&e.scopes.includes(`send`));return n||r?`ready`:e===void 0||t===void 0?`unknown`:`missing`}function R(e,t){return e instanceof Error?e.message:t}function z(e){return e===`1`?1:e===`30`?30:7}function B(e){return e===`engagement`?`engagement`:`delivery`}var oe={title:`运行概览`,subtitle:`从投递健康开始,快速定位需要处理的问题。`,loading:`正在加载运行概览`,loadFailed:`概览加载失败`,retry:`重试`,rangeLabel:`统计时间范围`,last24Hours:`24 小时`,last7Days:`7 天`,last30Days:`30 天`,sent:`发送量`,recipients:`位收件人`,deliveryRate:`送达率`,delivered:`已送达`,failuresAndDelays:`失败 / 延迟`,failed:`失败`,deferred:`延迟`,opensAndClicks:`打开 / 点击`,opens:`打开`,clicks:`点击`,actionNeeded:`需要处理`,items:`项`,allClear:`状态正常`,statusUnknown:`状态未知`,needsAction:`需要处理`,noActionNeeded:`当前没有检测到需要处理的投递问题。`,actionStatusUnknown:`部分运维状态暂时无法获取,请重试后再确认。`,partialFailure:`部分数据刷新失败`,dependencyFailureTitle:`部分运维状态获取失败`,dependencyLabel:e=>({smtp:`SMTP 凭据`,apiTokens:`API 密钥`,webhooks:`Webhook 失败投递`})[e],dependencyError:(e,t)=>`${e}:${R(t,`加载失败`)}`,analyticsDependency:`投递统计`,domainsDependency:`域名状态`,defaultPassword:`当前仍在使用默认管理员密码`,defaultPasswordDescription:`请修改部署环境中的 ADMIN_PASSWORD,并重启 MailHub 服务使新密码生效。`,getReady:`发送就绪清单`,getReadyHint:`完成以下步骤后即可进行首次测试发送`,addDomain:`添加发信域名`,configureDns:`配置并验证 DNS`,createCredential:`创建 SMTP 或 API 凭据`,smtpEntry:`SMTP`,apiKeyEntry:`API 密钥`,sendTest:`发送测试邮件`,review:`查看`,start:`开始`,deliveryQuality:`投递质量`,engagementAnalysis:`互动分析`,deliveryTrend:`发送与送达趋势`,engagementTrend:`打开与点击趋势`,domainRanking:`域名发送排行`,topLinks:`热门链接`,link:`链接`,uniqueClicks:`独立点击`,noDeliveryData:`当前范围暂无发送数据`,noDomainData:`暂无域名发送数据`,noEngagementData:`暂无互动数据`,dnsNotReady:e=>`${e} 个域名的 DNS 尚未就绪`,dnsNotReadyHint:`认证记录不完整可能导致投递失败或进入垃圾箱。`,reviewDomains:`处理域名`,recentFailures:e=>`最近发现 ${e} 条发送失败`,recentFailuresHint:`请检查投递响应和队列日志。`,inspectActivity:`查看活动`,webhookFailures:e=>`${e} 条 Webhook 投递已停止重试`,webhookFailuresHint:`请检查回调地址、签名校验和服务可用性。`,reviewWebhooks:`检查 Webhooks`,missingCredential:`尚未创建可用的发送凭据`,missingCredentialHint:`配置 SMTP 凭据或创建具备 send 权限的 API 密钥后,应用即可发送邮件。`,configureSmtp:`配置 SMTP`,createApiKey:`创建 API 密钥`},se={title:`Operations overview`,subtitle:`Start with delivery health and move directly to issues that need attention.`,loading:`Loading operations overview`,loadFailed:`Unable to load overview`,retry:`Retry`,rangeLabel:`Analytics range`,last24Hours:`24 hours`,last7Days:`7 days`,last30Days:`30 days`,sent:`Sent`,recipients:`recipients`,deliveryRate:`Delivery rate`,delivered:`Delivered`,failuresAndDelays:`Failed / delayed`,failed:`Failed`,deferred:`Delayed`,opensAndClicks:`Opens / clicks`,opens:`Opens`,clicks:`Clicks`,actionNeeded:`Action needed`,items:`items`,allClear:`All clear`,statusUnknown:`Status unknown`,needsAction:`Needs action`,noActionNeeded:`No delivery issues currently require attention.`,actionStatusUnknown:`Some operational status is unavailable. Retry before treating the environment as healthy.`,partialFailure:`Some data could not be refreshed`,dependencyFailureTitle:`Some operational status could not be loaded`,dependencyLabel:e=>({smtp:`SMTP credentials`,apiTokens:`API keys`,webhooks:`Failed webhook deliveries`})[e],dependencyError:(e,t)=>`${e}: ${R(t,`Unable to load`)}`,analyticsDependency:`Delivery analytics`,domainsDependency:`Domain status`,defaultPassword:`The default administrator password is still in use`,defaultPasswordDescription:`Update ADMIN_PASSWORD in the deployment environment, then restart MailHub for the new password to take effect.`,getReady:`Sending readiness`,getReadyHint:`Complete these steps before your first test send`,addDomain:`Add a sending domain`,configureDns:`Configure and verify DNS`,createCredential:`Create an SMTP or API credential`,smtpEntry:`SMTP`,apiKeyEntry:`API key`,sendTest:`Send a test email`,review:`Review`,start:`Start`,deliveryQuality:`Delivery quality`,engagementAnalysis:`Engagement`,deliveryTrend:`Sending and delivery trend`,engagementTrend:`Open and click trend`,domainRanking:`Domain ranking`,topLinks:`Top links`,link:`Link`,uniqueClicks:`Unique clicks`,noDeliveryData:`No sending data in this range`,noDomainData:`No domain sending data`,noEngagementData:`No engagement data`,dnsNotReady:e=>`${e} domains have incomplete DNS`,dnsNotReadyHint:`Incomplete authentication records can cause delivery failures or spam placement.`,reviewDomains:`Review domains`,recentFailures:e=>`${e} recent sends failed`,recentFailuresHint:`Inspect the delivery response and queue log.`,inspectActivity:`Inspect activity`,webhookFailures:e=>`${e} webhook deliveries stopped retrying`,webhookFailuresHint:`Check the callback endpoint, signature validation, and service availability.`,reviewWebhooks:`Review webhooks`,missingCredential:`No usable sending credential`,missingCredentialHint:`Configure SMTP or create an API key with the send scope before applications send email.`,configureSmtp:`Configure SMTP`,createApiKey:`Create API key`};export{P as default};