Switch admin log to react-query

Signed-off-by: marcin mikołajczak <git@mkljczk.pl>
environments/review-main-yi2y9f/deployments/4540^2
marcin mikołajczak 6 months ago
parent f06ec3469b
commit 771c9643dc

@ -55,10 +55,6 @@ const ADMIN_STATUS_TOGGLE_SENSITIVITY_REQUEST = 'ADMIN_STATUS_TOGGLE_SENSITIVITY
const ADMIN_STATUS_TOGGLE_SENSITIVITY_SUCCESS = 'ADMIN_STATUS_TOGGLE_SENSITIVITY_SUCCESS';
const ADMIN_STATUS_TOGGLE_SENSITIVITY_FAIL = 'ADMIN_STATUS_TOGGLE_SENSITIVITY_FAIL';
const ADMIN_LOG_FETCH_REQUEST = 'ADMIN_LOG_FETCH_REQUEST';
const ADMIN_LOG_FETCH_SUCCESS = 'ADMIN_LOG_FETCH_SUCCESS';
const ADMIN_LOG_FETCH_FAIL = 'ADMIN_LOG_FETCH_FAIL';
const ADMIN_USERS_TAG_REQUEST = 'ADMIN_USERS_TAG_REQUEST';
const ADMIN_USERS_TAG_SUCCESS = 'ADMIN_USERS_TAG_SUCCESS';
const ADMIN_USERS_TAG_FAIL = 'ADMIN_USERS_TAG_FAIL';
@ -423,19 +419,6 @@ const toggleStatusSensitivity = (id: string, sensitive: boolean) =>
});
};
const fetchModerationLog = (params?: Record<string, any>) =>
(dispatch: AppDispatch, getState: () => RootState) => {
dispatch({ type: ADMIN_LOG_FETCH_REQUEST });
return api(getState)
.get('/api/v1/pleroma/admin/moderation_log', { params })
.then(({ data }) => {
dispatch({ type: ADMIN_LOG_FETCH_SUCCESS, items: data.items, total: data.total });
return data;
}).catch(error => {
dispatch({ type: ADMIN_LOG_FETCH_FAIL, error });
});
};
const tagUsers = (accountIds: string[], tags: string[]) =>
(dispatch: AppDispatch, getState: () => RootState) => {
const nicknames = accountIdsToAccts(getState(), accountIds);
@ -707,9 +690,6 @@ export {
ADMIN_STATUS_TOGGLE_SENSITIVITY_REQUEST,
ADMIN_STATUS_TOGGLE_SENSITIVITY_SUCCESS,
ADMIN_STATUS_TOGGLE_SENSITIVITY_FAIL,
ADMIN_LOG_FETCH_REQUEST,
ADMIN_LOG_FETCH_SUCCESS,
ADMIN_LOG_FETCH_FAIL,
ADMIN_USERS_TAG_REQUEST,
ADMIN_USERS_TAG_SUCCESS,
ADMIN_USERS_TAG_FAIL,
@ -757,7 +737,6 @@ export {
approveUsers,
deleteStatus,
toggleStatusSensitivity,
fetchModerationLog,
tagUsers,
untagUsers,
setTags,

@ -3,6 +3,7 @@ export { useCreateRelay } from './useCreateRelay';
export { useDeleteDomain } from './useDeleteDomain';
export { useDeleteRelay } from './useDeleteRelay';
export { useDomains } from './useDomains';
export { useModerationLog } from './useModerationLog';
export { useRelays } from './useRelays';
export { useSuggest } from './useSuggest';
export { useUpdateDomain } from './useUpdateDomain';

@ -0,0 +1,42 @@
import { useInfiniteQuery } from '@tanstack/react-query';
import { useApi } from 'soapbox/hooks';
import { moderationLogEntrySchema, type ModerationLogEntry } from 'soapbox/schemas';
interface ModerationLogResult {
items: ModerationLogEntry[];
total: number;
}
const flattenPages = (pages?: ModerationLogResult[]): ModerationLogEntry[] => (pages || []).map(({ items }) => items).flat();
const useModerationLog = () => {
const api = useApi();
const getModerationLog = async (page: number): Promise<ModerationLogResult> => {
const { data } = await api.get<ModerationLogResult>('/api/v1/pleroma/admin/moderation_log', { params: { page } });
const normalizedData = data.items.map((domain) => moderationLogEntrySchema.parse(domain));
return {
items: normalizedData,
total: data.total,
};
};
const queryInfo = useInfiniteQuery({
queryKey: ['moderation_log'],
queryFn: ({ pageParam }) => getModerationLog(pageParam),
initialPageParam: 1,
getNextPageParam: (page, allPages) => flattenPages(allPages)!.length >= page.total ? undefined : allPages.length + 1,
});
const data = flattenPages(queryInfo.data?.pages);
return {
...queryInfo,
data,
};
};
export { useModerationLog };

@ -1,11 +1,11 @@
import React, { useEffect, useState } from 'react';
import React from 'react';
import { defineMessages, FormattedDate, useIntl } from 'react-intl';
import { fetchModerationLog } from 'soapbox/actions/admin';
import { useModerationLog } from 'soapbox/api/hooks/admin';
import ScrollableList from 'soapbox/components/scrollable-list';
import { Column, Stack, Text } from 'soapbox/components/ui';
import { useAppDispatch, useAppSelector } from 'soapbox/hooks';
import { AdminLog } from 'soapbox/types/entities';
import type { ModerationLogEntry } from 'soapbox/schemas';
const messages = defineMessages({
heading: { id: 'column.admin.moderation_log', defaultMessage: 'Moderation Log' },
@ -14,37 +14,18 @@ const messages = defineMessages({
const ModerationLog = () => {
const intl = useIntl();
const dispatch = useAppDispatch();
const items = useAppSelector((state) => {
return state.admin_log.index.map((i) => state.admin_log.items.get(String(i)));
});
const hasMore = useAppSelector((state) => state.admin_log.total - state.admin_log.index.count() > 0);
const [isLoading, setIsLoading] = useState(true);
const [lastPage, setLastPage] = useState(0);
const {
data,
hasNextPage,
isLoading,
fetchNextPage,
} = useModerationLog();
const showLoading = isLoading && items.count() === 0;
useEffect(() => {
dispatch(fetchModerationLog())
.then(() => {
setIsLoading(false);
setLastPage(1);
})
.catch(() => { });
}, []);
const showLoading = isLoading && data.length === 0;
const handleLoadMore = () => {
const page = lastPage + 1;
setIsLoading(true);
dispatch(fetchModerationLog({ page }))
.then(() => {
setIsLoading(false);
setLastPage(page);
}).catch(() => { });
fetchNextPage();
};
return (
@ -54,11 +35,11 @@ const ModerationLog = () => {
showLoading={showLoading}
scrollKey='moderation-log'
emptyMessage={intl.formatMessage(messages.emptyMessage)}
hasMore={hasMore}
hasMore={hasNextPage}
onLoadMore={handleLoadMore}
listClassName='divide-y divide-solid divide-gray-200 dark:divide-gray-800'
>
{items.map(item => item && (
{data.map(item => item && (
<LogItem key={item.id} log={item} />
))}
</ScrollableList>
@ -67,7 +48,7 @@ const ModerationLog = () => {
};
interface ILogItem {
log: AdminLog;
log: ModerationLogEntry;
}
const LogItem: React.FC<ILogItem> = ({ log }) => {

@ -1,58 +0,0 @@
import {
Map as ImmutableMap,
Record as ImmutableRecord,
OrderedSet as ImmutableOrderedSet,
} from 'immutable';
import { ADMIN_LOG_FETCH_SUCCESS } from 'soapbox/actions/admin';
import type { AnyAction } from 'redux';
import type { APIEntity } from 'soapbox/types/entities';
export const LogEntryRecord = ImmutableRecord({
data: ImmutableMap<string, any>(),
id: 0,
message: '',
time: 0,
});
const ReducerRecord = ImmutableRecord({
items: ImmutableMap<string, LogEntry>(),
index: ImmutableOrderedSet<number>(),
total: 0,
});
type LogEntry = ReturnType<typeof LogEntryRecord>;
type State = ReturnType<typeof ReducerRecord>;
type APIEntities = Array<APIEntity>;
const parseItems = (items: APIEntities) => {
const ids: Array<number> = [];
const map: Record<string, LogEntry> = {};
items.forEach(item => {
ids.push(item.id);
map[item.id] = LogEntryRecord(item);
});
return { ids: ids, map: map };
};
const importItems = (state: State, items: APIEntities, total: number) => {
const { ids, map } = parseItems(items);
return state.withMutations(state => {
state.update('index', v => v.union(ids));
state.update('items', v => v.merge(map));
state.set('total', total);
});
};
export default function admin_log(state = ReducerRecord(), action: AnyAction) {
switch (action.type) {
case ADMIN_LOG_FETCH_SUCCESS:
return importItems(state, action.items, action.total);
default:
return state;
}
}

@ -8,7 +8,6 @@ import entities from 'soapbox/entity-store/reducer';
import accounts_meta from './accounts-meta';
import admin from './admin';
import admin_announcements from './admin-announcements';
import admin_log from './admin-log';
import admin_user_index from './admin-user-index';
import aliases from './aliases';
import announcements from './announcements';
@ -69,7 +68,6 @@ const reducers = {
accounts_meta,
admin,
admin_announcements,
admin_log,
admin_user_index,
aliases,
announcements,

@ -12,6 +12,7 @@ export { groupRelationshipSchema, type GroupRelationship } from './group-relatio
export { groupTagSchema, type GroupTag } from './group-tag';
export { instanceSchema, type Instance } from './instance';
export { mentionSchema, type Mention } from './mention';
export { moderationLogEntrySchema, type ModerationLogEntry } from './moderation-log-entry';
export { notificationSchema, type Notification } from './notification';
export { patronUserSchema, type PatronUser } from './patron';
export { pollSchema, type Poll, type PollOption } from './poll';

@ -0,0 +1,12 @@
import z from 'zod';
const moderationLogEntrySchema = z.object({
id: z.coerce.string(),
data: z.record(z.string(), z.any()).catch({}),
time: z.number().catch(0),
message: z.string().catch(''),
});
type ModerationLogEntry = z.infer<typeof moderationLogEntrySchema>
export { moderationLogEntrySchema, type ModerationLogEntry };

@ -20,14 +20,12 @@ import {
StatusRecord,
TagRecord,
} from 'soapbox/normalizers';
import { LogEntryRecord } from 'soapbox/reducers/admin-log';
import { Account as SchemaAccount } from 'soapbox/schemas';
import type { Record as ImmutableRecord } from 'immutable';
import type { LegacyMap } from 'soapbox/utils/legacy';
type AdminAccount = ReturnType<typeof AdminAccountRecord>;
type AdminLog = ReturnType<typeof LogEntryRecord>;
type AdminReport = ReturnType<typeof AdminReportRecord>;
type Announcement = ReturnType<typeof AnnouncementRecord>;
type AnnouncementReaction = ReturnType<typeof AnnouncementReactionRecord>;
@ -62,7 +60,6 @@ type EmbeddedEntity<T extends object> = null | string | ReturnType<ImmutableReco
export {
Account,
AdminAccount,
AdminLog,
AdminReport,
Announcement,
AnnouncementReaction,

Loading…
Cancel
Save