pl-fe: migrate admin dashboard, cleanup
Signed-off-by: nicole mikołajczyk <git@mkljczk.pl>
This commit is contained in:
@ -1,4 +1,4 @@
|
||||
import { Link, useNavigate } from '@tanstack/react-router';
|
||||
import { Link, linkOptions, useNavigate, useRouter } from '@tanstack/react-router';
|
||||
import clsx from 'clsx';
|
||||
import React, { useLayoutEffect, useRef, useState } from 'react';
|
||||
import { defineMessages, useIntl, FormattedMessage } from 'react-intl';
|
||||
@ -40,17 +40,18 @@ const messages = defineMessages({
|
||||
const InstanceFavicon: React.FC<IInstanceFavicon> = ({ account, disabled }) => {
|
||||
const navigate = useNavigate();
|
||||
const intl = useIntl();
|
||||
const router = useRouter();
|
||||
|
||||
const handleClick: React.MouseEventHandler = (e) => {
|
||||
e.stopPropagation();
|
||||
|
||||
if (disabled) return;
|
||||
|
||||
const timelineUrl = `/timeline/${account.domain}`;
|
||||
const link = linkOptions({ to: '/timeline/$instance', params: { instance: account.domain } });
|
||||
if (!(e.ctrlKey || e.metaKey)) {
|
||||
navigate({ to: timelineUrl });
|
||||
navigate(link);
|
||||
} else {
|
||||
window.open(timelineUrl, '_blank');
|
||||
window.open(router.buildLocation(link).href, '_blank');
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { useNavigate } from '@tanstack/react-router';
|
||||
import { linkOptions, useNavigate, useRouter } from '@tanstack/react-router';
|
||||
import clsx from 'clsx';
|
||||
import React, { MouseEventHandler } from 'react';
|
||||
import { defineMessages, useIntl } from 'react-intl';
|
||||
@ -33,17 +33,22 @@ interface IQuotedStatus {
|
||||
const QuotedStatus: React.FC<IQuotedStatus> = ({ status, onCancel, compose }) => {
|
||||
const intl = useIntl();
|
||||
const navigate = useNavigate();
|
||||
const router = useRouter();
|
||||
|
||||
const handleExpandClick: MouseEventHandler<HTMLDivElement> = (e) => {
|
||||
if (!status) return;
|
||||
const account = status.account;
|
||||
|
||||
if (!compose && e.button === 0) {
|
||||
const statusUrl = `/@${account.acct}/posts/${status.id}`;
|
||||
const link = linkOptions({
|
||||
to: '/@{$username}/posts/$statusId',
|
||||
params: { username: account.acct, statusId: status.id },
|
||||
});
|
||||
if (!(e.ctrlKey || e.metaKey)) {
|
||||
navigate({ to: '/@{$username}/posts/$statusId', params: { username: account.acct, statusId: status.id } });
|
||||
navigate(link);
|
||||
} else {
|
||||
window.open(statusUrl, '_blank');
|
||||
const url = router.buildLocation(link).href;
|
||||
window.open(url, '_blank');
|
||||
}
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { Link, useNavigate } from '@tanstack/react-router';
|
||||
import { Link, linkOptions, useNavigate, useRouter } from '@tanstack/react-router';
|
||||
import clsx from 'clsx';
|
||||
import React, { useEffect, useMemo, useRef } from 'react';
|
||||
import { defineMessages, useIntl, FormattedList, FormattedMessage } from 'react-intl';
|
||||
@ -76,6 +76,7 @@ const Status: React.FC<IStatus> = (props) => {
|
||||
const intl = useIntl();
|
||||
const navigate = useNavigate();
|
||||
const dispatch = useAppDispatch();
|
||||
const router = useRouter();
|
||||
|
||||
const { toggleStatusesMediaHidden } = useStatusMetaActions();
|
||||
const { openModal } = useModalsActions();
|
||||
@ -92,7 +93,6 @@ const Status: React.FC<IStatus> = (props) => {
|
||||
const { mutate: unreblogStatus } = useUnreblogStatus(actualStatus.id);
|
||||
|
||||
const isReblog = status.reblog_id;
|
||||
const statusUrl = '/@{$username}/posts/$postId';
|
||||
const group = actualStatus.group;
|
||||
|
||||
const filterResults = useMemo(() => [...status.filtered, ...actualStatus.filtered].filter(({ filter }) => filter.filter_action === 'warn'), [status.filtered, actualStatus.filtered]);
|
||||
@ -111,14 +111,20 @@ const Status: React.FC<IStatus> = (props) => {
|
||||
return;
|
||||
}
|
||||
|
||||
const link = linkOptions({
|
||||
to: '/@{$username}/posts/$statusId',
|
||||
params: { username: actualStatus.account.acct, statusId: actualStatus.id },
|
||||
});
|
||||
|
||||
if (!e || !(e.ctrlKey || e.metaKey)) {
|
||||
if (onClick) {
|
||||
onClick();
|
||||
} else {
|
||||
navigate({ to: '/@{$username}/posts/$statusId', params: { username: actualStatus.account.acct, statusId: actualStatus.id } });
|
||||
navigate(link);
|
||||
}
|
||||
} else {
|
||||
window.open(statusUrl, '_blank');
|
||||
const url = router.buildLocation(link).href;
|
||||
window.open(url, '_blank');
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@ -1,12 +1,19 @@
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
import { defineMessages, FormattedMessage, useIntl } from 'react-intl';
|
||||
|
||||
import ScrollableList from 'pl-fe/components/scrollable-list';
|
||||
import Column from 'pl-fe/components/ui/column';
|
||||
import { useAdminAccounts } from 'pl-fe/queries/admin/use-accounts';
|
||||
|
||||
import UnapprovedAccount from '../components/unapproved-account';
|
||||
|
||||
const messages = defineMessages({
|
||||
heading: { id: 'column.admin.awaiting_approval', defaultMessage: 'Awaiting approval' },
|
||||
});
|
||||
|
||||
const AwaitingApproval: React.FC = () => {
|
||||
const intl = useIntl();
|
||||
|
||||
const { data, isPending, isFetching } = useAdminAccounts({
|
||||
origin: 'local',
|
||||
status: 'pending',
|
||||
@ -19,19 +26,21 @@ const AwaitingApproval: React.FC = () => {
|
||||
}, [data]);
|
||||
|
||||
return (
|
||||
<ScrollableList
|
||||
scrollKey='awaitingApproval'
|
||||
isLoading={isFetching}
|
||||
showLoading={isPending}
|
||||
emptyMessageText={<FormattedMessage id='admin.awaiting_approval.empty_message' defaultMessage='There is nobody waiting for approval. When a new user signs up, you can review them here.' />}
|
||||
listClassName='divide-y divide-solid divide-gray-200 black:divide-gray-800 dark:divide-primary-800'
|
||||
>
|
||||
{accountIds.map(id => (
|
||||
<div key={id} className='px-5 py-4'>
|
||||
<UnapprovedAccount accountId={id} />
|
||||
</div>
|
||||
))}
|
||||
</ScrollableList>
|
||||
<Column label={intl.formatMessage(messages.heading)}>
|
||||
<ScrollableList
|
||||
scrollKey='awaitingApproval'
|
||||
isLoading={isFetching}
|
||||
showLoading={isPending}
|
||||
emptyMessageText={<FormattedMessage id='admin.awaiting_approval.empty_message' defaultMessage='There is nobody waiting for approval. When a new user signs up, you can review them here.' />}
|
||||
listClassName='divide-y divide-solid divide-gray-200 black:divide-gray-800 dark:divide-primary-800'
|
||||
>
|
||||
{accountIds.map(id => (
|
||||
<div key={id} className='px-5 py-4'>
|
||||
<UnapprovedAccount accountId={id} />
|
||||
</div>
|
||||
))}
|
||||
</ScrollableList>
|
||||
</Column>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@ -1,8 +1,9 @@
|
||||
import React, { useState } from 'react';
|
||||
import { FormattedMessage, FormattedNumber } from 'react-intl';
|
||||
import { defineMessages, FormattedMessage, FormattedNumber, useIntl } from 'react-intl';
|
||||
|
||||
import List, { ListItem } from 'pl-fe/components/list';
|
||||
import { CardTitle } from 'pl-fe/components/ui/card';
|
||||
import Column from 'pl-fe/components/ui/column';
|
||||
import Icon from 'pl-fe/components/ui/icon';
|
||||
import Stack from 'pl-fe/components/ui/stack';
|
||||
import { useFeatures } from 'pl-fe/hooks/use-features';
|
||||
@ -18,7 +19,12 @@ import { Dimension } from '../components/dimension';
|
||||
import RegistrationModePicker from '../components/registration-mode-picker';
|
||||
import { Retention } from '../components/retention';
|
||||
|
||||
const messages = defineMessages({
|
||||
heading: { id: 'column.admin.dashboard', defaultMessage: 'Dashboard' },
|
||||
});
|
||||
|
||||
const Dashboard: React.FC = () => {
|
||||
const intl = useIntl();
|
||||
const instance = useInstance();
|
||||
const features = useFeatures();
|
||||
const { account } = useOwnAccount();
|
||||
@ -44,199 +50,201 @@ const Dashboard: React.FC = () => {
|
||||
if (!account) return null;
|
||||
|
||||
return (
|
||||
<Stack space={6} className='mt-4'>
|
||||
<DashCounters>
|
||||
{features.mastodonAdminMetrics ? (
|
||||
<Counter
|
||||
measure='new_users'
|
||||
startAt={monthAgo}
|
||||
endAt={today}
|
||||
to='/pl-fe/admin/users'
|
||||
label={<FormattedMessage id='admin.counters.new_users' defaultMessage='new users' />}
|
||||
/>
|
||||
) : (
|
||||
<DashCounter
|
||||
to='/pl-fe/admin/users'
|
||||
count={userCount}
|
||||
label={<FormattedMessage id='admin.dashcounters.user_count_label' defaultMessage='total users' />}
|
||||
/>
|
||||
)}
|
||||
{features.mastodonAdminMetrics ? (
|
||||
<Counter
|
||||
measure='active_users'
|
||||
startAt={monthAgo}
|
||||
endAt={today}
|
||||
label={<FormattedMessage id='admin.counters.active_users' defaultMessage='active users' />}
|
||||
/>
|
||||
) : (
|
||||
<DashCounter
|
||||
count={mau}
|
||||
label={<FormattedMessage id='admin.dashcounters.mau_label' defaultMessage='monthly active users' />}
|
||||
/>
|
||||
)}
|
||||
{!features.mastodonAdminMetrics && (
|
||||
<DashCounter
|
||||
count={retention}
|
||||
label={<FormattedMessage id='admin.dashcounters.retention_label' defaultMessage='user retention' />}
|
||||
percent
|
||||
/>
|
||||
)}
|
||||
{features.mastodonAdminMetrics && (
|
||||
<>
|
||||
<Column label={intl.formatMessage(messages.heading)}>
|
||||
<Stack space={6} className='mt-4'>
|
||||
<DashCounters>
|
||||
{features.mastodonAdminMetrics ? (
|
||||
<Counter
|
||||
measure='interactions'
|
||||
measure='new_users'
|
||||
startAt={monthAgo}
|
||||
endAt={today}
|
||||
label={<FormattedMessage id='admin.counters.interactions' defaultMessage='interactions' />}
|
||||
to='/pl-fe/admin/users'
|
||||
label={<FormattedMessage id='admin.counters.new_users' defaultMessage='new users' />}
|
||||
/>
|
||||
) : (
|
||||
<DashCounter
|
||||
to='/pl-fe/admin/users'
|
||||
count={userCount}
|
||||
label={<FormattedMessage id='admin.dashcounters.user_count_label' defaultMessage='total users' />}
|
||||
/>
|
||||
)}
|
||||
{features.mastodonAdminMetrics ? (
|
||||
<Counter
|
||||
measure='opened_reports'
|
||||
measure='active_users'
|
||||
startAt={monthAgo}
|
||||
endAt={today}
|
||||
to='/pl-fe/admin/reports'
|
||||
label={<FormattedMessage id='admin.counters.opened_reports' defaultMessage='reports opened' />}
|
||||
label={<FormattedMessage id='admin.counters.active_users' defaultMessage='active users' />}
|
||||
/>
|
||||
<Counter
|
||||
measure='resolved_reports'
|
||||
startAt={monthAgo}
|
||||
endAt={today}
|
||||
to='/pl-fe/admin/reports'
|
||||
search={{ resolved: true }}
|
||||
label={<FormattedMessage id='admin.counters.resolved_reports' defaultMessage='reports resolved' />}
|
||||
) : (
|
||||
<DashCounter
|
||||
count={mau}
|
||||
label={<FormattedMessage id='admin.dashcounters.mau_label' defaultMessage='monthly active users' />}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
<DashCounter
|
||||
to='/timeline/local'
|
||||
count={statusCount}
|
||||
label={<FormattedMessage id='admin.dashcounters.status_count_label' defaultMessage='posts' />}
|
||||
/>
|
||||
<DashCounter
|
||||
count={domainCount}
|
||||
label={<FormattedMessage id='admin.dashcounters.domain_count_label' defaultMessage='peers' />}
|
||||
/>
|
||||
)}
|
||||
{!features.mastodonAdminMetrics && (
|
||||
<DashCounter
|
||||
count={retention}
|
||||
label={<FormattedMessage id='admin.dashcounters.retention_label' defaultMessage='user retention' />}
|
||||
percent
|
||||
/>
|
||||
)}
|
||||
{features.mastodonAdminMetrics && (
|
||||
<>
|
||||
<Counter
|
||||
measure='interactions'
|
||||
startAt={monthAgo}
|
||||
endAt={today}
|
||||
label={<FormattedMessage id='admin.counters.interactions' defaultMessage='interactions' />}
|
||||
/>
|
||||
<Counter
|
||||
measure='opened_reports'
|
||||
startAt={monthAgo}
|
||||
endAt={today}
|
||||
to='/pl-fe/admin/reports'
|
||||
label={<FormattedMessage id='admin.counters.opened_reports' defaultMessage='reports opened' />}
|
||||
/>
|
||||
<Counter
|
||||
measure='resolved_reports'
|
||||
startAt={monthAgo}
|
||||
endAt={today}
|
||||
to='/pl-fe/admin/reports'
|
||||
search={{ resolved: true }}
|
||||
label={<FormattedMessage id='admin.counters.resolved_reports' defaultMessage='reports resolved' />}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
<DashCounter
|
||||
to='/timeline/local'
|
||||
count={statusCount}
|
||||
label={<FormattedMessage id='admin.dashcounters.status_count_label' defaultMessage='posts' />}
|
||||
/>
|
||||
<DashCounter
|
||||
count={domainCount}
|
||||
label={<FormattedMessage id='admin.dashcounters.domain_count_label' defaultMessage='peers' />}
|
||||
/>
|
||||
<List>
|
||||
<ListItem size='sm' to='/pl-fe/admin/reports' search={{ resolved: false }} label={<FormattedMessage id='admin.links.pending_reports' defaultMessage='{count, plural, one {{formattedCount} pending report} other {{formattedCount} pending reports}}' values={{ count: pendingReportsCount, formattedCount: <strong><FormattedNumber value={pendingReportsCount} /></strong> }} />} />
|
||||
<ListItem size='sm' to='/pl-fe/admin/users' label={<FormattedMessage id='admin.links.pending_users' defaultMessage='{count, plural, one {{formattedCount} pending user} other {{formattedCount} pending users}}' values={{ count: awaitingApprovalCount, formattedCount: <strong><FormattedNumber value={awaitingApprovalCount} /></strong> }} />} />
|
||||
{/* <ListItem size='sm' to='/pl-fe/admin' label={<FormattedMessage id='admin.links.pending_tags' defaultMessage='{count} pending tags' values={{ count: <strong>0</strong> }} />} />
|
||||
<ListItem size='sm' to='/pl-fe/admin' label={<FormattedMessage id='admin.links.pending_appeals' defaultMessage='{count} pending appeals' values={{ count: <strong>0</strong> }} />} /> */}
|
||||
</List>
|
||||
{features.mastodonAdminMetrics && (
|
||||
<>
|
||||
<Dimension
|
||||
dimension='sources'
|
||||
startAt={monthAgo}
|
||||
endAt={today}
|
||||
params={{ limit: 8 }}
|
||||
label={<FormattedMessage id='admin.dimensions.sources' defaultMessage='Sign-up sources' />}
|
||||
/>
|
||||
<Dimension
|
||||
dimension='languages'
|
||||
startAt={monthAgo}
|
||||
endAt={today}
|
||||
params={{ limit: 8 }}
|
||||
label={<FormattedMessage id='admin.dimensions.top_languages' defaultMessage='Top active languages' />}
|
||||
/>
|
||||
<Dimension
|
||||
dimension='servers'
|
||||
startAt={monthAgo}
|
||||
endAt={today}
|
||||
params={{ limit: 8 }}
|
||||
label={<FormattedMessage id='admin.dimensions.top_servers' defaultMessage='Top active servers' />}
|
||||
/>
|
||||
<Retention startAt={sixMonthsAgo} endAt={today} frequency='month' />
|
||||
<Dimension
|
||||
dimension='software_versions'
|
||||
startAt={monthAgo}
|
||||
endAt={today}
|
||||
params={{ limit: 4 }}
|
||||
label={<FormattedMessage id='admin.dimensions.software' defaultMessage='Software' />}
|
||||
/>
|
||||
<Dimension
|
||||
dimension='space_usage'
|
||||
startAt={monthAgo}
|
||||
endAt={today}
|
||||
params={{ limit: 3 }}
|
||||
label={<FormattedMessage id='admin.dimensions.media_storage' defaultMessage='Media storage' />}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
</DashCounters>
|
||||
|
||||
<List>
|
||||
<ListItem size='sm' to='/pl-fe/admin/reports' search={{ resolved: false }} label={<FormattedMessage id='admin.links.pending_reports' defaultMessage='{count, plural, one {{formattedCount} pending report} other {{formattedCount} pending reports}}' values={{ count: pendingReportsCount, formattedCount: <strong><FormattedNumber value={pendingReportsCount} /></strong> }} />} />
|
||||
<ListItem size='sm' to='/pl-fe/admin/users' label={<FormattedMessage id='admin.links.pending_users' defaultMessage='{count, plural, one {{formattedCount} pending user} other {{formattedCount} pending users}}' values={{ count: awaitingApprovalCount, formattedCount: <strong><FormattedNumber value={awaitingApprovalCount} /></strong> }} />} />
|
||||
{/* <ListItem size='sm' to='/pl-fe/admin' label={<FormattedMessage id='admin.links.pending_tags' defaultMessage='{count} pending tags' values={{ count: <strong>0</strong> }} />} />
|
||||
<ListItem size='sm' to='/pl-fe/admin' label={<FormattedMessage id='admin.links.pending_appeals' defaultMessage='{count} pending appeals' values={{ count: <strong>0</strong> }} />} /> */}
|
||||
{features.pleromaAdminAccounts && account.is_admin && (
|
||||
<ListItem
|
||||
to='/pl-fe/config'
|
||||
label={<FormattedMessage id='navigation_bar.plfe_config' defaultMessage='Front-end configuration' />}
|
||||
/>
|
||||
)}
|
||||
|
||||
{features.pleromaAdminModerationLog && (
|
||||
<ListItem
|
||||
to='/pl-fe/admin/log'
|
||||
label={<FormattedMessage id='column.admin.moderation_log' defaultMessage='Moderation log' />}
|
||||
/>
|
||||
)}
|
||||
|
||||
{features.pleromaAdminAnnouncements && (
|
||||
<ListItem
|
||||
to='/pl-fe/admin/announcements'
|
||||
label={<FormattedMessage id='column.admin.announcements' defaultMessage='Announcements' />}
|
||||
/>
|
||||
)}
|
||||
|
||||
{features.adminRules && (
|
||||
<ListItem
|
||||
to='/pl-fe/admin/rules'
|
||||
label={<FormattedMessage id='column.admin.rules' defaultMessage='Instance rules' />}
|
||||
/>
|
||||
)}
|
||||
|
||||
{features.domains && (
|
||||
<ListItem
|
||||
to='/pl-fe/admin/domains'
|
||||
label={<FormattedMessage id='column.admin.domains' defaultMessage='Domains' />}
|
||||
/>
|
||||
)}
|
||||
</List>
|
||||
{features.mastodonAdminMetrics && (
|
||||
|
||||
{features.pleromaAdminAccounts && account.is_admin && (
|
||||
<>
|
||||
<Dimension
|
||||
dimension='sources'
|
||||
startAt={monthAgo}
|
||||
endAt={today}
|
||||
params={{ limit: 8 }}
|
||||
label={<FormattedMessage id='admin.dimensions.sources' defaultMessage='Sign-up sources' />}
|
||||
/>
|
||||
<Dimension
|
||||
dimension='languages'
|
||||
startAt={monthAgo}
|
||||
endAt={today}
|
||||
params={{ limit: 8 }}
|
||||
label={<FormattedMessage id='admin.dimensions.top_languages' defaultMessage='Top active languages' />}
|
||||
/>
|
||||
<Dimension
|
||||
dimension='servers'
|
||||
startAt={monthAgo}
|
||||
endAt={today}
|
||||
params={{ limit: 8 }}
|
||||
label={<FormattedMessage id='admin.dimensions.top_servers' defaultMessage='Top active servers' />}
|
||||
/>
|
||||
<Retention startAt={sixMonthsAgo} endAt={today} frequency='month' />
|
||||
<Dimension
|
||||
dimension='software_versions'
|
||||
startAt={monthAgo}
|
||||
endAt={today}
|
||||
params={{ limit: 4 }}
|
||||
label={<FormattedMessage id='admin.dimensions.software' defaultMessage='Software' />}
|
||||
/>
|
||||
<Dimension
|
||||
dimension='space_usage'
|
||||
startAt={monthAgo}
|
||||
endAt={today}
|
||||
params={{ limit: 3 }}
|
||||
label={<FormattedMessage id='admin.dimensions.media_storage' defaultMessage='Media storage' />}
|
||||
<CardTitle
|
||||
title={<FormattedMessage id='admin.dashboard.registration_mode_label' defaultMessage='Registrations' />}
|
||||
/>
|
||||
|
||||
<RegistrationModePicker />
|
||||
</>
|
||||
)}
|
||||
</DashCounters>
|
||||
|
||||
<List>
|
||||
{features.pleromaAdminAccounts && account.is_admin && (
|
||||
<ListItem
|
||||
to='/pl-fe/config'
|
||||
label={<FormattedMessage id='navigation_bar.plfe_config' defaultMessage='Front-end configuration' />}
|
||||
/>
|
||||
)}
|
||||
<CardTitle
|
||||
title={<FormattedMessage id='admin.dashwidgets.software_header' defaultMessage='Software' />}
|
||||
/>
|
||||
|
||||
{features.pleromaAdminModerationLog && (
|
||||
<ListItem
|
||||
to='/pl-fe/admin/log'
|
||||
label={<FormattedMessage id='column.admin.moderation_log' defaultMessage='Moderation log' />}
|
||||
/>
|
||||
)}
|
||||
<List>
|
||||
<ListItem label={<FormattedMessage id='admin.software.frontend' defaultMessage='Frontend' />}>
|
||||
<a
|
||||
href={sourceCode.ref ? `${sourceCode.url}/tree/${sourceCode.ref}` : sourceCode.url}
|
||||
className='flex items-center space-x-1 truncate'
|
||||
target='_blank'
|
||||
>
|
||||
<span>{sourceCode.displayName} {sourceCode.version}</span>
|
||||
|
||||
{features.pleromaAdminAnnouncements && (
|
||||
<ListItem
|
||||
to='/pl-fe/admin/announcements'
|
||||
label={<FormattedMessage id='column.admin.announcements' defaultMessage='Announcements' />}
|
||||
/>
|
||||
)}
|
||||
|
||||
{features.adminRules && (
|
||||
<ListItem
|
||||
to='/pl-fe/admin/rules'
|
||||
label={<FormattedMessage id='column.admin.rules' defaultMessage='Instance rules' />}
|
||||
/>
|
||||
)}
|
||||
|
||||
{features.domains && (
|
||||
<ListItem
|
||||
to='/pl-fe/admin/domains'
|
||||
label={<FormattedMessage id='column.admin.domains' defaultMessage='Domains' />}
|
||||
/>
|
||||
)}
|
||||
</List>
|
||||
|
||||
{features.pleromaAdminAccounts && account.is_admin && (
|
||||
<>
|
||||
<CardTitle
|
||||
title={<FormattedMessage id='admin.dashboard.registration_mode_label' defaultMessage='Registrations' />}
|
||||
/>
|
||||
|
||||
<RegistrationModePicker />
|
||||
</>
|
||||
)}
|
||||
|
||||
<CardTitle
|
||||
title={<FormattedMessage id='admin.dashwidgets.software_header' defaultMessage='Software' />}
|
||||
/>
|
||||
|
||||
<List>
|
||||
<ListItem label={<FormattedMessage id='admin.software.frontend' defaultMessage='Frontend' />}>
|
||||
<a
|
||||
href={sourceCode.ref ? `${sourceCode.url}/tree/${sourceCode.ref}` : sourceCode.url}
|
||||
className='flex items-center space-x-1 truncate'
|
||||
target='_blank'
|
||||
>
|
||||
<span>{sourceCode.displayName} {sourceCode.version}</span>
|
||||
|
||||
<Icon
|
||||
className='size-4'
|
||||
src={require('@phosphor-icons/core/regular/arrow-square-out.svg')}
|
||||
/>
|
||||
</a>
|
||||
</ListItem>
|
||||
|
||||
{!features.mastodonAdminMetrics && (
|
||||
<ListItem label={<FormattedMessage id='admin.software.backend' defaultMessage='Backend' />}>
|
||||
<span>{v.software + (v.build ? `+${v.build}` : '')} {v.version}</span>
|
||||
<Icon
|
||||
className='size-4'
|
||||
src={require('@phosphor-icons/core/regular/arrow-square-out.svg')}
|
||||
/>
|
||||
</a>
|
||||
</ListItem>
|
||||
)}
|
||||
</List>
|
||||
</Stack>
|
||||
|
||||
{!features.mastodonAdminMetrics && (
|
||||
<ListItem label={<FormattedMessage id='admin.software.backend' defaultMessage='Backend' />}>
|
||||
<span>{v.software + (v.build ? `+${v.build}` : '')} {v.version}</span>
|
||||
</ListItem>
|
||||
)}
|
||||
</List>
|
||||
</Stack>
|
||||
</Column>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@ -1,9 +1,10 @@
|
||||
import { useNavigate } from '@tanstack/react-router';
|
||||
import React from 'react';
|
||||
import { FormattedList, FormattedMessage } from 'react-intl';
|
||||
import { defineMessages, FormattedList, FormattedMessage, useIntl } from 'react-intl';
|
||||
|
||||
import { useAccount } from 'pl-fe/api/hooks/accounts/use-account';
|
||||
import ScrollableList from 'pl-fe/components/scrollable-list';
|
||||
import Column from 'pl-fe/components/ui/column';
|
||||
import HStack from 'pl-fe/components/ui/hstack';
|
||||
import IconButton from 'pl-fe/components/ui/icon-button';
|
||||
import Text from 'pl-fe/components/ui/text';
|
||||
@ -12,7 +13,13 @@ import { useReports } from 'pl-fe/queries/admin/use-reports';
|
||||
|
||||
import Report from '../components/report';
|
||||
|
||||
const messages = defineMessages({
|
||||
heading: { id: 'column.admin.reports', defaultMessage: 'Reports' },
|
||||
});
|
||||
|
||||
const Reports: React.FC = () => {
|
||||
const intl = useIntl();
|
||||
|
||||
const { resolved, account_id: accountId, target_account_id: targetAccountId } = adminReportsRoute.useSearch();
|
||||
const navigate = useNavigate({ from: adminReportsRoute.fullPath });
|
||||
|
||||
@ -28,7 +35,7 @@ const Reports: React.FC = () => {
|
||||
const handleUnsetAccounts = () => navigate({ search: (prev) => ({ resolved: prev.resolved }) });
|
||||
|
||||
return (
|
||||
<>
|
||||
<Column label={intl.formatMessage(messages.heading)}>
|
||||
{(accountId || targetAccountId) && (
|
||||
<HStack className='border-b border-solid border-gray-200 p-2 pb-4 dark:border-gray-800' alignItems='center' space={2}>
|
||||
<IconButton iconClassName='h-5 w-5' src={require('@phosphor-icons/core/regular/x.svg')} onClick={handleUnsetAccounts} />
|
||||
@ -64,7 +71,7 @@ const Reports: React.FC = () => {
|
||||
>
|
||||
{reportIds.map(report => report && <Report id={report} key={report} />)}
|
||||
</ScrollableList>
|
||||
</>
|
||||
</Column>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@ -144,6 +144,8 @@ import {
|
||||
UserIndex,
|
||||
WrenchedTimeline,
|
||||
EditEvent,
|
||||
Reports,
|
||||
AwaitingApproval,
|
||||
} from './util/async-components';
|
||||
|
||||
import type { Features } from 'pl-api';
|
||||
@ -992,10 +994,10 @@ export const adminAccountRoute = createRoute({
|
||||
}),
|
||||
});
|
||||
|
||||
export const adminApprovalRoute = createRoute({
|
||||
export const adminAwaitingApprovalRoute = createRoute({
|
||||
getParentRoute: () => layouts.admin,
|
||||
path: '/pl-fe/admin/approval',
|
||||
component: Dashboard,
|
||||
component: AwaitingApproval,
|
||||
beforeLoad: requireAuthMiddleware(({ context: { isAdmin } }) => {
|
||||
if (!isAdmin) throw notFound();
|
||||
}),
|
||||
@ -1004,7 +1006,7 @@ export const adminApprovalRoute = createRoute({
|
||||
export const adminReportsRoute = createRoute({
|
||||
getParentRoute: () => layouts.admin,
|
||||
path: '/pl-fe/admin/reports',
|
||||
component: Dashboard,
|
||||
component: Reports,
|
||||
validateSearch: v.object({
|
||||
resolved: v.optional(v.boolean(), false),
|
||||
account_id: v.optional(v.string()),
|
||||
@ -1187,7 +1189,7 @@ const routeTree = rootRoute.addChildren([
|
||||
layouts.admin.addChildren([
|
||||
adminDashboardRoute,
|
||||
adminAccountRoute,
|
||||
adminApprovalRoute,
|
||||
adminAwaitingApprovalRoute,
|
||||
adminReportsRoute,
|
||||
adminReportRoute,
|
||||
adminLogRoute,
|
||||
|
||||
@ -8,6 +8,7 @@ export const AdminAccount = lazy(() => import('pl-fe/pages/dashboard/account'));
|
||||
export const Aliases = lazy(() => import('pl-fe/pages/settings/aliases'));
|
||||
export const Announcements = lazy(() => import('pl-fe/pages/dashboard/announcements'));
|
||||
export const AuthTokenList = lazy(() => import('pl-fe/pages/settings/auth-token-list'));
|
||||
export const AwaitingApproval = lazy(() => import('pl-fe/features/admin/tabs/awaiting-approval'));
|
||||
export const Backups = lazy(() => import('pl-fe/pages/settings/backups'));
|
||||
export const Blocks = lazy(() => import('pl-fe/pages/settings/blocks'));
|
||||
export const BookmarkFolders = lazy(() => import('pl-fe/pages/status-lists/bookmark-folders'));
|
||||
@ -23,7 +24,7 @@ export const EditEvent = lazy(() => import('pl-fe/pages/statuses/compose-event')
|
||||
export const Conversations = lazy(() => import('pl-fe/pages/status-lists/conversations'));
|
||||
export const CreateApp = lazy(() => import('pl-fe/pages/developers/create-app'));
|
||||
export const CryptoDonate = lazy(() => import('pl-fe/pages/utils/crypto-donate'));
|
||||
export const Dashboard = lazy(() => import('pl-fe/pages/dashboard/dashboard'));
|
||||
export const Dashboard = lazy(() => import('pl-fe/features/admin/tabs/dashboard'));
|
||||
export const DeleteAccount = lazy(() => import('pl-fe/pages/settings/delete-account'));
|
||||
export const Developers = lazy(() => import('pl-fe/pages/developers/developers'));
|
||||
export const Directory = lazy(() => import('pl-fe/pages/account-lists/directory'));
|
||||
@ -82,6 +83,7 @@ export const PlFeConfig = lazy(() => import('pl-fe/pages/dashboard/pl-fe-config'
|
||||
export const PublicTimeline = lazy(() => import('pl-fe/pages/timelines/public-timeline'));
|
||||
export const Quotes = lazy(() => import('pl-fe/pages/status-lists/quotes'));
|
||||
export const Report = lazy(() => import('pl-fe/pages/dashboard/report'));
|
||||
export const Reports = lazy(() => import('pl-fe/features/admin/tabs/reports'));
|
||||
export const RegisterInvite = lazy(() => import('pl-fe/pages/auth/register-with-invite'));
|
||||
export const RegistrationPage = lazy(() => import('pl-fe/pages/auth/registration'));
|
||||
export const Relays = lazy(() => import('pl-fe/pages/dashboard/relays'));
|
||||
|
||||
@ -368,6 +368,7 @@
|
||||
"circles.subheading": "Your circles",
|
||||
"column.admin.account": "Moderate @{acct}",
|
||||
"column.admin.announcements": "Announcements",
|
||||
"column.admin.awaiting_approval": "Awaiting approval",
|
||||
"column.admin.create_announcement": "Create announcement",
|
||||
"column.admin.create_domain": "Create domain",
|
||||
"column.admin.create_rule": "Create rule",
|
||||
@ -378,6 +379,7 @@
|
||||
"column.admin.edit_rule": "Edit rule",
|
||||
"column.admin.moderation_log": "Moderation log",
|
||||
"column.admin.relays": "Instance relays",
|
||||
"column.admin.reports": "Reports",
|
||||
"column.admin.reports.filter_message": "You are displaying reports {query}.",
|
||||
"column.admin.reports.filter_message.account": "from @{acct}",
|
||||
"column.admin.reports.filter_message.target_account": "targeting @{acct}",
|
||||
|
||||
Reference in New Issue
Block a user