diff --git a/app/soapbox/features/admin/awaiting_approval.js b/app/soapbox/features/admin/awaiting_approval.js
index 6b67dd02e8..03a7d5a05e 100644
Binary files a/app/soapbox/features/admin/awaiting_approval.js and b/app/soapbox/features/admin/awaiting_approval.js differ
diff --git a/app/soapbox/features/admin/index.tsx b/app/soapbox/features/admin/index.tsx
index 0f8004e595..13e4d0cadf 100644
--- a/app/soapbox/features/admin/index.tsx
+++ b/app/soapbox/features/admin/index.tsx
@@ -1,154 +1,37 @@
import React from 'react';
-import { defineMessages, useIntl, FormattedMessage, FormattedNumber } from 'react-intl';
-import { Link } from 'react-router-dom';
+import { defineMessages, useIntl } from 'react-intl';
+import { Switch, Route } from 'react-router-dom';
-import { getSubscribersCsv, getUnsubscribersCsv, getCombinedCsv } from 'soapbox/actions/email_list';
-import { Text } from 'soapbox/components/ui';
-import { useAppSelector, useAppDispatch, useOwnAccount, useFeatures } from 'soapbox/hooks';
-import sourceCode from 'soapbox/utils/code';
-import { parseVersion } from 'soapbox/utils/features';
-import { isNumber } from 'soapbox/utils/numbers';
+import { useOwnAccount } from 'soapbox/hooks';
import Column from '../ui/components/column';
+import Waitlist from './awaiting_approval';
import AdminTabs from './components/admin-tabs';
-import RegistrationModePicker from './components/registration_mode_picker';
-
-import type { AxiosResponse } from 'axios';
-
-/** Download the file from the response instead of opening it in a tab. */
-// https://stackoverflow.com/a/53230807
-const download = (response: AxiosResponse, filename: string) => {
- 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();
-};
+import Reports from './reports';
+import Dashboard from './tabs/dashboard';
const messages = defineMessages({
heading: { id: 'column.admin.dashboard', defaultMessage: 'Dashboard' },
});
-const Dashboard: React.FC = () => {
+const Admin: 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;
+export default Admin;
diff --git a/app/soapbox/features/admin/reports.js b/app/soapbox/features/admin/reports.js
index 3f377ba701..1c9d921cd3 100644
Binary files a/app/soapbox/features/admin/reports.js and b/app/soapbox/features/admin/reports.js differ
diff --git a/app/soapbox/features/admin/tabs/dashboard.tsx b/app/soapbox/features/admin/tabs/dashboard.tsx
new file mode 100644
index 0000000000..248885b21f
--- /dev/null
+++ b/app/soapbox/features/admin/tabs/dashboard.tsx
@@ -0,0 +1,146 @@
+import React from 'react';
+import { FormattedMessage, FormattedNumber } from 'react-intl';
+import { Link } from 'react-router-dom';
+
+import { getSubscribersCsv, getUnsubscribersCsv, getCombinedCsv } from 'soapbox/actions/email_list';
+import { Text } from 'soapbox/components/ui';
+import { useAppSelector, useAppDispatch, useOwnAccount, useFeatures } from 'soapbox/hooks';
+import sourceCode from 'soapbox/utils/code';
+import { parseVersion } from 'soapbox/utils/features';
+import { isNumber } from 'soapbox/utils/numbers';
+
+import RegistrationModePicker from '../components/registration_mode_picker';
+
+import type { AxiosResponse } from 'axios';
+
+/** Download the file from the response instead of opening it in a tab. */
+// https://stackoverflow.com/a/53230807
+const download = (response: AxiosResponse, filename: string) => {
+ 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 Dashboard: React.FC = () => {
+ 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/features/ui/index.tsx b/app/soapbox/features/ui/index.tsx
index 25c060bfeb..9217a77d78 100644
--- a/app/soapbox/features/ui/index.tsx
+++ b/app/soapbox/features/ui/index.tsx
@@ -302,8 +302,8 @@ const SwitchingColumnsArea: React.FC = ({ children }) => {
-
-
+
+