Refactor some actions to be proper async actions instead of passing a continuation (#31453)

shrike
Claire 2024-08-19 16:41:32 +02:00 committed by GitHub
parent 40f6631ac9
commit 1e612c5a09
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 42 additions and 55 deletions

View File

@ -188,8 +188,8 @@ const noOp = () => {};
let expandNotificationsController = new AbortController(); let expandNotificationsController = new AbortController();
export function expandNotifications({ maxId, forceLoad = false } = {}, done = noOp) { export function expandNotifications({ maxId = undefined, forceLoad = false }) {
return (dispatch, getState) => { return async (dispatch, getState) => {
const activeFilter = getState().getIn(['settings', 'notifications', 'quickFilter', 'active']); const activeFilter = getState().getIn(['settings', 'notifications', 'quickFilter', 'active']);
const notifications = getState().get('notifications'); const notifications = getState().get('notifications');
const isLoadingMore = !!maxId; const isLoadingMore = !!maxId;
@ -199,7 +199,6 @@ export function expandNotifications({ maxId, forceLoad = false } = {}, done = no
expandNotificationsController.abort(); expandNotificationsController.abort();
expandNotificationsController = new AbortController(); expandNotificationsController = new AbortController();
} else { } else {
done();
return; return;
} }
} }
@ -226,7 +225,8 @@ export function expandNotifications({ maxId, forceLoad = false } = {}, done = no
dispatch(expandNotificationsRequest(isLoadingMore)); dispatch(expandNotificationsRequest(isLoadingMore));
api().get('/api/v1/notifications', { params, signal: expandNotificationsController.signal }).then(response => { try {
const response = await api().get('/api/v1/notifications', { params, signal: expandNotificationsController.signal });
const next = getLinks(response).refs.find(link => link.rel === 'next'); const next = getLinks(response).refs.find(link => link.rel === 'next');
dispatch(importFetchedAccounts(response.data.map(item => item.account))); dispatch(importFetchedAccounts(response.data.map(item => item.account)));
@ -236,11 +236,9 @@ export function expandNotifications({ maxId, forceLoad = false } = {}, done = no
dispatch(expandNotificationsSuccess(response.data, next ? next.uri : null, isLoadingMore, isLoadingRecent, isLoadingRecent && preferPendingItems)); dispatch(expandNotificationsSuccess(response.data, next ? next.uri : null, isLoadingMore, isLoadingRecent, isLoadingRecent && preferPendingItems));
fetchRelatedRelationships(dispatch, response.data); fetchRelatedRelationships(dispatch, response.data);
dispatch(submitMarkers()); dispatch(submitMarkers());
}).catch(error => { } catch(error) {
dispatch(expandNotificationsFail(error, isLoadingMore)); dispatch(expandNotificationsFail(error, isLoadingMore));
}).finally(() => { }
done();
});
}; };
} }

View File

@ -13,6 +13,6 @@ export const initializeNotifications = createAppAsyncThunk(
) as boolean; ) as boolean;
if (enableBeta) void dispatch(fetchNotifications()); if (enableBeta) void dispatch(fetchNotifications());
else dispatch(expandNotifications()); else void dispatch(expandNotifications());
}, },
); );

View File

