From 27b7fc4f3066f3cda343f8678441a40ad4327763 Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Thu, 28 Apr 2022 11:36:45 -0500 Subject: [PATCH] Convert admin/index to TSX --- app/soapbox/features/admin/index.js | Bin 5922 -> 0 bytes app/soapbox/features/admin/index.tsx | 151 +++++++++++++++++++++++++++ app/soapbox/utils/numbers.tsx | 2 +- 3 files changed, 152 insertions(+), 1 deletion(-) delete mode 100644 app/soapbox/features/admin/index.js create mode 100644 app/soapbox/features/admin/index.tsx diff --git a/app/soapbox/features/admin/index.js b/app/soapbox/features/admin/index.js deleted file mode 100644 index 93a38c53fa0d067c3c1a30ad9f3071567233ba09..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5922 zcmc&&ZExE)5dNND!C_b_54M!G8#cIB_L80Y0E?v9km3Z*T1qgCadH#Uyq=)lf!R*C)cjO|ubk&SKfXT5Op->Z3t&T1z7#os#f@PX+>D9H z|Ky2%nOiv~FO<%hwLGm~drw}M*@A1b_4Aqt(DH33D$l{#KuYtpy!OS;M1DDxQKjX2 zlBx^@8z492g4?&{!X#RNb8~9eV|?^JH@go3kp(1{f>3MQC{`@gbp$mKDmM|&n2>WR zj8~EkdB?B2kQBPlY`Lo-`f2bzRkFel%RY`qPg`w?tc<~9QfAOtwTSR$WTxq@pQSgWA?vdg4 zS8IW%z~g{6VN)+w6m5+!RC*J#qTqRYx)L%C&`9SXk$_jw{ntDLobbUGAgr>@>K4YB zdp#W>A}h{PkzY*7hKO`ZXjRRSrJ2Yfce7e3rc;OybXh5F-SHs#tbIwgr5S5coa}>H}N9oE4OA=M)pxVatG7mn``mq5dGXBvy z1c(u3e(ffHjSu;y9&SO_hhcQ|OE*G~63L7qErbL{3zXQ91H*fRfM7r(aUfQ!C2qm7 za@wt&P&qz_!kqKJN&#cF%B)Fx>Un{JI9nk^yQ8oN&vqY$3#H@$u`c-5tmcW*&Obs0 zbYpocxj(Cs!N34uLDiy!*p)D$qe_?xQ!tyXf}H^$j7Fhd@jPhTz2y~Bp=qr4?U+z+ z8H9;hSA9yzb`&PgM^ITnCZh=sG4M6?^s|cjRhw)Y$a}96& zy&N?5su2R~2)8w@Rzu^vG+dwJ`~YQN-pvqfU>qP6rRHwT(2q6S>RHXoeTs$TaEfH8 z+S~#YbjQbflLXCv z3hPxg+Md)F!DcGf#Lddru*PGG3(4UI;L}cwkPRjTnf{AHPaaIW;~bOX0-{X-IIbx% z;&1Ts_*znO#l^+S#;}i4QDy^WP;bw`^B#hSZ{8+vRyX)<&}Z#-oOdV-Lso*WJ(2rQr3_Ej(}CAHp1~f|IJ6gF8HjfcAu0aox*j zbWh$}k#RVe^GK?M$pP&D5%mu*7u*n~Y1hk_Zw)_yLxn1ofmL{yIW%mGyA%G4BM)CC zn8^P}Wx5>K!SIYha7$#DjY`QN!?zSS? z4IWjtWCk~v+~1c4oUA4q4;8ehRUag`vj{c7Gg$3;t{tu03~n>N4sW$Ni~8vd$_t}@ z=kkX|-mUtc^-}@Gn9diH<(KqiaEY8n>|n)ibJo8IVl2Dvc5ZqPaoAqj_WSbhWc%IhXHB;)dn}qo Q)rFuUv%BWN<#~Jb4~;!i!T { + const url = URL.createObjectURL(new Blob([response.data])); + const link = document.createElement('a'); + link.href = url; + link.setAttribute('download', filename); + document.body.appendChild(link); + link.click(); + link.remove(); +}; + +const messages = defineMessages({ + heading: { id: 'column.admin.dashboard', defaultMessage: 'Dashboard' }, +}); + +const Dashboard: React.FC = () => { + const intl = useIntl(); + const dispatch = useAppDispatch(); + const instance = useAppSelector(state => state.instance); + const features = useFeatures(); + const account = useOwnAccount(); + + const handleSubscribersClick: React.MouseEventHandler = e => { + dispatch(getSubscribersCsv()).then((response) => { + download(response, 'subscribers.csv'); + }).catch(() => {}); + e.preventDefault(); + }; + + const handleUnsubscribersClick: React.MouseEventHandler = e => { + dispatch(getUnsubscribersCsv()).then((response) => { + download(response, 'unsubscribers.csv'); + }).catch(() => {}); + e.preventDefault(); + }; + + const handleCombinedClick: React.MouseEventHandler = e => { + dispatch(getCombinedCsv()).then((response) => { + download(response, 'combined.csv'); + }).catch(() => {}); + e.preventDefault(); + }; + + const v = parseVersion(instance.version); + + const userCount = instance.stats.get('user_count'); + const statusCount = instance.stats.get('status_count'); + const domainCount = instance.stats.get('domain_count'); + + const mau = instance.pleroma.getIn(['stats', 'mau']) as number | undefined; + const retention = (userCount && mau) ? Math.round(mau / userCount * 100) : null; + + if (!account) return null; + + return ( + +
+ {isNumber(mau) && ( +
+ + + + + + +
+ )} + {isNumber(userCount) && ( + + + + + + + + + )} + {isNumber(retention) && ( +
+ + {retention}% + + + + +
+ )} + {isNumber(statusCount) && ( + + + + + + + + + )} + {isNumber(domainCount) && ( +
+ + + + + + +
+ )} +
+ + {account.admin && } + +
+
+

+
    +
  • {sourceCode.displayName} {sourceCode.version}
  • +
  • {v.software} {v.version}
  • +
+
+ {features.emailList && account.admin && } +
+
+ ); +}; + +export default Dashboard; diff --git a/app/soapbox/utils/numbers.tsx b/app/soapbox/utils/numbers.tsx index ba5e3cbe40..db04b30d23 100644 --- a/app/soapbox/utils/numbers.tsx +++ b/app/soapbox/utils/numbers.tsx @@ -2,7 +2,7 @@ import React from 'react'; import { FormattedNumber } from 'react-intl'; /** Check if a value is REALLY a number. */ -export const isNumber = (number: unknown): boolean => typeof number === 'number' && !isNaN(number); +export const isNumber = (value: unknown): value is number => typeof value === 'number' && !isNaN(value); /** Display a number nicely for the UI, eg 1000 becomes 1K. */ export const shortNumberFormat = (number: any): React.ReactNode => {