From eeaecf2d79b84ab5d99f8226d8045d1cac8761ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?marcin=20miko=C5=82ajczak?= Date: Sat, 26 Oct 2024 17:44:29 +0200 Subject: [PATCH 01/11] pl-hooks: Improve typings, update deps MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: marcin mikołajczak --- .../pl-hooks/lib/hooks/statuses/use-status.ts | 9 +++------ packages/pl-hooks/lib/main.ts | 1 + packages/pl-hooks/package.json | 2 +- packages/pl-hooks/yarn.lock | 18 +++++++++--------- 4 files changed, 14 insertions(+), 16 deletions(-) diff --git a/packages/pl-hooks/lib/hooks/statuses/use-status.ts b/packages/pl-hooks/lib/hooks/statuses/use-status.ts index 626cf3662..f123e2821 100644 --- a/packages/pl-hooks/lib/hooks/statuses/use-status.ts +++ b/packages/pl-hooks/lib/hooks/statuses/use-status.ts @@ -1,10 +1,10 @@ -import { useQueries, useQuery, type UseQueryResult } from '@tanstack/react-query'; +import { useQueries, useQuery, UseQueryOptions, type UseQueryResult } from '@tanstack/react-query'; import { usePlHooksApiClient } from 'pl-hooks/contexts/api-client'; import { queryClient, usePlHooksQueryClient } from 'pl-hooks/contexts/query-client'; import { importEntities } from 'pl-hooks/importer'; import { usePoll } from 'pl-hooks/main'; -import { normalizeAccount, type NormalizedAccount } from 'pl-hooks/normalizers/account'; +import { type NormalizedAccount } from 'pl-hooks/normalizers/account'; import { type NormalizedStatus, normalizeStatus } from 'pl-hooks/normalizers/status'; import type { Poll } from 'pl-api'; @@ -123,12 +123,9 @@ const useStatus = (statusId?: string, opts: UseStatusOpts = { withReblog: true } reblogQuery = useStatus(status?.reblog_id || undefined, { ...opts, withReblog: false }); } - const accountsQuery = useQueries({ + const accountsQuery = useQueries[]>({ queries: status?.account_ids.map(accountId => ({ queryKey: ['accounts', 'entities', accountId], - queryFn: () => client.accounts.getAccount(accountId!) - .then(account => (importEntities({ accounts: [account] }, { withParents: false }), account)) - .then(normalizeAccount), })) || [], }, queryClient); diff --git a/packages/pl-hooks/lib/main.ts b/packages/pl-hooks/lib/main.ts index db232ea0b..3c93843e3 100644 --- a/packages/pl-hooks/lib/main.ts +++ b/packages/pl-hooks/lib/main.ts @@ -17,3 +17,4 @@ export * from './hooks/statuses/use-status-translation'; export * from './importer'; export type { NormalizedAccount } from './normalizers/account'; +export type { NormalizedStatus } from './normalizers/status'; diff --git a/packages/pl-hooks/package.json b/packages/pl-hooks/package.json index 7f85af158..0e130793b 100644 --- a/packages/pl-hooks/package.json +++ b/packages/pl-hooks/package.json @@ -33,7 +33,7 @@ "vite-plugin-dts": "^4.2.1" }, "dependencies": { - "@tanstack/react-query": "^5.56.2", + "@tanstack/react-query": "^5.59.16", "lodash": "^4.17.21", "pl-api": "^0.1.1", "react": "^18.3.1", diff --git a/packages/pl-hooks/yarn.lock b/packages/pl-hooks/yarn.lock index c2bcb1ec3..a926ede4c 100644 --- a/packages/pl-hooks/yarn.lock +++ b/packages/pl-hooks/yarn.lock @@ -381,17 +381,17 @@ argparse "~1.0.9" string-argv "~0.3.1" -"@tanstack/query-core@5.56.2": - version "5.56.2" - resolved "https://registry.yarnpkg.com/@tanstack/query-core/-/query-core-5.56.2.tgz#2def2fb0290cd2836bbb08afb0c175595bb8109b" - integrity sha512-gor0RI3/R5rVV3gXfddh1MM+hgl0Z4G7tj6Xxpq6p2I03NGPaJ8dITY9Gz05zYYb/EJq9vPas/T4wn9EaDPd4Q== +"@tanstack/query-core@5.59.16": + version "5.59.16" + resolved "https://registry.yarnpkg.com/@tanstack/query-core/-/query-core-5.59.16.tgz#aa4616e8a9c12afeef4cfbf3ed0f55f404d66e67" + integrity sha512-crHn+G3ltqb5JG0oUv6q+PMz1m1YkjpASrXTU+sYWW9pLk0t2GybUHNRqYPZWhxgjPaVGC4yp92gSFEJgYEsPw== -"@tanstack/react-query@^5.56.2": - version "5.56.2" - resolved "https://registry.yarnpkg.com/@tanstack/react-query/-/react-query-5.56.2.tgz#3a0241b9d010910905382f5e99160997b8795f91" - integrity sha512-SR0GzHVo6yzhN72pnRhkEFRAHMsUo5ZPzAxfTMvUxFIDVS6W9LYUp6nXW3fcHVdg0ZJl8opSH85jqahvm6DSVg== +"@tanstack/react-query@^5.59.16": + version "5.59.16" + resolved "https://registry.yarnpkg.com/@tanstack/react-query/-/react-query-5.59.16.tgz#1e701c6e6681965c04aa426df9da54b8edc6db1b" + integrity sha512-MuyWheG47h6ERd4PKQ6V8gDyBu3ThNG22e1fRVwvq6ap3EqsFhyuxCAwhNP/03m/mLg+DAb0upgbPaX6VB+CkQ== dependencies: - "@tanstack/query-core" "5.56.2" + "@tanstack/query-core" "5.59.16" "@types/argparse@1.0.38": version "1.0.38" From 8f45242da40a1d7589acf9657c8b3b06f45c56c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?marcin=20miko=C5=82ajczak?= Date: Sat, 26 Oct 2024 17:44:44 +0200 Subject: [PATCH 02/11] pl-fe: Remove any MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: marcin mikołajczak --- packages/pl-fe/src/features/group/group-gallery.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/pl-fe/src/features/group/group-gallery.tsx b/packages/pl-fe/src/features/group/group-gallery.tsx index 045a3ab5f..906bce18b 100644 --- a/packages/pl-fe/src/features/group/group-gallery.tsx +++ b/packages/pl-fe/src/features/group/group-gallery.tsx @@ -34,7 +34,7 @@ const GroupGallery: React.FC = (props) => { } = useGroupMedia(groupId); const attachments = statuses.reduce((result, status) => { - result.push(...status.media_attachments.map((a) => ({ ...a, status: status as any, account: status.account }))); + result.push(...status.media_attachments.map((a) => ({ ...a, status, account: status.account }))); return result; }, []); From 12eb4d820aea2afa57e37e53a6b1c98298afad50 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?marcin=20miko=C5=82ajczak?= Date: Sat, 26 Oct 2024 17:44:51 +0200 Subject: [PATCH 03/11] Bump pl-api version MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: marcin mikołajczak --- packages/pl-api/package.json | 2 +- packages/pl-fe/package.json | 2 +- packages/pl-fe/yarn.lock | 8 ++++---- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/pl-api/package.json b/packages/pl-api/package.json index 73c958266..3158d0da7 100644 --- a/packages/pl-api/package.json +++ b/packages/pl-api/package.json @@ -1,6 +1,6 @@ { "name": "pl-api", - "version": "0.1.4", + "version": "0.1.5", "type": "module", "homepage": "https://github.com/mkljczk/pl-fe/tree/fork/packages/pl-api", "repository": { diff --git a/packages/pl-fe/package.json b/packages/pl-fe/package.json index f1e27d489..249a737fd 100644 --- a/packages/pl-fe/package.json +++ b/packages/pl-fe/package.json @@ -102,7 +102,7 @@ "mini-css-extract-plugin": "^2.9.1", "multiselect-react-dropdown": "^2.0.25", "path-browserify": "^1.0.1", - "pl-api": "^0.1.4", + "pl-api": "^0.1.5", "postcss": "^8.4.47", "process": "^0.11.10", "punycode": "^2.1.1", diff --git a/packages/pl-fe/yarn.lock b/packages/pl-fe/yarn.lock index 25e2d5838..47d77ceb7 100644 --- a/packages/pl-fe/yarn.lock +++ b/packages/pl-fe/yarn.lock @@ -7570,10 +7570,10 @@ pkg-dir@^4.1.0: dependencies: find-up "^4.0.0" -pl-api@^0.1.4: - version "0.1.4" - resolved "https://registry.yarnpkg.com/pl-api/-/pl-api-0.1.4.tgz#8062dc0ac34bb60f7dcbcb556cfbc18a19482948" - integrity sha512-8ZUQeoCgJZFsp9wrrBOEL2wKRPfLf7Jxz9vPTUnGQMPA0BBtQvsgDxomEC96fRjO+ycxK7gEZrKLVEaNFA0nyw== +pl-api@^0.1.5: + version "0.1.5" + resolved "https://registry.yarnpkg.com/pl-api/-/pl-api-0.1.5.tgz#373d58fc40ae23b12c6d20def8d3332112e2dd93" + integrity sha512-IMcwANPtTRMv+tTLW4ic/o/usYIHeapR+aOx5YhmmVQsXTiVUZQtCVLmrfIrqMnyXm8PHvE/arzzozRFU8+GXQ== dependencies: blurhash "^2.0.5" http-link-header "^1.1.3" From 36cc2e103ae124183315bd4ac6d3ab05a1d7dbce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?marcin=20miko=C5=82ajczak?= Date: Sat, 26 Oct 2024 19:53:26 +0200 Subject: [PATCH 04/11] pl-hooks: Improve useInstance behavior MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: marcin mikołajczak --- packages/pl-hooks/lib/hooks/instance/use-instance.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/pl-hooks/lib/hooks/instance/use-instance.ts b/packages/pl-hooks/lib/hooks/instance/use-instance.ts index b39752145..1348b3396 100644 --- a/packages/pl-hooks/lib/hooks/instance/use-instance.ts +++ b/packages/pl-hooks/lib/hooks/instance/use-instance.ts @@ -5,7 +5,7 @@ import * as v from 'valibot'; import { usePlHooksApiClient } from 'pl-hooks/contexts/api-client'; import { usePlHooksQueryClient } from 'pl-hooks/contexts/query-client'; -const placeholderData = v.parse(instanceSchema, {}); +const initialData = v.parse(instanceSchema, {}); const useInstance = () => { const { client } = usePlHooksApiClient(); @@ -14,7 +14,8 @@ const useInstance = () => { return useQuery({ queryKey: ['instance'], queryFn: client.instance.getInstance, - placeholderData, + initialData, + initialDataUpdatedAt: -1, }, queryClient); }; From ad7527bd4de307cdb2cc0742a20d085665d27087 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?marcin=20miko=C5=82ajczak?= Date: Sat, 26 Oct 2024 19:56:53 +0200 Subject: [PATCH 05/11] pl-hooks: actually improve useInstance behavior MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: marcin mikołajczak --- packages/pl-hooks/lib/hooks/instance/use-instance.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/pl-hooks/lib/hooks/instance/use-instance.ts b/packages/pl-hooks/lib/hooks/instance/use-instance.ts index 1348b3396..fcadcf90f 100644 --- a/packages/pl-hooks/lib/hooks/instance/use-instance.ts +++ b/packages/pl-hooks/lib/hooks/instance/use-instance.ts @@ -11,12 +11,12 @@ const useInstance = () => { const { client } = usePlHooksApiClient(); const queryClient = usePlHooksQueryClient(); - return useQuery({ + const query = useQuery({ queryKey: ['instance'], queryFn: client.instance.getInstance, - initialData, - initialDataUpdatedAt: -1, }, queryClient); + + return { ...query, data: query.data || initialData }; }; export { useInstance }; From 5691837235bfb16689889a1500899f0f69e1c80d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?marcin=20miko=C5=82ajczak?= Date: Sat, 26 Oct 2024 19:57:46 +0200 Subject: [PATCH 06/11] pl-fe: Don't display the same display name for grouped reposts twice MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: marcin mikołajczak --- packages/pl-fe/src/components/status.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/pl-fe/src/components/status.tsx b/packages/pl-fe/src/components/status.tsx index e8ef7344c..33ed00068 100644 --- a/packages/pl-fe/src/components/status.tsx +++ b/packages/pl-fe/src/components/status.tsx @@ -230,7 +230,7 @@ const Status: React.FC = (props) => { - + From 5f7863f130c0986ed07f529603b888003f58b7d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?marcin=20miko=C5=82ajczak?= Date: Sat, 26 Oct 2024 20:07:54 +0200 Subject: [PATCH 07/11] pl-fe: remove obsolete workaround MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: marcin mikołajczak --- packages/pl-fe/src/actions/statuses.ts | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/packages/pl-fe/src/actions/statuses.ts b/packages/pl-fe/src/actions/statuses.ts index 54fca4893..652771269 100644 --- a/packages/pl-fe/src/actions/statuses.ts +++ b/packages/pl-fe/src/actions/statuses.ts @@ -164,14 +164,10 @@ const fetchContext = (statusId: string, intl?: IntlShape) => } : undefined; return getClient(getState()).statuses.getContext(statusId, params).then(context => { - if (typeof context === 'object') { - const { ancestors, descendants } = context; - const statuses = ancestors.concat(descendants); - dispatch(importFetchedStatuses(statuses)); - dispatch({ type: CONTEXT_FETCH_SUCCESS, statusId, ancestors, descendants }); - } else { - throw context; - } + const { ancestors, descendants } = context; + const statuses = ancestors.concat(descendants); + dispatch(importFetchedStatuses(statuses)); + dispatch({ type: CONTEXT_FETCH_SUCCESS, statusId, ancestors, descendants }); return context; }).catch(error => { if (error.response?.status === 404) { From 2ceb21576feb0b0a88262ebb741a2ce02fd5f0de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?marcin=20miko=C5=82ajczak?= Date: Sat, 26 Oct 2024 22:36:58 +0200 Subject: [PATCH 08/11] pl-fe: migrate importer to just one function MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: marcin mikołajczak --- packages/pl-fe/src/actions/about.ts | 5 +- packages/pl-fe/src/actions/account-notes.ts | 10 +- packages/pl-fe/src/actions/accounts.ts | 35 ++-- packages/pl-fe/src/actions/admin.ts | 12 +- packages/pl-fe/src/actions/aliases.ts | 4 +- packages/pl-fe/src/actions/auth.ts | 8 +- packages/pl-fe/src/actions/bookmarks.ts | 6 +- packages/pl-fe/src/actions/compose.ts | 4 +- packages/pl-fe/src/actions/conversations.ts | 23 ++- packages/pl-fe/src/actions/directory.ts | 6 +- packages/pl-fe/src/actions/emoji-reacts.ts | 6 +- packages/pl-fe/src/actions/events.ts | 20 +-- .../pl-fe/src/actions/familiar-followers.ts | 4 +- packages/pl-fe/src/actions/favourites.ts | 10 +- packages/pl-fe/src/actions/groups.ts | 4 +- packages/pl-fe/src/actions/history.ts | 4 +- packages/pl-fe/src/actions/importer.ts | 121 +++++++++++++ packages/pl-fe/src/actions/importer/index.ts | 169 ------------------ packages/pl-fe/src/actions/interactions.ts | 24 +-- packages/pl-fe/src/actions/lists.ts | 6 +- packages/pl-fe/src/actions/me.ts | 4 +- packages/pl-fe/src/actions/notifications.ts | 31 +--- packages/pl-fe/src/actions/pin-statuses.ts | 4 +- packages/pl-fe/src/actions/polls.ts | 6 +- packages/pl-fe/src/actions/preload.ts | 4 +- packages/pl-fe/src/actions/search.ts | 18 +- packages/pl-fe/src/actions/status-quotes.ts | 6 +- packages/pl-fe/src/actions/statuses.ts | 12 +- packages/pl-fe/src/actions/suggestions.ts | 4 +- packages/pl-fe/src/actions/timelines.ts | 8 +- .../pl-fe/src/actions/trending-statuses.ts | 4 +- .../src/features/test-timeline/index.tsx | 4 +- packages/pl-fe/src/queries/chats.ts | 6 +- packages/pl-fe/src/queries/suggestions.ts | 6 +- 34 files changed, 258 insertions(+), 340 deletions(-) create mode 100644 packages/pl-fe/src/actions/importer.ts delete mode 100644 packages/pl-fe/src/actions/importer/index.ts diff --git a/packages/pl-fe/src/actions/about.ts b/packages/pl-fe/src/actions/about.ts index a1927d1da..6737b4508 100644 --- a/packages/pl-fe/src/actions/about.ts +++ b/packages/pl-fe/src/actions/about.ts @@ -1,13 +1,12 @@ import { staticFetch } from '../api'; -import type { RootState } from 'pl-fe/store'; -import type { AnyAction } from 'redux'; +import type { AppDispatch, RootState } from 'pl-fe/store'; const FETCH_ABOUT_PAGE_REQUEST = 'FETCH_ABOUT_PAGE_REQUEST' as const; const FETCH_ABOUT_PAGE_SUCCESS = 'FETCH_ABOUT_PAGE_SUCCESS' as const; const FETCH_ABOUT_PAGE_FAIL = 'FETCH_ABOUT_PAGE_FAIL' as const; -const fetchAboutPage = (slug = 'index', locale?: string) => (dispatch: React.Dispatch, getState: () => RootState) => { +const fetchAboutPage = (slug = 'index', locale?: string) => (dispatch: AppDispatch, getState: () => RootState) => { dispatch({ type: FETCH_ABOUT_PAGE_REQUEST, slug, locale }); const filename = `${slug}${locale ? `.${locale}` : ''}.html`; diff --git a/packages/pl-fe/src/actions/account-notes.ts b/packages/pl-fe/src/actions/account-notes.ts index eba436dcc..dc72037c1 100644 --- a/packages/pl-fe/src/actions/account-notes.ts +++ b/packages/pl-fe/src/actions/account-notes.ts @@ -1,14 +1,12 @@ -import { importEntities } from 'pl-fe/entity-store/actions'; -import { Entities } from 'pl-fe/entity-store/entities'; +import { importEntities } from 'pl-fe/actions/importer'; import { getClient } from '../api'; -import type { RootState } from 'pl-fe/store'; -import type { AnyAction } from 'redux'; +import type { AppDispatch, RootState } from 'pl-fe/store'; const submitAccountNote = (accountId: string, value: string) => - (dispatch: React.Dispatch, getState: () => RootState) => + (dispatch: AppDispatch, getState: () => RootState) => getClient(getState).accounts.updateAccountNote(accountId, value) - .then(response => dispatch(importEntities([response], Entities.RELATIONSHIPS))); + .then(response => dispatch(importEntities({ relationships: [response] }))); export { submitAccountNote }; diff --git a/packages/pl-fe/src/actions/accounts.ts b/packages/pl-fe/src/actions/accounts.ts index e50b6b150..770807208 100644 --- a/packages/pl-fe/src/actions/accounts.ts +++ b/packages/pl-fe/src/actions/accounts.ts @@ -1,13 +1,12 @@ import { PLEROMA, type UpdateNotificationSettingsParams, type Account, type CreateAccountParams, type PaginatedResponse, type Relationship } from 'pl-api'; -import { importEntities } from 'pl-fe/entity-store/actions'; import { Entities } from 'pl-fe/entity-store/entities'; import { selectAccount } from 'pl-fe/selectors'; import { isLoggedIn } from 'pl-fe/utils/auth'; import { getClient, type PlfeResponse } from '../api'; -import { importFetchedAccount, importFetchedAccounts } from './importer'; +import { importEntities } from './importer'; import type { Map as ImmutableMap } from 'immutable'; import type { MinifiedStatus } from 'pl-fe/reducers/statuses'; @@ -100,7 +99,7 @@ const fetchAccount = (accountId: string) => return getClient(getState()).accounts.getAccount(accountId) .then(response => { - dispatch(importFetchedAccount(response)); + dispatch(importEntities({ accounts: [response] })); dispatch(fetchAccountSuccess(response)); }) .catch(error => { @@ -116,7 +115,7 @@ const fetchAccountByUsername = (username: string, history?: History) => if (features.accountByUsername && (me || !features.accountLookup)) { return getClient(getState()).accounts.getAccount(username).then(response => { dispatch(fetchRelationships([response.id])); - dispatch(importFetchedAccount(response)); + dispatch(importEntities({ accounts: [response] })); dispatch(fetchAccountSuccess(response)); }).catch(error => { dispatch(fetchAccountFail(null, error)); @@ -170,7 +169,7 @@ const blockAccount = (accountId: string) => return getClient(getState).filtering.blockAccount(accountId) .then(response => { - dispatch(importEntities([response], Entities.RELATIONSHIPS)); + dispatch(importEntities({ relationships: [response] })); // Pass in entire statuses map so we can use it to filter stuff in different parts of the reducers return dispatch(blockAccountSuccess(response, getState().statuses)); }).catch(error => dispatch(blockAccountFail(error))); @@ -182,7 +181,7 @@ const unblockAccount = (accountId: string) => return getClient(getState).filtering.unblockAccount(accountId) .then(response => { - dispatch(importEntities([response], Entities.RELATIONSHIPS)); + dispatch(importEntities({ relationships: [response] })); }); }; @@ -226,7 +225,7 @@ const muteAccount = (accountId: string, notifications?: boolean, duration = 0) = return client.filtering.muteAccount(accountId, params) .then(response => { - dispatch(importEntities([response], Entities.RELATIONSHIPS)); + dispatch(importEntities({ relationships: [response] })); // Pass in entire statuses map so we can use it to filter stuff in different parts of the reducers return dispatch(muteAccountSuccess(response, getState().statuses)); }) @@ -238,7 +237,7 @@ const unmuteAccount = (accountId: string) => if (!isLoggedIn(getState)) return null; return getClient(getState()).filtering.unmuteAccount(accountId) - .then(response => dispatch(importEntities([response], Entities.RELATIONSHIPS))); + .then(response => dispatch(importEntities({ relationships: [response] }))); }; const muteAccountRequest = (accountId: string) => ({ @@ -263,7 +262,7 @@ const removeFromFollowers = (accountId: string) => if (!isLoggedIn(getState)) return null; return getClient(getState()).accounts.removeAccountFromFollowers(accountId) - .then(response => dispatch(importEntities([response], Entities.RELATIONSHIPS))); + .then(response => dispatch(importEntities({ relationships: [response] }))); }; const fetchRelationships = (accountIds: string[]) => @@ -278,7 +277,7 @@ const fetchRelationships = (accountIds: string[]) => } return getClient(getState()).accounts.getRelationships(newAccountIds) - .then(response => dispatch(importEntities(response, Entities.RELATIONSHIPS))); + .then(response => dispatch(importEntities({ relationships: response }))); }; const fetchFollowRequests = () => @@ -289,7 +288,7 @@ const fetchFollowRequests = () => return getClient(getState()).myAccount.getFollowRequests() .then(response => { - dispatch(importFetchedAccounts(response.items)); + dispatch(importEntities({ accounts: response.items })); dispatch(fetchFollowRequestsSuccess(response.items, response.next)); }) .catch(error => dispatch(fetchFollowRequestsFail(error))); @@ -321,7 +320,7 @@ const expandFollowRequests = () => dispatch(expandFollowRequestsRequest()); return next().then(response => { - dispatch(importFetchedAccounts(response.items)); + dispatch(importEntities({ accounts: response.items })); dispatch(expandFollowRequestsSuccess(response.items, response.next)); }).catch(error => dispatch(expandFollowRequestsFail(error))); }; @@ -400,7 +399,7 @@ const pinAccount = (accountId: string) => if (!isLoggedIn(getState)) return dispatch(noOp); return getClient(getState).accounts.pinAccount(accountId).then(response => - dispatch(importEntities([response], Entities.RELATIONSHIPS)), + dispatch(importEntities({ relationships: [response] })), ); }; @@ -409,7 +408,7 @@ const unpinAccount = (accountId: string) => if (!isLoggedIn(getState)) return dispatch(noOp); return getClient(getState).accounts.unpinAccount(accountId).then(response => - dispatch(importEntities([response], Entities.RELATIONSHIPS)), + dispatch(importEntities({ relationships: [response] })), ); }; @@ -429,7 +428,7 @@ const fetchPinnedAccounts = (accountId: string) => dispatch(fetchPinnedAccountsRequest(accountId)); return getClient(getState).accounts.getAccountEndorsements(accountId).then(response => { - dispatch(importFetchedAccounts(response)); + dispatch(importEntities({ accounts: response })); dispatch(fetchPinnedAccountsSuccess(accountId, response, null)); }).catch(error => { dispatch(fetchPinnedAccountsFail(accountId, error)); @@ -458,7 +457,7 @@ const accountSearch = (q: string, signal?: AbortSignal) => (dispatch: AppDispatch, getState: () => RootState) => { dispatch({ type: ACCOUNT_SEARCH_REQUEST, params: { q } }); return getClient(getState()).accounts.searchAccounts(q, { resolve: false, limit: 4, following: true }, { signal }).then((accounts) => { - dispatch(importFetchedAccounts(accounts)); + dispatch(importEntities({ accounts })); dispatch({ type: ACCOUNT_SEARCH_SUCCESS, accounts }); return accounts; }).catch(error => { @@ -471,7 +470,7 @@ const accountLookup = (acct: string, signal?: AbortSignal) => (dispatch: AppDispatch, getState: () => RootState) => { dispatch({ type: ACCOUNT_LOOKUP_REQUEST, acct }); return getClient(getState()).accounts.lookupAccount(acct, { signal }).then((account) => { - if (account && account.id) dispatch(importFetchedAccount(account)); + if (account && account.id) dispatch(importEntities({ accounts: [account] })); dispatch({ type: ACCOUNT_LOOKUP_SUCCESS, account }); return account; }).catch(error => { @@ -489,7 +488,7 @@ const fetchBirthdayReminders = (month: number, day: number) => dispatch({ type: BIRTHDAY_REMINDERS_FETCH_REQUEST, day, month, accountId: me }); return getClient(getState).accounts.getBirthdays(day, month).then(response => { - dispatch(importFetchedAccounts(response)); + dispatch(importEntities({ accounts: response })); dispatch({ type: BIRTHDAY_REMINDERS_FETCH_SUCCESS, accounts: response, diff --git a/packages/pl-fe/src/actions/admin.ts b/packages/pl-fe/src/actions/admin.ts index 23d11ff07..006c3a567 100644 --- a/packages/pl-fe/src/actions/admin.ts +++ b/packages/pl-fe/src/actions/admin.ts @@ -1,12 +1,12 @@ import { fetchRelationships } from 'pl-fe/actions/accounts'; -import { importFetchedAccount, importFetchedAccounts, importFetchedStatus, importFetchedStatuses } from 'pl-fe/actions/importer'; +import { importEntities } from 'pl-fe/actions/importer'; import { filterBadges, getTagDiff } from 'pl-fe/utils/badges'; import { getClient } from '../api'; import { deleteFromTimelines } from './timelines'; -import type { Account, AdminGetAccountsParams, AdminGetReportsParams, PleromaConfig } from 'pl-api'; +import type { Account, AdminGetAccountsParams, AdminGetReportsParams, PleromaConfig, Status } from 'pl-api'; import type { AppDispatch, RootState } from 'pl-fe/store'; const ADMIN_CONFIG_FETCH_REQUEST = 'ADMIN_CONFIG_FETCH_REQUEST' as const; @@ -111,9 +111,7 @@ const fetchReports = (params?: AdminGetReportsParams) => return getClient(state).admin.reports.getReports(params) .then(({ items }) => { items.forEach((report) => { - if (report.account?.account) dispatch(importFetchedAccount(report.account.account)); - if (report.target_account?.account) dispatch(importFetchedAccount(report.target_account.account)); - dispatch(importFetchedStatuses(report.statuses)); + dispatch(importEntities({ statuses: report.statuses as Array, accounts: [report.account?.account, report.target_account?.account] })); dispatch({ type: ADMIN_REPORTS_FETCH_SUCCESS, reports: items, params }); }); }).catch(error => { @@ -141,7 +139,7 @@ const fetchUsers = (params?: AdminGetAccountsParams) => dispatch({ type: ADMIN_USERS_FETCH_REQUEST, params }); return getClient(state).admin.accounts.getAccounts(params).then((res) => { - dispatch(importFetchedAccounts(res.items.map(({ account }) => account).filter((account): account is Account => account !== null))); + dispatch(importEntities({ accounts: res.items.map(({ account }) => account).filter((account): account is Account => account !== null) })); dispatch(fetchRelationships(res.items.map((account) => account.id))); dispatch({ type: ADMIN_USERS_FETCH_SUCCESS, users: res.items, params, next: res.next }); return res; @@ -203,7 +201,7 @@ const toggleStatusSensitivity = (statusId: string, sensitive: boolean) => dispatch({ type: ADMIN_STATUS_TOGGLE_SENSITIVITY_REQUEST, statusId }); return getClient(getState).admin.statuses.updateStatus(statusId, { sensitive: !sensitive }) .then((status) => { - dispatch(importFetchedStatus(status)); + dispatch(importEntities({ statuses: [status] })); dispatch({ type: ADMIN_STATUS_TOGGLE_SENSITIVITY_SUCCESS, statusId, status }); }).catch(error => { dispatch({ type: ADMIN_STATUS_TOGGLE_SENSITIVITY_FAIL, error, statusId }); diff --git a/packages/pl-fe/src/actions/aliases.ts b/packages/pl-fe/src/actions/aliases.ts index 891a5fcd3..f516add23 100644 --- a/packages/pl-fe/src/actions/aliases.ts +++ b/packages/pl-fe/src/actions/aliases.ts @@ -5,7 +5,7 @@ import { isLoggedIn } from 'pl-fe/utils/auth'; import { getClient } from '../api'; -import { importFetchedAccounts } from './importer'; +import { importEntities } from './importer'; import type { Account as BaseAccount } from 'pl-api'; import type { Account } from 'pl-fe/normalizers/account'; @@ -63,7 +63,7 @@ const fetchAliasesSuggestions = (q: string) => return getClient(getState()).accounts.searchAccounts(q, { resolve: true, limit: 4 }) .then((data) => { - dispatch(importFetchedAccounts(data)); + dispatch(importEntities({ accounts: data })); dispatch(fetchAliasesSuggestionsReady(q, data)); }).catch(error => toast.showAlertForError(error)); }; diff --git a/packages/pl-fe/src/actions/auth.ts b/packages/pl-fe/src/actions/auth.ts index 7b1d8c986..37241fc8f 100644 --- a/packages/pl-fe/src/actions/auth.ts +++ b/packages/pl-fe/src/actions/auth.ts @@ -30,7 +30,7 @@ import { isStandalone } from 'pl-fe/utils/state'; import { type PlfeResponse, getClient } from '../api'; -import { importFetchedAccount } from './importer'; +import { importEntities } from './importer'; import type { AppDispatch, RootState } from 'pl-fe/store'; @@ -150,7 +150,7 @@ const verifyCredentials = (token: string, accountUrl?: string) => const client = new PlApiClient(baseURL, token); return client.settings.verifyCredentials().then((account) => { - dispatch(importFetchedAccount(account)); + dispatch(importEntities({ accounts: [account] })); dispatch({ type: VERIFY_CREDENTIALS_SUCCESS, token, account }); if (account.id === getState().me) dispatch(fetchMeSuccess(account)); return account; @@ -159,7 +159,7 @@ const verifyCredentials = (token: string, accountUrl?: string) => // The user is waitlisted const account = error.response.json; const parsedAccount = v.parse(credentialAccountSchema, error.response.json); - dispatch(importFetchedAccount(parsedAccount)); + dispatch(importEntities({ accounts: [parsedAccount] })); dispatch({ type: VERIFY_CREDENTIALS_SUCCESS, token, account: parsedAccount }); if (account.id === getState().me) dispatch(fetchMeSuccess(parsedAccount)); return parsedAccount; @@ -175,7 +175,7 @@ const rememberAuthAccount = (accountUrl: string) => (dispatch: AppDispatch, getState: () => RootState) => { dispatch({ type: AUTH_ACCOUNT_REMEMBER_REQUEST, accountUrl }); return KVStore.getItemOrError(`authAccount:${accountUrl}`).then(account => { - dispatch(importFetchedAccount(account)); + dispatch(importEntities({ accounts: [account] })); dispatch({ type: AUTH_ACCOUNT_REMEMBER_SUCCESS, account, accountUrl }); if (account.id === getState().me) dispatch(fetchMeSuccess(account)); return account; diff --git a/packages/pl-fe/src/actions/bookmarks.ts b/packages/pl-fe/src/actions/bookmarks.ts index 49de0a058..c1ff1b064 100644 --- a/packages/pl-fe/src/actions/bookmarks.ts +++ b/packages/pl-fe/src/actions/bookmarks.ts @@ -1,6 +1,6 @@ import { getClient } from '../api'; -import { importFetchedStatuses } from './importer'; +import { importEntities } from './importer'; import type { PaginatedResponse, Status } from 'pl-api'; import type { AppDispatch, RootState } from 'pl-fe/store'; @@ -24,7 +24,7 @@ const fetchBookmarkedStatuses = (folderId?: string) => dispatch(fetchBookmarkedStatusesRequest(folderId)); return getClient(getState()).myAccount.getBookmarks({ folder_id: folderId }).then(response => { - dispatch(importFetchedStatuses(response.items)); + dispatch(importEntities({ statuses: response.items })); return dispatch(fetchBookmarkedStatusesSuccess(response.items, response.next, folderId)); }).catch(error => { dispatch(fetchBookmarkedStatusesFail(error, folderId)); @@ -61,7 +61,7 @@ const expandBookmarkedStatuses = (folderId?: string) => dispatch(expandBookmarkedStatusesRequest(folderId)); return next().then(response => { - dispatch(importFetchedStatuses(response.items)); + dispatch(importEntities({ statuses: response.items })); return dispatch(expandBookmarkedStatusesSuccess(response.items, response.next, folderId)); }).catch(error => { dispatch(expandBookmarkedStatusesFail(error, folderId)); diff --git a/packages/pl-fe/src/actions/compose.ts b/packages/pl-fe/src/actions/compose.ts index 2e0d85247..ebfbbe137 100644 --- a/packages/pl-fe/src/actions/compose.ts +++ b/packages/pl-fe/src/actions/compose.ts @@ -13,7 +13,7 @@ import toast from 'pl-fe/toast'; import { isLoggedIn } from 'pl-fe/utils/auth'; import { chooseEmoji } from './emojis'; -import { importFetchedAccounts } from './importer'; +import { importEntities } from './importer'; import { rememberLanguageUse } from './languages'; import { uploadFile, updateMedia } from './media'; import { createStatus } from './statuses'; @@ -593,7 +593,7 @@ const fetchComposeSuggestionsAccounts = throttle((dispatch, getState, composeId, return getClient(getState).accounts.searchAccounts(token.slice(1), { resolve: false, limit: 10 }, { signal }) .then(response => { - dispatch(importFetchedAccounts(response)); + dispatch(importEntities({ accounts: response })); dispatch(readyComposeSuggestionsAccounts(composeId, token, response)); }).catch(error => { if (!signal.aborted) { diff --git a/packages/pl-fe/src/actions/conversations.ts b/packages/pl-fe/src/actions/conversations.ts index 3f4a26ba7..31c43b8e4 100644 --- a/packages/pl-fe/src/actions/conversations.ts +++ b/packages/pl-fe/src/actions/conversations.ts @@ -2,13 +2,9 @@ import { isLoggedIn } from 'pl-fe/utils/auth'; import { getClient } from '../api'; -import { - importFetchedAccounts, - importFetchedStatuses, - importFetchedStatus, -} from './importer'; +import { importEntities } from './importer'; -import type { Account, Conversation, PaginatedResponse, Status } from 'pl-api'; +import type { Account, Conversation, PaginatedResponse } from 'pl-api'; import type { AppDispatch, RootState } from 'pl-fe/store'; const CONVERSATIONS_MOUNT = 'CONVERSATIONS_MOUNT' as const; @@ -48,8 +44,10 @@ const expandConversations = (expand = true) => (dispatch: AppDispatch, getState: return (state.conversations.next?.() || getClient(state).timelines.getConversations()) .then(response => { - dispatch(importFetchedAccounts(response.items.reduce((aggr: Array, item) => aggr.concat(item.accounts), []))); - dispatch(importFetchedStatuses(response.items.map((item) => item.last_status).filter((x): x is Status => x !== null))); + dispatch(importEntities({ + accounts: response.items.reduce((aggr: Array, item) => aggr.concat(item.accounts), []), + statuses: response.items.map((item) => item.last_status), + })); dispatch(expandConversationsSuccess(response.items, response.next, isLoadingRecent)); }) .catch(err => dispatch(expandConversationsFail(err))); @@ -74,11 +72,10 @@ const expandConversationsFail = (error: unknown) => ({ }); const updateConversations = (conversation: Conversation) => (dispatch: AppDispatch) => { - dispatch(importFetchedAccounts(conversation.accounts)); - - if (conversation.last_status) { - dispatch(importFetchedStatus(conversation.last_status)); - } + dispatch(importEntities({ + accounts: conversation.accounts, + statuses: [conversation.last_status], + })); return dispatch({ type: CONVERSATIONS_UPDATE, diff --git a/packages/pl-fe/src/actions/directory.ts b/packages/pl-fe/src/actions/directory.ts index 14a5e8151..58398b47d 100644 --- a/packages/pl-fe/src/actions/directory.ts +++ b/packages/pl-fe/src/actions/directory.ts @@ -1,7 +1,7 @@ import { getClient } from '../api'; import { fetchRelationships } from './accounts'; -import { importFetchedAccounts } from './importer'; +import { importEntities } from './importer'; import type { Account, ProfileDirectoryParams } from 'pl-api'; import type { AppDispatch, RootState } from 'pl-fe/store'; @@ -19,7 +19,7 @@ const fetchDirectory = (params: ProfileDirectoryParams) => dispatch(fetchDirectoryRequest()); return getClient(getState()).instance.profileDirectory({ ...params, limit: 20 }).then((data) => { - dispatch(importFetchedAccounts(data)); + dispatch(importEntities({ accounts: data })); dispatch(fetchDirectorySuccess(data)); dispatch(fetchRelationships(data.map((x) => x.id))); }).catch(error => dispatch(fetchDirectoryFail(error))); @@ -46,7 +46,7 @@ const expandDirectory = (params: Record) => const loadedItems = getState().user_lists.directory.items.size; return getClient(getState()).instance.profileDirectory({ ...params, offset: loadedItems, limit: 20 }).then((data) => { - dispatch(importFetchedAccounts(data)); + dispatch(importEntities({ accounts: data })); dispatch(expandDirectorySuccess(data)); dispatch(fetchRelationships(data.map((x) => x.id))); }).catch(error => dispatch(expandDirectoryFail(error))); diff --git a/packages/pl-fe/src/actions/emoji-reacts.ts b/packages/pl-fe/src/actions/emoji-reacts.ts index 5643b8b8f..a98a021f1 100644 --- a/packages/pl-fe/src/actions/emoji-reacts.ts +++ b/packages/pl-fe/src/actions/emoji-reacts.ts @@ -2,7 +2,7 @@ import { isLoggedIn } from 'pl-fe/utils/auth'; import { getClient } from '../api'; -import { importFetchedStatus } from './importer'; +import { importEntities } from './importer'; import type { Status } from 'pl-api'; import type { AppDispatch, RootState } from 'pl-fe/store'; @@ -24,7 +24,7 @@ const emojiReact = (status: Pick, emoji: string, custom?: string) dispatch(emojiReactRequest(status.id, emoji, custom)); return getClient(getState).statuses.createStatusReaction(status.id, emoji).then((response) => { - dispatch(importFetchedStatus(response)); + dispatch(importEntities({ statuses: [response] })); dispatch(emojiReactSuccess(response, emoji)); }).catch((error) => { dispatch(emojiReactFail(status.id, emoji, error)); @@ -38,7 +38,7 @@ const unEmojiReact = (status: Pick, emoji: string) => dispatch(unEmojiReactRequest(status.id, emoji)); return getClient(getState).statuses.deleteStatusReaction(status.id, emoji).then(response => { - dispatch(importFetchedStatus(response)); + dispatch(importEntities({ statuses: [response] })); dispatch(unEmojiReactSuccess(response, emoji)); }).catch(error => { dispatch(unEmojiReactFail(status.id, emoji, error)); diff --git a/packages/pl-fe/src/actions/events.ts b/packages/pl-fe/src/actions/events.ts index 64941ee66..8e7021e79 100644 --- a/packages/pl-fe/src/actions/events.ts +++ b/packages/pl-fe/src/actions/events.ts @@ -4,7 +4,7 @@ import { getClient } from 'pl-fe/api'; import { useModalsStore } from 'pl-fe/stores/modals'; import toast from 'pl-fe/toast'; -import { importFetchedAccounts, importFetchedStatus, importFetchedStatuses } from './importer'; +import { importEntities } from './importer'; import { STATUS_FETCH_SOURCE_FAIL, STATUS_FETCH_SOURCE_REQUEST, STATUS_FETCH_SOURCE_SUCCESS } from './statuses'; import type { Account, CreateEventParams, Location, MediaAttachment, PaginatedResponse, Status } from 'pl-api'; @@ -132,7 +132,7 @@ const submitEvent = ({ : getClient(state).events.editEvent(statusId, params) ).then((data) => { useModalsStore.getState().closeModal('COMPOSE_EVENT'); - dispatch(importFetchedStatus(data)); + dispatch(importEntities({ statuses: [data] })); dispatch(submitEventSuccess(data)); toast.success( statusId ? messages.editSuccess : messages.success, @@ -171,7 +171,7 @@ const joinEvent = (statusId: string, participationMessage?: string) => dispatch(joinEventRequest(status.id)); return getClient(getState).events.joinEvent(statusId, participationMessage).then((data) => { - dispatch(importFetchedStatus(data)); + dispatch(importEntities({ statuses: [data] })); dispatch(joinEventSuccess(status.id)); toast.success( data.event?.join_state === 'pending' ? messages.joinRequestSuccess : messages.joinSuccess, @@ -213,7 +213,7 @@ const leaveEvent = (statusId: string) => dispatch(leaveEventRequest(status.id)); return getClient(getState).events.leaveEvent(statusId).then((data) => { - dispatch(importFetchedStatus(data)); + dispatch(importEntities({ statuses: [data] })); dispatch(leaveEventSuccess(status.id)); }).catch((error) => { dispatch(leaveEventFail(error, status.id)); @@ -241,7 +241,7 @@ const fetchEventParticipations = (statusId: string) => dispatch(fetchEventParticipationsRequest(statusId)); return getClient(getState).events.getEventParticipations(statusId).then(response => { - dispatch(importFetchedAccounts(response.items)); + dispatch(importEntities({ accounts: response.items })); return dispatch(fetchEventParticipationsSuccess(statusId, response.items, response.next)); }).catch(error => { dispatch(fetchEventParticipationsFail(statusId, error)); @@ -277,7 +277,7 @@ const expandEventParticipations = (statusId: string) => dispatch(expandEventParticipationsRequest(statusId)); return next().then(response => { - dispatch(importFetchedAccounts(response.items)); + dispatch(importEntities({ accounts: response.items })); return dispatch(expandEventParticipationsSuccess(statusId, response.items, response.next)); }).catch(error => { dispatch(expandEventParticipationsFail(statusId, error)); @@ -307,7 +307,7 @@ const fetchEventParticipationRequests = (statusId: string) => dispatch(fetchEventParticipationRequestsRequest(statusId)); return getClient(getState).events.getEventParticipationRequests(statusId).then(response => { - dispatch(importFetchedAccounts(response.items.map(({ account }) => account))); + dispatch(importEntities({ accounts: response.items.map(({ account }) => account) })); return dispatch(fetchEventParticipationRequestsSuccess(statusId, response.items, response.next)); }).catch(error => { dispatch(fetchEventParticipationRequestsFail(statusId, error)); @@ -346,7 +346,7 @@ const expandEventParticipationRequests = (statusId: string) => dispatch(expandEventParticipationRequestsRequest(statusId)); return next().then(response => { - dispatch(importFetchedAccounts(response.items.map(({ account }) => account))); + dispatch(importEntities({ accounts: response.items.map(({ account }) => account) })); return dispatch(expandEventParticipationRequestsSuccess(statusId, response.items, response.next)); }).catch(error => { dispatch(expandEventParticipationRequestsFail(statusId, error)); @@ -479,7 +479,7 @@ const fetchRecentEvents = () => return getClient(getState()).timelines.publicTimeline({ only_events: true, }).then(response => { - dispatch(importFetchedStatuses(response.items)); + dispatch(importEntities({ statuses: response.items })); dispatch({ type: RECENT_EVENTS_FETCH_SUCCESS, statuses: response.items, @@ -499,7 +499,7 @@ const fetchJoinedEvents = () => dispatch({ type: JOINED_EVENTS_FETCH_REQUEST }); getClient(getState).events.getJoinedEvents().then(response => { - dispatch(importFetchedStatuses(response.items)); + dispatch(importEntities({ statuses: response.items })); dispatch({ type: JOINED_EVENTS_FETCH_SUCCESS, statuses: response.items, diff --git a/packages/pl-fe/src/actions/familiar-followers.ts b/packages/pl-fe/src/actions/familiar-followers.ts index 12bf81f83..b344728e0 100644 --- a/packages/pl-fe/src/actions/familiar-followers.ts +++ b/packages/pl-fe/src/actions/familiar-followers.ts @@ -3,7 +3,7 @@ import { AppDispatch, RootState } from 'pl-fe/store'; import { getClient } from '../api'; import { fetchRelationships } from './accounts'; -import { importFetchedAccounts } from './importer'; +import { importEntities } from './importer'; const FAMILIAR_FOLLOWERS_FETCH_REQUEST = 'FAMILIAR_FOLLOWERS_FETCH_REQUEST' as const; const FAMILIAR_FOLLOWERS_FETCH_SUCCESS = 'FAMILIAR_FOLLOWERS_FETCH_SUCCESS' as const; @@ -19,7 +19,7 @@ const fetchAccountFamiliarFollowers = (accountId: string) => (dispatch: AppDispa .then((data) => { const accounts = data.find(({ id }: { id: string }) => id === accountId)!.accounts; - dispatch(importFetchedAccounts(accounts)); + dispatch(importEntities({ accounts })); dispatch(fetchRelationships(accounts.map((item) => item.id))); dispatch({ type: FAMILIAR_FOLLOWERS_FETCH_SUCCESS, diff --git a/packages/pl-fe/src/actions/favourites.ts b/packages/pl-fe/src/actions/favourites.ts index 958e6517b..736a3b88a 100644 --- a/packages/pl-fe/src/actions/favourites.ts +++ b/packages/pl-fe/src/actions/favourites.ts @@ -2,7 +2,7 @@ import { isLoggedIn } from 'pl-fe/utils/auth'; import { getClient } from '../api'; -import { importFetchedStatuses } from './importer'; +import { importEntities } from './importer'; import type { PaginatedResponse, Status } from 'pl-api'; import type { AppDispatch, RootState } from 'pl-fe/store'; @@ -34,7 +34,7 @@ const fetchFavouritedStatuses = () => dispatch(fetchFavouritedStatusesRequest()); return getClient(getState()).myAccount.getFavourites().then(response => { - dispatch(importFetchedStatuses(response.items)); + dispatch(importEntities({ statuses: response.items })); dispatch(fetchFavouritedStatusesSuccess(response.items, response.next)); }).catch(error => { dispatch(fetchFavouritedStatusesFail(error)); @@ -69,7 +69,7 @@ const expandFavouritedStatuses = () => dispatch(expandFavouritedStatusesRequest()); return next().then(response => { - dispatch(importFetchedStatuses(response.items)); + dispatch(importEntities({ statuses: response.items })); dispatch(expandFavouritedStatusesSuccess(response.items, response.next)); }).catch(error => { dispatch(expandFavouritedStatusesFail(error)); @@ -102,7 +102,7 @@ const fetchAccountFavouritedStatuses = (accountId: string) => dispatch(fetchAccountFavouritedStatusesRequest(accountId)); return getClient(getState).accounts.getAccountFavourites(accountId).then(response => { - dispatch(importFetchedStatuses(response.items)); + dispatch(importEntities({ statuses: response.items })); dispatch(fetchAccountFavouritedStatusesSuccess(accountId, response.items, response.next)); }).catch(error => { dispatch(fetchAccountFavouritedStatusesFail(accountId, error)); @@ -140,7 +140,7 @@ const expandAccountFavouritedStatuses = (accountId: string) => dispatch(expandAccountFavouritedStatusesRequest(accountId)); return next().then(response => { - dispatch(importFetchedStatuses(response.items)); + dispatch(importEntities({ statuses: response.items })); dispatch(expandAccountFavouritedStatusesSuccess(accountId, response.items, response.next)); }).catch(error => { dispatch(expandAccountFavouritedStatusesFail(accountId, error)); diff --git a/packages/pl-fe/src/actions/groups.ts b/packages/pl-fe/src/actions/groups.ts index ed201388a..23686e258 100644 --- a/packages/pl-fe/src/actions/groups.ts +++ b/packages/pl-fe/src/actions/groups.ts @@ -1,6 +1,6 @@ import { getClient } from '../api'; -import { importFetchedAccounts } from './importer'; +import { importEntities } from './importer'; import type { Account, PaginatedResponse } from 'pl-api'; import type { AppDispatch, RootState } from 'pl-fe/store'; @@ -23,7 +23,7 @@ const fetchGroupBlocks = (groupId: string) => dispatch(fetchGroupBlocksRequest(groupId)); return getClient(getState).experimental.groups.getGroupBlocks(groupId).then(response => { - dispatch(importFetchedAccounts(response.items)); + dispatch(importEntities({ accounts: response.items })); dispatch(fetchGroupBlocksSuccess(groupId, response.items, response.next)); }).catch(error => { dispatch(fetchGroupBlocksFail(groupId, error)); diff --git a/packages/pl-fe/src/actions/history.ts b/packages/pl-fe/src/actions/history.ts index 733871b17..059a92487 100644 --- a/packages/pl-fe/src/actions/history.ts +++ b/packages/pl-fe/src/actions/history.ts @@ -1,6 +1,6 @@ import { getClient } from 'pl-fe/api'; -import { importFetchedAccounts } from './importer'; +import { importEntities } from './importer'; import type { StatusEdit } from 'pl-api'; import type { AppDispatch, RootState } from 'pl-fe/store'; @@ -18,7 +18,7 @@ const fetchHistory = (statusId: string) => dispatch(fetchHistoryRequest(statusId)); return getClient(getState()).statuses.getStatusHistory(statusId).then(data => { - dispatch(importFetchedAccounts(data.map((x) => x.account))); + dispatch(importEntities({ accounts: data.map((x) => x.account) })); dispatch(fetchHistorySuccess(statusId, data)); }).catch(error => dispatch(fetchHistoryFail(statusId, error))); }; diff --git a/packages/pl-fe/src/actions/importer.ts b/packages/pl-fe/src/actions/importer.ts new file mode 100644 index 000000000..15272d79f --- /dev/null +++ b/packages/pl-fe/src/actions/importer.ts @@ -0,0 +1,121 @@ +import { importEntities as importEntityStoreEntities } from 'pl-fe/entity-store/actions'; +import { Entities } from 'pl-fe/entity-store/entities'; +import { normalizeGroup } from 'pl-fe/normalizers/group'; + +import type { Account as BaseAccount, Group as BaseGroup, Poll as BasePoll, Relationship as BaseRelationship, Status as BaseStatus } from 'pl-api'; +import type { AppDispatch } from 'pl-fe/store'; + +const STATUS_IMPORT = 'STATUS_IMPORT' as const; +const STATUSES_IMPORT = 'STATUSES_IMPORT' as const; +const POLLS_IMPORT = 'POLLS_IMPORT' as const; + +// Sometimes Pleroma can return an empty account, +// or a repost can appear of a deleted account. Skip these statuses. +const isBroken = (status: BaseStatus) => { + try { + if (status.scheduled_at !== null) return true; + // Skip empty accounts + // https://gitlab.com/soapbox-pub/soapbox/-/issues/424 + if (!status.account.id) return true; + // Skip broken reposts + // https://gitlab.com/soapbox-pub/rebased/-/issues/28 + if (status.reblog && !status.reblog.account.id) return true; + return false; + } catch (e) { + return true; + } +}; + +const isEmpty = (object: Record) => !Object.values(object).some(value => value); + +interface ImportStatusAction { + type: typeof STATUS_IMPORT; + status: BaseStatus; + idempotencyKey?: string; +} + +interface ImportStatusesAction { + type: typeof STATUSES_IMPORT; + statuses: Array; +} + +interface ImportPollAction { + type: typeof POLLS_IMPORT; + polls: Array; +} + +const importEntities = (entities: { + accounts?: Array; + groups?: Array; + polls?: Array; + statuses?: Array; + relationships?: Array; +}, options: { + withParents?: boolean; + idempotencyKey?: string; +} = { + withParents: true, +}) => (dispatch: AppDispatch) => { + const accounts: Record = {}; + const groups: Record = {}; + const polls: Record = {}; + const relationships: Record = {}; + const statuses: Record = {}; + + const processAccount = (account: BaseAccount, withSelf = true) => { + if (withSelf) accounts[account.id] = account; + + if (account.moved) processAccount(account.moved); + if (account.relationship) relationships[account.relationship.id] = account.relationship; + }; + + const processStatus = (status: BaseStatus, withSelf = true) => { + // Skip broken statuses + if (isBroken(status)) return; + + if (withSelf) statuses[status.id] = status; + + if (status.account) { + processAccount(status.account); + } + + if (status.quote) processStatus(status.quote); + if (status.reblog) processStatus(status.reblog); + if (status.poll) polls[status.poll.id] = status.poll; + if (status.group) groups[status.group.id] = status.group; + }; + + if (options.withParents) { + entities.groups?.forEach(group => group && (groups[group.id] = group)); + entities.polls?.forEach(poll => poll && (polls[poll.id] = poll)); + entities.relationships?.forEach(relationship => relationship && (relationships[relationship.id] = relationship)); + } + + entities.accounts?.forEach((account) => account && processAccount(account, options.withParents)); + + if (entities.statuses?.length === 1 && entities.statuses[0] && options.idempotencyKey) { + dispatch({ + type: STATUS_IMPORT, + status: entities.statuses[0], idempotencyKey: options.idempotencyKey, + }); + processStatus(entities.statuses[0], false); + } else { + entities.statuses?.forEach((status) => status && processStatus(status, options.withParents)); + } + + if (!isEmpty(accounts)) dispatch(importEntityStoreEntities(Object.values(accounts), Entities.ACCOUNTS)); + if (!isEmpty(groups)) dispatch(importEntityStoreEntities(Object.values(groups).map(normalizeGroup), Entities.GROUPS)); + if (!isEmpty(polls)) dispatch(({ type: POLLS_IMPORT, polls: Object.values(polls) })); + if (!isEmpty(relationships)) dispatch(importEntityStoreEntities(Object.values(relationships), Entities.RELATIONSHIPS)); + if (!isEmpty(statuses)) dispatch({ type: STATUSES_IMPORT, statuses: Object.values(statuses) }); +}; + +type ImporterAction = ImportStatusAction | ImportStatusesAction | ImportPollAction; + +export { + STATUS_IMPORT, + STATUSES_IMPORT, + POLLS_IMPORT, + importEntities, + type ImporterAction, +}; diff --git a/packages/pl-fe/src/actions/importer/index.ts b/packages/pl-fe/src/actions/importer/index.ts deleted file mode 100644 index c97486900..000000000 --- a/packages/pl-fe/src/actions/importer/index.ts +++ /dev/null @@ -1,169 +0,0 @@ -import { importEntities } from 'pl-fe/entity-store/actions'; -import { Entities } from 'pl-fe/entity-store/entities'; -import { normalizeAccount } from 'pl-fe/normalizers/account'; -import { normalizeGroup } from 'pl-fe/normalizers/group'; - -import type { Account as BaseAccount, Group, Poll, Status as BaseStatus } from 'pl-api'; -import type { AppDispatch } from 'pl-fe/store'; - -const STATUS_IMPORT = 'STATUS_IMPORT' as const; -const STATUSES_IMPORT = 'STATUSES_IMPORT' as const; -const POLLS_IMPORT = 'POLLS_IMPORT' as const; - -const importAccounts = (data: Array) => (dispatch: AppDispatch) => { - try { - const accounts = data.map(normalizeAccount); - const relationships = accounts.map(account => account.relationship).filter(relationship => !!relationship); - - dispatch(importEntities(accounts, Entities.ACCOUNTS)); - dispatch(importEntities(relationships, Entities.RELATIONSHIPS)); - } catch (e) { - // - } -}; - -const importGroup = (data: Group) => importGroups([data]); - -const importGroups = (data: Array) => (dispatch: AppDispatch) => { - try { - const groups = data.map(normalizeGroup); - dispatch(importEntities(groups, Entities.GROUPS)); - } catch (e) { - // - } -}; - -const importStatus = (status: BaseStatus & { expectsCard?: boolean }, idempotencyKey?: string) => ({ type: STATUS_IMPORT, status, idempotencyKey }); - -const importStatuses = (statuses: Array) => ({ type: STATUSES_IMPORT, statuses }); - -const importPolls = (polls: Array) => ({ type: POLLS_IMPORT, polls }); - -const importFetchedAccount = (account: BaseAccount) => - importFetchedAccounts([account]); - -const importFetchedAccounts = (accounts: Array) => { - const normalAccounts: Array = []; - - const processAccount = (account: BaseAccount) => { - if (!account.id) return; - - normalAccounts.push(account); - - if (account.moved) { - processAccount(account.moved); - } - }; - - accounts.forEach(processAccount); - - return importAccounts(normalAccounts); -}; - -const importFetchedStatus = (status: BaseStatus & { expectsCard?: boolean }, idempotencyKey?: string) => - (dispatch: AppDispatch) => { - // Skip broken statuses - if (isBroken(status)) return; - - if (status.reblog?.id) { - dispatch(importFetchedStatus(status.reblog as BaseStatus)); - } - - // Fedibird quotes - if (status.quote?.id) { - dispatch(importFetchedStatus(status.quote as BaseStatus)); - } - - // Fedibird quote from reblog - if (status.reblog?.quote?.id) { - dispatch(importFetchedStatus(status.reblog.quote)); - } - - if (status.poll?.id) { - dispatch(importFetchedPoll(status.poll)); - } - - if (status.group?.id) { - dispatch(importGroup(status.group)); - } - - dispatch(importFetchedAccount(status.account)); - dispatch(importStatus(status, idempotencyKey)); - }; - -// Sometimes Pleroma can return an empty account, -// or a repost can appear of a deleted account. Skip these statuses. -const isBroken = (status: BaseStatus) => { - try { - if (status.scheduled_at !== null) return true; - // Skip empty accounts - // https://gitlab.com/soapbox-pub/soapbox/-/issues/424 - if (!status.account.id) return true; - // Skip broken reposts - // https://gitlab.com/soapbox-pub/rebased/-/issues/28 - if (status.reblog && !status.reblog.account.id) return true; - return false; - } catch (e) { - return true; - } -}; - -const importFetchedStatuses = (statuses: Array & { account: BaseAccount | null }>) => (dispatch: AppDispatch) => { - const accounts: Record = {}; - const normalStatuses: Array = []; - const polls: Array = []; - - const processStatus = (status: BaseStatus) => { - if (status.account === null) return; - // Skip broken statuses - if (isBroken(status)) return; - - normalStatuses.push(status); - - accounts[status.account.id] = status.account; - // if (status.accounts) { - // accounts.push(...status.accounts); - // } - - if (status.reblog?.id) { - processStatus(status.reblog as BaseStatus); - } - - // Fedibird quotes - if (status.quote?.id) { - processStatus(status.quote as BaseStatus); - } - - if (status.poll?.id) { - polls.push(status.poll); - } - }; - - (statuses as Array).forEach(processStatus); - - dispatch(importPolls(polls)); - dispatch(importFetchedAccounts(Object.values(accounts))); - dispatch(importStatuses(normalStatuses)); -}; - -const importFetchedPoll = (poll: Poll) => - (dispatch: AppDispatch) => { - dispatch(importPolls([poll])); - }; - -type ImporterAction = - | ReturnType - | ReturnType - | ReturnType; - -export { - STATUS_IMPORT, - STATUSES_IMPORT, - POLLS_IMPORT, - importFetchedAccount, - importFetchedAccounts, - importFetchedStatus, - importFetchedStatuses, - importFetchedPoll, - type ImporterAction, -}; diff --git a/packages/pl-fe/src/actions/interactions.ts b/packages/pl-fe/src/actions/interactions.ts index 43e467f2a..2909fb1c2 100644 --- a/packages/pl-fe/src/actions/interactions.ts +++ b/packages/pl-fe/src/actions/interactions.ts @@ -7,7 +7,7 @@ import { isLoggedIn } from 'pl-fe/utils/auth'; import { getClient } from '../api'; import { fetchRelationships } from './accounts'; -import { importFetchedAccounts, importFetchedStatus } from './importer'; +import { importEntities } from './importer'; import type { Account, EmojiReaction, PaginatedResponse, Status } from 'pl-api'; import type { AppDispatch, RootState } from 'pl-fe/store'; @@ -97,7 +97,7 @@ const reblog = (status: Pick) => return getClient(getState()).statuses.reblogStatus(status.id).then((response) => { // The reblog API method returns a new status wrapped around the original. In this case we are only // interested in how the original is modified, hence passing it skipping the wrapper - if (response.reblog) dispatch(importFetchedStatus(response.reblog as Status)); + if (response.reblog) dispatch(importEntities({ statuses: [response.reblog] })); dispatch(reblogSuccess(response)); }).catch(error => { dispatch(reblogFail(status.id, error)); @@ -307,7 +307,7 @@ const bookmark = (status: Pick, folderId?: string) => dispatch(bookmarkRequest(status.id)); return getClient(getState()).statuses.bookmarkStatus(status.id, folderId).then((response) => { - dispatch(importFetchedStatus(response)); + dispatch(importEntities({ statuses: [response] })); dispatch(bookmarkSuccess(response)); let opts: IToastOptions = { @@ -335,7 +335,7 @@ const unbookmark = (status: Pick) => dispatch(unbookmarkRequest(status.id)); return getClient(getState()).statuses.unbookmarkStatus(status.id).then(response => { - dispatch(importFetchedStatus(response)); + dispatch(importEntities({ statuses: [response] })); dispatch(unbookmarkSuccess(response)); toast.success(messages.bookmarkRemoved); }).catch(error => { @@ -391,7 +391,7 @@ const fetchReblogs = (statusId: string) => dispatch(fetchReblogsRequest(statusId)); return getClient(getState()).statuses.getRebloggedBy(statusId).then(response => { - dispatch(importFetchedAccounts(response.items)); + dispatch(importEntities({ accounts: response.items })); dispatch(fetchRelationships(response.items.map((item) => item.id))); dispatch(fetchReblogsSuccess(statusId, response.items, response.next)); }).catch(error => { @@ -420,7 +420,7 @@ const fetchReblogsFail = (statusId: string, error: unknown) => ({ const expandReblogs = (statusId: string, next: AccountListLink) => (dispatch: AppDispatch, getState: () => RootState) => { next().then(response => { - dispatch(importFetchedAccounts(response.items)); + dispatch(importEntities({ accounts: response.items })); dispatch(fetchRelationships(response.items.map((item) => item.id))); dispatch(expandReblogsSuccess(statusId, response.items, response.next)); }).catch(error => { @@ -446,7 +446,7 @@ const fetchFavourites = (statusId: string) => dispatch(fetchFavouritesRequest(statusId)); return getClient(getState()).statuses.getFavouritedBy(statusId).then(response => { - dispatch(importFetchedAccounts(response.items)); + dispatch(importEntities({ accounts: response.items })); dispatch(fetchRelationships(response.items.map((item) => item.id))); dispatch(fetchFavouritesSuccess(statusId, response.items, response.next)); }).catch(error => { @@ -475,7 +475,7 @@ const fetchFavouritesFail = (statusId: string, error: unknown) => ({ const expandFavourites = (statusId: string, next: AccountListLink) => (dispatch: AppDispatch) => { next().then(response => { - dispatch(importFetchedAccounts(response.items)); + dispatch(importEntities({ accounts: response.items })); dispatch(fetchRelationships(response.items.map((item) => item.id))); dispatch(expandFavouritesSuccess(statusId, response.items, response.next)); }).catch(error => { @@ -501,7 +501,7 @@ const fetchDislikes = (statusId: string) => dispatch(fetchDislikesRequest(statusId)); return getClient(getState).statuses.getDislikedBy(statusId).then(response => { - dispatch(importFetchedAccounts(response)); + dispatch(importEntities({ accounts: response })); dispatch(fetchRelationships(response.map((item) => item.id))); dispatch(fetchDislikesSuccess(statusId, response)); }).catch(error => { @@ -531,7 +531,7 @@ const fetchReactions = (statusId: string) => dispatch(fetchReactionsRequest(statusId)); return getClient(getState).statuses.getStatusReactions(statusId).then(response => { - dispatch(importFetchedAccounts((response).map(({ accounts }) => accounts).flat())); + dispatch(importEntities({ accounts: (response).map(({ accounts }) => accounts).flat() })); dispatch(fetchReactionsSuccess(statusId, response)); }).catch(error => { dispatch(fetchReactionsFail(statusId, error)); @@ -562,7 +562,7 @@ const pin = (status: Pick, accountId: string) => dispatch(pinRequest(status.id, accountId)); return getClient(getState()).statuses.pinStatus(status.id).then(response => { - dispatch(importFetchedStatus(response)); + dispatch(importEntities({ statuses: [response] })); dispatch(pinSuccess(response, accountId)); }).catch(error => { dispatch(pinFail(status.id, error, accountId)); @@ -596,7 +596,7 @@ const unpin = (status: Pick, accountId: string) => dispatch(unpinRequest(status.id, accountId)); return getClient(getState()).statuses.unpinStatus(status.id).then(response => { - dispatch(importFetchedStatus(response)); + dispatch(importEntities({ statuses: [response] })); dispatch(unpinSuccess(response, accountId)); }).catch(error => { dispatch(unpinFail(status.id, error, accountId)); diff --git a/packages/pl-fe/src/actions/lists.ts b/packages/pl-fe/src/actions/lists.ts index df7ba4c0e..5c8625730 100644 --- a/packages/pl-fe/src/actions/lists.ts +++ b/packages/pl-fe/src/actions/lists.ts @@ -4,7 +4,7 @@ import { isLoggedIn } from 'pl-fe/utils/auth'; import { getClient } from '../api'; -import { importFetchedAccounts } from './importer'; +import { importEntities } from './importer'; import type { Account, List, PaginatedResponse } from 'pl-api'; import type { AppDispatch, RootState } from 'pl-fe/store'; @@ -229,7 +229,7 @@ const fetchListAccounts = (listId: string) => (dispatch: AppDispatch, getState: dispatch(fetchListAccountsRequest(listId)); return getClient(getState()).lists.getListAccounts(listId).then(({ items, next }) => { - dispatch(importFetchedAccounts(items)); + dispatch(importEntities({ accounts: items })); dispatch(fetchListAccountsSuccess(listId, items, next)); }).catch(err => dispatch(fetchListAccountsFail(listId, err))); }; @@ -256,7 +256,7 @@ const fetchListSuggestions = (q: string) => (dispatch: AppDispatch, getState: () if (!isLoggedIn(getState)) return; return getClient(getState()).accounts.searchAccounts(q, { resolve: false, limit: 4, following: true }).then((data) => { - dispatch(importFetchedAccounts(data)); + dispatch(importEntities({ accounts: data })); dispatch(fetchListSuggestionsReady(q, data)); }).catch(error => toast.showAlertForError(error)); }; diff --git a/packages/pl-fe/src/actions/me.ts b/packages/pl-fe/src/actions/me.ts index 03a374ef4..60535df7e 100644 --- a/packages/pl-fe/src/actions/me.ts +++ b/packages/pl-fe/src/actions/me.ts @@ -7,7 +7,7 @@ import { getAuthUserId, getAuthUserUrl } from 'pl-fe/utils/auth'; import { getClient } from '../api'; import { loadCredentials } from './auth'; -import { importFetchedAccount } from './importer'; +import { importEntities } from './importer'; import { FE_NAME } from './settings'; import type { CredentialAccount, UpdateCredentialsParams } from 'pl-api'; @@ -127,7 +127,7 @@ const patchMeSuccess = (me: CredentialAccount) => me, }; - dispatch(importFetchedAccount(me)); + dispatch(importEntities({ accounts: [me] })); dispatch(action); }; diff --git a/packages/pl-fe/src/actions/notifications.ts b/packages/pl-fe/src/actions/notifications.ts index 6e2e1fe68..e41c7a091 100644 --- a/packages/pl-fe/src/actions/notifications.ts +++ b/packages/pl-fe/src/actions/notifications.ts @@ -14,12 +14,7 @@ import { EXCLUDE_TYPES, NOTIFICATION_TYPES } from 'pl-fe/utils/notification'; import { joinPublicPath } from 'pl-fe/utils/static'; import { fetchRelationships } from './accounts'; -import { - importFetchedAccount, - importFetchedAccounts, - importFetchedStatus, - importFetchedStatuses, -} from './importer'; +import { importEntities } from './importer'; import { saveMarker } from './markers'; import { saveSettings } from './settings'; @@ -76,20 +71,10 @@ const updateNotifications = (notification: BaseNotification) => const selectedFilter = useSettingsStore.getState().settings.notifications.quickFilter.active; const showInColumn = selectedFilter === 'all' ? true : (FILTER_TYPES[selectedFilter as FilterType] || [notification.type]).includes(notification.type); - if (notification.account) { - dispatch(importFetchedAccount(notification.account)); - } - - // Used by Move notification - if (notification.type === 'move' && notification.target) { - dispatch(importFetchedAccount(notification.target)); - } - - const status = getNotificationStatus(notification); - - if (status) { - dispatch(importFetchedStatus(status)); - } + dispatch(importEntities({ + accounts: [notification.account, notification.type === 'move' ? notification.target : undefined], + statuses: [getNotificationStatus(notification)], + })); if (showInColumn) { dispatch({ @@ -256,8 +241,10 @@ const expandNotifications = ({ maxId }: Record = {}, done: () => an return acc; }, { accounts: {}, statuses: {} } as { accounts: Record; statuses: Record }); - dispatch(importFetchedAccounts(Object.values(entries.accounts))); - dispatch(importFetchedStatuses(Object.values(entries.statuses))); + dispatch(importEntities({ + accounts: Object.values(entries.accounts), + statuses: Object.values(entries.statuses), + })); const deduplicatedNotifications = normalizeNotifications(response.items, state.notifications.items); diff --git a/packages/pl-fe/src/actions/pin-statuses.ts b/packages/pl-fe/src/actions/pin-statuses.ts index 86b18e6b9..f1e61bfc0 100644 --- a/packages/pl-fe/src/actions/pin-statuses.ts +++ b/packages/pl-fe/src/actions/pin-statuses.ts @@ -2,7 +2,7 @@ import { isLoggedIn } from 'pl-fe/utils/auth'; import { getClient } from '../api'; -import { importFetchedStatuses } from './importer'; +import { importEntities } from './importer'; import type { Status } from 'pl-api'; import type { AppDispatch, RootState } from 'pl-fe/store'; @@ -19,7 +19,7 @@ const fetchPinnedStatuses = () => dispatch(fetchPinnedStatusesRequest()); return getClient(getState()).accounts.getAccountStatuses(me as string, { pinned: true }).then(response => { - dispatch(importFetchedStatuses(response.items)); + dispatch(importEntities({ statuses: response.items })); dispatch(fetchPinnedStatusesSuccess(response.items, null)); }).catch(error => { dispatch(fetchPinnedStatusesFail(error)); diff --git a/packages/pl-fe/src/actions/polls.ts b/packages/pl-fe/src/actions/polls.ts index f343be4ec..e7311edc7 100644 --- a/packages/pl-fe/src/actions/polls.ts +++ b/packages/pl-fe/src/actions/polls.ts @@ -1,6 +1,6 @@ import { getClient } from '../api'; -import { importFetchedPoll } from './importer'; +import { importEntities } from './importer'; import type { Poll } from 'pl-api'; import type { AppDispatch, RootState } from 'pl-fe/store'; @@ -18,7 +18,7 @@ const vote = (pollId: string, choices: number[]) => dispatch(voteRequest()); return getClient(getState()).polls.vote(pollId, choices).then((data) => { - dispatch(importFetchedPoll(data)); + dispatch(importEntities({ polls: [data] })); dispatch(voteSuccess(data)); }).catch(err => dispatch(voteFail(err))); }; @@ -28,7 +28,7 @@ const fetchPoll = (pollId: string) => dispatch(fetchPollRequest()); return getClient(getState()).polls.getPoll(pollId).then((data) => { - dispatch(importFetchedPoll(data)); + dispatch(importEntities({ polls: [data] })); dispatch(fetchPollSuccess(data)); }).catch(err => dispatch(fetchPollFail(err))); }; diff --git a/packages/pl-fe/src/actions/preload.ts b/packages/pl-fe/src/actions/preload.ts index 29a212a66..e20095cfb 100644 --- a/packages/pl-fe/src/actions/preload.ts +++ b/packages/pl-fe/src/actions/preload.ts @@ -1,7 +1,7 @@ import mapValues from 'lodash/mapValues'; import { verifyCredentials } from './auth'; -import { importFetchedAccounts } from './importer'; +import { importEntities } from './importer'; import type { AppDispatch } from 'pl-fe/store'; @@ -54,7 +54,7 @@ const preloadMastodon = (data: Record) => const { me, access_token } = data.meta; const { url } = data.accounts[me]; - dispatch(importFetchedAccounts(Object.values(data.accounts))); + dispatch(importEntities({ accounts: Object.values(data.accounts) })); dispatch(verifyCredentials(access_token, url)); dispatch({ type: MASTODON_PRELOAD_IMPORT, data }); }; diff --git a/packages/pl-fe/src/actions/search.ts b/packages/pl-fe/src/actions/search.ts index a72e253f1..4efe4cce6 100644 --- a/packages/pl-fe/src/actions/search.ts +++ b/packages/pl-fe/src/actions/search.ts @@ -3,7 +3,7 @@ import { useSettingsStore } from 'pl-fe/stores/settings'; import { getClient } from '../api'; import { fetchRelationships } from './accounts'; -import { importFetchedAccounts, importFetchedStatuses } from './importer'; +import { importEntities } from './importer'; import type { Search } from 'pl-api'; import type { SearchFilter } from 'pl-fe/reducers/search'; @@ -54,13 +54,7 @@ const submitSearch = (value: string, filter?: SearchFilter) => if (accountId) params.account_id = accountId; return getClient(getState()).search.search(value, params).then(response => { - if (response.accounts) { - dispatch(importFetchedAccounts(response.accounts)); - } - - if (response.statuses) { - dispatch(importFetchedStatuses(response.statuses)); - } + dispatch(importEntities({ accounts: response.accounts, statuses: response.statuses })); dispatch(fetchSearchSuccess(response, value, type)); dispatch(fetchRelationships(response.accounts.map((item) => item.id))); @@ -113,13 +107,7 @@ const expandSearch = (type: SearchFilter) => (dispatch: AppDispatch, getState: ( if (accountId) params.account_id = accountId; return getClient(getState()).search.search(value, params).then(response => { - if (response.accounts) { - dispatch(importFetchedAccounts(response.accounts)); - } - - if (response.statuses) { - dispatch(importFetchedStatuses(response.statuses)); - } + dispatch(importEntities({ accounts: response.accounts, statuses: response.statuses })); dispatch(expandSearchSuccess(response, value, type)); dispatch(fetchRelationships(response.accounts.map((item) => item.id))); diff --git a/packages/pl-fe/src/actions/status-quotes.ts b/packages/pl-fe/src/actions/status-quotes.ts index b0669e409..f10956691 100644 --- a/packages/pl-fe/src/actions/status-quotes.ts +++ b/packages/pl-fe/src/actions/status-quotes.ts @@ -1,6 +1,6 @@ import { getClient } from '../api'; -import { importFetchedStatuses } from './importer'; +import { importEntities } from './importer'; import type { Status as BaseStatus, PaginatedResponse } from 'pl-api'; import type { AppDispatch, RootState } from 'pl-fe/store'; @@ -43,7 +43,7 @@ const fetchStatusQuotes = (statusId: string) => dispatch(action); return getClient(getState).statuses.getStatusQuotes(statusId).then(response => { - dispatch(importFetchedStatuses(response.items)); + dispatch(importEntities({ statuses: response.items })); const action: FetchStatusQuotesSuccessAction = { type: STATUS_QUOTES_FETCH_SUCCESS, statusId, @@ -94,7 +94,7 @@ const expandStatusQuotes = (statusId: string) => dispatch(action); return next().then(response => { - dispatch(importFetchedStatuses(response.items)); + dispatch(importEntities({ statuses: response.items })); const action: ExpandStatusQuotesSuccessAction = { type: STATUS_QUOTES_EXPAND_SUCCESS, statusId, diff --git a/packages/pl-fe/src/actions/statuses.ts b/packages/pl-fe/src/actions/statuses.ts index 652771269..b9a3e6547 100644 --- a/packages/pl-fe/src/actions/statuses.ts +++ b/packages/pl-fe/src/actions/statuses.ts @@ -6,7 +6,7 @@ import { shouldHaveCard } from 'pl-fe/utils/status'; import { getClient } from '../api'; import { setComposeToStatus } from './compose'; -import { importFetchedStatus, importFetchedStatuses } from './importer'; +import { importEntities } from './importer'; import { deleteFromTimelines } from './timelines'; import type { CreateStatusParams, Status as BaseStatus } from 'pl-api'; @@ -66,7 +66,7 @@ const createStatus = (params: CreateStatusParams, idempotencyKey: string, status // The backend might still be processing the rich media attachment const expectsCard = status.scheduled_at === null && !status.card && shouldHaveCard(status); - if (status.scheduled_at === null) dispatch(importFetchedStatus({ ...status, expectsCard }, idempotencyKey)); + if (status.scheduled_at === null) dispatch(importEntities({ statuses: [{ ...status, expectsCard }] }, { idempotencyKey, withParents: true })); dispatch({ type: STATUS_CREATE_SUCCESS, status, params, idempotencyKey, editing: !!statusId }); // Poll the backend for the updated card @@ -76,7 +76,7 @@ const createStatus = (params: CreateStatusParams, idempotencyKey: string, status const poll = (retries = 5) => { return getClient(getState()).statuses.getStatus(status.id).then(response => { if (response.card) { - dispatch(importFetchedStatus(response)); + dispatch(importEntities({ statuses: [response] })); } else if (retries > 0 && response) { setTimeout(() => poll(retries - 1), delay); } @@ -119,7 +119,7 @@ const fetchStatus = (statusId: string, intl?: IntlShape) => } : undefined; return getClient(getState()).statuses.getStatus(statusId, params).then(status => { - dispatch(importFetchedStatus(status)); + dispatch(importEntities({ statuses: [status] })); dispatch({ type: STATUS_FETCH_SUCCESS, status }); return status; }).catch(error => { @@ -153,7 +153,7 @@ const deleteStatus = (statusId: string, withRedraft = false) => }; const updateStatus = (status: BaseStatus) => (dispatch: AppDispatch) => - dispatch(importFetchedStatus(status)); + dispatch(importEntities({ statuses: [status] })); const fetchContext = (statusId: string, intl?: IntlShape) => (dispatch: AppDispatch, getState: () => RootState) => { @@ -166,7 +166,7 @@ const fetchContext = (statusId: string, intl?: IntlShape) => return getClient(getState()).statuses.getContext(statusId, params).then(context => { const { ancestors, descendants } = context; const statuses = ancestors.concat(descendants); - dispatch(importFetchedStatuses(statuses)); + dispatch(importEntities({ statuses })); dispatch({ type: CONTEXT_FETCH_SUCCESS, statusId, ancestors, descendants }); return context; }).catch(error => { diff --git a/packages/pl-fe/src/actions/suggestions.ts b/packages/pl-fe/src/actions/suggestions.ts index 8e8a8a7ad..326997169 100644 --- a/packages/pl-fe/src/actions/suggestions.ts +++ b/packages/pl-fe/src/actions/suggestions.ts @@ -1,7 +1,7 @@ import { getClient } from '../api'; import { fetchRelationships } from './accounts'; -import { importFetchedAccounts } from './importer'; +import { importEntities } from './importer'; import { insertSuggestionsIntoTimeline } from './timelines'; import type { AppDispatch, RootState } from 'pl-fe/store'; @@ -24,7 +24,7 @@ const fetchSuggestions = (limit = 50) => return getClient(getState).myAccount.getSuggestions(limit).then((suggestions) => { const accounts = suggestions.map(({ account }) => account); - dispatch(importFetchedAccounts(accounts)); + dispatch(importEntities({ accounts })); dispatch({ type: SUGGESTIONS_FETCH_SUCCESS, suggestions }); dispatch(fetchRelationships(accounts.map(({ id }) => id))); diff --git a/packages/pl-fe/src/actions/timelines.ts b/packages/pl-fe/src/actions/timelines.ts index b2e1db7f7..d3767ea47 100644 --- a/packages/pl-fe/src/actions/timelines.ts +++ b/packages/pl-fe/src/actions/timelines.ts @@ -6,7 +6,7 @@ import { shouldFilter } from 'pl-fe/utils/timelines'; import { getClient } from '../api'; -import { importFetchedStatus, importFetchedStatuses } from './importer'; +import { importEntities } from './importer'; import type { PaginatedResponse, Status as BaseStatus, PublicTimelineParams, HomeTimelineParams, ListTimelineParams, HashtagTimelineParams, GetAccountStatusesParams, GroupTimelineParams } from 'pl-api'; import type { AppDispatch, RootState } from 'pl-fe/store'; @@ -46,7 +46,7 @@ const processTimelineUpdate = (timeline: string, status: BaseStatus) => return; } - dispatch(importFetchedStatus(status)); + dispatch(importEntities({ statuses: [status] })); if (shouldSkipQueue) { dispatch(updateTimeline(timeline, status.id)); @@ -159,10 +159,10 @@ const handleTimelineExpand = (timelineId: string, fn: Promise { - dispatch(importFetchedStatuses(response.items)); + dispatch(importEntities({ statuses: response.items })); const statuses = deduplicateStatuses(response.items); - dispatch(importFetchedStatuses(statuses.filter(status => status.accounts))); + dispatch(importEntities({ statuses: statuses.filter(status => status.accounts) })); dispatch(expandTimelineSuccess( timelineId, diff --git a/packages/pl-fe/src/actions/trending-statuses.ts b/packages/pl-fe/src/actions/trending-statuses.ts index 692f13241..008e5b47f 100644 --- a/packages/pl-fe/src/actions/trending-statuses.ts +++ b/packages/pl-fe/src/actions/trending-statuses.ts @@ -1,6 +1,6 @@ import { getClient } from '../api'; -import { importFetchedStatuses } from './importer'; +import { importEntities } from './importer'; import type { AppDispatch, RootState } from 'pl-fe/store'; @@ -18,7 +18,7 @@ const fetchTrendingStatuses = () => dispatch({ type: TRENDING_STATUSES_FETCH_REQUEST }); return client.trends.getTrendingStatuses().then((statuses) => { - dispatch(importFetchedStatuses(statuses)); + dispatch(importEntities({ statuses })); dispatch({ type: TRENDING_STATUSES_FETCH_SUCCESS, statuses }); return statuses; }).catch(error => { diff --git a/packages/pl-fe/src/features/test-timeline/index.tsx b/packages/pl-fe/src/features/test-timeline/index.tsx index fbfc8f063..7cbcb354a 100644 --- a/packages/pl-fe/src/features/test-timeline/index.tsx +++ b/packages/pl-fe/src/features/test-timeline/index.tsx @@ -1,7 +1,7 @@ import React from 'react'; import { defineMessages, useIntl, FormattedMessage } from 'react-intl'; -import { importFetchedStatuses } from 'pl-fe/actions/importer'; +import { importEntities } from 'pl-fe/actions/importer'; import { expandTimelineSuccess } from 'pl-fe/actions/timelines'; import Column from 'pl-fe/components/ui/column'; import Timeline from 'pl-fe/features/ui/components/timeline'; @@ -35,7 +35,7 @@ const TestTimeline: React.FC = () => { const isMobile = useIsMobile(); React.useEffect(() => { - dispatch(importFetchedStatuses(MOCK_STATUSES)); + dispatch(importEntities({ statuses: MOCK_STATUSES })); dispatch(expandTimelineSuccess(timelineId, MOCK_STATUSES, null, null, false, false)); }, []); diff --git a/packages/pl-fe/src/queries/chats.ts b/packages/pl-fe/src/queries/chats.ts index b8a155fcd..d4f6789fb 100644 --- a/packages/pl-fe/src/queries/chats.ts +++ b/packages/pl-fe/src/queries/chats.ts @@ -3,7 +3,7 @@ import sumBy from 'lodash/sumBy'; import { type Chat, type ChatMessage as BaseChatMessage, type PaginatedResponse, chatMessageSchema, type Relationship } from 'pl-api'; import * as v from 'valibot'; -import { importFetchedAccount, importFetchedAccounts } from 'pl-fe/actions/importer'; +import { importEntities } from 'pl-fe/actions/importer'; import { ChatWidgetScreens, useChatContext } from 'pl-fe/contexts/chat-context'; import { useStatContext } from 'pl-fe/contexts/stat-context'; import { Entities } from 'pl-fe/entity-store/entities'; @@ -72,7 +72,7 @@ const useChats = () => { // Set the relationships to these users in the redux store. fetchRelationships.mutate({ accountIds: items.map((item) => item.account.id) }); - dispatch(importFetchedAccounts(items.map((item) => item.account))); + dispatch(importEntities({ accounts: items.map((item) => item.account) })); return response; }; @@ -109,7 +109,7 @@ const useChat = (chatId?: string) => { const data = await client.chats.getChat(chatId); fetchRelationships.mutate({ accountIds: [data.account.id] }); - dispatch(importFetchedAccount(data.account)); + dispatch(importEntities({ accounts: [data.account] })); return data; } diff --git a/packages/pl-fe/src/queries/suggestions.ts b/packages/pl-fe/src/queries/suggestions.ts index 31476edb9..7b6e28f5e 100644 --- a/packages/pl-fe/src/queries/suggestions.ts +++ b/packages/pl-fe/src/queries/suggestions.ts @@ -1,7 +1,7 @@ import { useMutation, keepPreviousData, useQuery } from '@tanstack/react-query'; import { fetchRelationships } from 'pl-fe/actions/accounts'; -import { importFetchedAccounts } from 'pl-fe/actions/importer'; +import { importEntities } from 'pl-fe/actions/importer'; import { useAppDispatch } from 'pl-fe/hooks/use-app-dispatch'; import { useClient } from 'pl-fe/hooks/use-client'; @@ -20,7 +20,7 @@ const useSuggestions = () => { const accounts = response.map(({ account }) => account); const accountIds = accounts.map((account) => account.id); - dispatch(importFetchedAccounts(accounts)); + dispatch(importEntities({ accounts })); dispatch(fetchRelationships(accountIds)); return response.map(({ account, ...x }) => ({ ...x, account_id: account.id })); @@ -60,7 +60,7 @@ const useOnboardingSuggestions = () => { const accounts = response.map(({ account }) => account); const accountIds = accounts.map((account) => account.id); - dispatch(importFetchedAccounts(accounts)); + dispatch(importEntities({ accounts })); dispatch(fetchRelationships(accountIds)); return response; From a1a5df348d4c426a19c6d74217a200d43dc9c7df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?marcin=20miko=C5=82ajczak?= Date: Sat, 26 Oct 2024 22:38:10 +0200 Subject: [PATCH 09/11] pl-fe: Do not truncate modal headers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: marcin mikołajczak --- packages/pl-fe/src/components/ui/modal.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/pl-fe/src/components/ui/modal.tsx b/packages/pl-fe/src/components/ui/modal.tsx index ce90bd1ca..5b5f94715 100644 --- a/packages/pl-fe/src/components/ui/modal.tsx +++ b/packages/pl-fe/src/components/ui/modal.tsx @@ -121,7 +121,7 @@ const Modal = React.forwardRef(({ /> )} -

+

{title}

From cd3c35fcf9302c724709ad026c8dd8492484ae19 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?marcin=20miko=C5=82ajczak?= Date: Sat, 26 Oct 2024 22:42:00 +0200 Subject: [PATCH 10/11] pl-fe: remove duplicate toaster MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: marcin mikołajczak --- .../ui/components/modals/missing-description-modal.tsx | 2 +- packages/pl-fe/src/init/pl-fe.tsx | 7 ------- 2 files changed, 1 insertion(+), 8 deletions(-) diff --git a/packages/pl-fe/src/features/ui/components/modals/missing-description-modal.tsx b/packages/pl-fe/src/features/ui/components/modals/missing-description-modal.tsx index 41fe3ab62..406438b5b 100644 --- a/packages/pl-fe/src/features/ui/components/modals/missing-description-modal.tsx +++ b/packages/pl-fe/src/features/ui/components/modals/missing-description-modal.tsx @@ -25,7 +25,7 @@ const MissingDescriptionModal: React.FC onClose('MISSING_DESCRIPTION')} >

diff --git a/packages/pl-fe/src/init/pl-fe.tsx b/packages/pl-fe/src/init/pl-fe.tsx index 3643cfef2..0cc06618b 100644 --- a/packages/pl-fe/src/init/pl-fe.tsx +++ b/packages/pl-fe/src/init/pl-fe.tsx @@ -1,7 +1,6 @@ import { QueryClientProvider } from '@tanstack/react-query'; import React from 'react'; import { HelmetProvider } from 'react-helmet-async'; -import { Toaster } from 'react-hot-toast'; import { Provider } from 'react-redux'; import { StatProvider } from 'pl-fe/contexts/stat-context'; @@ -40,12 +39,6 @@ const PlFe: React.FC = () => ( -

- -
); From b9475efdec608b50579fa64cc87c9c7dd5aafbb2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?marcin=20miko=C5=82ajczak?= Date: Sat, 26 Oct 2024 22:47:12 +0200 Subject: [PATCH 11/11] pl-fe: do not clear editor before sending post MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: marcin mikołajczak --- packages/pl-fe/src/actions/compose.ts | 6 ++++-- .../pl-fe/src/features/compose/components/compose-form.tsx | 4 ++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/packages/pl-fe/src/actions/compose.ts b/packages/pl-fe/src/actions/compose.ts index ebfbbe137..8e766170e 100644 --- a/packages/pl-fe/src/actions/compose.ts +++ b/packages/pl-fe/src/actions/compose.ts @@ -343,11 +343,12 @@ const validateSchedule = (state: RootState, composeId: string) => { interface SubmitComposeOpts { history?: History; force?: boolean; + onSuccess?: () => void; } const submitCompose = (composeId: string, opts: SubmitComposeOpts = {}) => async (dispatch: AppDispatch, getState: () => RootState) => { - const { history, force = false } = opts; + const { history, force = false, onSuccess } = opts; if (!isLoggedIn(getState)) return; const state = getState(); @@ -372,7 +373,7 @@ const submitCompose = (composeId: string, opts: SubmitComposeOpts = {}) => useModalsStore.getState().openModal('MISSING_DESCRIPTION', { onContinue: () => { useModalsStore.getState().closeModal('MISSING_DESCRIPTION'); - dispatch(submitCompose(composeId, { history, force: true })); + dispatch(submitCompose(composeId, { history, force: true, onSuccess })); }, }); return; @@ -444,6 +445,7 @@ const submitCompose = (composeId: string, opts: SubmitComposeOpts = {}) => history.push('/conversations'); } handleComposeSubmit(dispatch, getState, composeId, data, status, !!statusId); + onSuccess?.(); }).catch((error) => { dispatch(submitComposeFail(composeId, error)); }); diff --git a/packages/pl-fe/src/features/compose/components/compose-form.tsx b/packages/pl-fe/src/features/compose/components/compose-form.tsx index d2b9bf2e8..6d443f505 100644 --- a/packages/pl-fe/src/features/compose/components/compose-form.tsx +++ b/packages/pl-fe/src/features/compose/components/compose-form.tsx @@ -142,9 +142,9 @@ const ComposeForm = ({ id, shouldCondense, autoFocus, clickab if (!canSubmit) return; e?.preventDefault(); - dispatch(submitCompose(id, { history })).then(() => { + dispatch(submitCompose(id, { history, onSuccess: () => { editorRef.current?.dispatchCommand(CLEAR_EDITOR_COMMAND, undefined); - }).catch(() => {}); + } })); }; const onSuggestionsClearRequested = () => {