@ -37,7 +37,7 @@ const randomUpTo = max =>
* @param {string} channelName * @param {string} channelName
* @param {Object.<string, string>} params * @param {Object.<string, string>} params
* @param {Object} options * @param {Object} options
* @param {function(Function, Function): void} [options.fallback] * @param {function(Function): Promise<void>} [options.fallback]
* @param {function(): void} [options.fillGaps] * @param {function(): void} [options.fillGaps]
* @param {function(object): boolean} [options.accept] * @param {function(object): boolean} [options.accept]
* @returns {function(): void} * @returns {function(): void}
@ -52,14 +52,13 @@ export const connectTimelineStream = (timelineId, channelName, params = {}, opti
let pollingId; let pollingId;
/** /**
* @param {function(Function, Function): void} fallback * @param {function(Function): Promise<void>} fallback
*/ */
const useFallback = fallback => { const useFallback = async fallback => {
fallback(dispatch, () => { await fallback(dispatch);
// eslint-disable-next-line react-hooks/rules-of-hooks -- this is not a react hook // eslint-disable-next-line react-hooks/rules-of-hooks -- this is not a react hook
pollingId = setTimeout(() => useFallback(fallback), 20000 + randomUpTo(20000)); pollingId = setTimeout(() => useFallback(fallback), 20000 + randomUpTo(20000));
});
}; };
return { return {
@ -132,21 +131,17 @@ export const connectTimelineStream = (timelineId, channelName, params = {}, opti
/** /**
* @param {Function} dispatch * @param {Function} dispatch
* @param {function(): void} done
*/ */
const refreshHomeTimelineAndNotification = (dispatch, done) => { async function refreshHomeTimelineAndNotification(dispatch) {
// @ts-expect-error await dispatch(expandHomeTimeline({ maxId: undefined }));
dispatch(expandHomeTimeline({}, () => await dispatch(expandNotifications({}));
// @ts-expect-error await dispatch(fetchAnnouncements());
dispatch(expandNotifications({}, () => }
dispatch(fetchAnnouncements(done))))));
};
/** /**
* @returns {function(): void} * @returns {function(): void}
*/ */
export const connectUserStream = () => export const connectUserStream = () =>
// @ts-expect-error
connectTimelineStream('home', 'user', {}, { fallback: refreshHomeTimelineAndNotification, fillGaps: fillHomeTimelineGaps }); connectTimelineStream('home', 'user', {}, { fallback: refreshHomeTimelineAndNotification, fillGaps: fillHomeTimelineGaps });
/** /**

View File

@ -76,21 +76,18 @@ export function clearTimeline(timeline) {
}; };
} }
const noOp = () => {};
const parseTags = (tags = {}, mode) => { const parseTags = (tags = {}, mode) => {
return (tags[mode] || []).map((tag) => { return (tags[mode] || []).map((tag) => {
return tag.value; return tag.value;
}); });
}; };
export function expandTimeline(timelineId, path, params = {}, done = noOp) { export function expandTimeline(timelineId, path, params = {}) {
return (dispatch, getState) => { return async (dispatch, getState) => {
const timeline = getState().getIn(['timelines', timelineId], ImmutableMap()); const timeline = getState().getIn(['timelines', timelineId], ImmutableMap());
const isLoadingMore = !!params.max_id; const isLoadingMore = !!params.max_id;
if (timeline.get('isLoading')) { if (timeline.get('isLoading')) {
done();
return; return;
} }
@ -109,7 +106,8 @@ export function expandTimeline(timelineId, path, params = {}, done = noOp) {
dispatch(expandTimelineRequest(timelineId, isLoadingMore)); dispatch(expandTimelineRequest(timelineId, isLoadingMore));
api().get(path, { params }).then(response => { try {
const response = await api().get(path, { params });
const next = getLinks(response).refs.find(link => link.rel === 'next'); const next = getLinks(response).refs.find(link => link.rel === 'next');
dispatch(importFetchedStatuses(response.data)); dispatch(importFetchedStatuses(response.data));
@ -127,52 +125,48 @@ export function expandTimeline(timelineId, path, params = {}, done = noOp) {
if (timelineId === 'home') { if (timelineId === 'home') {
dispatch(submitMarkers()); dispatch(submitMarkers());
} }
}).catch(error => { } catch(error) {
dispatch(expandTimelineFail(timelineId, error, isLoadingMore)); dispatch(expandTimelineFail(timelineId, error, isLoadingMore));
}).finally(() => { }
done();
});
}; };
} }
export function fillTimelineGaps(timelineId, path, params = {}, done = noOp) { export function fillTimelineGaps(timelineId, path, params = {}) {
return (dispatch, getState) => { return async (dispatch, getState) => {
const timeline = getState().getIn(['timelines', timelineId], ImmutableMap()); const timeline = getState().getIn(['timelines', timelineId], ImmutableMap());
const items = timeline.get('items'); const items = timeline.get('items');
const nullIndexes = items.map((statusId, index) => statusId === null ? index : null); const nullIndexes = items.map((statusId, index) => statusId === null ? index : null);
const gaps = nullIndexes.map(index => index > 0 ? items.get(index - 1) : null); const gaps = nullIndexes.map(index => index > 0 ? items.get(index - 1) : null);
// Only expand at most two gaps to avoid doing too many requests // Only expand at most two gaps to avoid doing too many requests
done = gaps.take(2).reduce((done, maxId) => { for (const maxId of gaps.take(2)) {
return (() => dispatch(expandTimeline(timelineId, path, { ...params, maxId }, done))); await dispatch(expandTimeline(timelineId, path, { ...params, maxId }));
}, done); }
done();
}; };
} }
export const expandHomeTimeline = ({ maxId } = {}, done = noOp) => expandTimeline('home', '/api/v1/timelines/home', { max_id: maxId }, done); export const expandHomeTimeline = ({ maxId } = {}) => expandTimeline('home', '/api/v1/timelines/home', { max_id: maxId });
export const expandPublicTimeline = ({ maxId, onlyMedia, onlyRemote } = {}, done = noOp) => expandTimeline(`public${onlyRemote ? ':remote' : ''}${onlyMedia ? ':media' : ''}`, '/api/v1/timelines/public', { remote: !!onlyRemote, max_id: maxId, only_media: !!onlyMedia }, done); export const expandPublicTimeline = ({ maxId, onlyMedia, onlyRemote } = {}) => expandTimeline(`public${onlyRemote ? ':remote' : ''}${onlyMedia ? ':media' : ''}`, '/api/v1/timelines/public', { remote: !!onlyRemote, max_id: maxId, only_media: !!onlyMedia });
export const expandCommunityTimeline = ({ maxId, onlyMedia } = {}, done = noOp) => expandTimeline(`community${onlyMedia ? ':media' : ''}`, '/api/v1/timelines/public', { local: true, max_id: maxId, only_media: !!onlyMedia }, done); export const expandCommunityTimeline = ({ maxId, onlyMedia } = {}) => expandTimeline(`community${onlyMedia ? ':media' : ''}`, '/api/v1/timelines/public', { local: true, max_id: maxId, only_media: !!onlyMedia });
export const expandAccountTimeline = (accountId, { maxId, withReplies, tagged } = {}) => expandTimeline(`account:${accountId}${withReplies ? ':with_replies' : ''}${tagged ? `:${tagged}` : ''}`, `/api/v1/accounts/${accountId}/statuses`, { exclude_replies: !withReplies, exclude_reblogs: withReplies, tagged, max_id: maxId }); export const expandAccountTimeline = (accountId, { maxId, withReplies, tagged } = {}) => expandTimeline(`account:${accountId}${withReplies ? ':with_replies' : ''}${tagged ? `:${tagged}` : ''}`, `/api/v1/accounts/${accountId}/statuses`, { exclude_replies: !withReplies, exclude_reblogs: withReplies, tagged, max_id: maxId });
export const expandAccountFeaturedTimeline = (accountId, { tagged } = {}) => expandTimeline(`account:${accountId}:pinned${tagged ? `:${tagged}` : ''}`, `/api/v1/accounts/${accountId}/statuses`, { pinned: true, tagged }); export const expandAccountFeaturedTimeline = (accountId, { tagged } = {}) => expandTimeline(`account:${accountId}:pinned${tagged ? `:${tagged}` : ''}`, `/api/v1/accounts/${accountId}/statuses`, { pinned: true, tagged });
export const expandAccountMediaTimeline = (accountId, { maxId } = {}) => expandTimeline(`account:${accountId}:media`, `/api/v1/accounts/${accountId}/statuses`, { max_id: maxId, only_media: true, limit: 40 }); export const expandAccountMediaTimeline = (accountId, { maxId } = {}) => expandTimeline(`account:${accountId}:media`, `/api/v1/accounts/${accountId}/statuses`, { max_id: maxId, only_media: true, limit: 40 });
export const expandListTimeline = (id, { maxId } = {}, done = noOp) => expandTimeline(`list:${id}`, `/api/v1/timelines/list/${id}`, { max_id: maxId }, done); export const expandListTimeline = (id, { maxId } = {}) => expandTimeline(`list:${id}`, `/api/v1/timelines/list/${id}`, { max_id: maxId });
export const expandLinkTimeline = (url, { maxId } = {}, done = noOp) => expandTimeline(`link:${url}`, `/api/v1/timelines/link`, { url, max_id: maxId }, done); export const expandLinkTimeline = (url, { maxId } = {}) => expandTimeline(`link:${url}`, `/api/v1/timelines/link`, { url, max_id: maxId });
export const expandHashtagTimeline = (hashtag, { maxId, tags, local } = {}, done = noOp) => { export const expandHashtagTimeline = (hashtag, { maxId, tags, local } = {}) => {
return expandTimeline(`hashtag:${hashtag}${local ? ':local' : ''}`, `/api/v1/timelines/tag/${hashtag}`, { return expandTimeline(`hashtag:${hashtag}${local ? ':local' : ''}`, `/api/v1/timelines/tag/${hashtag}`, {
max_id: maxId, max_id: maxId,
any: parseTags(tags, 'any'), any: parseTags(tags, 'any'),
all: parseTags(tags, 'all'), all: parseTags(tags, 'all'),
none: parseTags(tags, 'none'), none: parseTags(tags, 'none'),
local: local, local: local,
}, done); });
}; };
export const fillHomeTimelineGaps = (done = noOp) => fillTimelineGaps('home', '/api/v1/timelines/home', {}, done); export const fillHomeTimelineGaps = () => fillTimelineGaps('home', '/api/v1/timelines/home', {});
export const fillPublicTimelineGaps = ({ onlyMedia, onlyRemote } = {}, done = noOp) => fillTimelineGaps(`public${onlyRemote ? ':remote' : ''}${onlyMedia ? ':media' : ''}`, '/api/v1/timelines/public', { remote: !!onlyRemote, only_media: !!onlyMedia }, done); export const fillPublicTimelineGaps = ({ onlyMedia, onlyRemote } = {}) => fillTimelineGaps(`public${onlyRemote ? ':remote' : ''}${onlyMedia ? ':media' : ''}`, '/api/v1/timelines/public', { remote: !!onlyRemote, only_media: !!onlyMedia });
export const fillCommunityTimelineGaps = ({ onlyMedia } = {}, done = noOp) => fillTimelineGaps(`community${onlyMedia ? ':media' : ''}`, '/api/v1/timelines/public', { local: true, only_media: !!onlyMedia }, done); export const fillCommunityTimelineGaps = ({ onlyMedia } = {}) => fillTimelineGaps(`community${onlyMedia ? ':media' : ''}`, '/api/v1/timelines/public', { local: true, only_media: !!onlyMedia });
export const fillListTimelineGaps = (id, done = noOp) => fillTimelineGaps(`list:${id}`, `/api/v1/timelines/list/${id}`, {}, done); export const fillListTimelineGaps = (id) => fillTimelineGaps(`list:${id}`, `/api/v1/timelines/list/${id}`, {});
export function expandTimelineRequest(timeline, isLoadingMore) { export function expandTimelineRequest(timeline, isLoadingMore) {
return { return {

View File

@ -36,13 +36,13 @@ export const LinkTimeline: React.FC<{
const handleLoadMore = useCallback( const handleLoadMore = useCallback(
(maxId: string) => { (maxId: string) => {
dispatch(expandLinkTimeline(decodedUrl, { maxId })); void dispatch(expandLinkTimeline(decodedUrl, { maxId }));
}, },
[dispatch, decodedUrl], [dispatch, decodedUrl],
); );
useEffect(() => { useEffect(() => {
dispatch(expandLinkTimeline(decodedUrl)); void dispatch(expandLinkTimeline(decodedUrl));
}, [dispatch, decodedUrl]); }, [dispatch, decodedUrl]);
return ( return (