From 2086e027adb040ac57d29958399cd2f9436410f4 Mon Sep 17 00:00:00 2001 From: mkljczk Date: Mon, 2 Dec 2024 08:47:08 +0100 Subject: [PATCH 01/76] pl-fe: update en.json Signed-off-by: mkljczk --- packages/pl-fe/src/locales/en.json | 3 --- 1 file changed, 3 deletions(-) diff --git a/packages/pl-fe/src/locales/en.json b/packages/pl-fe/src/locales/en.json index 798826dde..8a01b42c6 100644 --- a/packages/pl-fe/src/locales/en.json +++ b/packages/pl-fe/src/locales/en.json @@ -792,7 +792,6 @@ "fediverse_tab.explanation_box.dismiss": "Don't show again", "fediverse_tab.explanation_box.explanation": "{site_title} is part of the Fediverse, a social network made up of thousands of independent social media sites (aka \"servers\"). The posts you see here are from 3rd-party servers. You have the freedom to engage with them, or to block any server you don't like. Pay attention to the full username after the second @ symbol to know which server a post is from. To see only {site_title} posts, visit {local}.", "fediverse_tab.explanation_box.title": "What is the Fediverse?", - "feed_suggestions.heading": "Suggested profiles", "feed_suggestions.view_all": "View all", "filters.added": "Filter added.", "filters.context_header": "Filter contexts", @@ -1191,8 +1190,6 @@ "plfe_config.crypto_donate_panel_limit.meta_fields.limit_placeholder": "Number of items to display in the crypto homepage widget", "plfe_config.cta_label": "Display call to action panels if not authenticated", "plfe_config.display_fqn_label": "Display domain (eg @user@domain) for local accounts.", - "plfe_config.feed_injection_hint": "Inject the feed with additional content, such as suggested profiles.", - "plfe_config.feed_injection_label": "Feed injection", "plfe_config.fields.crypto_addresses_label": "Cryptocurrency addresses", "plfe_config.fields.edit_theme_label": "Edit theme", "plfe_config.fields.home_footer_fields_label": "Home footer items", From 1f8b79f309d26bea2b545c4d041fa3bf9cb288bc Mon Sep 17 00:00:00 2001 From: mkljczk Date: Tue, 3 Dec 2024 15:03:17 +0100 Subject: [PATCH 02/76] pl-fe: migrate /api/v*/instance to tanstack query Signed-off-by: mkljczk --- packages/pl-fe/index.html | 2 + packages/pl-fe/src/actions/admin.ts | 2 + packages/pl-fe/src/actions/auth.ts | 8 +- packages/pl-fe/src/actions/compose.ts | 5 +- packages/pl-fe/src/actions/consumer-auth.ts | 13 ++- packages/pl-fe/src/actions/instance.ts | 40 +------ packages/pl-fe/src/actions/media.ts | 11 +- packages/pl-fe/src/actions/preload.ts | 2 + .../actions/push-notifications/registerer.ts | 12 +-- .../src/api/hooks/instance/use-instance.ts | 23 ++++ .../instance/use-translation-languages.ts | 4 +- .../hooks/streaming/use-timeline-stream.ts | 4 +- .../pl-fe/src/components/birthday-input.tsx | 4 +- packages/pl-fe/src/components/gdpr-banner.tsx | 4 +- packages/pl-fe/src/components/helmet.tsx | 4 +- .../pl-fe/src/components/sidebar-menu.tsx | 4 +- .../src/components/sidebar-navigation.tsx | 4 +- .../src/components/status-action-bar.tsx | 4 +- .../pl-fe/src/components/translate-button.tsx | 4 +- .../components/registration-mode-picker.tsx | 4 +- .../src/features/admin/tabs/dashboard.tsx | 4 +- .../auth-login/components/consumers-list.tsx | 4 +- .../auth-login/components/login-page.tsx | 6 -- .../components/registration-form.tsx | 4 +- .../components/registration-page.tsx | 4 +- .../chats/components/chat-composer.tsx | 4 +- .../components/upload-button.tsx | 4 +- .../compose/components/compose-form.tsx | 4 +- .../components/content-type-button.tsx | 4 +- .../compose/components/polls/poll-form.tsx | 4 +- .../compose/components/upload-button.tsx | 4 +- .../features/compose/components/upload.tsx | 4 +- .../features/compose/editor/nodes/index.ts | 4 +- .../floating-block-type-toolbar-plugin.tsx | 6 +- .../floating-text-format-toolbar-plugin.tsx | 4 +- .../components/crypto-donate-panel.tsx | 4 +- .../src/features/crypto-donate/index.tsx | 4 +- .../pl-fe/src/features/directory/index.tsx | 4 +- .../pl-fe/src/features/edit-profile/index.tsx | 7 +- .../components/instance-restrictions.tsx | 4 +- .../components/restricted-instance.tsx | 4 +- .../federation-restrictions/index.tsx | 8 +- .../pl-fe/src/features/group/edit-group.tsx | 7 +- .../src/features/home-timeline/index.tsx | 4 +- .../components/site-banner.tsx | 4 +- .../src/features/landing-timeline/index.tsx | 4 +- .../pl-fe/src/features/migration/index.tsx | 4 +- .../notifications/components/notification.tsx | 4 +- .../onboarding/steps/fediverse-step.tsx | 4 +- .../pl-fe/src/features/preferences/index.tsx | 4 +- .../src/features/public-timeline/index.tsx | 4 +- .../src/features/register-invite/index.tsx | 4 +- .../pl-fe/src/features/server-info/index.tsx | 4 +- .../status/components/thread-login-cta.tsx | 4 +- .../modals/edit-federation-modal.tsx | 4 +- .../manage-group-modal/steps/details-step.tsx | 7 +- .../components/modals/report-modal/index.tsx | 4 +- .../modals/report-modal/steps/reason-step.tsx | 4 +- .../components/modals/unauthorized-modal.tsx | 4 +- .../components/panels/instance-info-panel.tsx | 4 +- .../panels/instance-moderation-panel.tsx | 4 +- .../ui/components/panels/promo-panel.tsx | 4 +- .../ui/components/panels/sign-up-panel.tsx | 10 +- packages/pl-fe/src/features/ui/index.tsx | 10 +- packages/pl-fe/src/hooks/use-features.ts | 3 +- packages/pl-fe/src/hooks/use-instance.ts | 6 -- .../src/hooks/use-registration-status.ts | 5 +- packages/pl-fe/src/hooks/use-vapid-key.ts | 11 ++ packages/pl-fe/src/init/pl-fe-load.tsx | 6 +- packages/pl-fe/src/initial-state.ts | 11 ++ .../src/layouts/remote-instance-layout.tsx | 4 +- packages/pl-fe/src/reducers/compose.ts | 15 ++- packages/pl-fe/src/reducers/index.ts | 6 +- packages/pl-fe/src/reducers/instance.ts | 100 +----------------- packages/pl-fe/src/reducers/meta.ts | 14 +-- packages/pl-fe/src/selectors/index.ts | 8 +- packages/pl-fe/src/utils/auth.ts | 5 - packages/pl-fe/src/utils/scopes.ts | 15 ++- packages/pl-fe/src/utils/state.ts | 5 +- 79 files changed, 240 insertions(+), 337 deletions(-) create mode 100644 packages/pl-fe/src/api/hooks/instance/use-instance.ts delete mode 100644 packages/pl-fe/src/hooks/use-instance.ts create mode 100644 packages/pl-fe/src/hooks/use-vapid-key.ts create mode 100644 packages/pl-fe/src/initial-state.ts diff --git a/packages/pl-fe/index.html b/packages/pl-fe/index.html index 9b173ed0d..c7a0d3fcd 100644 --- a/packages/pl-fe/index.html +++ b/packages/pl-fe/index.html @@ -11,6 +11,8 @@ <%- snippets %> +
diff --git a/packages/pl-fe/src/actions/admin.ts b/packages/pl-fe/src/actions/admin.ts index ee97042b0..eb0b33bc9 100644 --- a/packages/pl-fe/src/actions/admin.ts +++ b/packages/pl-fe/src/actions/admin.ts @@ -1,5 +1,6 @@ import { fetchRelationships } from 'pl-fe/actions/accounts'; import { importEntities } from 'pl-fe/actions/importer'; +import { queryClient } from 'pl-fe/queries/client'; import { filterBadges, getTagDiff } from 'pl-fe/utils/badges'; import { getClient } from '../api'; @@ -83,6 +84,7 @@ const updateConfig = (configs: PleromaConfig['configs']) => dispatch({ type: ADMIN_CONFIG_UPDATE_REQUEST, configs }); return getClient(getState).admin.config.updatePleromaConfig(configs) .then((data) => { + queryClient.invalidateQueries({ queryKey: ['instance', 'instanceInformation'] }); dispatch({ type: ADMIN_CONFIG_UPDATE_SUCCESS, configs: data.configs, needsReboot: data.need_reboot }); }).catch(error => { dispatch({ type: ADMIN_CONFIG_UPDATE_FAIL, error, configs }); diff --git a/packages/pl-fe/src/actions/auth.ts b/packages/pl-fe/src/actions/auth.ts index a0d6da0bc..5842dcf57 100644 --- a/packages/pl-fe/src/actions/auth.ts +++ b/packages/pl-fe/src/actions/auth.ts @@ -93,7 +93,7 @@ const createAuthApp = () => const params = { client_name: `${sourceCode.displayName} (${new URL(window.origin).host})`, redirect_uris: 'urn:ietf:wg:oauth:2.0:oob', - scopes: getScopes(getState()), + scopes: getScopes(), website: sourceCode.homepage, }; @@ -117,7 +117,7 @@ const createAppToken = () => client_secret: app.client_secret!, redirect_uri: 'urn:ietf:wg:oauth:2.0:oob', grant_type: 'client_credentials', - scope: getScopes(getState()), + scope: getScopes(), }; return dispatch(obtainOAuthToken(params)).then((token) => @@ -136,7 +136,7 @@ const createUserToken = (username: string, password: string) => grant_type: 'password', username: username, password: password, - scope: getScopes(getState()), + scope: getScopes(), }; return dispatch(obtainOAuthToken(params)) @@ -156,7 +156,7 @@ const otpVerify = (code: string, mfa_token: string) => code: code, challenge_type: 'totp', // redirect_uri: 'urn:ietf:wg:oauth:2.0:oob', - // scope: getScopes(getState()), + // scope: getScopes(), }).then((token) => dispatch(authLoggedIn(token))); }; diff --git a/packages/pl-fe/src/actions/compose.ts b/packages/pl-fe/src/actions/compose.ts index 3d8fb8fed..c4055cd89 100644 --- a/packages/pl-fe/src/actions/compose.ts +++ b/packages/pl-fe/src/actions/compose.ts @@ -20,7 +20,7 @@ import { uploadFile, updateMedia } from './media'; import { createStatus } from './statuses'; import type { EditorState } from 'lexical'; -import type { Account as BaseAccount, CreateStatusParams, Group, MediaAttachment, Status as BaseStatus, Tag, Poll, ScheduledStatus } from 'pl-api'; +import type { Account as BaseAccount, CreateStatusParams, Group, MediaAttachment, Status as BaseStatus, Tag, Poll, ScheduledStatus, Instance } from 'pl-api'; import type { AutoSuggestion } from 'pl-fe/components/autosuggest-input'; import type { Emoji } from 'pl-fe/features/emoji'; import type { Account } from 'pl-fe/normalizers/account'; @@ -467,7 +467,8 @@ const submitComposeFail = (composeId: string, error: unknown) => ({ const uploadCompose = (composeId: string, files: FileList, intl: IntlShape) => (dispatch: AppDispatch, getState: () => RootState) => { if (!isLoggedIn(getState)) return; - const attachmentLimit = getState().instance.configuration.statuses.max_media_attachments; + const instance = queryClient.getQueryData(['instance', 'instanceInformation', getState().auth.client.baseURL]); + const attachmentLimit = instance!.configuration.statuses.max_media_attachments; const media = getState().compose[composeId]?.media_attachments; const progress = new Array(files.length).fill(0); diff --git a/packages/pl-fe/src/actions/consumer-auth.ts b/packages/pl-fe/src/actions/consumer-auth.ts index 4e66b343d..b527ac1c0 100644 --- a/packages/pl-fe/src/actions/consumer-auth.ts +++ b/packages/pl-fe/src/actions/consumer-auth.ts @@ -1,17 +1,19 @@ +import { Instance } from 'pl-api'; import queryString from 'query-string'; import * as BuildConfig from 'pl-fe/build-config'; +import { queryClient } from 'pl-fe/queries/client'; import { isURL } from 'pl-fe/utils/auth'; import sourceCode from 'pl-fe/utils/code'; -import { getScopes } from 'pl-fe/utils/scopes'; +import { getInstanceScopes } from 'pl-fe/utils/scopes'; import { createApp } from './apps'; import type { AppDispatch, RootState } from 'pl-fe/store'; -const createProviderApp = () => +const createProviderApp = (instance: Instance) => async(dispatch: AppDispatch, getState: () => RootState) => { - const scopes = getScopes(getState()); + const scopes = getInstanceScopes(instance); const params = { client_name: `${sourceCode.displayName} (${new URL(window.origin).host})`, @@ -27,8 +29,9 @@ const prepareRequest = (provider: string) => async(dispatch: AppDispatch, getState: () => RootState) => { const baseURL = isURL(BuildConfig.BACKEND_URL) ? BuildConfig.BACKEND_URL : ''; - const scopes = getScopes(getState()); - const app = await dispatch(createProviderApp()); + const instance = queryClient.getQueryData(['instance', 'instanceInformation', baseURL])!; + const scopes = getInstanceScopes(instance); + const app = await dispatch(createProviderApp(instance)); const { client_id, redirect_uri } = app; localStorage.setItem('plfe:external:app', JSON.stringify(app)); diff --git a/packages/pl-fe/src/actions/instance.ts b/packages/pl-fe/src/actions/instance.ts index 4363b121e..5e2a0d1c0 100644 --- a/packages/pl-fe/src/actions/instance.ts +++ b/packages/pl-fe/src/actions/instance.ts @@ -1,12 +1,6 @@ import { getAuthUserUrl, getMeUrl } from 'pl-fe/utils/auth'; -import { getClient } from '../api'; - -import type { Instance } from 'pl-api'; -import type { AppDispatch, RootState } from 'pl-fe/store'; - -const INSTANCE_FETCH_SUCCESS = 'INSTANCE_FETCH_SUCCESS' as const; -const INSTANCE_FETCH_FAIL = 'INSTANCE_FETCH_FAIL' as const; +import type { RootState } from 'pl-fe/store'; /** Figure out the appropriate instance to fetch depending on the state */ const getHost = (state: RootState) => { @@ -19,34 +13,4 @@ const getHost = (state: RootState) => { } }; -interface InstanceFetchSuccessAction { - type: typeof INSTANCE_FETCH_SUCCESS; - instance: Instance; -} - -interface InstanceFetchFailAction { - type: typeof INSTANCE_FETCH_FAIL; - error: unknown; -} - -const fetchInstance = () => async (dispatch: AppDispatch, getState: () => RootState) => { - try { - const instance = await getClient(getState).instance.getInstance(); - - dispatch({ type: INSTANCE_FETCH_SUCCESS, instance }); - } catch (error) { - dispatch({ type: INSTANCE_FETCH_FAIL, error }); - } -}; - -type InstanceAction = - InstanceFetchSuccessAction - | InstanceFetchFailAction - -export { - INSTANCE_FETCH_SUCCESS, - INSTANCE_FETCH_FAIL, - getHost, - fetchInstance, - type InstanceAction, -}; +export { getHost }; diff --git a/packages/pl-fe/src/actions/media.ts b/packages/pl-fe/src/actions/media.ts index 0879dfe6f..2f1b89dd5 100644 --- a/packages/pl-fe/src/actions/media.ts +++ b/packages/pl-fe/src/actions/media.ts @@ -1,5 +1,6 @@ import { defineMessages, type IntlShape } from 'react-intl'; +import { queryClient } from 'pl-fe/queries/client'; import toast from 'pl-fe/toast'; import { isLoggedIn } from 'pl-fe/utils/auth'; import { formatBytes, getVideoDuration } from 'pl-fe/utils/media'; @@ -7,7 +8,7 @@ import resizeImage from 'pl-fe/utils/resize-image'; import { getClient } from '../api'; -import type { MediaAttachment, UploadMediaParams } from 'pl-api'; +import type { Instance, MediaAttachment, UploadMediaParams } from 'pl-api'; import type { AppDispatch, RootState } from 'pl-fe/store'; const messages = defineMessages({ @@ -35,9 +36,11 @@ const uploadFile = ( changeTotal: (value: number) => void = () => {}, ) => async (dispatch: AppDispatch, getState: () => RootState) => { if (!isLoggedIn(getState)) return; - const maxImageSize = getState().instance.configuration.media_attachments.image_size_limit; - const maxVideoSize = getState().instance.configuration.media_attachments.video_size_limit; - const maxVideoDuration = getState().instance.configuration.media_attachments.video_duration_limit; + const instance = queryClient.getQueryData(['instance', 'instanceInformation', getState().auth.client.baseURL])!; + + const { + image_size_limit: maxImageSize, video_size_limit: maxVideoSize, video_duration_limit: maxVideoDuration, + } = instance.configuration.media_attachments; const isImage = file.type.match(/image.*/); const isVideo = file.type.match(/video.*/); diff --git a/packages/pl-fe/src/actions/preload.ts b/packages/pl-fe/src/actions/preload.ts index e20095cfb..f2567265a 100644 --- a/packages/pl-fe/src/actions/preload.ts +++ b/packages/pl-fe/src/actions/preload.ts @@ -67,6 +67,8 @@ interface PreloadAction { export { PLEROMA_PRELOAD_IMPORT, MASTODON_PRELOAD_IMPORT, + decodeFromMarkup, + pleromaDecoder, preload, preloadMastodon, type PreloadAction, diff --git a/packages/pl-fe/src/actions/push-notifications/registerer.ts b/packages/pl-fe/src/actions/push-notifications/registerer.ts index ac19530a3..cc6ea0565 100644 --- a/packages/pl-fe/src/actions/push-notifications/registerer.ts +++ b/packages/pl-fe/src/actions/push-notifications/registerer.ts @@ -1,6 +1,5 @@ import { createPushSubscription, updatePushSubscription } from 'pl-fe/actions/push-subscriptions'; import { pushNotificationsSetting } from 'pl-fe/settings'; -import { getVapidKey } from 'pl-fe/utils/auth'; import { decode as decodeBase64 } from 'pl-fe/utils/base64'; import { setBrowserSupport, setSubscription, clearSubscription } from './setter'; @@ -30,10 +29,10 @@ const getPushSubscription = (registration: ServiceWorkerRegistration) => registration.pushManager.getSubscription() .then(subscription => ({ registration, subscription })); -const subscribe = (registration: ServiceWorkerRegistration, getState: () => RootState) => +const subscribe = (registration: ServiceWorkerRegistration, vapidKey: string) => registration.pushManager.subscribe({ userVisibleOnly: true, - applicationServerKey: urlBase64ToUint8Array(getVapidKey(getState())), + applicationServerKey: urlBase64ToUint8Array(vapidKey), }); const unsubscribe = ({ registration, subscription }: { @@ -61,10 +60,9 @@ const sendSubscriptionToBackend = (subscription: PushSubscription, me: Me) => // eslint-disable-next-line compat/compat const supportsPushNotifications = ('serviceWorker' in navigator && 'PushManager' in window && 'getKey' in PushSubscription.prototype); -const register = () => +const register = (vapidKey?: string) => (dispatch: AppDispatch, getState: () => RootState) => { const me = getState().me; - const vapidKey = getVapidKey(getState()); dispatch(setBrowserSupport(supportsPushNotifications)); @@ -95,13 +93,13 @@ const register = () => } else { // Something went wrong, try to subscribe again return unsubscribe({ registration, subscription }) - .then((registration) => subscribe(registration, getState)) + .then((registration) => subscribe(registration, vapidKey)) .then((pushSubscription) => dispatch(sendSubscriptionToBackend(pushSubscription, me))); } } // No subscription, try to subscribe - return subscribe(registration, getState) + return subscribe(registration, vapidKey) .then((pushSubscription) => dispatch(sendSubscriptionToBackend(pushSubscription, me))); }) .then((subscription) => { diff --git a/packages/pl-fe/src/api/hooks/instance/use-instance.ts b/packages/pl-fe/src/api/hooks/instance/use-instance.ts new file mode 100644 index 000000000..dd75aacd1 --- /dev/null +++ b/packages/pl-fe/src/api/hooks/instance/use-instance.ts @@ -0,0 +1,23 @@ +import { useQuery } from '@tanstack/react-query'; +import { instanceSchema } from 'pl-api'; +import * as v from 'valibot'; + +import { useClient } from 'pl-fe/hooks/use-client'; +import { initialState } from 'pl-fe/initial-state'; + +const placeholderData = v.parse(instanceSchema, {}); +const initialData = initialState['/api/v1/instance'] ? v.parse(instanceSchema, initialState['/api/v1/instance']) : undefined; + +const useInstance = () => { + const client = useClient(); + + const query = useQuery({ + queryKey: ['instance', 'instanceInformation', client.baseURL], + queryFn: client.instance.getInstance, + initialData: client.baseURL === '' ? initialData : undefined, + }); + + return { ...query, data: query.data || placeholderData }; +}; + +export { useInstance }; diff --git a/packages/pl-fe/src/api/hooks/instance/use-translation-languages.ts b/packages/pl-fe/src/api/hooks/instance/use-translation-languages.ts index 0fcdc3fab..2a15c09d5 100644 --- a/packages/pl-fe/src/api/hooks/instance/use-translation-languages.ts +++ b/packages/pl-fe/src/api/hooks/instance/use-translation-languages.ts @@ -1,15 +1,15 @@ import { useQuery } from '@tanstack/react-query'; +import { useInstance } from 'pl-fe/api/hooks/instance/use-instance'; import { useClient } from 'pl-fe/hooks/use-client'; import { useFeatures } from 'pl-fe/hooks/use-features'; -import { useInstance } from 'pl-fe/hooks/use-instance'; import { useLoggedIn } from 'pl-fe/hooks/use-logged-in'; const useTranslationLanguages = () => { const client = useClient(); const { isLoggedIn } = useLoggedIn(); const features = useFeatures(); - const instance = useInstance(); + const { data: instance } = useInstance(); const getTranslationLanguages = async () => { const metadata = instance.pleroma.metadata; diff --git a/packages/pl-fe/src/api/hooks/streaming/use-timeline-stream.ts b/packages/pl-fe/src/api/hooks/streaming/use-timeline-stream.ts index 07c2a140a..6f8fbe2f0 100644 --- a/packages/pl-fe/src/api/hooks/streaming/use-timeline-stream.ts +++ b/packages/pl-fe/src/api/hooks/streaming/use-timeline-stream.ts @@ -1,8 +1,8 @@ import { useEffect, useRef } from 'react'; +import { useInstance } from 'pl-fe/api/hooks/instance/use-instance'; import { useAppSelector } from 'pl-fe/hooks/use-app-selector'; import { useClient } from 'pl-fe/hooks/use-client'; -import { useInstance } from 'pl-fe/hooks/use-instance'; import { getAccessToken } from 'pl-fe/utils/auth'; import type { StreamingEvent } from 'pl-api'; @@ -12,7 +12,7 @@ const useTimelineStream = (stream: string, params: { list?: string; tag?: string const client = useClient(); - const instance = useInstance(); + const { data: instance } = useInstance(); const socket = useRef<({ listen: (listener: any, stream?: string) => number; unlisten: (listener: any) => void; diff --git a/packages/pl-fe/src/components/birthday-input.tsx b/packages/pl-fe/src/components/birthday-input.tsx index 58688074e..6a8fd6f8d 100644 --- a/packages/pl-fe/src/components/birthday-input.tsx +++ b/packages/pl-fe/src/components/birthday-input.tsx @@ -1,10 +1,10 @@ import React, { useMemo } from 'react'; import { defineMessages, useIntl } from 'react-intl'; +import { useInstance } from 'pl-fe/api/hooks/instance/use-instance'; import IconButton from 'pl-fe/components/icon-button'; import { DatePicker } from 'pl-fe/features/ui/util/async-components'; import { useFeatures } from 'pl-fe/hooks/use-features'; -import { useInstance } from 'pl-fe/hooks/use-instance'; const messages = defineMessages({ birthdayPlaceholder: { id: 'edit_profile.fields.birthday_placeholder', defaultMessage: 'Your birthday' }, @@ -23,7 +23,7 @@ interface IBirthdayInput { const BirthdayInput: React.FC = ({ value, onChange, required }) => { const intl = useIntl(); const features = useFeatures(); - const instance = useInstance(); + const { data: instance } = useInstance(); const supportsBirthdays = features.birthdays; const minAge = instance.pleroma.metadata.birthday_min_age; diff --git a/packages/pl-fe/src/components/gdpr-banner.tsx b/packages/pl-fe/src/components/gdpr-banner.tsx index 0f86c8e2d..aa16f6514 100644 --- a/packages/pl-fe/src/components/gdpr-banner.tsx +++ b/packages/pl-fe/src/components/gdpr-banner.tsx @@ -2,12 +2,12 @@ import clsx from 'clsx'; import React, { useState } from 'react'; import { FormattedMessage } from 'react-intl'; +import { useInstance } from 'pl-fe/api/hooks/instance/use-instance'; import Banner from 'pl-fe/components/ui/banner'; import Button from 'pl-fe/components/ui/button'; import HStack from 'pl-fe/components/ui/hstack'; import Stack from 'pl-fe/components/ui/stack'; import Text from 'pl-fe/components/ui/text'; -import { useInstance } from 'pl-fe/hooks/use-instance'; import { usePlFeConfig } from 'pl-fe/hooks/use-pl-fe-config'; const acceptedGdpr = !!localStorage.getItem('plfe:gdpr'); @@ -18,7 +18,7 @@ const GdprBanner: React.FC = () => { const [shown, setShown] = useState(acceptedGdpr); const [slideout, setSlideout] = useState(false); - const instance = useInstance(); + const { data: instance } = useInstance(); const { gdprUrl } = usePlFeConfig(); const handleAccept = () => { diff --git a/packages/pl-fe/src/components/helmet.tsx b/packages/pl-fe/src/components/helmet.tsx index dafab6605..81073f53b 100644 --- a/packages/pl-fe/src/components/helmet.tsx +++ b/packages/pl-fe/src/components/helmet.tsx @@ -1,9 +1,9 @@ import React from 'react'; import { Helmet as ReactHelmet } from 'react-helmet-async'; +import { useInstance } from 'pl-fe/api/hooks/instance/use-instance'; import { useStatContext } from 'pl-fe/contexts/stat-context'; import { useAppSelector } from 'pl-fe/hooks/use-app-selector'; -import { useInstance } from 'pl-fe/hooks/use-instance'; import { useSettings } from 'pl-fe/hooks/use-settings'; import { RootState } from 'pl-fe/store'; import FaviconService from 'pl-fe/utils/favicon-service'; @@ -22,7 +22,7 @@ interface IHelmet { } const Helmet: React.FC = ({ children }) => { - const instance = useInstance(); + const { data: instance } = useInstance(); const { unreadChatsCount } = useStatContext(); const unreadCount = useAppSelector((state) => getNotifTotals(state) + unreadChatsCount); const { demetricator } = useSettings(); diff --git a/packages/pl-fe/src/components/sidebar-menu.tsx b/packages/pl-fe/src/components/sidebar-menu.tsx index 928b57377..555655b9f 100644 --- a/packages/pl-fe/src/components/sidebar-menu.tsx +++ b/packages/pl-fe/src/components/sidebar-menu.tsx @@ -6,6 +6,7 @@ import { Link, NavLink } from 'react-router-dom'; import { fetchOwnAccounts, logOut, switchAccount } from 'pl-fe/actions/auth'; import { useAccount } from 'pl-fe/api/hooks/accounts/use-account'; +import { useInstance } from 'pl-fe/api/hooks/instance/use-instance'; import { useInteractionRequestsCount } from 'pl-fe/api/hooks/statuses/use-interaction-requests'; import Account from 'pl-fe/components/account'; import Divider from 'pl-fe/components/ui/divider'; @@ -17,7 +18,6 @@ import ProfileStats from 'pl-fe/features/ui/components/profile-stats'; import { useAppDispatch } from 'pl-fe/hooks/use-app-dispatch'; import { useAppSelector } from 'pl-fe/hooks/use-app-selector'; import { useFeatures } from 'pl-fe/hooks/use-features'; -import { useInstance } from 'pl-fe/hooks/use-instance'; import { useRegistrationStatus } from 'pl-fe/hooks/use-registration-status'; import { makeGetOtherAccounts } from 'pl-fe/selectors'; import { useSettingsStore } from 'pl-fe/stores/settings'; @@ -106,7 +106,7 @@ const SidebarMenu: React.FC = (): JSX.Element | null => { const touchEnd = useRef(null); const { isOpen } = useRegistrationStatus(); - const instance = useInstance(); + const { data: instance } = useInstance(); const restrictUnauth = instance.pleroma.metadata.restrict_unauthenticated; const containerRef = React.useRef(null); diff --git a/packages/pl-fe/src/components/sidebar-navigation.tsx b/packages/pl-fe/src/components/sidebar-navigation.tsx index e24dfecb1..02c70db74 100644 --- a/packages/pl-fe/src/components/sidebar-navigation.tsx +++ b/packages/pl-fe/src/components/sidebar-navigation.tsx @@ -1,6 +1,7 @@ import React from 'react'; import { defineMessages, FormattedMessage, useIntl } from 'react-intl'; +import { useInstance } from 'pl-fe/api/hooks/instance/use-instance'; import { useInteractionRequestsCount } from 'pl-fe/api/hooks/statuses/use-interaction-requests'; import Icon from 'pl-fe/components/ui/icon'; import Stack from 'pl-fe/components/ui/stack'; @@ -9,7 +10,6 @@ import ComposeButton from 'pl-fe/features/ui/components/compose-button'; import ProfileDropdown from 'pl-fe/features/ui/components/profile-dropdown'; import { useAppSelector } from 'pl-fe/hooks/use-app-selector'; import { useFeatures } from 'pl-fe/hooks/use-features'; -import { useInstance } from 'pl-fe/hooks/use-instance'; import { useLogo } from 'pl-fe/hooks/use-logo'; import { useOwnAccount } from 'pl-fe/hooks/use-own-account'; import { useRegistrationStatus } from 'pl-fe/hooks/use-registration-status'; @@ -40,7 +40,7 @@ const SidebarNavigation = () => { const intl = useIntl(); const { unreadChatsCount } = useStatContext(); - const instance = useInstance(); + const { data: instance } = useInstance(); const features = useFeatures(); const { isDeveloper } = useSettings(); const { account } = useOwnAccount(); diff --git a/packages/pl-fe/src/components/status-action-bar.tsx b/packages/pl-fe/src/components/status-action-bar.tsx index 413173f89..65f173437 100644 --- a/packages/pl-fe/src/components/status-action-bar.tsx +++ b/packages/pl-fe/src/components/status-action-bar.tsx @@ -17,6 +17,7 @@ import { useBlockGroupMember } from 'pl-fe/api/hooks/groups/use-block-group-memb import { useDeleteGroupStatus } from 'pl-fe/api/hooks/groups/use-delete-group-status'; import { useGroup } from 'pl-fe/api/hooks/groups/use-group'; import { useGroupRelationship } from 'pl-fe/api/hooks/groups/use-group-relationship'; +import { useInstance } from 'pl-fe/api/hooks/instance/use-instance'; import { useTranslationLanguages } from 'pl-fe/api/hooks/instance/use-translation-languages'; import DropdownMenu from 'pl-fe/components/dropdown-menu'; import StatusActionButton from 'pl-fe/components/status-action-button'; @@ -27,7 +28,6 @@ import { useAppDispatch } from 'pl-fe/hooks/use-app-dispatch'; import { useAppSelector } from 'pl-fe/hooks/use-app-selector'; import { useCanInteract } from 'pl-fe/hooks/use-can-interact'; import { useFeatures } from 'pl-fe/hooks/use-features'; -import { useInstance } from 'pl-fe/hooks/use-instance'; import { useOwnAccount } from 'pl-fe/hooks/use-own-account'; import { useSettings } from 'pl-fe/hooks/use-settings'; import { useChats } from 'pl-fe/queries/chats'; @@ -595,7 +595,7 @@ const MenuButton: React.FC = ({ const { groupRelationship } = useGroupRelationship(status.group_id || undefined); const features = useFeatures(); - const instance = useInstance(); + const { data: instance } = useInstance(); const { autoTranslate, deleteModal, knownLanguages } = useSettings(); const { translationLanguages } = useTranslationLanguages(); diff --git a/packages/pl-fe/src/components/translate-button.tsx b/packages/pl-fe/src/components/translate-button.tsx index 3d8e41198..9fd1c92a0 100644 --- a/packages/pl-fe/src/components/translate-button.tsx +++ b/packages/pl-fe/src/components/translate-button.tsx @@ -1,6 +1,7 @@ import React, { useEffect } from 'react'; import { FormattedMessage, useIntl } from 'react-intl'; +import { useInstance } from 'pl-fe/api/hooks/instance/use-instance'; import { useTranslationLanguages } from 'pl-fe/api/hooks/instance/use-translation-languages'; import { useStatusTranslation } from 'pl-fe/api/hooks/statuses/use-status-translation'; import HStack from 'pl-fe/components/ui/hstack'; @@ -9,7 +10,6 @@ import Stack from 'pl-fe/components/ui/stack'; import Text from 'pl-fe/components/ui/text'; import { useAppSelector } from 'pl-fe/hooks/use-app-selector'; import { useFeatures } from 'pl-fe/hooks/use-features'; -import { useInstance } from 'pl-fe/hooks/use-instance'; import { useSettings } from 'pl-fe/hooks/use-settings'; import { useStatusMetaStore } from 'pl-fe/stores/status-meta'; @@ -22,7 +22,7 @@ interface ITranslateButton { const TranslateButton: React.FC = ({ status }) => { const intl = useIntl(); const features = useFeatures(); - const instance = useInstance(); + const { data: instance } = useInstance(); const settings = useSettings(); const autoTranslate = settings.autoTranslate; const knownLanguages = autoTranslate ? [...settings.knownLanguages, intl.locale] : [intl.locale]; diff --git a/packages/pl-fe/src/features/admin/components/registration-mode-picker.tsx b/packages/pl-fe/src/features/admin/components/registration-mode-picker.tsx index 416aaee10..eb47d3163 100644 --- a/packages/pl-fe/src/features/admin/components/registration-mode-picker.tsx +++ b/packages/pl-fe/src/features/admin/components/registration-mode-picker.tsx @@ -3,9 +3,9 @@ import React from 'react'; import { useIntl, defineMessages, FormattedMessage } from 'react-intl'; import { updateConfig } from 'pl-fe/actions/admin'; +import { useInstance } from 'pl-fe/api/hooks/instance/use-instance'; import { RadioGroup, RadioItem } from 'pl-fe/components/radio'; import { useAppDispatch } from 'pl-fe/hooks/use-app-dispatch'; -import { useInstance } from 'pl-fe/hooks/use-instance'; import toast from 'pl-fe/toast'; type RegistrationMode = 'open' | 'approval' | 'closed'; @@ -37,7 +37,7 @@ const modeFromInstance = ({ registrations }: Instance): RegistrationMode => { const RegistrationModePicker: React.FC = () => { const intl = useIntl(); const dispatch = useAppDispatch(); - const instance = useInstance(); + const { data: instance } = useInstance(); const mode = modeFromInstance(instance); diff --git a/packages/pl-fe/src/features/admin/tabs/dashboard.tsx b/packages/pl-fe/src/features/admin/tabs/dashboard.tsx index 73b56cfcf..5ac6706c1 100644 --- a/packages/pl-fe/src/features/admin/tabs/dashboard.tsx +++ b/packages/pl-fe/src/features/admin/tabs/dashboard.tsx @@ -1,12 +1,12 @@ import React from 'react'; import { FormattedMessage } from 'react-intl'; +import { useInstance } from 'pl-fe/api/hooks/instance/use-instance'; import List, { ListItem } from 'pl-fe/components/list'; import { CardTitle } from 'pl-fe/components/ui/card'; import Icon from 'pl-fe/components/ui/icon'; import Stack from 'pl-fe/components/ui/stack'; import { useFeatures } from 'pl-fe/hooks/use-features'; -import { useInstance } from 'pl-fe/hooks/use-instance'; import { useOwnAccount } from 'pl-fe/hooks/use-own-account'; import sourceCode from 'pl-fe/utils/code'; @@ -14,7 +14,7 @@ import { DashCounter, DashCounters } from '../components/dashcounter'; import RegistrationModePicker from '../components/registration-mode-picker'; const Dashboard: React.FC = () => { - const instance = useInstance(); + const { data: instance } = useInstance(); const features = useFeatures(); const { account } = useOwnAccount(); diff --git a/packages/pl-fe/src/features/auth-login/components/consumers-list.tsx b/packages/pl-fe/src/features/auth-login/components/consumers-list.tsx index cacdf1afe..8ca7d38d2 100644 --- a/packages/pl-fe/src/features/auth-login/components/consumers-list.tsx +++ b/packages/pl-fe/src/features/auth-login/components/consumers-list.tsx @@ -1,11 +1,11 @@ import React from 'react'; import { FormattedMessage } from 'react-intl'; +import { useInstance } from 'pl-fe/api/hooks/instance/use-instance'; import Card from 'pl-fe/components/ui/card'; import HStack from 'pl-fe/components/ui/hstack'; import Stack from 'pl-fe/components/ui/stack'; import Text from 'pl-fe/components/ui/text'; -import { useInstance } from 'pl-fe/hooks/use-instance'; import ConsumerButton from './consumer-button'; @@ -14,7 +14,7 @@ interface IConsumersList { /** Displays OAuth consumers to log in with. */ const ConsumersList: React.FC = () => { - const instance = useInstance(); + const { data: instance } = useInstance(); const providers = instance.pleroma.oauth_consumer_strategies; if (providers.length > 0) { diff --git a/packages/pl-fe/src/features/auth-login/components/login-page.tsx b/packages/pl-fe/src/features/auth-login/components/login-page.tsx index f13f4cde3..05c63bff7 100644 --- a/packages/pl-fe/src/features/auth-login/components/login-page.tsx +++ b/packages/pl-fe/src/features/auth-login/components/login-page.tsx @@ -3,7 +3,6 @@ import { FormattedMessage } from 'react-intl'; import { Redirect } from 'react-router-dom'; import { logIn, verifyCredentials, switchAccount } from 'pl-fe/actions/auth'; -import { fetchInstance } from 'pl-fe/actions/instance'; import { BigCard } from 'pl-fe/components/big-card'; import Button from 'pl-fe/components/ui/button'; import Stack from 'pl-fe/components/ui/stack'; @@ -43,11 +42,6 @@ const LoginPage = () => { const { username, password } = getFormData(event.target as HTMLFormElement); dispatch(logIn(username, password)) .then(({ access_token }) => dispatch(verifyCredentials(access_token))) - // Refetch the instance for authenticated fetch - .then(async (account) => { - await dispatch(fetchInstance()); - return account; - }) .then((account: { id: string }) => { closeModal(); if (typeof me === 'string') { diff --git a/packages/pl-fe/src/features/auth-login/components/registration-form.tsx b/packages/pl-fe/src/features/auth-login/components/registration-form.tsx index fc65c71c1..c4b5ec38d 100644 --- a/packages/pl-fe/src/features/auth-login/components/registration-form.tsx +++ b/packages/pl-fe/src/features/auth-login/components/registration-form.tsx @@ -5,6 +5,7 @@ import { Link, useHistory } from 'react-router-dom'; import { accountLookup } from 'pl-fe/actions/accounts'; import { register, verifyCredentials } from 'pl-fe/actions/auth'; +import { useInstance } from 'pl-fe/api/hooks/instance/use-instance'; import BirthdayInput from 'pl-fe/components/birthday-input'; import Button from 'pl-fe/components/ui/button'; import Checkbox from 'pl-fe/components/ui/checkbox'; @@ -17,7 +18,6 @@ import Textarea from 'pl-fe/components/ui/textarea'; import CaptchaField from 'pl-fe/features/auth-login/components/captcha'; import { useAppDispatch } from 'pl-fe/hooks/use-app-dispatch'; import { useFeatures } from 'pl-fe/hooks/use-features'; -import { useInstance } from 'pl-fe/hooks/use-instance'; import { useSettings } from 'pl-fe/hooks/use-settings'; import { useModalsStore } from 'pl-fe/stores/modals'; @@ -52,7 +52,7 @@ const RegistrationForm: React.FC = ({ inviteToken }) => { const { locale } = useSettings(); const features = useFeatures(); - const instance = useInstance(); + const { data: instance } = useInstance(); const { openModal } = useModalsStore(); const needsConfirmation = instance.pleroma.metadata.account_activation_required; diff --git a/packages/pl-fe/src/features/auth-login/components/registration-page.tsx b/packages/pl-fe/src/features/auth-login/components/registration-page.tsx index cce5bf427..84da7ef5a 100644 --- a/packages/pl-fe/src/features/auth-login/components/registration-page.tsx +++ b/packages/pl-fe/src/features/auth-login/components/registration-page.tsx @@ -1,15 +1,15 @@ import React from 'react'; import { FormattedMessage } from 'react-intl'; +import { useInstance } from 'pl-fe/api/hooks/instance/use-instance'; import { BigCard } from 'pl-fe/components/big-card'; import Text from 'pl-fe/components/ui/text'; -import { useInstance } from 'pl-fe/hooks/use-instance'; import { useRegistrationStatus } from 'pl-fe/hooks/use-registration-status'; import RegistrationForm from './registration-form'; const RegistrationPage: React.FC = () => { - const instance = useInstance(); + const { data: instance } = useInstance(); const { isOpen } = useRegistrationStatus(); if (!isOpen) { diff --git a/packages/pl-fe/src/features/chats/components/chat-composer.tsx b/packages/pl-fe/src/features/chats/components/chat-composer.tsx index ed0c7b39c..5c948a8f7 100644 --- a/packages/pl-fe/src/features/chats/components/chat-composer.tsx +++ b/packages/pl-fe/src/features/chats/components/chat-composer.tsx @@ -3,6 +3,7 @@ import { defineMessages, IntlShape, useIntl } from 'react-intl'; import { unblockAccount } from 'pl-fe/actions/accounts'; import { useRelationship } from 'pl-fe/api/hooks/accounts/use-relationship'; +import { useInstance } from 'pl-fe/api/hooks/instance/use-instance'; import Button from 'pl-fe/components/ui/button'; import Combobox, { ComboboxInput, ComboboxList, ComboboxOption, ComboboxPopover } from 'pl-fe/components/ui/combobox'; import HStack from 'pl-fe/components/ui/hstack'; @@ -13,7 +14,6 @@ import { useChatContext } from 'pl-fe/contexts/chat-context'; import UploadButton from 'pl-fe/features/compose/components/upload-button'; import emojiSearch from 'pl-fe/features/emoji/search'; import { useAppDispatch } from 'pl-fe/hooks/use-app-dispatch'; -import { useInstance } from 'pl-fe/hooks/use-instance'; import { useModalsStore } from 'pl-fe/stores/modals'; import { textAtCursorMatchesToken } from 'pl-fe/utils/suggestions'; @@ -85,7 +85,7 @@ const ChatComposer = React.forwardRef const isBlocked = relationship?.blocked_by && false; const isBlocking = relationship?.blocking && false; - const maxCharacterCount = useInstance().configuration.chats.max_characters; + const maxCharacterCount = useInstance().data.configuration.chats.max_characters; const [suggestions, setSuggestions] = useState(initialSuggestionState); const isSuggestionsAvailable = suggestions.list.length > 0; diff --git a/packages/pl-fe/src/features/compose-event/components/upload-button.tsx b/packages/pl-fe/src/features/compose-event/components/upload-button.tsx index 7b696e9be..3e17dae64 100644 --- a/packages/pl-fe/src/features/compose-event/components/upload-button.tsx +++ b/packages/pl-fe/src/features/compose-event/components/upload-button.tsx @@ -1,10 +1,10 @@ import React, { useRef } from 'react'; import { FormattedMessage } from 'react-intl'; +import { useInstance } from 'pl-fe/api/hooks/instance/use-instance'; import Icon from 'pl-fe/components/icon'; import HStack from 'pl-fe/components/ui/hstack'; import Text from 'pl-fe/components/ui/text'; -import { useAppSelector } from 'pl-fe/hooks/use-app-selector'; interface IUploadButton { disabled?: boolean; @@ -14,7 +14,7 @@ interface IUploadButton { const UploadButton: React.FC = ({ disabled, onSelectFile }) => { const fileElement = useRef(null); - const attachmentTypes = useAppSelector(state => state.instance.configuration.media_attachments.supported_mime_types) + const attachmentTypes = useInstance().data.configuration.media_attachments.supported_mime_types ?.filter((type) => type.startsWith('image/')); let accept = attachmentTypes?.join(','); 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 ef8149e2a..15dc3efa0 100644 --- a/packages/pl-fe/src/features/compose/components/compose-form.tsx +++ b/packages/pl-fe/src/features/compose/components/compose-form.tsx @@ -12,6 +12,7 @@ import { selectComposeSuggestion, uploadCompose, } from 'pl-fe/actions/compose'; +import { useInstance } from 'pl-fe/api/hooks/instance/use-instance'; import Button from 'pl-fe/components/ui/button'; import HStack from 'pl-fe/components/ui/hstack'; import Stack from 'pl-fe/components/ui/stack'; @@ -21,7 +22,6 @@ import { useAppDispatch } from 'pl-fe/hooks/use-app-dispatch'; import { useCompose } from 'pl-fe/hooks/use-compose'; import { useDraggedFiles } from 'pl-fe/hooks/use-dragged-files'; import { useFeatures } from 'pl-fe/hooks/use-features'; -import { useInstance } from 'pl-fe/hooks/use-instance'; import QuotedStatusContainer from '../containers/quoted-status-container'; import ReplyIndicatorContainer from '../containers/reply-indicator-container'; @@ -75,7 +75,7 @@ const ComposeForm = ({ id, shouldCondense, autoFocus, clickab const history = useHistory(); const intl = useIntl(); const dispatch = useAppDispatch(); - const { configuration } = useInstance(); + const { configuration } = useInstance().data; const compose = useCompose(id); const maxTootChars = configuration.statuses.max_characters; diff --git a/packages/pl-fe/src/features/compose/components/content-type-button.tsx b/packages/pl-fe/src/features/compose/components/content-type-button.tsx index 9565d2b43..6d27bf95c 100644 --- a/packages/pl-fe/src/features/compose/components/content-type-button.tsx +++ b/packages/pl-fe/src/features/compose/components/content-type-button.tsx @@ -2,11 +2,11 @@ import React from 'react'; import { defineMessages, useIntl } from 'react-intl'; import { changeComposeContentType } from 'pl-fe/actions/compose'; +import { useInstance } from 'pl-fe/api/hooks/instance/use-instance'; import DropdownMenu from 'pl-fe/components/dropdown-menu'; import Button from 'pl-fe/components/ui/button'; import { useAppDispatch } from 'pl-fe/hooks/use-app-dispatch'; import { useCompose } from 'pl-fe/hooks/use-compose'; -import { useInstance } from 'pl-fe/hooks/use-instance'; const messages = defineMessages({ content_type_plaintext: { id: 'preferences.options.content_type_plaintext', defaultMessage: 'Plain text' }, @@ -24,7 +24,7 @@ interface IContentTypeButton { const ContentTypeButton: React.FC = ({ composeId }) => { const intl = useIntl(); const dispatch = useAppDispatch(); - const instance = useInstance(); + const { data: instance } = useInstance(); const contentType = useCompose(composeId).content_type; diff --git a/packages/pl-fe/src/features/compose/components/polls/poll-form.tsx b/packages/pl-fe/src/features/compose/components/polls/poll-form.tsx index f2247bd43..095f9e0c7 100644 --- a/packages/pl-fe/src/features/compose/components/polls/poll-form.tsx +++ b/packages/pl-fe/src/features/compose/components/polls/poll-form.tsx @@ -2,6 +2,7 @@ import React from 'react'; import { defineMessages, FormattedMessage, useIntl } from 'react-intl'; import { addPollOption, changePollOption, changePollSettings, clearComposeSuggestions, fetchComposeSuggestions, removePoll, removePollOption, selectComposeSuggestion } from 'pl-fe/actions/compose'; +import { useInstance } from 'pl-fe/api/hooks/instance/use-instance'; import AutosuggestInput from 'pl-fe/components/autosuggest-input'; import Button from 'pl-fe/components/ui/button'; import Divider from 'pl-fe/components/ui/divider'; @@ -11,7 +12,6 @@ import Text from 'pl-fe/components/ui/text'; import Toggle from 'pl-fe/components/ui/toggle'; import { useAppDispatch } from 'pl-fe/hooks/use-app-dispatch'; import { useCompose } from 'pl-fe/hooks/use-compose'; -import { useInstance } from 'pl-fe/hooks/use-instance'; import DurationSelector from './duration-selector'; @@ -118,7 +118,7 @@ interface IPollForm { const PollForm: React.FC = ({ composeId }) => { const dispatch = useAppDispatch(); const intl = useIntl(); - const { configuration } = useInstance(); + const { configuration } = useInstance().data; const { poll, language, modified_language: modifiedLanguage } = useCompose(composeId); diff --git a/packages/pl-fe/src/features/compose/components/upload-button.tsx b/packages/pl-fe/src/features/compose/components/upload-button.tsx index 1d6d35245..174f22a28 100644 --- a/packages/pl-fe/src/features/compose/components/upload-button.tsx +++ b/packages/pl-fe/src/features/compose/components/upload-button.tsx @@ -1,8 +1,8 @@ import React, { useRef } from 'react'; import { defineMessages, IntlShape, useIntl } from 'react-intl'; +import { useInstance } from 'pl-fe/api/hooks/instance/use-instance'; import IconButton from 'pl-fe/components/ui/icon-button'; -import { useInstance } from 'pl-fe/hooks/use-instance'; const messages = defineMessages({ upload: { id: 'upload_button.label', defaultMessage: 'Add media attachment' }, @@ -32,7 +32,7 @@ const UploadButton: React.FC = ({ icon, }) => { const intl = useIntl(); - const { configuration } = useInstance(); + const { configuration } = useInstance().data; const fileElement = useRef(null); const attachmentTypes = configuration.media_attachments.supported_mime_types; diff --git a/packages/pl-fe/src/features/compose/components/upload.tsx b/packages/pl-fe/src/features/compose/components/upload.tsx index 4726c4a94..187203992 100644 --- a/packages/pl-fe/src/features/compose/components/upload.tsx +++ b/packages/pl-fe/src/features/compose/components/upload.tsx @@ -1,10 +1,10 @@ import React, { useCallback } from 'react'; import { undoUploadCompose, changeUploadCompose } from 'pl-fe/actions/compose'; +import { useInstance } from 'pl-fe/api/hooks/instance/use-instance'; import Upload from 'pl-fe/components/upload'; import { useAppDispatch } from 'pl-fe/hooks/use-app-dispatch'; import { useCompose } from 'pl-fe/hooks/use-compose'; -import { useInstance } from 'pl-fe/hooks/use-instance'; interface IUploadCompose { id: string; @@ -17,7 +17,7 @@ interface IUploadCompose { const UploadCompose: React.FC = ({ composeId, id, onSubmit, onDragStart, onDragEnter, onDragEnd }) => { const dispatch = useAppDispatch(); - const { pleroma: { metadata: { description_limit: descriptionLimit } } } = useInstance(); + const { pleroma: { metadata: { description_limit: descriptionLimit } } } = useInstance().data; const media = useCompose(composeId).media_attachments.find(item => item.id === id)!; diff --git a/packages/pl-fe/src/features/compose/editor/nodes/index.ts b/packages/pl-fe/src/features/compose/editor/nodes/index.ts index 1daec172c..d35644260 100644 --- a/packages/pl-fe/src/features/compose/editor/nodes/index.ts +++ b/packages/pl-fe/src/features/compose/editor/nodes/index.ts @@ -11,7 +11,7 @@ import { ListItemNode, ListNode } from '@lexical/list'; import { HorizontalRuleNode } from '@lexical/react/LexicalHorizontalRuleNode'; import { HeadingNode, QuoteNode } from '@lexical/rich-text'; -import { useInstance } from 'pl-fe/hooks/use-instance'; +import { useInstance } from 'pl-fe/api/hooks/instance/use-instance'; import { EmojiNode } from './emoji-node'; import { ImageNode } from './image-node'; @@ -20,7 +20,7 @@ import { MentionNode } from './mention-node'; import type { Klass, LexicalNode } from 'lexical'; const useNodes = (isWysiwyg?: boolean) => { - const instance = useInstance(); + const { data: instance } = useInstance(); const nodes: Array> = [ AutoLinkNode, diff --git a/packages/pl-fe/src/features/compose/editor/plugins/floating-block-type-toolbar-plugin.tsx b/packages/pl-fe/src/features/compose/editor/plugins/floating-block-type-toolbar-plugin.tsx index 96dc90568..c9eb578e6 100644 --- a/packages/pl-fe/src/features/compose/editor/plugins/floating-block-type-toolbar-plugin.tsx +++ b/packages/pl-fe/src/features/compose/editor/plugins/floating-block-type-toolbar-plugin.tsx @@ -23,8 +23,8 @@ import { createPortal } from 'react-dom'; import { defineMessages, useIntl } from 'react-intl'; import { uploadFile } from 'pl-fe/actions/compose'; +import { useInstance } from 'pl-fe/api/hooks/instance/use-instance'; import { useAppDispatch } from 'pl-fe/hooks/use-app-dispatch'; -import { useInstance } from 'pl-fe/hooks/use-instance'; import { $createImageNode } from '../nodes/image-node'; import { setFloatingElemPosition } from '../utils/set-floating-elem-position'; @@ -42,7 +42,7 @@ interface IUploadButton { const UploadButton: React.FC = ({ onSelectFile }) => { const intl = useIntl(); - const { configuration } = useInstance(); + const { configuration } = useInstance().data; const dispatch = useAppDispatch(); const [disabled, setDisabled] = useState(false); @@ -101,7 +101,7 @@ const BlockTypeFloatingToolbar = ({ }): JSX.Element => { const intl = useIntl(); const popupCharStylesEditorRef = useRef(null); - const instance = useInstance(); + const { data: instance } = useInstance(); const allowInlineImages = instance.pleroma.metadata.markup.allow_inline_images; diff --git a/packages/pl-fe/src/features/compose/editor/plugins/floating-text-format-toolbar-plugin.tsx b/packages/pl-fe/src/features/compose/editor/plugins/floating-text-format-toolbar-plugin.tsx index f1f955d37..f62db9602 100644 --- a/packages/pl-fe/src/features/compose/editor/plugins/floating-text-format-toolbar-plugin.tsx +++ b/packages/pl-fe/src/features/compose/editor/plugins/floating-text-format-toolbar-plugin.tsx @@ -39,8 +39,8 @@ import * as React from 'react'; import { createPortal } from 'react-dom'; import { defineMessages, useIntl } from 'react-intl'; +import { useInstance } from 'pl-fe/api/hooks/instance/use-instance'; import Icon from 'pl-fe/components/ui/icon'; -import { useInstance } from 'pl-fe/hooks/use-instance'; import { getDOMRangeRect } from '../utils/get-dom-range-rect'; import { getSelectedNode } from '../utils/get-selected-node'; @@ -109,7 +109,7 @@ const BlockTypeDropdown = ({ editor, anchorElem, blockType, icon }: { blockType: keyof typeof blockTypeToBlockName; icon: string; }) => { - const instance = useInstance(); + const { data: instance } = useInstance(); const [showDropDown, setShowDropDown] = useState(false); diff --git a/packages/pl-fe/src/features/crypto-donate/components/crypto-donate-panel.tsx b/packages/pl-fe/src/features/crypto-donate/components/crypto-donate-panel.tsx index 96032e34a..ebe6b36bb 100644 --- a/packages/pl-fe/src/features/crypto-donate/components/crypto-donate-panel.tsx +++ b/packages/pl-fe/src/features/crypto-donate/components/crypto-donate-panel.tsx @@ -2,9 +2,9 @@ import React from 'react'; import { FormattedMessage, defineMessages, useIntl } from 'react-intl'; import { useHistory } from 'react-router-dom'; +import { useInstance } from 'pl-fe/api/hooks/instance/use-instance'; import Text from 'pl-fe/components/ui/text'; import Widget from 'pl-fe/components/ui/widget'; -import { useInstance } from 'pl-fe/hooks/use-instance'; import { usePlFeConfig } from 'pl-fe/hooks/use-pl-fe-config'; import SiteWallet from './site-wallet'; @@ -20,7 +20,7 @@ interface ICryptoDonatePanel { const CryptoDonatePanel: React.FC = ({ limit = 3 }): JSX.Element | null => { const intl = useIntl(); const history = useHistory(); - const instance = useInstance(); + const { data: instance } = useInstance(); const addresses = usePlFeConfig().cryptoAddresses; diff --git a/packages/pl-fe/src/features/crypto-donate/index.tsx b/packages/pl-fe/src/features/crypto-donate/index.tsx index 1fbaffb20..9dd76d01c 100644 --- a/packages/pl-fe/src/features/crypto-donate/index.tsx +++ b/packages/pl-fe/src/features/crypto-donate/index.tsx @@ -1,10 +1,10 @@ import React, { useState } from 'react'; import { defineMessages, useIntl, FormattedMessage } from 'react-intl'; +import { useInstance } from 'pl-fe/api/hooks/instance/use-instance'; import Accordion from 'pl-fe/components/ui/accordion'; import Column from 'pl-fe/components/ui/column'; import Stack from 'pl-fe/components/ui/stack'; -import { useInstance } from 'pl-fe/hooks/use-instance'; import SiteWallet from './components/site-wallet'; @@ -14,7 +14,7 @@ const messages = defineMessages({ const CryptoDonate: React.FC = (): JSX.Element => { const intl = useIntl(); - const instance = useInstance(); + const { data: instance } = useInstance(); const [explanationBoxExpanded, toggleExplanationBox] = useState(true); diff --git a/packages/pl-fe/src/features/directory/index.tsx b/packages/pl-fe/src/features/directory/index.tsx index 3c6e5fc2b..ce5aaf4ca 100644 --- a/packages/pl-fe/src/features/directory/index.tsx +++ b/packages/pl-fe/src/features/directory/index.tsx @@ -4,13 +4,13 @@ import { FormattedMessage, defineMessages, useIntl } from 'react-intl'; import { useSearchParams } from 'react-router-dom-v5-compat'; import { useDirectory } from 'pl-fe/api/hooks/account-lists/use-directory'; +import { useInstance } from 'pl-fe/api/hooks/instance/use-instance'; import LoadMore from 'pl-fe/components/load-more'; import { RadioGroup, RadioItem } from 'pl-fe/components/radio'; import { CardTitle } from 'pl-fe/components/ui/card'; import Column from 'pl-fe/components/ui/column'; import Stack from 'pl-fe/components/ui/stack'; import { useFeatures } from 'pl-fe/hooks/use-features'; -import { useInstance } from 'pl-fe/hooks/use-instance'; import AccountCard from './components/account-card'; @@ -25,7 +25,7 @@ const messages = defineMessages({ const Directory = () => { const intl = useIntl(); const [params, setParams] = useSearchParams(); - const instance = useInstance(); + const { data: instance } = useInstance(); const features = useFeatures(); const order = (params.get('order') || 'active') as 'active' | 'new'; diff --git a/packages/pl-fe/src/features/edit-profile/index.tsx b/packages/pl-fe/src/features/edit-profile/index.tsx index cc068e5df..22d4284a6 100644 --- a/packages/pl-fe/src/features/edit-profile/index.tsx +++ b/packages/pl-fe/src/features/edit-profile/index.tsx @@ -5,6 +5,7 @@ import { defineMessages, useIntl, FormattedMessage } from 'react-intl'; import { updateNotificationSettings } from 'pl-fe/actions/accounts'; import { patchMe } from 'pl-fe/actions/me'; +import { useInstance } from 'pl-fe/api/hooks/instance/use-instance'; import BirthdayInput from 'pl-fe/components/birthday-input'; import List, { ListItem } from 'pl-fe/components/list'; import Button from 'pl-fe/components/ui/button'; @@ -21,7 +22,6 @@ import { useImageField } from 'pl-fe/hooks/forms/use-image-field'; import { useAppDispatch } from 'pl-fe/hooks/use-app-dispatch'; import { useAppSelector } from 'pl-fe/hooks/use-app-selector'; import { useFeatures } from 'pl-fe/hooks/use-features'; -import { useInstance } from 'pl-fe/hooks/use-instance'; import { useOwnAccount } from 'pl-fe/hooks/use-own-account'; import toast from 'pl-fe/toast'; import { isDefaultAvatar, isDefaultHeader } from 'pl-fe/utils/accounts'; @@ -173,7 +173,7 @@ const ProfileField: StreamfieldComponent = ({ index, va const EditProfile: React.FC = () => { const intl = useIntl(); const dispatch = useAppDispatch(); - const instance = useInstance(); + const { data: instance } = useInstance(); const { account } = useOwnAccount(); const features = useFeatures(); @@ -181,8 +181,7 @@ const EditProfile: React.FC = () => { ? instance.configuration.accounts.max_profile_fields : instance.pleroma.metadata.fields_limits.max_fields; - const attachmentTypes = useAppSelector( - state => state.instance.configuration.media_attachments.supported_mime_types) + const attachmentTypes = useInstance().data.configuration.media_attachments.supported_mime_types ?.filter(type => type.startsWith('image/')) .join(','); diff --git a/packages/pl-fe/src/features/federation-restrictions/components/instance-restrictions.tsx b/packages/pl-fe/src/features/federation-restrictions/components/instance-restrictions.tsx index b537c292e..7377a2ea0 100644 --- a/packages/pl-fe/src/features/federation-restrictions/components/instance-restrictions.tsx +++ b/packages/pl-fe/src/features/federation-restrictions/components/instance-restrictions.tsx @@ -1,11 +1,11 @@ import React from 'react'; import { FormattedMessage } from 'react-intl'; +import { useInstance } from 'pl-fe/api/hooks/instance/use-instance'; import Icon from 'pl-fe/components/icon'; import HStack from 'pl-fe/components/ui/hstack'; import Stack from 'pl-fe/components/ui/stack'; import Text from 'pl-fe/components/ui/text'; -import { useInstance } from 'pl-fe/hooks/use-instance'; import type { RemoteInstance } from 'pl-fe/selectors'; @@ -34,7 +34,7 @@ interface IInstanceRestrictions { } const InstanceRestrictions: React.FC = ({ remoteInstance }) => { - const instance = useInstance(); + const { data: instance } = useInstance(); const renderRestrictions = () => { const items = []; diff --git a/packages/pl-fe/src/features/federation-restrictions/components/restricted-instance.tsx b/packages/pl-fe/src/features/federation-restrictions/components/restricted-instance.tsx index f709a9385..0a0dd9aef 100644 --- a/packages/pl-fe/src/features/federation-restrictions/components/restricted-instance.tsx +++ b/packages/pl-fe/src/features/federation-restrictions/components/restricted-instance.tsx @@ -1,6 +1,7 @@ import clsx from 'clsx'; import React, { useState } from 'react'; +import { useInstance } from 'pl-fe/api/hooks/instance/use-instance'; import Icon from 'pl-fe/components/icon'; import { useAppSelector } from 'pl-fe/hooks/use-app-selector'; import { makeGetRemoteInstance } from 'pl-fe/selectors'; @@ -14,7 +15,8 @@ interface IRestrictedInstance { } const RestrictedInstance: React.FC = ({ host }) => { - const remoteInstance: any = useAppSelector((state) => getRemoteInstance(state, host)); + const { data: instance } = useInstance(); + const remoteInstance: any = useAppSelector((state) => getRemoteInstance(state, host, instance)); const [expanded, setExpanded] = useState(false); diff --git a/packages/pl-fe/src/features/federation-restrictions/index.tsx b/packages/pl-fe/src/features/federation-restrictions/index.tsx index 0c07d8bcd..16b716c7d 100644 --- a/packages/pl-fe/src/features/federation-restrictions/index.tsx +++ b/packages/pl-fe/src/features/federation-restrictions/index.tsx @@ -1,11 +1,11 @@ import React, { useState, useCallback } from 'react'; import { defineMessages, useIntl } from 'react-intl'; +import { useInstance } from 'pl-fe/api/hooks/instance/use-instance'; import ScrollableList from 'pl-fe/components/scrollable-list'; import Accordion from 'pl-fe/components/ui/accordion'; import Column from 'pl-fe/components/ui/column'; import { useAppSelector } from 'pl-fe/hooks/use-app-selector'; -import { useInstance } from 'pl-fe/hooks/use-instance'; import { makeGetHosts } from 'pl-fe/selectors'; import { federationRestrictionsDisclosed } from 'pl-fe/utils/state'; @@ -21,12 +21,12 @@ const messages = defineMessages({ const FederationRestrictions = () => { const intl = useIntl(); - const instance = useInstance(); + const { data: instance } = useInstance(); const getHosts = useCallback(makeGetHosts(), []); - const hosts = useAppSelector((state) => getHosts(state)); - const disclosed = useAppSelector((state) => federationRestrictionsDisclosed(state)); + const hosts = useAppSelector((state) => getHosts(state, instance)); + const disclosed = federationRestrictionsDisclosed(instance); const [explanationBoxExpanded, setExplanationBoxExpanded] = useState(true); diff --git a/packages/pl-fe/src/features/group/edit-group.tsx b/packages/pl-fe/src/features/group/edit-group.tsx index eb3ceefbe..936d1d4ae 100644 --- a/packages/pl-fe/src/features/group/edit-group.tsx +++ b/packages/pl-fe/src/features/group/edit-group.tsx @@ -3,6 +3,7 @@ import { defineMessages, FormattedMessage, useIntl } from 'react-intl'; import { useGroup } from 'pl-fe/api/hooks/groups/use-group'; import { useUpdateGroup } from 'pl-fe/api/hooks/groups/use-update-group'; +import { useInstance } from 'pl-fe/api/hooks/instance/use-instance'; import Button from 'pl-fe/components/ui/button'; import Column from 'pl-fe/components/ui/column'; import Form from 'pl-fe/components/ui/form'; @@ -14,8 +15,6 @@ import Spinner from 'pl-fe/components/ui/spinner'; import Textarea from 'pl-fe/components/ui/textarea'; import { useImageField } from 'pl-fe/hooks/forms/use-image-field'; import { useTextField } from 'pl-fe/hooks/forms/use-text-field'; -import { useAppSelector } from 'pl-fe/hooks/use-app-selector'; -import { useInstance } from 'pl-fe/hooks/use-instance'; import toast from 'pl-fe/toast'; import { isDefaultAvatar, isDefaultHeader } from 'pl-fe/utils/accounts'; import { unescapeHTML } from 'pl-fe/utils/html'; @@ -41,7 +40,7 @@ interface IEditGroup { const EditGroup: React.FC = ({ params: { groupId } }) => { const intl = useIntl(); - const instance = useInstance(); + const { data: instance } = useInstance(); const { group, isLoading } = useGroup(groupId); const { updateGroup } = useUpdateGroup(groupId); @@ -57,7 +56,7 @@ const EditGroup: React.FC = ({ params: { groupId } }) => { const maxName = Number(instance.configuration.groups.max_characters_name); const maxNote = Number(instance.configuration.groups.max_characters_description); - const attachmentTypes = useAppSelector(state => state.instance.configuration.media_attachments.supported_mime_types) + const attachmentTypes = useInstance().data.configuration.media_attachments.supported_mime_types ?.filter((type) => type.startsWith('image/')) .join(','); diff --git a/packages/pl-fe/src/features/home-timeline/index.tsx b/packages/pl-fe/src/features/home-timeline/index.tsx index cab35870d..c8646a566 100644 --- a/packages/pl-fe/src/features/home-timeline/index.tsx +++ b/packages/pl-fe/src/features/home-timeline/index.tsx @@ -3,6 +3,7 @@ import { defineMessages, useIntl, FormattedMessage } from 'react-intl'; import { Link } from 'react-router-dom'; import { fetchHomeTimeline } from 'pl-fe/actions/timelines'; +import { useInstance } from 'pl-fe/api/hooks/instance/use-instance'; import PullToRefresh from 'pl-fe/components/pull-to-refresh'; import Column from 'pl-fe/components/ui/column'; import Stack from 'pl-fe/components/ui/stack'; @@ -11,7 +12,6 @@ import Timeline from 'pl-fe/features/ui/components/timeline'; import { useAppDispatch } from 'pl-fe/hooks/use-app-dispatch'; import { useAppSelector } from 'pl-fe/hooks/use-app-selector'; import { useFeatures } from 'pl-fe/hooks/use-features'; -import { useInstance } from 'pl-fe/hooks/use-instance'; import { useIsMobile } from 'pl-fe/hooks/use-is-mobile'; import { useTheme } from 'pl-fe/hooks/use-theme'; @@ -23,7 +23,7 @@ const HomeTimeline: React.FC = () => { const intl = useIntl(); const dispatch = useAppDispatch(); const features = useFeatures(); - const instance = useInstance(); + const { data: instance } = useInstance(); const theme = useTheme(); const polling = useRef(null); diff --git a/packages/pl-fe/src/features/landing-timeline/components/site-banner.tsx b/packages/pl-fe/src/features/landing-timeline/components/site-banner.tsx index a82bcc84e..a3ab2be82 100644 --- a/packages/pl-fe/src/features/landing-timeline/components/site-banner.tsx +++ b/packages/pl-fe/src/features/landing-timeline/components/site-banner.tsx @@ -1,15 +1,15 @@ import React from 'react'; +import { useInstance } from 'pl-fe/api/hooks/instance/use-instance'; import Markup from 'pl-fe/components/markup'; import { ParsedContent } from 'pl-fe/components/parsed-content'; import Stack from 'pl-fe/components/ui/stack'; -import { useInstance } from 'pl-fe/hooks/use-instance'; import { getTextDirection } from 'pl-fe/utils/rtl'; import { LogoText } from './logo-text'; const SiteBanner: React.FC = () => { - const instance = useInstance(); + const { data: instance } = useInstance(); return ( diff --git a/packages/pl-fe/src/features/landing-timeline/index.tsx b/packages/pl-fe/src/features/landing-timeline/index.tsx index 25fc67af4..3d1c3e842 100644 --- a/packages/pl-fe/src/features/landing-timeline/index.tsx +++ b/packages/pl-fe/src/features/landing-timeline/index.tsx @@ -2,11 +2,11 @@ import React, { useEffect } from 'react'; import { FormattedMessage } from 'react-intl'; import { fetchPublicTimeline } from 'pl-fe/actions/timelines'; +import { useInstance } from 'pl-fe/api/hooks/instance/use-instance'; import { useCommunityStream } from 'pl-fe/api/hooks/streaming/use-community-stream'; import PullToRefresh from 'pl-fe/components/pull-to-refresh'; import Column from 'pl-fe/components/ui/column'; import { useAppDispatch } from 'pl-fe/hooks/use-app-dispatch'; -import { useInstance } from 'pl-fe/hooks/use-instance'; import { useIsMobile } from 'pl-fe/hooks/use-is-mobile'; import { useTheme } from 'pl-fe/hooks/use-theme'; @@ -17,7 +17,7 @@ import { SiteBanner } from './components/site-banner'; const LandingTimeline = () => { const dispatch = useAppDispatch(); - const instance = useInstance(); + const { data: instance } = useInstance(); const theme = useTheme(); const isMobile = useIsMobile(); diff --git a/packages/pl-fe/src/features/migration/index.tsx b/packages/pl-fe/src/features/migration/index.tsx index d1ca4df7f..779b4df4b 100644 --- a/packages/pl-fe/src/features/migration/index.tsx +++ b/packages/pl-fe/src/features/migration/index.tsx @@ -3,6 +3,7 @@ import { defineMessages, FormattedMessage, useIntl } from 'react-intl'; import { Link } from 'react-router-dom'; import { moveAccount } from 'pl-fe/actions/security'; +import { useInstance } from 'pl-fe/api/hooks/instance/use-instance'; import Button from 'pl-fe/components/ui/button'; import Column from 'pl-fe/components/ui/column'; import Form from 'pl-fe/components/ui/form'; @@ -11,7 +12,6 @@ import FormGroup from 'pl-fe/components/ui/form-group'; import Input from 'pl-fe/components/ui/input'; import Text from 'pl-fe/components/ui/text'; import { useAppDispatch } from 'pl-fe/hooks/use-app-dispatch'; -import { useInstance } from 'pl-fe/hooks/use-instance'; import toast from 'pl-fe/toast'; const messages = defineMessages({ @@ -28,7 +28,7 @@ const messages = defineMessages({ const Migration = () => { const intl = useIntl(); const dispatch = useAppDispatch(); - const instance = useInstance(); + const { data: instance } = useInstance(); const cooldownPeriod = instance.pleroma.metadata.migration_cooldown_period; diff --git a/packages/pl-fe/src/features/notifications/components/notification.tsx b/packages/pl-fe/src/features/notifications/components/notification.tsx index eeea9071c..dc815749e 100644 --- a/packages/pl-fe/src/features/notifications/components/notification.tsx +++ b/packages/pl-fe/src/features/notifications/components/notification.tsx @@ -4,6 +4,7 @@ import { Link, useHistory } from 'react-router-dom'; import { mentionCompose } from 'pl-fe/actions/compose'; import { reblog, favourite, unreblog, unfavourite } from 'pl-fe/actions/interactions'; +import { useInstance } from 'pl-fe/api/hooks/instance/use-instance'; import HoverAccountWrapper from 'pl-fe/components/hover-account-wrapper'; import Icon from 'pl-fe/components/icon'; import RelativeTimestamp from 'pl-fe/components/relative-timestamp'; @@ -16,7 +17,6 @@ import Emojify from 'pl-fe/features/emoji/emojify'; import { HotKeys } from 'pl-fe/features/ui/components/hotkeys'; import { useAppDispatch } from 'pl-fe/hooks/use-app-dispatch'; import { useAppSelector } from 'pl-fe/hooks/use-app-selector'; -import { useInstance } from 'pl-fe/hooks/use-instance'; import { useLoggedIn } from 'pl-fe/hooks/use-logged-in'; import { makeGetNotification } from 'pl-fe/selectors'; import { useModalsStore } from 'pl-fe/stores/modals'; @@ -212,7 +212,7 @@ const Notification: React.FC = (props) => { const history = useHistory(); const intl = useIntl(); - const instance = useInstance(); + const { data: instance } = useInstance(); const type = notification.type; const { accounts } = notification; diff --git a/packages/pl-fe/src/features/onboarding/steps/fediverse-step.tsx b/packages/pl-fe/src/features/onboarding/steps/fediverse-step.tsx index 46b0fbe78..2140cb79c 100644 --- a/packages/pl-fe/src/features/onboarding/steps/fediverse-step.tsx +++ b/packages/pl-fe/src/features/onboarding/steps/fediverse-step.tsx @@ -1,18 +1,18 @@ import React from 'react'; import { FormattedMessage } from 'react-intl'; +import { useInstance } from 'pl-fe/api/hooks/instance/use-instance'; import Account from 'pl-fe/components/account'; import Button from 'pl-fe/components/ui/button'; import Card, { CardBody } from 'pl-fe/components/ui/card'; import Icon from 'pl-fe/components/ui/icon'; import Stack from 'pl-fe/components/ui/stack'; import Text from 'pl-fe/components/ui/text'; -import { useInstance } from 'pl-fe/hooks/use-instance'; import { useOwnAccount } from 'pl-fe/hooks/use-own-account'; const FediverseStep = ({ onNext }: { onNext: () => void }) => { const { account } = useOwnAccount(); - const instance = useInstance(); + const { data: instance } = useInstance(); return ( diff --git a/packages/pl-fe/src/features/preferences/index.tsx b/packages/pl-fe/src/features/preferences/index.tsx index 306cbcbb1..e4c4e2609 100644 --- a/packages/pl-fe/src/features/preferences/index.tsx +++ b/packages/pl-fe/src/features/preferences/index.tsx @@ -2,13 +2,13 @@ import React from 'react'; import { defineMessages, FormattedMessage, useIntl } from 'react-intl'; import { changeSetting } from 'pl-fe/actions/settings'; +import { useInstance } from 'pl-fe/api/hooks/instance/use-instance'; import List, { ListItem } from 'pl-fe/components/list'; import Form from 'pl-fe/components/ui/form'; import { Mutliselect, SelectDropdown } from 'pl-fe/features/forms'; import SettingToggle from 'pl-fe/features/notifications/components/setting-toggle'; import { useAppDispatch } from 'pl-fe/hooks/use-app-dispatch'; import { useFeatures } from 'pl-fe/hooks/use-features'; -import { useInstance } from 'pl-fe/hooks/use-instance'; import { useSettings } from 'pl-fe/hooks/use-settings'; import ThemeToggle from '../ui/components/theme-toggle'; @@ -98,7 +98,7 @@ const Preferences = () => { const dispatch = useAppDispatch(); const features = useFeatures(); const settings = useSettings(); - const instance = useInstance(); + const { data: instance } = useInstance(); const onSelectChange = (event: React.ChangeEvent, path: string[]) => { dispatch(changeSetting(path, event.target.value, { showAlert: true })); diff --git a/packages/pl-fe/src/features/public-timeline/index.tsx b/packages/pl-fe/src/features/public-timeline/index.tsx index 9f64cbebd..977d1bd8c 100644 --- a/packages/pl-fe/src/features/public-timeline/index.tsx +++ b/packages/pl-fe/src/features/public-timeline/index.tsx @@ -4,12 +4,12 @@ import { Link } from 'react-router-dom'; import { changeSetting } from 'pl-fe/actions/settings'; import { fetchPublicTimeline } from 'pl-fe/actions/timelines'; +import { useInstance } from 'pl-fe/api/hooks/instance/use-instance'; import { usePublicStream } from 'pl-fe/api/hooks/streaming/use-public-stream'; import PullToRefresh from 'pl-fe/components/pull-to-refresh'; import Accordion from 'pl-fe/components/ui/accordion'; import Column from 'pl-fe/components/ui/column'; import { useAppDispatch } from 'pl-fe/hooks/use-app-dispatch'; -import { useInstance } from 'pl-fe/hooks/use-instance'; import { useIsMobile } from 'pl-fe/hooks/use-is-mobile'; import { useSettings } from 'pl-fe/hooks/use-settings'; import { useTheme } from 'pl-fe/hooks/use-theme'; @@ -27,7 +27,7 @@ const CommunityTimeline = () => { const dispatch = useAppDispatch(); const theme = useTheme(); - const instance = useInstance(); + const { data: instance } = useInstance(); const settings = useSettings(); const onlyMedia = settings.timelines.public?.other.onlyMedia ?? false; diff --git a/packages/pl-fe/src/features/register-invite/index.tsx b/packages/pl-fe/src/features/register-invite/index.tsx index 4591d3222..81af6fac2 100644 --- a/packages/pl-fe/src/features/register-invite/index.tsx +++ b/packages/pl-fe/src/features/register-invite/index.tsx @@ -2,9 +2,9 @@ import React from 'react'; import { FormattedMessage } from 'react-intl'; import { useParams } from 'react-router-dom'; +import { useInstance } from 'pl-fe/api/hooks/instance/use-instance'; import { BigCard } from 'pl-fe/components/big-card'; import RegistrationForm from 'pl-fe/features/auth-login/components/registration-form'; -import { useInstance } from 'pl-fe/hooks/use-instance'; interface RegisterInviteParams { token: string; @@ -12,7 +12,7 @@ interface RegisterInviteParams { /** Page to register with an invitation. */ const RegisterInvite: React.FC = () => { - const instance = useInstance(); + const { data: instance } = useInstance(); const { token } = useParams(); const title = ( diff --git a/packages/pl-fe/src/features/server-info/index.tsx b/packages/pl-fe/src/features/server-info/index.tsx index 3c2928ee3..7ced0eed0 100644 --- a/packages/pl-fe/src/features/server-info/index.tsx +++ b/packages/pl-fe/src/features/server-info/index.tsx @@ -1,11 +1,11 @@ import React from 'react'; import { defineMessages, useIntl } from 'react-intl'; +import { useInstance } from 'pl-fe/api/hooks/instance/use-instance'; import Column from 'pl-fe/components/ui/column'; import Divider from 'pl-fe/components/ui/divider'; import Stack from 'pl-fe/components/ui/stack'; import Text from 'pl-fe/components/ui/text'; -import { useInstance } from 'pl-fe/hooks/use-instance'; import LinkFooter from '../ui/components/link-footer'; import PromoPanel from '../ui/components/panels/promo-panel'; @@ -16,7 +16,7 @@ const messages = defineMessages({ const ServerInfo = () => { const intl = useIntl(); - const instance = useInstance(); + const { data: instance } = useInstance(); return ( diff --git a/packages/pl-fe/src/features/status/components/thread-login-cta.tsx b/packages/pl-fe/src/features/status/components/thread-login-cta.tsx index 1c3167dd6..c145925c4 100644 --- a/packages/pl-fe/src/features/status/components/thread-login-cta.tsx +++ b/packages/pl-fe/src/features/status/components/thread-login-cta.tsx @@ -1,16 +1,16 @@ import React from 'react'; import { FormattedMessage } from 'react-intl'; +import { useInstance } from 'pl-fe/api/hooks/instance/use-instance'; import Button from 'pl-fe/components/ui/button'; import Card, { CardTitle } from 'pl-fe/components/ui/card'; import Stack from 'pl-fe/components/ui/stack'; import Text from 'pl-fe/components/ui/text'; -import { useInstance } from 'pl-fe/hooks/use-instance'; import { usePlFeConfig } from 'pl-fe/hooks/use-pl-fe-config'; /** Prompts logged-out users to log in when viewing a thread. */ const ThreadLoginCta: React.FC = () => { - const instance = useInstance(); + const { data: instance } = useInstance(); const { displayCta } = usePlFeConfig(); if (!displayCta) return null; diff --git a/packages/pl-fe/src/features/ui/components/modals/edit-federation-modal.tsx b/packages/pl-fe/src/features/ui/components/modals/edit-federation-modal.tsx index 13127c475..5766626ed 100644 --- a/packages/pl-fe/src/features/ui/components/modals/edit-federation-modal.tsx +++ b/packages/pl-fe/src/features/ui/components/modals/edit-federation-modal.tsx @@ -2,6 +2,7 @@ import React, { useState, useEffect, useCallback } from 'react'; import { defineMessages, FormattedMessage, useIntl } from 'react-intl'; import { updateMrf } from 'pl-fe/actions/mrf'; +import { useInstance } from 'pl-fe/api/hooks/instance/use-instance'; import List, { ListItem } from 'pl-fe/components/list'; import Modal from 'pl-fe/components/ui/modal'; import Toggle from 'pl-fe/components/ui/toggle'; @@ -30,8 +31,9 @@ const EditFederationModal: React.FC = const intl = useIntl(); const dispatch = useAppDispatch(); + const { data: instance } = useInstance(); const getRemoteInstance = useCallback(makeGetRemoteInstance(), []); - const remoteInstance = useAppSelector(state => getRemoteInstance(state, host)); + const remoteInstance = useAppSelector(state => getRemoteInstance(state, host, instance)); const [data, setData] = useState>({}); diff --git a/packages/pl-fe/src/features/ui/components/modals/manage-group-modal/steps/details-step.tsx b/packages/pl-fe/src/features/ui/components/modals/manage-group-modal/steps/details-step.tsx index e269632ab..48397c5f6 100644 --- a/packages/pl-fe/src/features/ui/components/modals/manage-group-modal/steps/details-step.tsx +++ b/packages/pl-fe/src/features/ui/components/modals/manage-group-modal/steps/details-step.tsx @@ -1,6 +1,7 @@ import React from 'react'; import { defineMessages, FormattedMessage, useIntl } from 'react-intl'; +import { useInstance } from 'pl-fe/api/hooks/instance/use-instance'; import Form from 'pl-fe/components/ui/form'; import FormGroup from 'pl-fe/components/ui/form-group'; import Input from 'pl-fe/components/ui/input'; @@ -8,8 +9,6 @@ import Textarea from 'pl-fe/components/ui/textarea'; import AvatarPicker from 'pl-fe/features/edit-profile/components/avatar-picker'; import HeaderPicker from 'pl-fe/features/edit-profile/components/header-picker'; import { usePreview } from 'pl-fe/hooks/forms/use-preview'; -import { useAppSelector } from 'pl-fe/hooks/use-app-selector'; -import { useInstance } from 'pl-fe/hooks/use-instance'; import resizeImage from 'pl-fe/utils/resize-image'; import type { CreateGroupParams } from 'pl-api'; @@ -27,7 +26,7 @@ interface IDetailsStep { const DetailsStep: React.FC = ({ params, onChange }) => { const intl = useIntl(); - const instance = useInstance(); + const { data: instance } = useInstance(); const { display_name: displayName = '', @@ -37,7 +36,7 @@ const DetailsStep: React.FC = ({ params, onChange }) => { const avatarSrc = usePreview(params.avatar); const headerSrc = usePreview(params.header); - const attachmentTypes = useAppSelector(state => state.instance.configuration.media_attachments.supported_mime_types) + const attachmentTypes = useInstance().data.configuration.media_attachments.supported_mime_types ?.filter((type) => type.startsWith('image/')) .join(','); diff --git a/packages/pl-fe/src/features/ui/components/modals/report-modal/index.tsx b/packages/pl-fe/src/features/ui/components/modals/report-modal/index.tsx index e949a7b9f..c8f203e56 100644 --- a/packages/pl-fe/src/features/ui/components/modals/report-modal/index.tsx +++ b/packages/pl-fe/src/features/ui/components/modals/report-modal/index.tsx @@ -5,6 +5,7 @@ import { blockAccount } from 'pl-fe/actions/accounts'; import { submitReport, ReportableEntities } from 'pl-fe/actions/reports'; import { fetchAccountTimeline } from 'pl-fe/actions/timelines'; import { useAccount } from 'pl-fe/api/hooks/accounts/use-account'; +import { useInstance } from 'pl-fe/api/hooks/instance/use-instance'; import AttachmentThumbs from 'pl-fe/components/attachment-thumbs'; import StatusContent from 'pl-fe/components/status-content'; import Modal from 'pl-fe/components/ui/modal'; @@ -14,7 +15,6 @@ import Text from 'pl-fe/components/ui/text'; import AccountContainer from 'pl-fe/containers/account-container'; import { useAppDispatch } from 'pl-fe/hooks/use-app-dispatch'; import { useAppSelector } from 'pl-fe/hooks/use-app-selector'; -import { useInstance } from 'pl-fe/hooks/use-instance'; import ConfirmationStep from './steps/confirmation-step'; import OtherActionsStep from './steps/other-actions-step'; @@ -83,7 +83,7 @@ const ReportModal: React.FC = ({ onClose, acc const [block, setBlock] = useState(false); const [isSubmitting, setIsSubmitting] = useState(false); - const { rules } = useInstance(); + const { rules } = useInstance().data; const [ruleIds, setRuleIds] = useState>([]); const [selectedStatusIds, setSelectedStatusIds] = useState(statusIds); const [comment, setComment] = useState(''); diff --git a/packages/pl-fe/src/features/ui/components/modals/report-modal/steps/reason-step.tsx b/packages/pl-fe/src/features/ui/components/modals/report-modal/steps/reason-step.tsx index fd4b9ac86..3e9fa59c4 100644 --- a/packages/pl-fe/src/features/ui/components/modals/report-modal/steps/reason-step.tsx +++ b/packages/pl-fe/src/features/ui/components/modals/report-modal/steps/reason-step.tsx @@ -2,11 +2,11 @@ import clsx from 'clsx'; import React, { useEffect, useRef, useState } from 'react'; import { defineMessages, useIntl } from 'react-intl'; +import { useInstance } from 'pl-fe/api/hooks/instance/use-instance'; import FormGroup from 'pl-fe/components/ui/form-group'; import Stack from 'pl-fe/components/ui/stack'; import Text from 'pl-fe/components/ui/text'; import Textarea from 'pl-fe/components/ui/textarea'; -import { useInstance } from 'pl-fe/hooks/use-instance'; import type { Account } from 'pl-fe/normalizers/account'; @@ -33,7 +33,7 @@ const ReasonStep: React.FC = ({ comment, setComment, ruleIds, setRu const [isNearBottom, setNearBottom] = useState(false); const [isNearTop, setNearTop] = useState(true); - const { rules } = useInstance(); + const { rules } = useInstance().data; const shouldRequireRule = rules.length > 0; const handleCommentChange = (event: React.ChangeEvent) => { diff --git a/packages/pl-fe/src/features/ui/components/modals/unauthorized-modal.tsx b/packages/pl-fe/src/features/ui/components/modals/unauthorized-modal.tsx index 2fb49f939..7bda58852 100644 --- a/packages/pl-fe/src/features/ui/components/modals/unauthorized-modal.tsx +++ b/packages/pl-fe/src/features/ui/components/modals/unauthorized-modal.tsx @@ -3,6 +3,7 @@ import { defineMessages, useIntl, FormattedMessage } from 'react-intl'; import { useHistory } from 'react-router-dom'; import { remoteInteraction } from 'pl-fe/actions/interactions'; +import { useInstance } from 'pl-fe/api/hooks/instance/use-instance'; import Button from 'pl-fe/components/ui/button'; import Form from 'pl-fe/components/ui/form'; import Input from 'pl-fe/components/ui/input'; @@ -12,7 +13,6 @@ import Text from 'pl-fe/components/ui/text'; import { useAppDispatch } from 'pl-fe/hooks/use-app-dispatch'; import { useAppSelector } from 'pl-fe/hooks/use-app-selector'; import { useFeatures } from 'pl-fe/hooks/use-features'; -import { useInstance } from 'pl-fe/hooks/use-instance'; import { useRegistrationStatus } from 'pl-fe/hooks/use-registration-status'; import { selectAccount } from 'pl-fe/selectors'; import toast from 'pl-fe/toast'; @@ -40,7 +40,7 @@ const UnauthorizedModal: React.FC = ({ const intl = useIntl(); const history = useHistory(); const dispatch = useAppDispatch(); - const instance = useInstance(); + const { data: instance } = useInstance(); const { isOpen } = useRegistrationStatus(); const username = useAppSelector(state => selectAccount(state, accountId!)?.display_name); diff --git a/packages/pl-fe/src/features/ui/components/panels/instance-info-panel.tsx b/packages/pl-fe/src/features/ui/components/panels/instance-info-panel.tsx index 3273c4fe7..b88fe2203 100644 --- a/packages/pl-fe/src/features/ui/components/panels/instance-info-panel.tsx +++ b/packages/pl-fe/src/features/ui/components/panels/instance-info-panel.tsx @@ -2,6 +2,7 @@ import React from 'react'; import { useIntl, defineMessages } from 'react-intl'; import { pinHost, unpinHost } from 'pl-fe/actions/remote-timeline'; +import { useInstance } from 'pl-fe/api/hooks/instance/use-instance'; import Widget from 'pl-fe/components/ui/widget'; import { useAppDispatch } from 'pl-fe/hooks/use-app-dispatch'; import { useAppSelector } from 'pl-fe/hooks/use-app-selector'; @@ -26,8 +27,9 @@ const InstanceInfoPanel: React.FC = ({ host }) => { const dispatch = useAppDispatch(); const settings = useSettings(); - const remoteInstance: any = useAppSelector(state => getRemoteInstance(state, host)); const pinned = settings.remote_timeline.pinnedHosts.includes(host); + const { data: instance } = useInstance(); + const remoteInstance = useAppSelector(state => getRemoteInstance(state, host, instance)); const handlePinHost = () => { if (!pinned) { diff --git a/packages/pl-fe/src/features/ui/components/panels/instance-moderation-panel.tsx b/packages/pl-fe/src/features/ui/components/panels/instance-moderation-panel.tsx index e0c55aa00..f344f5d48 100644 --- a/packages/pl-fe/src/features/ui/components/panels/instance-moderation-panel.tsx +++ b/packages/pl-fe/src/features/ui/components/panels/instance-moderation-panel.tsx @@ -1,6 +1,7 @@ import React from 'react'; import { useIntl, defineMessages, FormattedMessage } from 'react-intl'; +import { useInstance } from 'pl-fe/api/hooks/instance/use-instance'; import DropdownMenu from 'pl-fe/components/dropdown-menu'; import Widget from 'pl-fe/components/ui/widget'; import InstanceRestrictions from 'pl-fe/features/federation-restrictions/components/instance-restrictions'; @@ -25,8 +26,9 @@ const InstanceModerationPanel: React.FC = ({ host }) = const intl = useIntl(); const { openModal } = useModalsStore(); + const { data: instance } = useInstance(); const { account } = useOwnAccount(); - const remoteInstance = useAppSelector(state => getRemoteInstance(state, host)); + const remoteInstance = useAppSelector(state => getRemoteInstance(state, host, instance)); const handleEditFederation = () => { openModal('EDIT_FEDERATION', { host }); diff --git a/packages/pl-fe/src/features/ui/components/panels/promo-panel.tsx b/packages/pl-fe/src/features/ui/components/panels/promo-panel.tsx index 80eef9584..165517d23 100644 --- a/packages/pl-fe/src/features/ui/components/panels/promo-panel.tsx +++ b/packages/pl-fe/src/features/ui/components/panels/promo-panel.tsx @@ -1,15 +1,15 @@ import React from 'react'; +import { useInstance } from 'pl-fe/api/hooks/instance/use-instance'; import ForkAwesomeIcon from 'pl-fe/components/fork-awesome-icon'; import List, { ListItem } from 'pl-fe/components/list'; import HStack from 'pl-fe/components/ui/hstack'; import Widget from 'pl-fe/components/ui/widget'; -import { useInstance } from 'pl-fe/hooks/use-instance'; import { usePlFeConfig } from 'pl-fe/hooks/use-pl-fe-config'; import { useSettings } from 'pl-fe/hooks/use-settings'; const PromoPanel: React.FC = () => { - const instance = useInstance(); + const { data: instance } = useInstance(); const { promoPanel } = usePlFeConfig(); const { locale } = useSettings(); diff --git a/packages/pl-fe/src/features/ui/components/panels/sign-up-panel.tsx b/packages/pl-fe/src/features/ui/components/panels/sign-up-panel.tsx index 201f3f4d7..cb265daa2 100644 --- a/packages/pl-fe/src/features/ui/components/panels/sign-up-panel.tsx +++ b/packages/pl-fe/src/features/ui/components/panels/sign-up-panel.tsx @@ -3,7 +3,7 @@ import { FormattedMessage } from 'react-intl'; import { Redirect } from 'react-router-dom'; import { logIn, switchAccount, verifyCredentials } from 'pl-fe/actions/auth'; -import { fetchInstance } from 'pl-fe/actions/instance'; +import { useInstance } from 'pl-fe/api/hooks/instance/use-instance'; import Button from 'pl-fe/components/ui/button'; import Stack from 'pl-fe/components/ui/stack'; import Text from 'pl-fe/components/ui/text'; @@ -12,7 +12,6 @@ import OtpAuthForm from 'pl-fe/features/auth-login/components/otp-auth-form'; import ExternalLoginForm from 'pl-fe/features/external-login/components/external-login-form'; import { useAppDispatch } from 'pl-fe/hooks/use-app-dispatch'; import { useAppSelector } from 'pl-fe/hooks/use-app-selector'; -import { useInstance } from 'pl-fe/hooks/use-instance'; import { useRegistrationStatus } from 'pl-fe/hooks/use-registration-status'; import { getRedirectUrl } from 'pl-fe/utils/redirect'; import { isStandalone } from 'pl-fe/utils/state'; @@ -21,7 +20,7 @@ import type { PlfeResponse } from 'pl-fe/api'; const SignUpPanel = () => { const dispatch = useAppDispatch(); - const instance = useInstance(); + const { data: instance } = useInstance(); const { isOpen } = useRegistrationStatus(); const me = useAppSelector((state) => state.me); const standalone = useAppSelector(isStandalone); @@ -42,11 +41,6 @@ const SignUpPanel = () => { const { username, password } = getFormData(event.target as HTMLFormElement); dispatch(logIn(username, password)) .then(({ access_token }) => dispatch(verifyCredentials(access_token as string))) - // Refetch the instance for authenticated fetch - .then(async (account) => { - await dispatch(fetchInstance()); - return account; - }) .then((account: { id: string }) => { if (typeof me === 'string') { dispatch(switchAccount(account.id)); diff --git a/packages/pl-fe/src/features/ui/index.tsx b/packages/pl-fe/src/features/ui/index.tsx index 05b8bc729..dbe28f08b 100644 --- a/packages/pl-fe/src/features/ui/index.tsx +++ b/packages/pl-fe/src/features/ui/index.tsx @@ -12,6 +12,7 @@ import { expandNotifications } from 'pl-fe/actions/notifications'; import { register as registerPushNotifications } from 'pl-fe/actions/push-notifications/registerer'; import { fetchScheduledStatuses } from 'pl-fe/actions/scheduled-statuses'; import { fetchHomeTimeline } from 'pl-fe/actions/timelines'; +import { useInstance } from 'pl-fe/api/hooks/instance/use-instance'; import { useUserStream } from 'pl-fe/api/hooks/streaming/use-user-stream'; import SidebarNavigation from 'pl-fe/components/sidebar-navigation'; import ThumbNavigation from 'pl-fe/components/thumb-navigation'; @@ -20,7 +21,6 @@ import { useAppDispatch } from 'pl-fe/hooks/use-app-dispatch'; import { useAppSelector } from 'pl-fe/hooks/use-app-selector'; import { useDraggedFiles } from 'pl-fe/hooks/use-dragged-files'; import { useFeatures } from 'pl-fe/hooks/use-features'; -import { useInstance } from 'pl-fe/hooks/use-instance'; import { useLoggedIn } from 'pl-fe/hooks/use-logged-in'; import { useOwnAccount } from 'pl-fe/hooks/use-own-account'; import { usePlFeConfig } from 'pl-fe/hooks/use-pl-fe-config'; @@ -41,7 +41,6 @@ import RemoteInstanceLayout from 'pl-fe/layouts/remote-instance-layout'; import SearchLayout from 'pl-fe/layouts/search-layout'; import StatusLayout from 'pl-fe/layouts/status-layout'; import { useUiStore } from 'pl-fe/stores/ui'; -import { getVapidKey } from 'pl-fe/utils/auth'; import { isStandalone } from 'pl-fe/utils/state'; import BackgroundShapes from './components/background-shapes'; @@ -146,13 +145,14 @@ import { WrappedRoute } from './util/react-router-helpers'; // Dummy import, to make sure that ends up in the application bundle. // Without this it ends up in ~8 very commonly used bundles. import 'pl-fe/components/status'; +import { useVapidKey } from 'pl-fe/hooks/use-vapid-key'; interface ISwitchingColumnsArea { children: React.ReactNode; } const SwitchingColumnsArea: React.FC = ({ children }) => { - const instance = useInstance(); + const { data: instance } = useInstance(); const features = useFeatures(); const { search } = useLocation(); const { isLoggedIn } = useLoggedIn(); @@ -361,7 +361,7 @@ const UI: React.FC = ({ children }) => { const me = useAppSelector(state => state.me); const { account } = useOwnAccount(); const features = useFeatures(); - const vapidKey = useAppSelector(state => getVapidKey(state)); + const vapidKey = useVapidKey(); const { isDropdownMenuOpen } = useUiStore(); const standalone = useAppSelector(isStandalone); @@ -447,7 +447,7 @@ const UI: React.FC = ({ children }) => { }, [!!account]); useEffect(() => { - dispatch(registerPushNotifications()); + dispatch(registerPushNotifications(vapidKey)); }, [vapidKey]); // Wait for login to succeed or fail diff --git a/packages/pl-fe/src/hooks/use-features.ts b/packages/pl-fe/src/hooks/use-features.ts index 0b6560f76..81fb49024 100644 --- a/packages/pl-fe/src/hooks/use-features.ts +++ b/packages/pl-fe/src/hooks/use-features.ts @@ -1,7 +1,8 @@ import { Features } from 'pl-api'; +import { useInstance } from 'pl-fe/api/hooks/instance/use-instance'; + import { useAppSelector } from './use-app-selector'; -import { useInstance } from './use-instance'; /** Get features for the current instance. */ const useFeatures = (): Features => { diff --git a/packages/pl-fe/src/hooks/use-instance.ts b/packages/pl-fe/src/hooks/use-instance.ts deleted file mode 100644 index 4c94a4ab2..000000000 --- a/packages/pl-fe/src/hooks/use-instance.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { useAppSelector } from './use-app-selector'; - -/** Get the Instance for the current backend. */ -const useInstance = () => useAppSelector((state) => state.instance); - -export { useInstance }; diff --git a/packages/pl-fe/src/hooks/use-registration-status.ts b/packages/pl-fe/src/hooks/use-registration-status.ts index aa4700e24..8ab5d48ab 100644 --- a/packages/pl-fe/src/hooks/use-registration-status.ts +++ b/packages/pl-fe/src/hooks/use-registration-status.ts @@ -1,8 +1,9 @@ +import { useInstance } from 'pl-fe/api/hooks/instance/use-instance'; + import { useFeatures } from './use-features'; -import { useInstance } from './use-instance'; const useRegistrationStatus = () => { - const instance = useInstance(); + const { data: instance } = useInstance(); const features = useFeatures(); return { diff --git a/packages/pl-fe/src/hooks/use-vapid-key.ts b/packages/pl-fe/src/hooks/use-vapid-key.ts new file mode 100644 index 000000000..b52879aed --- /dev/null +++ b/packages/pl-fe/src/hooks/use-vapid-key.ts @@ -0,0 +1,11 @@ +import { useInstance } from 'pl-fe/api/hooks/instance/use-instance'; + +import { useAppSelector } from './use-app-selector'; + +const useVapidKey = () => { + const { data: instance } = useInstance(); + + return useAppSelector((state) => instance.configuration.vapid.public_key || state.auth.app?.vapid_key); +}; + +export { useVapidKey }; diff --git a/packages/pl-fe/src/init/pl-fe-load.tsx b/packages/pl-fe/src/init/pl-fe-load.tsx index cfcc6be64..bbe56dbbd 100644 --- a/packages/pl-fe/src/init/pl-fe-load.tsx +++ b/packages/pl-fe/src/init/pl-fe-load.tsx @@ -1,9 +1,9 @@ import React, { useState, useEffect } from 'react'; import { IntlProvider } from 'react-intl'; -import { fetchInstance } from 'pl-fe/actions/instance'; import { fetchMe } from 'pl-fe/actions/me'; import { loadPlFeConfig } from 'pl-fe/actions/pl-fe'; +import { useInstance } from 'pl-fe/api/hooks/instance/use-instance'; import LoadingScreen from 'pl-fe/components/loading-screen'; import { useAppDispatch } from 'pl-fe/hooks/use-app-dispatch'; import { useAppSelector } from 'pl-fe/hooks/use-app-selector'; @@ -17,8 +17,6 @@ const loadInitial = () => { return async(dispatch, getState) => { // Await for authenticated fetch await dispatch(fetchMe()); - // Await for feature detection - await dispatch(fetchInstance()); // Await for configuration await dispatch(loadPlFeConfig()); }; @@ -31,6 +29,7 @@ interface IPlFeLoad { /** Initial data loader. */ const PlFeLoad: React.FC = ({ children }) => { const dispatch = useAppDispatch(); + const { isLoading: isLoadingInstance } = useInstance(); const me = useAppSelector(state => state.me); const { account } = useOwnAccount(); @@ -46,6 +45,7 @@ const PlFeLoad: React.FC = ({ children }) => { me && !account, !isLoaded, localeLoading, + isLoadingInstance, ].some(Boolean); // Load the user's locale diff --git a/packages/pl-fe/src/initial-state.ts b/packages/pl-fe/src/initial-state.ts new file mode 100644 index 000000000..9dcdce221 --- /dev/null +++ b/packages/pl-fe/src/initial-state.ts @@ -0,0 +1,11 @@ +import { decodeFromMarkup, pleromaDecoder } from './actions/preload'; + +let initialState: Record = {}; + +try { + initialState = decodeFromMarkup('initial-results', pleromaDecoder); +} catch (e) { + // +} + +export { initialState }; diff --git a/packages/pl-fe/src/layouts/remote-instance-layout.tsx b/packages/pl-fe/src/layouts/remote-instance-layout.tsx index 424f903aa..4ecc060a6 100644 --- a/packages/pl-fe/src/layouts/remote-instance-layout.tsx +++ b/packages/pl-fe/src/layouts/remote-instance-layout.tsx @@ -10,6 +10,7 @@ import { import { useAppSelector } from 'pl-fe/hooks/use-app-selector'; import { useOwnAccount } from 'pl-fe/hooks/use-own-account'; import { federationRestrictionsDisclosed } from 'pl-fe/utils/state'; +import { useInstance } from 'pl-fe/api/hooks/instance/use-instance'; interface IRemoteInstanceLayout { params?: { @@ -23,7 +24,8 @@ const RemoteInstanceLayout: React.FC = ({ children, param const host = params!.instance!; const { account } = useOwnAccount(); - const disclosed = useAppSelector(federationRestrictionsDisclosed); + const { data: instance } = useInstance(); + const disclosed = federationRestrictionsDisclosed(instance); return ( <> diff --git a/packages/pl-fe/src/reducers/compose.ts b/packages/pl-fe/src/reducers/compose.ts index d68a931bb..853904fd2 100644 --- a/packages/pl-fe/src/reducers/compose.ts +++ b/packages/pl-fe/src/reducers/compose.ts @@ -1,7 +1,5 @@ import { create } from 'mutative'; -import { type CredentialAccount, type Instance, type MediaAttachment, type Tag } from 'pl-api'; -import { INSTANCE_FETCH_SUCCESS, type InstanceAction } from 'pl-fe/actions/instance'; import { isNativeEmoji, type Emoji } from 'pl-fe/features/emoji'; import { tagHistory } from 'pl-fe/settings'; @@ -67,6 +65,7 @@ import { FE_NAME } from '../actions/settings'; import { TIMELINE_DELETE, type TimelineAction } from '../actions/timelines'; import { unescapeHTML } from '../utils/html'; +import type { CredentialAccount, MediaAttachment, Tag } from 'pl-api'; import type { Language } from 'pl-fe/features/preferences'; import type { Account } from 'pl-fe/normalizers/account'; import type { Status } from 'pl-fe/normalizers/status'; @@ -310,11 +309,11 @@ const importAccount = (compose: Compose, account: CredentialAccount) => { // } // }; -const updateDefaultContentType = (compose: Compose, instance: Instance) => { - const postFormats = instance.pleroma.metadata.post_formats; +// const updateDefaultContentType = (compose: Compose, instance: Instance) => { +// const postFormats = instance.pleroma.metadata.post_formats; - compose.content_type = postFormats.includes(compose.content_type) ? compose.content_type : postFormats.includes('text/markdown') ? 'text/markdown' : postFormats[0]; -}; +// compose.content_type = postFormats.includes(compose.content_type) ? compose.content_type : postFormats.includes('text/markdown') ? 'text/markdown' : postFormats[0]; +// }; const updateCompose = (state: State, key: string, updater: (compose: Compose) => void) => create(state, draft => { @@ -327,7 +326,7 @@ const initialState: State = { default: newCompose({ idempotencyKey: crypto.randomUUID(), resetFileKey: getResetFileKey() }), }; -const compose = (state = initialState, action: ComposeAction | EventsAction | InstanceAction | MeAction | TimelineAction): State => { +const compose = (state = initialState, action: ComposeAction | EventsAction | MeAction | TimelineAction): State => { switch (action.type) { case COMPOSE_TYPE_CHANGE: return updateCompose(state, action.composeId, compose => { @@ -688,8 +687,6 @@ const compose = (state = initialState, action: ComposeAction | EventsAction | In return updateCompose(state, action.composeId, compose => { compose.federated = !compose.federated; }); - case INSTANCE_FETCH_SUCCESS: - return updateCompose(state, 'default', (compose) => updateDefaultContentType(compose, action.instance)); default: return state; } diff --git a/packages/pl-fe/src/reducers/index.ts b/packages/pl-fe/src/reducers/index.ts index 945556710..c26ad4915 100644 --- a/packages/pl-fe/src/reducers/index.ts +++ b/packages/pl-fe/src/reducers/index.ts @@ -18,7 +18,6 @@ import domain_lists from './domain-lists'; import draft_statuses from './draft-statuses'; import filters from './filters'; import followed_tags from './followed-tags'; -import instance from './instance'; import listAdder from './list-adder'; import listEditor from './list-editor'; import lists from './lists'; @@ -54,7 +53,6 @@ const reducers = { entities, filters, followed_tags, - instance, listAdder, listEditor, lists, @@ -87,8 +85,8 @@ const logOut = (state: AppState): ReturnType => { const newState = rootReducer(undefined, { type: '' }); - const { instance, plfe, custom_emojis, auth } = state; - return { ...newState, instance, plfe, custom_emojis, auth }; + const { plfe, custom_emojis, auth } = state; + return { ...newState, plfe, custom_emojis, auth }; }; const rootReducer: typeof appReducer = (state, action) => { diff --git a/packages/pl-fe/src/reducers/instance.ts b/packages/pl-fe/src/reducers/instance.ts index 9d4475dc5..96312b8c3 100644 --- a/packages/pl-fe/src/reducers/instance.ts +++ b/packages/pl-fe/src/reducers/instance.ts @@ -1,102 +1,8 @@ -import { create } from 'mutative'; -import { type Instance, instanceSchema, PleromaConfig } from 'pl-api'; +import { instanceSchema } from 'pl-api'; import * as v from 'valibot'; -import { ADMIN_CONFIG_UPDATE_REQUEST, ADMIN_CONFIG_UPDATE_SUCCESS, type AdminActions } from 'pl-fe/actions/admin'; -import { INSTANCE_FETCH_FAIL, INSTANCE_FETCH_SUCCESS, type InstanceAction } from 'pl-fe/actions/instance'; -import { PLEROMA_PRELOAD_IMPORT, type PreloadAction } from 'pl-fe/actions/preload'; -import KVStore from 'pl-fe/storage/kv-store'; -import ConfigDB from 'pl-fe/utils/config-db'; +const initialState = v.parse(instanceSchema, {}); -const initialState: State = v.parse(instanceSchema, {}); +const instance = () => initialState; -type State = Instance; - -const preloadImport = (state: State, action: Record, path: string) => { - const instance = action.data[path]; - return instance ? v.parse(instanceSchema, instance) : state; -}; - -const getConfigValue = (instanceConfig: Array, key: string) => { - const v = instanceConfig - .find(value => value?.tuple?.[0] === key); - - return v ? v?.tuple?.[1] : undefined; -}; - -const importConfigs = (state: State, configs: PleromaConfig['configs']) => { - // FIXME: This is pretty hacked together. Need to make a cleaner map. - const config = ConfigDB.find(configs, ':pleroma', ':instance'); - const simplePolicy = ConfigDB.toSimplePolicy(configs); - - if (!config && !simplePolicy) return state; - - if (config) { - const value = config.value || []; - const registrationsOpen = getConfigValue(value, ':registrations_open') as boolean | undefined; - const approvalRequired = getConfigValue(value, ':account_approval_required') as boolean | undefined; - - state.registrations = { - enabled: registrationsOpen ?? state.registrations.enabled, - approval_required: approvalRequired ?? state.registrations.approval_required, - }; - } - - if (simplePolicy) { - state.pleroma.metadata.federation.mrf_simple = simplePolicy; - } -}; - -const handleAuthFetch = (state: State) => { - // Authenticated fetch is enabled, so make the instance appear censored - return { - ...state, - title: state.title || '██████', - description: state.description || '████████████', - }; -}; - -const getHost = (instance: { domain: string }) => { - const domain = instance.domain; - try { - return new URL(domain).host; - } catch { - try { - return new URL(`https://${domain}`).host; - } catch { - return null; - } - } -}; - -const persistInstance = (instance: { domain: string }, host: string | null = getHost(instance)) => { - if (host) { - KVStore.setItem(`instance:${host}`, instance).catch(console.error); - } -}; - -const handleInstanceFetchFail = (state: State, error: any) => { - if (error.response?.status === 401) { - return handleAuthFetch(state); - } else { - return state; - } -}; - -const instance = (state = initialState, action: AdminActions | InstanceAction | PreloadAction): State => { - switch (action.type) { - case PLEROMA_PRELOAD_IMPORT: - return create(state, (draft) => preloadImport(draft, action, '/api/v1/instance')); - case INSTANCE_FETCH_SUCCESS: - persistInstance(action.instance); - return action.instance; - case INSTANCE_FETCH_FAIL: - return handleInstanceFetchFail(state, action.error); - case ADMIN_CONFIG_UPDATE_REQUEST: - case ADMIN_CONFIG_UPDATE_SUCCESS: - return create(state, (draft) => importConfigs(draft, action.configs)); - default: - return state; - } -}; export { instance as default }; diff --git a/packages/pl-fe/src/reducers/meta.ts b/packages/pl-fe/src/reducers/meta.ts index 78e5e9f3b..4ab9d37e1 100644 --- a/packages/pl-fe/src/reducers/meta.ts +++ b/packages/pl-fe/src/reducers/meta.ts @@ -1,20 +1,10 @@ -import { INSTANCE_FETCH_FAIL, type InstanceAction } from 'pl-fe/actions/instance'; +import type { AnyAction } from 'redux'; const initialState = { /** Whether /api/v1/instance 404'd (and we should display the external auth form). */ instance_fetch_failed: false, }; -const meta = (state = initialState, action: InstanceAction): typeof initialState => { - switch (action.type) { - case INSTANCE_FETCH_FAIL: - if ((action.error as any)?.response?.status === 404) { - return { instance_fetch_failed: true }; - } - return state; - default: - return state; - } -}; +const meta = (state = initialState, action: AnyAction): typeof initialState => state; export { meta as default }; diff --git a/packages/pl-fe/src/selectors/index.ts b/packages/pl-fe/src/selectors/index.ts index 1eddc1584..dd538d5ce 100644 --- a/packages/pl-fe/src/selectors/index.ts +++ b/packages/pl-fe/src/selectors/index.ts @@ -8,7 +8,7 @@ import { validId } from 'pl-fe/utils/auth'; import ConfigDB from 'pl-fe/utils/config-db'; import { shouldFilter } from 'pl-fe/utils/timelines'; -import type { Account as BaseAccount, Filter, MediaAttachment, NotificationGroup, Relationship } from 'pl-api'; +import type { Account as BaseAccount, Filter, Instance, MediaAttachment, NotificationGroup, Relationship } from 'pl-api'; import type { EntityStore } from 'pl-fe/entity-store/types'; import type { Account } from 'pl-fe/normalizers/account'; import type { Group } from 'pl-fe/normalizers/group'; @@ -275,7 +275,7 @@ const makeGetOtherAccounts = () => createSelector([ const getSimplePolicy = createSelector([ (state: RootState) => state.admin.configs, - (state: RootState) => state.instance.pleroma.metadata.federation.mrf_simple, + (_state: RootState, instance: Instance) => instance.pleroma.metadata.federation.mrf_simple, ], (configs, instancePolicy) => ({ ...instancePolicy, ...ConfigDB.toSimplePolicy(configs), @@ -291,8 +291,8 @@ type HostFederation = { [key in keyof MRFSimple]: boolean; }; -const getRemoteInstanceFederation = (state: RootState, host: string): HostFederation => { - const simplePolicy = getSimplePolicy(state); +const getRemoteInstanceFederation = (state: RootState, host: string, instance: Instance): HostFederation => { + const simplePolicy = getSimplePolicy(state, instance); return Object.fromEntries( Object.entries(simplePolicy).map(([key, hosts]) => [key, hosts.includes(host)]), diff --git a/packages/pl-fe/src/utils/auth.ts b/packages/pl-fe/src/utils/auth.ts index 59cd8e545..8bd27659e 100644 --- a/packages/pl-fe/src/utils/auth.ts +++ b/packages/pl-fe/src/utils/auth.ts @@ -56,10 +56,6 @@ const getAuthUserUrl = (state: RootState) => { ].filter(url => url).find(isURL); }; -/** Get the VAPID public key. */ -const getVapidKey = (state: RootState) => - state.auth.app?.vapid_key || state.instance.configuration.vapid.public_key; - const getMeUrl = (state: RootState) => selectOwnAccount(state)?.url; export { @@ -71,6 +67,5 @@ export { getAccessToken, getAuthUserId, getAuthUserUrl, - getVapidKey, getMeUrl, }; diff --git a/packages/pl-fe/src/utils/scopes.ts b/packages/pl-fe/src/utils/scopes.ts index bfaf61d22..966b146ff 100644 --- a/packages/pl-fe/src/utils/scopes.ts +++ b/packages/pl-fe/src/utils/scopes.ts @@ -1,15 +1,16 @@ import { getFeatures, PLEROMA, TOKI, type Instance } from 'pl-api'; -import type { RootState } from 'pl-fe/store'; +import * as BuildConfig from 'pl-fe/build-config'; +import { queryClient } from 'pl-fe/queries/client'; /** * Get the OAuth scopes to use for login & signup. * Mastodon will refuse scopes it doesn't know, so care is needed. */ -const getInstanceScopes = (instance: Instance) => { - const v = getFeatures(instance).version; +const getInstanceScopes = (instance?: Instance) => { + const software = instance ? getFeatures(instance).version.software : null; - switch (v.software) { + switch (software) { case TOKI: return 'read write follow push write:bites'; case PLEROMA: @@ -20,7 +21,11 @@ const getInstanceScopes = (instance: Instance) => { }; /** Convenience function to get scopes from instance in store. */ -const getScopes = (state: RootState) => getInstanceScopes(state.instance); +const getScopes = (baseURL = BuildConfig.BACKEND_URL || '') => { + const instance = queryClient.getQueryData(['instance', 'instanceInformation', baseURL]); + + return getInstanceScopes(instance); +}; export { getInstanceScopes, diff --git a/packages/pl-fe/src/utils/state.ts b/packages/pl-fe/src/utils/state.ts index f461bff42..5ec11d05a 100644 --- a/packages/pl-fe/src/utils/state.ts +++ b/packages/pl-fe/src/utils/state.ts @@ -9,14 +9,15 @@ import { isPrerendered } from 'pl-fe/precheck'; import { selectOwnAccount } from 'pl-fe/selectors'; import { isURL } from 'pl-fe/utils/auth'; +import type { Instance } from 'pl-api'; import type { RootState } from 'pl-fe/store'; /** Whether to display the fqn instead of the acct. */ const displayFqn = (state: RootState): boolean => getPlFeConfig(state).displayFqn; /** Whether the instance exposes instance blocks through the API. */ -const federationRestrictionsDisclosed = (state: RootState): boolean => - !!state.instance.pleroma.metadata.federation.mrf_policies; +const federationRestrictionsDisclosed = (instance: Instance): boolean => + !!instance.pleroma.metadata.federation.mrf_policies; /** * Determine whether pl-fe is running in standalone mode. From a1ab1e624abca2b2189799fddf7de57e23abd60f Mon Sep 17 00:00:00 2001 From: mkljczk Date: Tue, 3 Dec 2024 15:04:33 +0100 Subject: [PATCH 03/76] pl-fe: this wasn't meant to be committed Signed-off-by: mkljczk --- packages/pl-fe/index.html | 2 -- packages/pl-fe/src/layouts/remote-instance-layout.tsx | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/packages/pl-fe/index.html b/packages/pl-fe/index.html index c7a0d3fcd..9b173ed0d 100644 --- a/packages/pl-fe/index.html +++ b/packages/pl-fe/index.html @@ -11,8 +11,6 @@ <%- snippets %> -
diff --git a/packages/pl-fe/src/layouts/remote-instance-layout.tsx b/packages/pl-fe/src/layouts/remote-instance-layout.tsx index 4ecc060a6..44f58a6ca 100644 --- a/packages/pl-fe/src/layouts/remote-instance-layout.tsx +++ b/packages/pl-fe/src/layouts/remote-instance-layout.tsx @@ -1,5 +1,6 @@ import React from 'react'; +import { useInstance } from 'pl-fe/api/hooks/instance/use-instance'; import Layout from 'pl-fe/components/ui/layout'; import LinkFooter from 'pl-fe/features/ui/components/link-footer'; import { @@ -10,7 +11,6 @@ import { import { useAppSelector } from 'pl-fe/hooks/use-app-selector'; import { useOwnAccount } from 'pl-fe/hooks/use-own-account'; import { federationRestrictionsDisclosed } from 'pl-fe/utils/state'; -import { useInstance } from 'pl-fe/api/hooks/instance/use-instance'; interface IRemoteInstanceLayout { params?: { From 3fd2db075bea8f5b52e79bcc16b1f9f59c0a5151 Mon Sep 17 00:00:00 2001 From: mkljczk Date: Tue, 3 Dec 2024 15:07:35 +0100 Subject: [PATCH 04/76] pl-fe: lint Signed-off-by: mkljczk --- packages/pl-fe/src/features/edit-profile/index.tsx | 1 - packages/pl-fe/src/layouts/remote-instance-layout.tsx | 1 - 2 files changed, 2 deletions(-) diff --git a/packages/pl-fe/src/features/edit-profile/index.tsx b/packages/pl-fe/src/features/edit-profile/index.tsx index 22d4284a6..fe5e95745 100644 --- a/packages/pl-fe/src/features/edit-profile/index.tsx +++ b/packages/pl-fe/src/features/edit-profile/index.tsx @@ -20,7 +20,6 @@ import Textarea from 'pl-fe/components/ui/textarea'; import Toggle from 'pl-fe/components/ui/toggle'; import { useImageField } from 'pl-fe/hooks/forms/use-image-field'; import { useAppDispatch } from 'pl-fe/hooks/use-app-dispatch'; -import { useAppSelector } from 'pl-fe/hooks/use-app-selector'; import { useFeatures } from 'pl-fe/hooks/use-features'; import { useOwnAccount } from 'pl-fe/hooks/use-own-account'; import toast from 'pl-fe/toast'; diff --git a/packages/pl-fe/src/layouts/remote-instance-layout.tsx b/packages/pl-fe/src/layouts/remote-instance-layout.tsx index 44f58a6ca..269e3e687 100644 --- a/packages/pl-fe/src/layouts/remote-instance-layout.tsx +++ b/packages/pl-fe/src/layouts/remote-instance-layout.tsx @@ -8,7 +8,6 @@ import { InstanceInfoPanel, InstanceModerationPanel, } from 'pl-fe/features/ui/util/async-components'; -import { useAppSelector } from 'pl-fe/hooks/use-app-selector'; import { useOwnAccount } from 'pl-fe/hooks/use-own-account'; import { federationRestrictionsDisclosed } from 'pl-fe/utils/state'; From 649b659b632ea3ae5d9130456f9af0e1a61d8e69 Mon Sep 17 00:00:00 2001 From: mkljczk Date: Tue, 3 Dec 2024 15:20:49 +0100 Subject: [PATCH 05/76] Revert "pl-fe: lint" This reverts commit 3fd2db075bea8f5b52e79bcc16b1f9f59c0a5151. --- packages/pl-fe/src/features/edit-profile/index.tsx | 1 + packages/pl-fe/src/layouts/remote-instance-layout.tsx | 1 + 2 files changed, 2 insertions(+) diff --git a/packages/pl-fe/src/features/edit-profile/index.tsx b/packages/pl-fe/src/features/edit-profile/index.tsx index fe5e95745..22d4284a6 100644 --- a/packages/pl-fe/src/features/edit-profile/index.tsx +++ b/packages/pl-fe/src/features/edit-profile/index.tsx @@ -20,6 +20,7 @@ import Textarea from 'pl-fe/components/ui/textarea'; import Toggle from 'pl-fe/components/ui/toggle'; import { useImageField } from 'pl-fe/hooks/forms/use-image-field'; import { useAppDispatch } from 'pl-fe/hooks/use-app-dispatch'; +import { useAppSelector } from 'pl-fe/hooks/use-app-selector'; import { useFeatures } from 'pl-fe/hooks/use-features'; import { useOwnAccount } from 'pl-fe/hooks/use-own-account'; import toast from 'pl-fe/toast'; diff --git a/packages/pl-fe/src/layouts/remote-instance-layout.tsx b/packages/pl-fe/src/layouts/remote-instance-layout.tsx index 269e3e687..44f58a6ca 100644 --- a/packages/pl-fe/src/layouts/remote-instance-layout.tsx +++ b/packages/pl-fe/src/layouts/remote-instance-layout.tsx @@ -8,6 +8,7 @@ import { InstanceInfoPanel, InstanceModerationPanel, } from 'pl-fe/features/ui/util/async-components'; +import { useAppSelector } from 'pl-fe/hooks/use-app-selector'; import { useOwnAccount } from 'pl-fe/hooks/use-own-account'; import { federationRestrictionsDisclosed } from 'pl-fe/utils/state'; From 76b8ff28195248d31786b88fe632163b2d913a4f Mon Sep 17 00:00:00 2001 From: mkljczk Date: Tue, 3 Dec 2024 15:20:50 +0100 Subject: [PATCH 06/76] Revert "pl-fe: this wasn't meant to be committed" This reverts commit a1ab1e624abca2b2189799fddf7de57e23abd60f. --- packages/pl-fe/index.html | 2 ++ packages/pl-fe/src/layouts/remote-instance-layout.tsx | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/pl-fe/index.html b/packages/pl-fe/index.html index 9b173ed0d..c7a0d3fcd 100644 --- a/packages/pl-fe/index.html +++ b/packages/pl-fe/index.html @@ -11,6 +11,8 @@ <%- snippets %> +
diff --git a/packages/pl-fe/src/layouts/remote-instance-layout.tsx b/packages/pl-fe/src/layouts/remote-instance-layout.tsx index 44f58a6ca..4ecc060a6 100644 --- a/packages/pl-fe/src/layouts/remote-instance-layout.tsx +++ b/packages/pl-fe/src/layouts/remote-instance-layout.tsx @@ -1,6 +1,5 @@ import React from 'react'; -import { useInstance } from 'pl-fe/api/hooks/instance/use-instance'; import Layout from 'pl-fe/components/ui/layout'; import LinkFooter from 'pl-fe/features/ui/components/link-footer'; import { @@ -11,6 +10,7 @@ import { import { useAppSelector } from 'pl-fe/hooks/use-app-selector'; import { useOwnAccount } from 'pl-fe/hooks/use-own-account'; import { federationRestrictionsDisclosed } from 'pl-fe/utils/state'; +import { useInstance } from 'pl-fe/api/hooks/instance/use-instance'; interface IRemoteInstanceLayout { params?: { From 6472a5e4e2387f570cb8b3308875abef3a8cb980 Mon Sep 17 00:00:00 2001 From: mkljczk Date: Tue, 3 Dec 2024 15:20:51 +0100 Subject: [PATCH 07/76] Revert "pl-fe: migrate /api/v*/instance to tanstack query" This reverts commit 1f8b79f309d26bea2b545c4d041fa3bf9cb288bc. --- packages/pl-fe/index.html | 2 - packages/pl-fe/src/actions/admin.ts | 2 - packages/pl-fe/src/actions/auth.ts | 8 +- packages/pl-fe/src/actions/compose.ts | 5 +- packages/pl-fe/src/actions/consumer-auth.ts | 13 +-- packages/pl-fe/src/actions/instance.ts | 40 ++++++- packages/pl-fe/src/actions/media.ts | 11 +- packages/pl-fe/src/actions/preload.ts | 2 - .../actions/push-notifications/registerer.ts | 12 ++- .../src/api/hooks/instance/use-instance.ts | 23 ---- .../instance/use-translation-languages.ts | 4 +- .../hooks/streaming/use-timeline-stream.ts | 4 +- .../pl-fe/src/components/birthday-input.tsx | 4 +- packages/pl-fe/src/components/gdpr-banner.tsx | 4 +- packages/pl-fe/src/components/helmet.tsx | 4 +- .../pl-fe/src/components/sidebar-menu.tsx | 4 +- .../src/components/sidebar-navigation.tsx | 4 +- .../src/components/status-action-bar.tsx | 4 +- .../pl-fe/src/components/translate-button.tsx | 4 +- .../components/registration-mode-picker.tsx | 4 +- .../src/features/admin/tabs/dashboard.tsx | 4 +- .../auth-login/components/consumers-list.tsx | 4 +- .../auth-login/components/login-page.tsx | 6 ++ .../components/registration-form.tsx | 4 +- .../components/registration-page.tsx | 4 +- .../chats/components/chat-composer.tsx | 4 +- .../components/upload-button.tsx | 4 +- .../compose/components/compose-form.tsx | 4 +- .../components/content-type-button.tsx | 4 +- .../compose/components/polls/poll-form.tsx | 4 +- .../compose/components/upload-button.tsx | 4 +- .../features/compose/components/upload.tsx | 4 +- .../features/compose/editor/nodes/index.ts | 4 +- .../floating-block-type-toolbar-plugin.tsx | 6 +- .../floating-text-format-toolbar-plugin.tsx | 4 +- .../components/crypto-donate-panel.tsx | 4 +- .../src/features/crypto-donate/index.tsx | 4 +- .../pl-fe/src/features/directory/index.tsx | 4 +- .../pl-fe/src/features/edit-profile/index.tsx | 7 +- .../components/instance-restrictions.tsx | 4 +- .../components/restricted-instance.tsx | 4 +- .../federation-restrictions/index.tsx | 8 +- .../pl-fe/src/features/group/edit-group.tsx | 7 +- .../src/features/home-timeline/index.tsx | 4 +- .../components/site-banner.tsx | 4 +- .../src/features/landing-timeline/index.tsx | 4 +- .../pl-fe/src/features/migration/index.tsx | 4 +- .../notifications/components/notification.tsx | 4 +- .../onboarding/steps/fediverse-step.tsx | 4 +- .../pl-fe/src/features/preferences/index.tsx | 4 +- .../src/features/public-timeline/index.tsx | 4 +- .../src/features/register-invite/index.tsx | 4 +- .../pl-fe/src/features/server-info/index.tsx | 4 +- .../status/components/thread-login-cta.tsx | 4 +- .../modals/edit-federation-modal.tsx | 4 +- .../manage-group-modal/steps/details-step.tsx | 7 +- .../components/modals/report-modal/index.tsx | 4 +- .../modals/report-modal/steps/reason-step.tsx | 4 +- .../components/modals/unauthorized-modal.tsx | 4 +- .../components/panels/instance-info-panel.tsx | 4 +- .../panels/instance-moderation-panel.tsx | 4 +- .../ui/components/panels/promo-panel.tsx | 4 +- .../ui/components/panels/sign-up-panel.tsx | 10 +- packages/pl-fe/src/features/ui/index.tsx | 10 +- packages/pl-fe/src/hooks/use-features.ts | 3 +- packages/pl-fe/src/hooks/use-instance.ts | 6 ++ .../src/hooks/use-registration-status.ts | 5 +- packages/pl-fe/src/hooks/use-vapid-key.ts | 11 -- packages/pl-fe/src/init/pl-fe-load.tsx | 6 +- packages/pl-fe/src/initial-state.ts | 11 -- .../src/layouts/remote-instance-layout.tsx | 4 +- packages/pl-fe/src/reducers/compose.ts | 15 +-- packages/pl-fe/src/reducers/index.ts | 6 +- packages/pl-fe/src/reducers/instance.ts | 100 +++++++++++++++++- packages/pl-fe/src/reducers/meta.ts | 14 ++- packages/pl-fe/src/selectors/index.ts | 8 +- packages/pl-fe/src/utils/auth.ts | 5 + packages/pl-fe/src/utils/scopes.ts | 15 +-- packages/pl-fe/src/utils/state.ts | 5 +- 79 files changed, 337 insertions(+), 240 deletions(-) delete mode 100644 packages/pl-fe/src/api/hooks/instance/use-instance.ts create mode 100644 packages/pl-fe/src/hooks/use-instance.ts delete mode 100644 packages/pl-fe/src/hooks/use-vapid-key.ts delete mode 100644 packages/pl-fe/src/initial-state.ts diff --git a/packages/pl-fe/index.html b/packages/pl-fe/index.html index c7a0d3fcd..9b173ed0d 100644 --- a/packages/pl-fe/index.html +++ b/packages/pl-fe/index.html @@ -11,8 +11,6 @@ <%- snippets %> -
diff --git a/packages/pl-fe/src/actions/admin.ts b/packages/pl-fe/src/actions/admin.ts index eb0b33bc9..ee97042b0 100644 --- a/packages/pl-fe/src/actions/admin.ts +++ b/packages/pl-fe/src/actions/admin.ts @@ -1,6 +1,5 @@ import { fetchRelationships } from 'pl-fe/actions/accounts'; import { importEntities } from 'pl-fe/actions/importer'; -import { queryClient } from 'pl-fe/queries/client'; import { filterBadges, getTagDiff } from 'pl-fe/utils/badges'; import { getClient } from '../api'; @@ -84,7 +83,6 @@ const updateConfig = (configs: PleromaConfig['configs']) => dispatch({ type: ADMIN_CONFIG_UPDATE_REQUEST, configs }); return getClient(getState).admin.config.updatePleromaConfig(configs) .then((data) => { - queryClient.invalidateQueries({ queryKey: ['instance', 'instanceInformation'] }); dispatch({ type: ADMIN_CONFIG_UPDATE_SUCCESS, configs: data.configs, needsReboot: data.need_reboot }); }).catch(error => { dispatch({ type: ADMIN_CONFIG_UPDATE_FAIL, error, configs }); diff --git a/packages/pl-fe/src/actions/auth.ts b/packages/pl-fe/src/actions/auth.ts index 5842dcf57..a0d6da0bc 100644 --- a/packages/pl-fe/src/actions/auth.ts +++ b/packages/pl-fe/src/actions/auth.ts @@ -93,7 +93,7 @@ const createAuthApp = () => const params = { client_name: `${sourceCode.displayName} (${new URL(window.origin).host})`, redirect_uris: 'urn:ietf:wg:oauth:2.0:oob', - scopes: getScopes(), + scopes: getScopes(getState()), website: sourceCode.homepage, }; @@ -117,7 +117,7 @@ const createAppToken = () => client_secret: app.client_secret!, redirect_uri: 'urn:ietf:wg:oauth:2.0:oob', grant_type: 'client_credentials', - scope: getScopes(), + scope: getScopes(getState()), }; return dispatch(obtainOAuthToken(params)).then((token) => @@ -136,7 +136,7 @@ const createUserToken = (username: string, password: string) => grant_type: 'password', username: username, password: password, - scope: getScopes(), + scope: getScopes(getState()), }; return dispatch(obtainOAuthToken(params)) @@ -156,7 +156,7 @@ const otpVerify = (code: string, mfa_token: string) => code: code, challenge_type: 'totp', // redirect_uri: 'urn:ietf:wg:oauth:2.0:oob', - // scope: getScopes(), + // scope: getScopes(getState()), }).then((token) => dispatch(authLoggedIn(token))); }; diff --git a/packages/pl-fe/src/actions/compose.ts b/packages/pl-fe/src/actions/compose.ts index c4055cd89..3d8fb8fed 100644 --- a/packages/pl-fe/src/actions/compose.ts +++ b/packages/pl-fe/src/actions/compose.ts @@ -20,7 +20,7 @@ import { uploadFile, updateMedia } from './media'; import { createStatus } from './statuses'; import type { EditorState } from 'lexical'; -import type { Account as BaseAccount, CreateStatusParams, Group, MediaAttachment, Status as BaseStatus, Tag, Poll, ScheduledStatus, Instance } from 'pl-api'; +import type { Account as BaseAccount, CreateStatusParams, Group, MediaAttachment, Status as BaseStatus, Tag, Poll, ScheduledStatus } from 'pl-api'; import type { AutoSuggestion } from 'pl-fe/components/autosuggest-input'; import type { Emoji } from 'pl-fe/features/emoji'; import type { Account } from 'pl-fe/normalizers/account'; @@ -467,8 +467,7 @@ const submitComposeFail = (composeId: string, error: unknown) => ({ const uploadCompose = (composeId: string, files: FileList, intl: IntlShape) => (dispatch: AppDispatch, getState: () => RootState) => { if (!isLoggedIn(getState)) return; - const instance = queryClient.getQueryData(['instance', 'instanceInformation', getState().auth.client.baseURL]); - const attachmentLimit = instance!.configuration.statuses.max_media_attachments; + const attachmentLimit = getState().instance.configuration.statuses.max_media_attachments; const media = getState().compose[composeId]?.media_attachments; const progress = new Array(files.length).fill(0); diff --git a/packages/pl-fe/src/actions/consumer-auth.ts b/packages/pl-fe/src/actions/consumer-auth.ts index b527ac1c0..4e66b343d 100644 --- a/packages/pl-fe/src/actions/consumer-auth.ts +++ b/packages/pl-fe/src/actions/consumer-auth.ts @@ -1,19 +1,17 @@ -import { Instance } from 'pl-api'; import queryString from 'query-string'; import * as BuildConfig from 'pl-fe/build-config'; -import { queryClient } from 'pl-fe/queries/client'; import { isURL } from 'pl-fe/utils/auth'; import sourceCode from 'pl-fe/utils/code'; -import { getInstanceScopes } from 'pl-fe/utils/scopes'; +import { getScopes } from 'pl-fe/utils/scopes'; import { createApp } from './apps'; import type { AppDispatch, RootState } from 'pl-fe/store'; -const createProviderApp = (instance: Instance) => +const createProviderApp = () => async(dispatch: AppDispatch, getState: () => RootState) => { - const scopes = getInstanceScopes(instance); + const scopes = getScopes(getState()); const params = { client_name: `${sourceCode.displayName} (${new URL(window.origin).host})`, @@ -29,9 +27,8 @@ const prepareRequest = (provider: string) => async(dispatch: AppDispatch, getState: () => RootState) => { const baseURL = isURL(BuildConfig.BACKEND_URL) ? BuildConfig.BACKEND_URL : ''; - const instance = queryClient.getQueryData(['instance', 'instanceInformation', baseURL])!; - const scopes = getInstanceScopes(instance); - const app = await dispatch(createProviderApp(instance)); + const scopes = getScopes(getState()); + const app = await dispatch(createProviderApp()); const { client_id, redirect_uri } = app; localStorage.setItem('plfe:external:app', JSON.stringify(app)); diff --git a/packages/pl-fe/src/actions/instance.ts b/packages/pl-fe/src/actions/instance.ts index 5e2a0d1c0..4363b121e 100644 --- a/packages/pl-fe/src/actions/instance.ts +++ b/packages/pl-fe/src/actions/instance.ts @@ -1,6 +1,12 @@ import { getAuthUserUrl, getMeUrl } from 'pl-fe/utils/auth'; -import type { RootState } from 'pl-fe/store'; +import { getClient } from '../api'; + +import type { Instance } from 'pl-api'; +import type { AppDispatch, RootState } from 'pl-fe/store'; + +const INSTANCE_FETCH_SUCCESS = 'INSTANCE_FETCH_SUCCESS' as const; +const INSTANCE_FETCH_FAIL = 'INSTANCE_FETCH_FAIL' as const; /** Figure out the appropriate instance to fetch depending on the state */ const getHost = (state: RootState) => { @@ -13,4 +19,34 @@ const getHost = (state: RootState) => { } }; -export { getHost }; +interface InstanceFetchSuccessAction { + type: typeof INSTANCE_FETCH_SUCCESS; + instance: Instance; +} + +interface InstanceFetchFailAction { + type: typeof INSTANCE_FETCH_FAIL; + error: unknown; +} + +const fetchInstance = () => async (dispatch: AppDispatch, getState: () => RootState) => { + try { + const instance = await getClient(getState).instance.getInstance(); + + dispatch({ type: INSTANCE_FETCH_SUCCESS, instance }); + } catch (error) { + dispatch({ type: INSTANCE_FETCH_FAIL, error }); + } +}; + +type InstanceAction = + InstanceFetchSuccessAction + | InstanceFetchFailAction + +export { + INSTANCE_FETCH_SUCCESS, + INSTANCE_FETCH_FAIL, + getHost, + fetchInstance, + type InstanceAction, +}; diff --git a/packages/pl-fe/src/actions/media.ts b/packages/pl-fe/src/actions/media.ts index 2f1b89dd5..0879dfe6f 100644 --- a/packages/pl-fe/src/actions/media.ts +++ b/packages/pl-fe/src/actions/media.ts @@ -1,6 +1,5 @@ import { defineMessages, type IntlShape } from 'react-intl'; -import { queryClient } from 'pl-fe/queries/client'; import toast from 'pl-fe/toast'; import { isLoggedIn } from 'pl-fe/utils/auth'; import { formatBytes, getVideoDuration } from 'pl-fe/utils/media'; @@ -8,7 +7,7 @@ import resizeImage from 'pl-fe/utils/resize-image'; import { getClient } from '../api'; -import type { Instance, MediaAttachment, UploadMediaParams } from 'pl-api'; +import type { MediaAttachment, UploadMediaParams } from 'pl-api'; import type { AppDispatch, RootState } from 'pl-fe/store'; const messages = defineMessages({ @@ -36,11 +35,9 @@ const uploadFile = ( changeTotal: (value: number) => void = () => {}, ) => async (dispatch: AppDispatch, getState: () => RootState) => { if (!isLoggedIn(getState)) return; - const instance = queryClient.getQueryData(['instance', 'instanceInformation', getState().auth.client.baseURL])!; - - const { - image_size_limit: maxImageSize, video_size_limit: maxVideoSize, video_duration_limit: maxVideoDuration, - } = instance.configuration.media_attachments; + const maxImageSize = getState().instance.configuration.media_attachments.image_size_limit; + const maxVideoSize = getState().instance.configuration.media_attachments.video_size_limit; + const maxVideoDuration = getState().instance.configuration.media_attachments.video_duration_limit; const isImage = file.type.match(/image.*/); const isVideo = file.type.match(/video.*/); diff --git a/packages/pl-fe/src/actions/preload.ts b/packages/pl-fe/src/actions/preload.ts index f2567265a..e20095cfb 100644 --- a/packages/pl-fe/src/actions/preload.ts +++ b/packages/pl-fe/src/actions/preload.ts @@ -67,8 +67,6 @@ interface PreloadAction { export { PLEROMA_PRELOAD_IMPORT, MASTODON_PRELOAD_IMPORT, - decodeFromMarkup, - pleromaDecoder, preload, preloadMastodon, type PreloadAction, diff --git a/packages/pl-fe/src/actions/push-notifications/registerer.ts b/packages/pl-fe/src/actions/push-notifications/registerer.ts index cc6ea0565..ac19530a3 100644 --- a/packages/pl-fe/src/actions/push-notifications/registerer.ts +++ b/packages/pl-fe/src/actions/push-notifications/registerer.ts @@ -1,5 +1,6 @@ import { createPushSubscription, updatePushSubscription } from 'pl-fe/actions/push-subscriptions'; import { pushNotificationsSetting } from 'pl-fe/settings'; +import { getVapidKey } from 'pl-fe/utils/auth'; import { decode as decodeBase64 } from 'pl-fe/utils/base64'; import { setBrowserSupport, setSubscription, clearSubscription } from './setter'; @@ -29,10 +30,10 @@ const getPushSubscription = (registration: ServiceWorkerRegistration) => registration.pushManager.getSubscription() .then(subscription => ({ registration, subscription })); -const subscribe = (registration: ServiceWorkerRegistration, vapidKey: string) => +const subscribe = (registration: ServiceWorkerRegistration, getState: () => RootState) => registration.pushManager.subscribe({ userVisibleOnly: true, - applicationServerKey: urlBase64ToUint8Array(vapidKey), + applicationServerKey: urlBase64ToUint8Array(getVapidKey(getState())), }); const unsubscribe = ({ registration, subscription }: { @@ -60,9 +61,10 @@ const sendSubscriptionToBackend = (subscription: PushSubscription, me: Me) => // eslint-disable-next-line compat/compat const supportsPushNotifications = ('serviceWorker' in navigator && 'PushManager' in window && 'getKey' in PushSubscription.prototype); -const register = (vapidKey?: string) => +const register = () => (dispatch: AppDispatch, getState: () => RootState) => { const me = getState().me; + const vapidKey = getVapidKey(getState()); dispatch(setBrowserSupport(supportsPushNotifications)); @@ -93,13 +95,13 @@ const register = (vapidKey?: string) => } else { // Something went wrong, try to subscribe again return unsubscribe({ registration, subscription }) - .then((registration) => subscribe(registration, vapidKey)) + .then((registration) => subscribe(registration, getState)) .then((pushSubscription) => dispatch(sendSubscriptionToBackend(pushSubscription, me))); } } // No subscription, try to subscribe - return subscribe(registration, vapidKey) + return subscribe(registration, getState) .then((pushSubscription) => dispatch(sendSubscriptionToBackend(pushSubscription, me))); }) .then((subscription) => { diff --git a/packages/pl-fe/src/api/hooks/instance/use-instance.ts b/packages/pl-fe/src/api/hooks/instance/use-instance.ts deleted file mode 100644 index dd75aacd1..000000000 --- a/packages/pl-fe/src/api/hooks/instance/use-instance.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { useQuery } from '@tanstack/react-query'; -import { instanceSchema } from 'pl-api'; -import * as v from 'valibot'; - -import { useClient } from 'pl-fe/hooks/use-client'; -import { initialState } from 'pl-fe/initial-state'; - -const placeholderData = v.parse(instanceSchema, {}); -const initialData = initialState['/api/v1/instance'] ? v.parse(instanceSchema, initialState['/api/v1/instance']) : undefined; - -const useInstance = () => { - const client = useClient(); - - const query = useQuery({ - queryKey: ['instance', 'instanceInformation', client.baseURL], - queryFn: client.instance.getInstance, - initialData: client.baseURL === '' ? initialData : undefined, - }); - - return { ...query, data: query.data || placeholderData }; -}; - -export { useInstance }; diff --git a/packages/pl-fe/src/api/hooks/instance/use-translation-languages.ts b/packages/pl-fe/src/api/hooks/instance/use-translation-languages.ts index 2a15c09d5..0fcdc3fab 100644 --- a/packages/pl-fe/src/api/hooks/instance/use-translation-languages.ts +++ b/packages/pl-fe/src/api/hooks/instance/use-translation-languages.ts @@ -1,15 +1,15 @@ import { useQuery } from '@tanstack/react-query'; -import { useInstance } from 'pl-fe/api/hooks/instance/use-instance'; import { useClient } from 'pl-fe/hooks/use-client'; import { useFeatures } from 'pl-fe/hooks/use-features'; +import { useInstance } from 'pl-fe/hooks/use-instance'; import { useLoggedIn } from 'pl-fe/hooks/use-logged-in'; const useTranslationLanguages = () => { const client = useClient(); const { isLoggedIn } = useLoggedIn(); const features = useFeatures(); - const { data: instance } = useInstance(); + const instance = useInstance(); const getTranslationLanguages = async () => { const metadata = instance.pleroma.metadata; diff --git a/packages/pl-fe/src/api/hooks/streaming/use-timeline-stream.ts b/packages/pl-fe/src/api/hooks/streaming/use-timeline-stream.ts index 6f8fbe2f0..07c2a140a 100644 --- a/packages/pl-fe/src/api/hooks/streaming/use-timeline-stream.ts +++ b/packages/pl-fe/src/api/hooks/streaming/use-timeline-stream.ts @@ -1,8 +1,8 @@ import { useEffect, useRef } from 'react'; -import { useInstance } from 'pl-fe/api/hooks/instance/use-instance'; import { useAppSelector } from 'pl-fe/hooks/use-app-selector'; import { useClient } from 'pl-fe/hooks/use-client'; +import { useInstance } from 'pl-fe/hooks/use-instance'; import { getAccessToken } from 'pl-fe/utils/auth'; import type { StreamingEvent } from 'pl-api'; @@ -12,7 +12,7 @@ const useTimelineStream = (stream: string, params: { list?: string; tag?: string const client = useClient(); - const { data: instance } = useInstance(); + const instance = useInstance(); const socket = useRef<({ listen: (listener: any, stream?: string) => number; unlisten: (listener: any) => void; diff --git a/packages/pl-fe/src/components/birthday-input.tsx b/packages/pl-fe/src/components/birthday-input.tsx index 6a8fd6f8d..58688074e 100644 --- a/packages/pl-fe/src/components/birthday-input.tsx +++ b/packages/pl-fe/src/components/birthday-input.tsx @@ -1,10 +1,10 @@ import React, { useMemo } from 'react'; import { defineMessages, useIntl } from 'react-intl'; -import { useInstance } from 'pl-fe/api/hooks/instance/use-instance'; import IconButton from 'pl-fe/components/icon-button'; import { DatePicker } from 'pl-fe/features/ui/util/async-components'; import { useFeatures } from 'pl-fe/hooks/use-features'; +import { useInstance } from 'pl-fe/hooks/use-instance'; const messages = defineMessages({ birthdayPlaceholder: { id: 'edit_profile.fields.birthday_placeholder', defaultMessage: 'Your birthday' }, @@ -23,7 +23,7 @@ interface IBirthdayInput { const BirthdayInput: React.FC = ({ value, onChange, required }) => { const intl = useIntl(); const features = useFeatures(); - const { data: instance } = useInstance(); + const instance = useInstance(); const supportsBirthdays = features.birthdays; const minAge = instance.pleroma.metadata.birthday_min_age; diff --git a/packages/pl-fe/src/components/gdpr-banner.tsx b/packages/pl-fe/src/components/gdpr-banner.tsx index aa16f6514..0f86c8e2d 100644 --- a/packages/pl-fe/src/components/gdpr-banner.tsx +++ b/packages/pl-fe/src/components/gdpr-banner.tsx @@ -2,12 +2,12 @@ import clsx from 'clsx'; import React, { useState } from 'react'; import { FormattedMessage } from 'react-intl'; -import { useInstance } from 'pl-fe/api/hooks/instance/use-instance'; import Banner from 'pl-fe/components/ui/banner'; import Button from 'pl-fe/components/ui/button'; import HStack from 'pl-fe/components/ui/hstack'; import Stack from 'pl-fe/components/ui/stack'; import Text from 'pl-fe/components/ui/text'; +import { useInstance } from 'pl-fe/hooks/use-instance'; import { usePlFeConfig } from 'pl-fe/hooks/use-pl-fe-config'; const acceptedGdpr = !!localStorage.getItem('plfe:gdpr'); @@ -18,7 +18,7 @@ const GdprBanner: React.FC = () => { const [shown, setShown] = useState(acceptedGdpr); const [slideout, setSlideout] = useState(false); - const { data: instance } = useInstance(); + const instance = useInstance(); const { gdprUrl } = usePlFeConfig(); const handleAccept = () => { diff --git a/packages/pl-fe/src/components/helmet.tsx b/packages/pl-fe/src/components/helmet.tsx index 81073f53b..dafab6605 100644 --- a/packages/pl-fe/src/components/helmet.tsx +++ b/packages/pl-fe/src/components/helmet.tsx @@ -1,9 +1,9 @@ import React from 'react'; import { Helmet as ReactHelmet } from 'react-helmet-async'; -import { useInstance } from 'pl-fe/api/hooks/instance/use-instance'; import { useStatContext } from 'pl-fe/contexts/stat-context'; import { useAppSelector } from 'pl-fe/hooks/use-app-selector'; +import { useInstance } from 'pl-fe/hooks/use-instance'; import { useSettings } from 'pl-fe/hooks/use-settings'; import { RootState } from 'pl-fe/store'; import FaviconService from 'pl-fe/utils/favicon-service'; @@ -22,7 +22,7 @@ interface IHelmet { } const Helmet: React.FC = ({ children }) => { - const { data: instance } = useInstance(); + const instance = useInstance(); const { unreadChatsCount } = useStatContext(); const unreadCount = useAppSelector((state) => getNotifTotals(state) + unreadChatsCount); const { demetricator } = useSettings(); diff --git a/packages/pl-fe/src/components/sidebar-menu.tsx b/packages/pl-fe/src/components/sidebar-menu.tsx index 555655b9f..928b57377 100644 --- a/packages/pl-fe/src/components/sidebar-menu.tsx +++ b/packages/pl-fe/src/components/sidebar-menu.tsx @@ -6,7 +6,6 @@ import { Link, NavLink } from 'react-router-dom'; import { fetchOwnAccounts, logOut, switchAccount } from 'pl-fe/actions/auth'; import { useAccount } from 'pl-fe/api/hooks/accounts/use-account'; -import { useInstance } from 'pl-fe/api/hooks/instance/use-instance'; import { useInteractionRequestsCount } from 'pl-fe/api/hooks/statuses/use-interaction-requests'; import Account from 'pl-fe/components/account'; import Divider from 'pl-fe/components/ui/divider'; @@ -18,6 +17,7 @@ import ProfileStats from 'pl-fe/features/ui/components/profile-stats'; import { useAppDispatch } from 'pl-fe/hooks/use-app-dispatch'; import { useAppSelector } from 'pl-fe/hooks/use-app-selector'; import { useFeatures } from 'pl-fe/hooks/use-features'; +import { useInstance } from 'pl-fe/hooks/use-instance'; import { useRegistrationStatus } from 'pl-fe/hooks/use-registration-status'; import { makeGetOtherAccounts } from 'pl-fe/selectors'; import { useSettingsStore } from 'pl-fe/stores/settings'; @@ -106,7 +106,7 @@ const SidebarMenu: React.FC = (): JSX.Element | null => { const touchEnd = useRef(null); const { isOpen } = useRegistrationStatus(); - const { data: instance } = useInstance(); + const instance = useInstance(); const restrictUnauth = instance.pleroma.metadata.restrict_unauthenticated; const containerRef = React.useRef(null); diff --git a/packages/pl-fe/src/components/sidebar-navigation.tsx b/packages/pl-fe/src/components/sidebar-navigation.tsx index 02c70db74..e24dfecb1 100644 --- a/packages/pl-fe/src/components/sidebar-navigation.tsx +++ b/packages/pl-fe/src/components/sidebar-navigation.tsx @@ -1,7 +1,6 @@ import React from 'react'; import { defineMessages, FormattedMessage, useIntl } from 'react-intl'; -import { useInstance } from 'pl-fe/api/hooks/instance/use-instance'; import { useInteractionRequestsCount } from 'pl-fe/api/hooks/statuses/use-interaction-requests'; import Icon from 'pl-fe/components/ui/icon'; import Stack from 'pl-fe/components/ui/stack'; @@ -10,6 +9,7 @@ import ComposeButton from 'pl-fe/features/ui/components/compose-button'; import ProfileDropdown from 'pl-fe/features/ui/components/profile-dropdown'; import { useAppSelector } from 'pl-fe/hooks/use-app-selector'; import { useFeatures } from 'pl-fe/hooks/use-features'; +import { useInstance } from 'pl-fe/hooks/use-instance'; import { useLogo } from 'pl-fe/hooks/use-logo'; import { useOwnAccount } from 'pl-fe/hooks/use-own-account'; import { useRegistrationStatus } from 'pl-fe/hooks/use-registration-status'; @@ -40,7 +40,7 @@ const SidebarNavigation = () => { const intl = useIntl(); const { unreadChatsCount } = useStatContext(); - const { data: instance } = useInstance(); + const instance = useInstance(); const features = useFeatures(); const { isDeveloper } = useSettings(); const { account } = useOwnAccount(); diff --git a/packages/pl-fe/src/components/status-action-bar.tsx b/packages/pl-fe/src/components/status-action-bar.tsx index 65f173437..413173f89 100644 --- a/packages/pl-fe/src/components/status-action-bar.tsx +++ b/packages/pl-fe/src/components/status-action-bar.tsx @@ -17,7 +17,6 @@ import { useBlockGroupMember } from 'pl-fe/api/hooks/groups/use-block-group-memb import { useDeleteGroupStatus } from 'pl-fe/api/hooks/groups/use-delete-group-status'; import { useGroup } from 'pl-fe/api/hooks/groups/use-group'; import { useGroupRelationship } from 'pl-fe/api/hooks/groups/use-group-relationship'; -import { useInstance } from 'pl-fe/api/hooks/instance/use-instance'; import { useTranslationLanguages } from 'pl-fe/api/hooks/instance/use-translation-languages'; import DropdownMenu from 'pl-fe/components/dropdown-menu'; import StatusActionButton from 'pl-fe/components/status-action-button'; @@ -28,6 +27,7 @@ import { useAppDispatch } from 'pl-fe/hooks/use-app-dispatch'; import { useAppSelector } from 'pl-fe/hooks/use-app-selector'; import { useCanInteract } from 'pl-fe/hooks/use-can-interact'; import { useFeatures } from 'pl-fe/hooks/use-features'; +import { useInstance } from 'pl-fe/hooks/use-instance'; import { useOwnAccount } from 'pl-fe/hooks/use-own-account'; import { useSettings } from 'pl-fe/hooks/use-settings'; import { useChats } from 'pl-fe/queries/chats'; @@ -595,7 +595,7 @@ const MenuButton: React.FC = ({ const { groupRelationship } = useGroupRelationship(status.group_id || undefined); const features = useFeatures(); - const { data: instance } = useInstance(); + const instance = useInstance(); const { autoTranslate, deleteModal, knownLanguages } = useSettings(); const { translationLanguages } = useTranslationLanguages(); diff --git a/packages/pl-fe/src/components/translate-button.tsx b/packages/pl-fe/src/components/translate-button.tsx index 9fd1c92a0..3d8e41198 100644 --- a/packages/pl-fe/src/components/translate-button.tsx +++ b/packages/pl-fe/src/components/translate-button.tsx @@ -1,7 +1,6 @@ import React, { useEffect } from 'react'; import { FormattedMessage, useIntl } from 'react-intl'; -import { useInstance } from 'pl-fe/api/hooks/instance/use-instance'; import { useTranslationLanguages } from 'pl-fe/api/hooks/instance/use-translation-languages'; import { useStatusTranslation } from 'pl-fe/api/hooks/statuses/use-status-translation'; import HStack from 'pl-fe/components/ui/hstack'; @@ -10,6 +9,7 @@ import Stack from 'pl-fe/components/ui/stack'; import Text from 'pl-fe/components/ui/text'; import { useAppSelector } from 'pl-fe/hooks/use-app-selector'; import { useFeatures } from 'pl-fe/hooks/use-features'; +import { useInstance } from 'pl-fe/hooks/use-instance'; import { useSettings } from 'pl-fe/hooks/use-settings'; import { useStatusMetaStore } from 'pl-fe/stores/status-meta'; @@ -22,7 +22,7 @@ interface ITranslateButton { const TranslateButton: React.FC = ({ status }) => { const intl = useIntl(); const features = useFeatures(); - const { data: instance } = useInstance(); + const instance = useInstance(); const settings = useSettings(); const autoTranslate = settings.autoTranslate; const knownLanguages = autoTranslate ? [...settings.knownLanguages, intl.locale] : [intl.locale]; diff --git a/packages/pl-fe/src/features/admin/components/registration-mode-picker.tsx b/packages/pl-fe/src/features/admin/components/registration-mode-picker.tsx index eb47d3163..416aaee10 100644 --- a/packages/pl-fe/src/features/admin/components/registration-mode-picker.tsx +++ b/packages/pl-fe/src/features/admin/components/registration-mode-picker.tsx @@ -3,9 +3,9 @@ import React from 'react'; import { useIntl, defineMessages, FormattedMessage } from 'react-intl'; import { updateConfig } from 'pl-fe/actions/admin'; -import { useInstance } from 'pl-fe/api/hooks/instance/use-instance'; import { RadioGroup, RadioItem } from 'pl-fe/components/radio'; import { useAppDispatch } from 'pl-fe/hooks/use-app-dispatch'; +import { useInstance } from 'pl-fe/hooks/use-instance'; import toast from 'pl-fe/toast'; type RegistrationMode = 'open' | 'approval' | 'closed'; @@ -37,7 +37,7 @@ const modeFromInstance = ({ registrations }: Instance): RegistrationMode => { const RegistrationModePicker: React.FC = () => { const intl = useIntl(); const dispatch = useAppDispatch(); - const { data: instance } = useInstance(); + const instance = useInstance(); const mode = modeFromInstance(instance); diff --git a/packages/pl-fe/src/features/admin/tabs/dashboard.tsx b/packages/pl-fe/src/features/admin/tabs/dashboard.tsx index 5ac6706c1..73b56cfcf 100644 --- a/packages/pl-fe/src/features/admin/tabs/dashboard.tsx +++ b/packages/pl-fe/src/features/admin/tabs/dashboard.tsx @@ -1,12 +1,12 @@ import React from 'react'; import { FormattedMessage } from 'react-intl'; -import { useInstance } from 'pl-fe/api/hooks/instance/use-instance'; import List, { ListItem } from 'pl-fe/components/list'; import { CardTitle } from 'pl-fe/components/ui/card'; import Icon from 'pl-fe/components/ui/icon'; import Stack from 'pl-fe/components/ui/stack'; import { useFeatures } from 'pl-fe/hooks/use-features'; +import { useInstance } from 'pl-fe/hooks/use-instance'; import { useOwnAccount } from 'pl-fe/hooks/use-own-account'; import sourceCode from 'pl-fe/utils/code'; @@ -14,7 +14,7 @@ import { DashCounter, DashCounters } from '../components/dashcounter'; import RegistrationModePicker from '../components/registration-mode-picker'; const Dashboard: React.FC = () => { - const { data: instance } = useInstance(); + const instance = useInstance(); const features = useFeatures(); const { account } = useOwnAccount(); diff --git a/packages/pl-fe/src/features/auth-login/components/consumers-list.tsx b/packages/pl-fe/src/features/auth-login/components/consumers-list.tsx index 8ca7d38d2..cacdf1afe 100644 --- a/packages/pl-fe/src/features/auth-login/components/consumers-list.tsx +++ b/packages/pl-fe/src/features/auth-login/components/consumers-list.tsx @@ -1,11 +1,11 @@ import React from 'react'; import { FormattedMessage } from 'react-intl'; -import { useInstance } from 'pl-fe/api/hooks/instance/use-instance'; import Card from 'pl-fe/components/ui/card'; import HStack from 'pl-fe/components/ui/hstack'; import Stack from 'pl-fe/components/ui/stack'; import Text from 'pl-fe/components/ui/text'; +import { useInstance } from 'pl-fe/hooks/use-instance'; import ConsumerButton from './consumer-button'; @@ -14,7 +14,7 @@ interface IConsumersList { /** Displays OAuth consumers to log in with. */ const ConsumersList: React.FC = () => { - const { data: instance } = useInstance(); + const instance = useInstance(); const providers = instance.pleroma.oauth_consumer_strategies; if (providers.length > 0) { diff --git a/packages/pl-fe/src/features/auth-login/components/login-page.tsx b/packages/pl-fe/src/features/auth-login/components/login-page.tsx index 05c63bff7..f13f4cde3 100644 --- a/packages/pl-fe/src/features/auth-login/components/login-page.tsx +++ b/packages/pl-fe/src/features/auth-login/components/login-page.tsx @@ -3,6 +3,7 @@ import { FormattedMessage } from 'react-intl'; import { Redirect } from 'react-router-dom'; import { logIn, verifyCredentials, switchAccount } from 'pl-fe/actions/auth'; +import { fetchInstance } from 'pl-fe/actions/instance'; import { BigCard } from 'pl-fe/components/big-card'; import Button from 'pl-fe/components/ui/button'; import Stack from 'pl-fe/components/ui/stack'; @@ -42,6 +43,11 @@ const LoginPage = () => { const { username, password } = getFormData(event.target as HTMLFormElement); dispatch(logIn(username, password)) .then(({ access_token }) => dispatch(verifyCredentials(access_token))) + // Refetch the instance for authenticated fetch + .then(async (account) => { + await dispatch(fetchInstance()); + return account; + }) .then((account: { id: string }) => { closeModal(); if (typeof me === 'string') { diff --git a/packages/pl-fe/src/features/auth-login/components/registration-form.tsx b/packages/pl-fe/src/features/auth-login/components/registration-form.tsx index c4b5ec38d..fc65c71c1 100644 --- a/packages/pl-fe/src/features/auth-login/components/registration-form.tsx +++ b/packages/pl-fe/src/features/auth-login/components/registration-form.tsx @@ -5,7 +5,6 @@ import { Link, useHistory } from 'react-router-dom'; import { accountLookup } from 'pl-fe/actions/accounts'; import { register, verifyCredentials } from 'pl-fe/actions/auth'; -import { useInstance } from 'pl-fe/api/hooks/instance/use-instance'; import BirthdayInput from 'pl-fe/components/birthday-input'; import Button from 'pl-fe/components/ui/button'; import Checkbox from 'pl-fe/components/ui/checkbox'; @@ -18,6 +17,7 @@ import Textarea from 'pl-fe/components/ui/textarea'; import CaptchaField from 'pl-fe/features/auth-login/components/captcha'; import { useAppDispatch } from 'pl-fe/hooks/use-app-dispatch'; import { useFeatures } from 'pl-fe/hooks/use-features'; +import { useInstance } from 'pl-fe/hooks/use-instance'; import { useSettings } from 'pl-fe/hooks/use-settings'; import { useModalsStore } from 'pl-fe/stores/modals'; @@ -52,7 +52,7 @@ const RegistrationForm: React.FC = ({ inviteToken }) => { const { locale } = useSettings(); const features = useFeatures(); - const { data: instance } = useInstance(); + const instance = useInstance(); const { openModal } = useModalsStore(); const needsConfirmation = instance.pleroma.metadata.account_activation_required; diff --git a/packages/pl-fe/src/features/auth-login/components/registration-page.tsx b/packages/pl-fe/src/features/auth-login/components/registration-page.tsx index 84da7ef5a..cce5bf427 100644 --- a/packages/pl-fe/src/features/auth-login/components/registration-page.tsx +++ b/packages/pl-fe/src/features/auth-login/components/registration-page.tsx @@ -1,15 +1,15 @@ import React from 'react'; import { FormattedMessage } from 'react-intl'; -import { useInstance } from 'pl-fe/api/hooks/instance/use-instance'; import { BigCard } from 'pl-fe/components/big-card'; import Text from 'pl-fe/components/ui/text'; +import { useInstance } from 'pl-fe/hooks/use-instance'; import { useRegistrationStatus } from 'pl-fe/hooks/use-registration-status'; import RegistrationForm from './registration-form'; const RegistrationPage: React.FC = () => { - const { data: instance } = useInstance(); + const instance = useInstance(); const { isOpen } = useRegistrationStatus(); if (!isOpen) { diff --git a/packages/pl-fe/src/features/chats/components/chat-composer.tsx b/packages/pl-fe/src/features/chats/components/chat-composer.tsx index 5c948a8f7..ed0c7b39c 100644 --- a/packages/pl-fe/src/features/chats/components/chat-composer.tsx +++ b/packages/pl-fe/src/features/chats/components/chat-composer.tsx @@ -3,7 +3,6 @@ import { defineMessages, IntlShape, useIntl } from 'react-intl'; import { unblockAccount } from 'pl-fe/actions/accounts'; import { useRelationship } from 'pl-fe/api/hooks/accounts/use-relationship'; -import { useInstance } from 'pl-fe/api/hooks/instance/use-instance'; import Button from 'pl-fe/components/ui/button'; import Combobox, { ComboboxInput, ComboboxList, ComboboxOption, ComboboxPopover } from 'pl-fe/components/ui/combobox'; import HStack from 'pl-fe/components/ui/hstack'; @@ -14,6 +13,7 @@ import { useChatContext } from 'pl-fe/contexts/chat-context'; import UploadButton from 'pl-fe/features/compose/components/upload-button'; import emojiSearch from 'pl-fe/features/emoji/search'; import { useAppDispatch } from 'pl-fe/hooks/use-app-dispatch'; +import { useInstance } from 'pl-fe/hooks/use-instance'; import { useModalsStore } from 'pl-fe/stores/modals'; import { textAtCursorMatchesToken } from 'pl-fe/utils/suggestions'; @@ -85,7 +85,7 @@ const ChatComposer = React.forwardRef const isBlocked = relationship?.blocked_by && false; const isBlocking = relationship?.blocking && false; - const maxCharacterCount = useInstance().data.configuration.chats.max_characters; + const maxCharacterCount = useInstance().configuration.chats.max_characters; const [suggestions, setSuggestions] = useState(initialSuggestionState); const isSuggestionsAvailable = suggestions.list.length > 0; diff --git a/packages/pl-fe/src/features/compose-event/components/upload-button.tsx b/packages/pl-fe/src/features/compose-event/components/upload-button.tsx index 3e17dae64..7b696e9be 100644 --- a/packages/pl-fe/src/features/compose-event/components/upload-button.tsx +++ b/packages/pl-fe/src/features/compose-event/components/upload-button.tsx @@ -1,10 +1,10 @@ import React, { useRef } from 'react'; import { FormattedMessage } from 'react-intl'; -import { useInstance } from 'pl-fe/api/hooks/instance/use-instance'; import Icon from 'pl-fe/components/icon'; import HStack from 'pl-fe/components/ui/hstack'; import Text from 'pl-fe/components/ui/text'; +import { useAppSelector } from 'pl-fe/hooks/use-app-selector'; interface IUploadButton { disabled?: boolean; @@ -14,7 +14,7 @@ interface IUploadButton { const UploadButton: React.FC = ({ disabled, onSelectFile }) => { const fileElement = useRef(null); - const attachmentTypes = useInstance().data.configuration.media_attachments.supported_mime_types + const attachmentTypes = useAppSelector(state => state.instance.configuration.media_attachments.supported_mime_types) ?.filter((type) => type.startsWith('image/')); let accept = attachmentTypes?.join(','); 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 15dc3efa0..ef8149e2a 100644 --- a/packages/pl-fe/src/features/compose/components/compose-form.tsx +++ b/packages/pl-fe/src/features/compose/components/compose-form.tsx @@ -12,7 +12,6 @@ import { selectComposeSuggestion, uploadCompose, } from 'pl-fe/actions/compose'; -import { useInstance } from 'pl-fe/api/hooks/instance/use-instance'; import Button from 'pl-fe/components/ui/button'; import HStack from 'pl-fe/components/ui/hstack'; import Stack from 'pl-fe/components/ui/stack'; @@ -22,6 +21,7 @@ import { useAppDispatch } from 'pl-fe/hooks/use-app-dispatch'; import { useCompose } from 'pl-fe/hooks/use-compose'; import { useDraggedFiles } from 'pl-fe/hooks/use-dragged-files'; import { useFeatures } from 'pl-fe/hooks/use-features'; +import { useInstance } from 'pl-fe/hooks/use-instance'; import QuotedStatusContainer from '../containers/quoted-status-container'; import ReplyIndicatorContainer from '../containers/reply-indicator-container'; @@ -75,7 +75,7 @@ const ComposeForm = ({ id, shouldCondense, autoFocus, clickab const history = useHistory(); const intl = useIntl(); const dispatch = useAppDispatch(); - const { configuration } = useInstance().data; + const { configuration } = useInstance(); const compose = useCompose(id); const maxTootChars = configuration.statuses.max_characters; diff --git a/packages/pl-fe/src/features/compose/components/content-type-button.tsx b/packages/pl-fe/src/features/compose/components/content-type-button.tsx index 6d27bf95c..9565d2b43 100644 --- a/packages/pl-fe/src/features/compose/components/content-type-button.tsx +++ b/packages/pl-fe/src/features/compose/components/content-type-button.tsx @@ -2,11 +2,11 @@ import React from 'react'; import { defineMessages, useIntl } from 'react-intl'; import { changeComposeContentType } from 'pl-fe/actions/compose'; -import { useInstance } from 'pl-fe/api/hooks/instance/use-instance'; import DropdownMenu from 'pl-fe/components/dropdown-menu'; import Button from 'pl-fe/components/ui/button'; import { useAppDispatch } from 'pl-fe/hooks/use-app-dispatch'; import { useCompose } from 'pl-fe/hooks/use-compose'; +import { useInstance } from 'pl-fe/hooks/use-instance'; const messages = defineMessages({ content_type_plaintext: { id: 'preferences.options.content_type_plaintext', defaultMessage: 'Plain text' }, @@ -24,7 +24,7 @@ interface IContentTypeButton { const ContentTypeButton: React.FC = ({ composeId }) => { const intl = useIntl(); const dispatch = useAppDispatch(); - const { data: instance } = useInstance(); + const instance = useInstance(); const contentType = useCompose(composeId).content_type; diff --git a/packages/pl-fe/src/features/compose/components/polls/poll-form.tsx b/packages/pl-fe/src/features/compose/components/polls/poll-form.tsx index 095f9e0c7..f2247bd43 100644 --- a/packages/pl-fe/src/features/compose/components/polls/poll-form.tsx +++ b/packages/pl-fe/src/features/compose/components/polls/poll-form.tsx @@ -2,7 +2,6 @@ import React from 'react'; import { defineMessages, FormattedMessage, useIntl } from 'react-intl'; import { addPollOption, changePollOption, changePollSettings, clearComposeSuggestions, fetchComposeSuggestions, removePoll, removePollOption, selectComposeSuggestion } from 'pl-fe/actions/compose'; -import { useInstance } from 'pl-fe/api/hooks/instance/use-instance'; import AutosuggestInput from 'pl-fe/components/autosuggest-input'; import Button from 'pl-fe/components/ui/button'; import Divider from 'pl-fe/components/ui/divider'; @@ -12,6 +11,7 @@ import Text from 'pl-fe/components/ui/text'; import Toggle from 'pl-fe/components/ui/toggle'; import { useAppDispatch } from 'pl-fe/hooks/use-app-dispatch'; import { useCompose } from 'pl-fe/hooks/use-compose'; +import { useInstance } from 'pl-fe/hooks/use-instance'; import DurationSelector from './duration-selector'; @@ -118,7 +118,7 @@ interface IPollForm { const PollForm: React.FC = ({ composeId }) => { const dispatch = useAppDispatch(); const intl = useIntl(); - const { configuration } = useInstance().data; + const { configuration } = useInstance(); const { poll, language, modified_language: modifiedLanguage } = useCompose(composeId); diff --git a/packages/pl-fe/src/features/compose/components/upload-button.tsx b/packages/pl-fe/src/features/compose/components/upload-button.tsx index 174f22a28..1d6d35245 100644 --- a/packages/pl-fe/src/features/compose/components/upload-button.tsx +++ b/packages/pl-fe/src/features/compose/components/upload-button.tsx @@ -1,8 +1,8 @@ import React, { useRef } from 'react'; import { defineMessages, IntlShape, useIntl } from 'react-intl'; -import { useInstance } from 'pl-fe/api/hooks/instance/use-instance'; import IconButton from 'pl-fe/components/ui/icon-button'; +import { useInstance } from 'pl-fe/hooks/use-instance'; const messages = defineMessages({ upload: { id: 'upload_button.label', defaultMessage: 'Add media attachment' }, @@ -32,7 +32,7 @@ const UploadButton: React.FC = ({ icon, }) => { const intl = useIntl(); - const { configuration } = useInstance().data; + const { configuration } = useInstance(); const fileElement = useRef(null); const attachmentTypes = configuration.media_attachments.supported_mime_types; diff --git a/packages/pl-fe/src/features/compose/components/upload.tsx b/packages/pl-fe/src/features/compose/components/upload.tsx index 187203992..4726c4a94 100644 --- a/packages/pl-fe/src/features/compose/components/upload.tsx +++ b/packages/pl-fe/src/features/compose/components/upload.tsx @@ -1,10 +1,10 @@ import React, { useCallback } from 'react'; import { undoUploadCompose, changeUploadCompose } from 'pl-fe/actions/compose'; -import { useInstance } from 'pl-fe/api/hooks/instance/use-instance'; import Upload from 'pl-fe/components/upload'; import { useAppDispatch } from 'pl-fe/hooks/use-app-dispatch'; import { useCompose } from 'pl-fe/hooks/use-compose'; +import { useInstance } from 'pl-fe/hooks/use-instance'; interface IUploadCompose { id: string; @@ -17,7 +17,7 @@ interface IUploadCompose { const UploadCompose: React.FC = ({ composeId, id, onSubmit, onDragStart, onDragEnter, onDragEnd }) => { const dispatch = useAppDispatch(); - const { pleroma: { metadata: { description_limit: descriptionLimit } } } = useInstance().data; + const { pleroma: { metadata: { description_limit: descriptionLimit } } } = useInstance(); const media = useCompose(composeId).media_attachments.find(item => item.id === id)!; diff --git a/packages/pl-fe/src/features/compose/editor/nodes/index.ts b/packages/pl-fe/src/features/compose/editor/nodes/index.ts index d35644260..1daec172c 100644 --- a/packages/pl-fe/src/features/compose/editor/nodes/index.ts +++ b/packages/pl-fe/src/features/compose/editor/nodes/index.ts @@ -11,7 +11,7 @@ import { ListItemNode, ListNode } from '@lexical/list'; import { HorizontalRuleNode } from '@lexical/react/LexicalHorizontalRuleNode'; import { HeadingNode, QuoteNode } from '@lexical/rich-text'; -import { useInstance } from 'pl-fe/api/hooks/instance/use-instance'; +import { useInstance } from 'pl-fe/hooks/use-instance'; import { EmojiNode } from './emoji-node'; import { ImageNode } from './image-node'; @@ -20,7 +20,7 @@ import { MentionNode } from './mention-node'; import type { Klass, LexicalNode } from 'lexical'; const useNodes = (isWysiwyg?: boolean) => { - const { data: instance } = useInstance(); + const instance = useInstance(); const nodes: Array> = [ AutoLinkNode, diff --git a/packages/pl-fe/src/features/compose/editor/plugins/floating-block-type-toolbar-plugin.tsx b/packages/pl-fe/src/features/compose/editor/plugins/floating-block-type-toolbar-plugin.tsx index c9eb578e6..96dc90568 100644 --- a/packages/pl-fe/src/features/compose/editor/plugins/floating-block-type-toolbar-plugin.tsx +++ b/packages/pl-fe/src/features/compose/editor/plugins/floating-block-type-toolbar-plugin.tsx @@ -23,8 +23,8 @@ import { createPortal } from 'react-dom'; import { defineMessages, useIntl } from 'react-intl'; import { uploadFile } from 'pl-fe/actions/compose'; -import { useInstance } from 'pl-fe/api/hooks/instance/use-instance'; import { useAppDispatch } from 'pl-fe/hooks/use-app-dispatch'; +import { useInstance } from 'pl-fe/hooks/use-instance'; import { $createImageNode } from '../nodes/image-node'; import { setFloatingElemPosition } from '../utils/set-floating-elem-position'; @@ -42,7 +42,7 @@ interface IUploadButton { const UploadButton: React.FC = ({ onSelectFile }) => { const intl = useIntl(); - const { configuration } = useInstance().data; + const { configuration } = useInstance(); const dispatch = useAppDispatch(); const [disabled, setDisabled] = useState(false); @@ -101,7 +101,7 @@ const BlockTypeFloatingToolbar = ({ }): JSX.Element => { const intl = useIntl(); const popupCharStylesEditorRef = useRef(null); - const { data: instance } = useInstance(); + const instance = useInstance(); const allowInlineImages = instance.pleroma.metadata.markup.allow_inline_images; diff --git a/packages/pl-fe/src/features/compose/editor/plugins/floating-text-format-toolbar-plugin.tsx b/packages/pl-fe/src/features/compose/editor/plugins/floating-text-format-toolbar-plugin.tsx index f62db9602..f1f955d37 100644 --- a/packages/pl-fe/src/features/compose/editor/plugins/floating-text-format-toolbar-plugin.tsx +++ b/packages/pl-fe/src/features/compose/editor/plugins/floating-text-format-toolbar-plugin.tsx @@ -39,8 +39,8 @@ import * as React from 'react'; import { createPortal } from 'react-dom'; import { defineMessages, useIntl } from 'react-intl'; -import { useInstance } from 'pl-fe/api/hooks/instance/use-instance'; import Icon from 'pl-fe/components/ui/icon'; +import { useInstance } from 'pl-fe/hooks/use-instance'; import { getDOMRangeRect } from '../utils/get-dom-range-rect'; import { getSelectedNode } from '../utils/get-selected-node'; @@ -109,7 +109,7 @@ const BlockTypeDropdown = ({ editor, anchorElem, blockType, icon }: { blockType: keyof typeof blockTypeToBlockName; icon: string; }) => { - const { data: instance } = useInstance(); + const instance = useInstance(); const [showDropDown, setShowDropDown] = useState(false); diff --git a/packages/pl-fe/src/features/crypto-donate/components/crypto-donate-panel.tsx b/packages/pl-fe/src/features/crypto-donate/components/crypto-donate-panel.tsx index ebe6b36bb..96032e34a 100644 --- a/packages/pl-fe/src/features/crypto-donate/components/crypto-donate-panel.tsx +++ b/packages/pl-fe/src/features/crypto-donate/components/crypto-donate-panel.tsx @@ -2,9 +2,9 @@ import React from 'react'; import { FormattedMessage, defineMessages, useIntl } from 'react-intl'; import { useHistory } from 'react-router-dom'; -import { useInstance } from 'pl-fe/api/hooks/instance/use-instance'; import Text from 'pl-fe/components/ui/text'; import Widget from 'pl-fe/components/ui/widget'; +import { useInstance } from 'pl-fe/hooks/use-instance'; import { usePlFeConfig } from 'pl-fe/hooks/use-pl-fe-config'; import SiteWallet from './site-wallet'; @@ -20,7 +20,7 @@ interface ICryptoDonatePanel { const CryptoDonatePanel: React.FC = ({ limit = 3 }): JSX.Element | null => { const intl = useIntl(); const history = useHistory(); - const { data: instance } = useInstance(); + const instance = useInstance(); const addresses = usePlFeConfig().cryptoAddresses; diff --git a/packages/pl-fe/src/features/crypto-donate/index.tsx b/packages/pl-fe/src/features/crypto-donate/index.tsx index 9dd76d01c..1fbaffb20 100644 --- a/packages/pl-fe/src/features/crypto-donate/index.tsx +++ b/packages/pl-fe/src/features/crypto-donate/index.tsx @@ -1,10 +1,10 @@ import React, { useState } from 'react'; import { defineMessages, useIntl, FormattedMessage } from 'react-intl'; -import { useInstance } from 'pl-fe/api/hooks/instance/use-instance'; import Accordion from 'pl-fe/components/ui/accordion'; import Column from 'pl-fe/components/ui/column'; import Stack from 'pl-fe/components/ui/stack'; +import { useInstance } from 'pl-fe/hooks/use-instance'; import SiteWallet from './components/site-wallet'; @@ -14,7 +14,7 @@ const messages = defineMessages({ const CryptoDonate: React.FC = (): JSX.Element => { const intl = useIntl(); - const { data: instance } = useInstance(); + const instance = useInstance(); const [explanationBoxExpanded, toggleExplanationBox] = useState(true); diff --git a/packages/pl-fe/src/features/directory/index.tsx b/packages/pl-fe/src/features/directory/index.tsx index ce5aaf4ca..3c6e5fc2b 100644 --- a/packages/pl-fe/src/features/directory/index.tsx +++ b/packages/pl-fe/src/features/directory/index.tsx @@ -4,13 +4,13 @@ import { FormattedMessage, defineMessages, useIntl } from 'react-intl'; import { useSearchParams } from 'react-router-dom-v5-compat'; import { useDirectory } from 'pl-fe/api/hooks/account-lists/use-directory'; -import { useInstance } from 'pl-fe/api/hooks/instance/use-instance'; import LoadMore from 'pl-fe/components/load-more'; import { RadioGroup, RadioItem } from 'pl-fe/components/radio'; import { CardTitle } from 'pl-fe/components/ui/card'; import Column from 'pl-fe/components/ui/column'; import Stack from 'pl-fe/components/ui/stack'; import { useFeatures } from 'pl-fe/hooks/use-features'; +import { useInstance } from 'pl-fe/hooks/use-instance'; import AccountCard from './components/account-card'; @@ -25,7 +25,7 @@ const messages = defineMessages({ const Directory = () => { const intl = useIntl(); const [params, setParams] = useSearchParams(); - const { data: instance } = useInstance(); + const instance = useInstance(); const features = useFeatures(); const order = (params.get('order') || 'active') as 'active' | 'new'; diff --git a/packages/pl-fe/src/features/edit-profile/index.tsx b/packages/pl-fe/src/features/edit-profile/index.tsx index 22d4284a6..cc068e5df 100644 --- a/packages/pl-fe/src/features/edit-profile/index.tsx +++ b/packages/pl-fe/src/features/edit-profile/index.tsx @@ -5,7 +5,6 @@ import { defineMessages, useIntl, FormattedMessage } from 'react-intl'; import { updateNotificationSettings } from 'pl-fe/actions/accounts'; import { patchMe } from 'pl-fe/actions/me'; -import { useInstance } from 'pl-fe/api/hooks/instance/use-instance'; import BirthdayInput from 'pl-fe/components/birthday-input'; import List, { ListItem } from 'pl-fe/components/list'; import Button from 'pl-fe/components/ui/button'; @@ -22,6 +21,7 @@ import { useImageField } from 'pl-fe/hooks/forms/use-image-field'; import { useAppDispatch } from 'pl-fe/hooks/use-app-dispatch'; import { useAppSelector } from 'pl-fe/hooks/use-app-selector'; import { useFeatures } from 'pl-fe/hooks/use-features'; +import { useInstance } from 'pl-fe/hooks/use-instance'; import { useOwnAccount } from 'pl-fe/hooks/use-own-account'; import toast from 'pl-fe/toast'; import { isDefaultAvatar, isDefaultHeader } from 'pl-fe/utils/accounts'; @@ -173,7 +173,7 @@ const ProfileField: StreamfieldComponent = ({ index, va const EditProfile: React.FC = () => { const intl = useIntl(); const dispatch = useAppDispatch(); - const { data: instance } = useInstance(); + const instance = useInstance(); const { account } = useOwnAccount(); const features = useFeatures(); @@ -181,7 +181,8 @@ const EditProfile: React.FC = () => { ? instance.configuration.accounts.max_profile_fields : instance.pleroma.metadata.fields_limits.max_fields; - const attachmentTypes = useInstance().data.configuration.media_attachments.supported_mime_types + const attachmentTypes = useAppSelector( + state => state.instance.configuration.media_attachments.supported_mime_types) ?.filter(type => type.startsWith('image/')) .join(','); diff --git a/packages/pl-fe/src/features/federation-restrictions/components/instance-restrictions.tsx b/packages/pl-fe/src/features/federation-restrictions/components/instance-restrictions.tsx index 7377a2ea0..b537c292e 100644 --- a/packages/pl-fe/src/features/federation-restrictions/components/instance-restrictions.tsx +++ b/packages/pl-fe/src/features/federation-restrictions/components/instance-restrictions.tsx @@ -1,11 +1,11 @@ import React from 'react'; import { FormattedMessage } from 'react-intl'; -import { useInstance } from 'pl-fe/api/hooks/instance/use-instance'; import Icon from 'pl-fe/components/icon'; import HStack from 'pl-fe/components/ui/hstack'; import Stack from 'pl-fe/components/ui/stack'; import Text from 'pl-fe/components/ui/text'; +import { useInstance } from 'pl-fe/hooks/use-instance'; import type { RemoteInstance } from 'pl-fe/selectors'; @@ -34,7 +34,7 @@ interface IInstanceRestrictions { } const InstanceRestrictions: React.FC = ({ remoteInstance }) => { - const { data: instance } = useInstance(); + const instance = useInstance(); const renderRestrictions = () => { const items = []; diff --git a/packages/pl-fe/src/features/federation-restrictions/components/restricted-instance.tsx b/packages/pl-fe/src/features/federation-restrictions/components/restricted-instance.tsx index 0a0dd9aef..f709a9385 100644 --- a/packages/pl-fe/src/features/federation-restrictions/components/restricted-instance.tsx +++ b/packages/pl-fe/src/features/federation-restrictions/components/restricted-instance.tsx @@ -1,7 +1,6 @@ import clsx from 'clsx'; import React, { useState } from 'react'; -import { useInstance } from 'pl-fe/api/hooks/instance/use-instance'; import Icon from 'pl-fe/components/icon'; import { useAppSelector } from 'pl-fe/hooks/use-app-selector'; import { makeGetRemoteInstance } from 'pl-fe/selectors'; @@ -15,8 +14,7 @@ interface IRestrictedInstance { } const RestrictedInstance: React.FC = ({ host }) => { - const { data: instance } = useInstance(); - const remoteInstance: any = useAppSelector((state) => getRemoteInstance(state, host, instance)); + const remoteInstance: any = useAppSelector((state) => getRemoteInstance(state, host)); const [expanded, setExpanded] = useState(false); diff --git a/packages/pl-fe/src/features/federation-restrictions/index.tsx b/packages/pl-fe/src/features/federation-restrictions/index.tsx index 16b716c7d..0c07d8bcd 100644 --- a/packages/pl-fe/src/features/federation-restrictions/index.tsx +++ b/packages/pl-fe/src/features/federation-restrictions/index.tsx @@ -1,11 +1,11 @@ import React, { useState, useCallback } from 'react'; import { defineMessages, useIntl } from 'react-intl'; -import { useInstance } from 'pl-fe/api/hooks/instance/use-instance'; import ScrollableList from 'pl-fe/components/scrollable-list'; import Accordion from 'pl-fe/components/ui/accordion'; import Column from 'pl-fe/components/ui/column'; import { useAppSelector } from 'pl-fe/hooks/use-app-selector'; +import { useInstance } from 'pl-fe/hooks/use-instance'; import { makeGetHosts } from 'pl-fe/selectors'; import { federationRestrictionsDisclosed } from 'pl-fe/utils/state'; @@ -21,12 +21,12 @@ const messages = defineMessages({ const FederationRestrictions = () => { const intl = useIntl(); - const { data: instance } = useInstance(); + const instance = useInstance(); const getHosts = useCallback(makeGetHosts(), []); - const hosts = useAppSelector((state) => getHosts(state, instance)); - const disclosed = federationRestrictionsDisclosed(instance); + const hosts = useAppSelector((state) => getHosts(state)); + const disclosed = useAppSelector((state) => federationRestrictionsDisclosed(state)); const [explanationBoxExpanded, setExplanationBoxExpanded] = useState(true); diff --git a/packages/pl-fe/src/features/group/edit-group.tsx b/packages/pl-fe/src/features/group/edit-group.tsx index 936d1d4ae..eb3ceefbe 100644 --- a/packages/pl-fe/src/features/group/edit-group.tsx +++ b/packages/pl-fe/src/features/group/edit-group.tsx @@ -3,7 +3,6 @@ import { defineMessages, FormattedMessage, useIntl } from 'react-intl'; import { useGroup } from 'pl-fe/api/hooks/groups/use-group'; import { useUpdateGroup } from 'pl-fe/api/hooks/groups/use-update-group'; -import { useInstance } from 'pl-fe/api/hooks/instance/use-instance'; import Button from 'pl-fe/components/ui/button'; import Column from 'pl-fe/components/ui/column'; import Form from 'pl-fe/components/ui/form'; @@ -15,6 +14,8 @@ import Spinner from 'pl-fe/components/ui/spinner'; import Textarea from 'pl-fe/components/ui/textarea'; import { useImageField } from 'pl-fe/hooks/forms/use-image-field'; import { useTextField } from 'pl-fe/hooks/forms/use-text-field'; +import { useAppSelector } from 'pl-fe/hooks/use-app-selector'; +import { useInstance } from 'pl-fe/hooks/use-instance'; import toast from 'pl-fe/toast'; import { isDefaultAvatar, isDefaultHeader } from 'pl-fe/utils/accounts'; import { unescapeHTML } from 'pl-fe/utils/html'; @@ -40,7 +41,7 @@ interface IEditGroup { const EditGroup: React.FC = ({ params: { groupId } }) => { const intl = useIntl(); - const { data: instance } = useInstance(); + const instance = useInstance(); const { group, isLoading } = useGroup(groupId); const { updateGroup } = useUpdateGroup(groupId); @@ -56,7 +57,7 @@ const EditGroup: React.FC = ({ params: { groupId } }) => { const maxName = Number(instance.configuration.groups.max_characters_name); const maxNote = Number(instance.configuration.groups.max_characters_description); - const attachmentTypes = useInstance().data.configuration.media_attachments.supported_mime_types + const attachmentTypes = useAppSelector(state => state.instance.configuration.media_attachments.supported_mime_types) ?.filter((type) => type.startsWith('image/')) .join(','); diff --git a/packages/pl-fe/src/features/home-timeline/index.tsx b/packages/pl-fe/src/features/home-timeline/index.tsx index c8646a566..cab35870d 100644 --- a/packages/pl-fe/src/features/home-timeline/index.tsx +++ b/packages/pl-fe/src/features/home-timeline/index.tsx @@ -3,7 +3,6 @@ import { defineMessages, useIntl, FormattedMessage } from 'react-intl'; import { Link } from 'react-router-dom'; import { fetchHomeTimeline } from 'pl-fe/actions/timelines'; -import { useInstance } from 'pl-fe/api/hooks/instance/use-instance'; import PullToRefresh from 'pl-fe/components/pull-to-refresh'; import Column from 'pl-fe/components/ui/column'; import Stack from 'pl-fe/components/ui/stack'; @@ -12,6 +11,7 @@ import Timeline from 'pl-fe/features/ui/components/timeline'; import { useAppDispatch } from 'pl-fe/hooks/use-app-dispatch'; import { useAppSelector } from 'pl-fe/hooks/use-app-selector'; import { useFeatures } from 'pl-fe/hooks/use-features'; +import { useInstance } from 'pl-fe/hooks/use-instance'; import { useIsMobile } from 'pl-fe/hooks/use-is-mobile'; import { useTheme } from 'pl-fe/hooks/use-theme'; @@ -23,7 +23,7 @@ const HomeTimeline: React.FC = () => { const intl = useIntl(); const dispatch = useAppDispatch(); const features = useFeatures(); - const { data: instance } = useInstance(); + const instance = useInstance(); const theme = useTheme(); const polling = useRef(null); diff --git a/packages/pl-fe/src/features/landing-timeline/components/site-banner.tsx b/packages/pl-fe/src/features/landing-timeline/components/site-banner.tsx index a3ab2be82..a82bcc84e 100644 --- a/packages/pl-fe/src/features/landing-timeline/components/site-banner.tsx +++ b/packages/pl-fe/src/features/landing-timeline/components/site-banner.tsx @@ -1,15 +1,15 @@ import React from 'react'; -import { useInstance } from 'pl-fe/api/hooks/instance/use-instance'; import Markup from 'pl-fe/components/markup'; import { ParsedContent } from 'pl-fe/components/parsed-content'; import Stack from 'pl-fe/components/ui/stack'; +import { useInstance } from 'pl-fe/hooks/use-instance'; import { getTextDirection } from 'pl-fe/utils/rtl'; import { LogoText } from './logo-text'; const SiteBanner: React.FC = () => { - const { data: instance } = useInstance(); + const instance = useInstance(); return ( diff --git a/packages/pl-fe/src/features/landing-timeline/index.tsx b/packages/pl-fe/src/features/landing-timeline/index.tsx index 3d1c3e842..25fc67af4 100644 --- a/packages/pl-fe/src/features/landing-timeline/index.tsx +++ b/packages/pl-fe/src/features/landing-timeline/index.tsx @@ -2,11 +2,11 @@ import React, { useEffect } from 'react'; import { FormattedMessage } from 'react-intl'; import { fetchPublicTimeline } from 'pl-fe/actions/timelines'; -import { useInstance } from 'pl-fe/api/hooks/instance/use-instance'; import { useCommunityStream } from 'pl-fe/api/hooks/streaming/use-community-stream'; import PullToRefresh from 'pl-fe/components/pull-to-refresh'; import Column from 'pl-fe/components/ui/column'; import { useAppDispatch } from 'pl-fe/hooks/use-app-dispatch'; +import { useInstance } from 'pl-fe/hooks/use-instance'; import { useIsMobile } from 'pl-fe/hooks/use-is-mobile'; import { useTheme } from 'pl-fe/hooks/use-theme'; @@ -17,7 +17,7 @@ import { SiteBanner } from './components/site-banner'; const LandingTimeline = () => { const dispatch = useAppDispatch(); - const { data: instance } = useInstance(); + const instance = useInstance(); const theme = useTheme(); const isMobile = useIsMobile(); diff --git a/packages/pl-fe/src/features/migration/index.tsx b/packages/pl-fe/src/features/migration/index.tsx index 779b4df4b..d1ca4df7f 100644 --- a/packages/pl-fe/src/features/migration/index.tsx +++ b/packages/pl-fe/src/features/migration/index.tsx @@ -3,7 +3,6 @@ import { defineMessages, FormattedMessage, useIntl } from 'react-intl'; import { Link } from 'react-router-dom'; import { moveAccount } from 'pl-fe/actions/security'; -import { useInstance } from 'pl-fe/api/hooks/instance/use-instance'; import Button from 'pl-fe/components/ui/button'; import Column from 'pl-fe/components/ui/column'; import Form from 'pl-fe/components/ui/form'; @@ -12,6 +11,7 @@ import FormGroup from 'pl-fe/components/ui/form-group'; import Input from 'pl-fe/components/ui/input'; import Text from 'pl-fe/components/ui/text'; import { useAppDispatch } from 'pl-fe/hooks/use-app-dispatch'; +import { useInstance } from 'pl-fe/hooks/use-instance'; import toast from 'pl-fe/toast'; const messages = defineMessages({ @@ -28,7 +28,7 @@ const messages = defineMessages({ const Migration = () => { const intl = useIntl(); const dispatch = useAppDispatch(); - const { data: instance } = useInstance(); + const instance = useInstance(); const cooldownPeriod = instance.pleroma.metadata.migration_cooldown_period; diff --git a/packages/pl-fe/src/features/notifications/components/notification.tsx b/packages/pl-fe/src/features/notifications/components/notification.tsx index dc815749e..eeea9071c 100644 --- a/packages/pl-fe/src/features/notifications/components/notification.tsx +++ b/packages/pl-fe/src/features/notifications/components/notification.tsx @@ -4,7 +4,6 @@ import { Link, useHistory } from 'react-router-dom'; import { mentionCompose } from 'pl-fe/actions/compose'; import { reblog, favourite, unreblog, unfavourite } from 'pl-fe/actions/interactions'; -import { useInstance } from 'pl-fe/api/hooks/instance/use-instance'; import HoverAccountWrapper from 'pl-fe/components/hover-account-wrapper'; import Icon from 'pl-fe/components/icon'; import RelativeTimestamp from 'pl-fe/components/relative-timestamp'; @@ -17,6 +16,7 @@ import Emojify from 'pl-fe/features/emoji/emojify'; import { HotKeys } from 'pl-fe/features/ui/components/hotkeys'; import { useAppDispatch } from 'pl-fe/hooks/use-app-dispatch'; import { useAppSelector } from 'pl-fe/hooks/use-app-selector'; +import { useInstance } from 'pl-fe/hooks/use-instance'; import { useLoggedIn } from 'pl-fe/hooks/use-logged-in'; import { makeGetNotification } from 'pl-fe/selectors'; import { useModalsStore } from 'pl-fe/stores/modals'; @@ -212,7 +212,7 @@ const Notification: React.FC = (props) => { const history = useHistory(); const intl = useIntl(); - const { data: instance } = useInstance(); + const instance = useInstance(); const type = notification.type; const { accounts } = notification; diff --git a/packages/pl-fe/src/features/onboarding/steps/fediverse-step.tsx b/packages/pl-fe/src/features/onboarding/steps/fediverse-step.tsx index 2140cb79c..46b0fbe78 100644 --- a/packages/pl-fe/src/features/onboarding/steps/fediverse-step.tsx +++ b/packages/pl-fe/src/features/onboarding/steps/fediverse-step.tsx @@ -1,18 +1,18 @@ import React from 'react'; import { FormattedMessage } from 'react-intl'; -import { useInstance } from 'pl-fe/api/hooks/instance/use-instance'; import Account from 'pl-fe/components/account'; import Button from 'pl-fe/components/ui/button'; import Card, { CardBody } from 'pl-fe/components/ui/card'; import Icon from 'pl-fe/components/ui/icon'; import Stack from 'pl-fe/components/ui/stack'; import Text from 'pl-fe/components/ui/text'; +import { useInstance } from 'pl-fe/hooks/use-instance'; import { useOwnAccount } from 'pl-fe/hooks/use-own-account'; const FediverseStep = ({ onNext }: { onNext: () => void }) => { const { account } = useOwnAccount(); - const { data: instance } = useInstance(); + const instance = useInstance(); return ( diff --git a/packages/pl-fe/src/features/preferences/index.tsx b/packages/pl-fe/src/features/preferences/index.tsx index e4c4e2609..306cbcbb1 100644 --- a/packages/pl-fe/src/features/preferences/index.tsx +++ b/packages/pl-fe/src/features/preferences/index.tsx @@ -2,13 +2,13 @@ import React from 'react'; import { defineMessages, FormattedMessage, useIntl } from 'react-intl'; import { changeSetting } from 'pl-fe/actions/settings'; -import { useInstance } from 'pl-fe/api/hooks/instance/use-instance'; import List, { ListItem } from 'pl-fe/components/list'; import Form from 'pl-fe/components/ui/form'; import { Mutliselect, SelectDropdown } from 'pl-fe/features/forms'; import SettingToggle from 'pl-fe/features/notifications/components/setting-toggle'; import { useAppDispatch } from 'pl-fe/hooks/use-app-dispatch'; import { useFeatures } from 'pl-fe/hooks/use-features'; +import { useInstance } from 'pl-fe/hooks/use-instance'; import { useSettings } from 'pl-fe/hooks/use-settings'; import ThemeToggle from '../ui/components/theme-toggle'; @@ -98,7 +98,7 @@ const Preferences = () => { const dispatch = useAppDispatch(); const features = useFeatures(); const settings = useSettings(); - const { data: instance } = useInstance(); + const instance = useInstance(); const onSelectChange = (event: React.ChangeEvent, path: string[]) => { dispatch(changeSetting(path, event.target.value, { showAlert: true })); diff --git a/packages/pl-fe/src/features/public-timeline/index.tsx b/packages/pl-fe/src/features/public-timeline/index.tsx index 977d1bd8c..9f64cbebd 100644 --- a/packages/pl-fe/src/features/public-timeline/index.tsx +++ b/packages/pl-fe/src/features/public-timeline/index.tsx @@ -4,12 +4,12 @@ import { Link } from 'react-router-dom'; import { changeSetting } from 'pl-fe/actions/settings'; import { fetchPublicTimeline } from 'pl-fe/actions/timelines'; -import { useInstance } from 'pl-fe/api/hooks/instance/use-instance'; import { usePublicStream } from 'pl-fe/api/hooks/streaming/use-public-stream'; import PullToRefresh from 'pl-fe/components/pull-to-refresh'; import Accordion from 'pl-fe/components/ui/accordion'; import Column from 'pl-fe/components/ui/column'; import { useAppDispatch } from 'pl-fe/hooks/use-app-dispatch'; +import { useInstance } from 'pl-fe/hooks/use-instance'; import { useIsMobile } from 'pl-fe/hooks/use-is-mobile'; import { useSettings } from 'pl-fe/hooks/use-settings'; import { useTheme } from 'pl-fe/hooks/use-theme'; @@ -27,7 +27,7 @@ const CommunityTimeline = () => { const dispatch = useAppDispatch(); const theme = useTheme(); - const { data: instance } = useInstance(); + const instance = useInstance(); const settings = useSettings(); const onlyMedia = settings.timelines.public?.other.onlyMedia ?? false; diff --git a/packages/pl-fe/src/features/register-invite/index.tsx b/packages/pl-fe/src/features/register-invite/index.tsx index 81af6fac2..4591d3222 100644 --- a/packages/pl-fe/src/features/register-invite/index.tsx +++ b/packages/pl-fe/src/features/register-invite/index.tsx @@ -2,9 +2,9 @@ import React from 'react'; import { FormattedMessage } from 'react-intl'; import { useParams } from 'react-router-dom'; -import { useInstance } from 'pl-fe/api/hooks/instance/use-instance'; import { BigCard } from 'pl-fe/components/big-card'; import RegistrationForm from 'pl-fe/features/auth-login/components/registration-form'; +import { useInstance } from 'pl-fe/hooks/use-instance'; interface RegisterInviteParams { token: string; @@ -12,7 +12,7 @@ interface RegisterInviteParams { /** Page to register with an invitation. */ const RegisterInvite: React.FC = () => { - const { data: instance } = useInstance(); + const instance = useInstance(); const { token } = useParams(); const title = ( diff --git a/packages/pl-fe/src/features/server-info/index.tsx b/packages/pl-fe/src/features/server-info/index.tsx index 7ced0eed0..3c2928ee3 100644 --- a/packages/pl-fe/src/features/server-info/index.tsx +++ b/packages/pl-fe/src/features/server-info/index.tsx @@ -1,11 +1,11 @@ import React from 'react'; import { defineMessages, useIntl } from 'react-intl'; -import { useInstance } from 'pl-fe/api/hooks/instance/use-instance'; import Column from 'pl-fe/components/ui/column'; import Divider from 'pl-fe/components/ui/divider'; import Stack from 'pl-fe/components/ui/stack'; import Text from 'pl-fe/components/ui/text'; +import { useInstance } from 'pl-fe/hooks/use-instance'; import LinkFooter from '../ui/components/link-footer'; import PromoPanel from '../ui/components/panels/promo-panel'; @@ -16,7 +16,7 @@ const messages = defineMessages({ const ServerInfo = () => { const intl = useIntl(); - const { data: instance } = useInstance(); + const instance = useInstance(); return ( diff --git a/packages/pl-fe/src/features/status/components/thread-login-cta.tsx b/packages/pl-fe/src/features/status/components/thread-login-cta.tsx index c145925c4..1c3167dd6 100644 --- a/packages/pl-fe/src/features/status/components/thread-login-cta.tsx +++ b/packages/pl-fe/src/features/status/components/thread-login-cta.tsx @@ -1,16 +1,16 @@ import React from 'react'; import { FormattedMessage } from 'react-intl'; -import { useInstance } from 'pl-fe/api/hooks/instance/use-instance'; import Button from 'pl-fe/components/ui/button'; import Card, { CardTitle } from 'pl-fe/components/ui/card'; import Stack from 'pl-fe/components/ui/stack'; import Text from 'pl-fe/components/ui/text'; +import { useInstance } from 'pl-fe/hooks/use-instance'; import { usePlFeConfig } from 'pl-fe/hooks/use-pl-fe-config'; /** Prompts logged-out users to log in when viewing a thread. */ const ThreadLoginCta: React.FC = () => { - const { data: instance } = useInstance(); + const instance = useInstance(); const { displayCta } = usePlFeConfig(); if (!displayCta) return null; diff --git a/packages/pl-fe/src/features/ui/components/modals/edit-federation-modal.tsx b/packages/pl-fe/src/features/ui/components/modals/edit-federation-modal.tsx index 5766626ed..13127c475 100644 --- a/packages/pl-fe/src/features/ui/components/modals/edit-federation-modal.tsx +++ b/packages/pl-fe/src/features/ui/components/modals/edit-federation-modal.tsx @@ -2,7 +2,6 @@ import React, { useState, useEffect, useCallback } from 'react'; import { defineMessages, FormattedMessage, useIntl } from 'react-intl'; import { updateMrf } from 'pl-fe/actions/mrf'; -import { useInstance } from 'pl-fe/api/hooks/instance/use-instance'; import List, { ListItem } from 'pl-fe/components/list'; import Modal from 'pl-fe/components/ui/modal'; import Toggle from 'pl-fe/components/ui/toggle'; @@ -31,9 +30,8 @@ const EditFederationModal: React.FC = const intl = useIntl(); const dispatch = useAppDispatch(); - const { data: instance } = useInstance(); const getRemoteInstance = useCallback(makeGetRemoteInstance(), []); - const remoteInstance = useAppSelector(state => getRemoteInstance(state, host, instance)); + const remoteInstance = useAppSelector(state => getRemoteInstance(state, host)); const [data, setData] = useState>({}); diff --git a/packages/pl-fe/src/features/ui/components/modals/manage-group-modal/steps/details-step.tsx b/packages/pl-fe/src/features/ui/components/modals/manage-group-modal/steps/details-step.tsx index 48397c5f6..e269632ab 100644 --- a/packages/pl-fe/src/features/ui/components/modals/manage-group-modal/steps/details-step.tsx +++ b/packages/pl-fe/src/features/ui/components/modals/manage-group-modal/steps/details-step.tsx @@ -1,7 +1,6 @@ import React from 'react'; import { defineMessages, FormattedMessage, useIntl } from 'react-intl'; -import { useInstance } from 'pl-fe/api/hooks/instance/use-instance'; import Form from 'pl-fe/components/ui/form'; import FormGroup from 'pl-fe/components/ui/form-group'; import Input from 'pl-fe/components/ui/input'; @@ -9,6 +8,8 @@ import Textarea from 'pl-fe/components/ui/textarea'; import AvatarPicker from 'pl-fe/features/edit-profile/components/avatar-picker'; import HeaderPicker from 'pl-fe/features/edit-profile/components/header-picker'; import { usePreview } from 'pl-fe/hooks/forms/use-preview'; +import { useAppSelector } from 'pl-fe/hooks/use-app-selector'; +import { useInstance } from 'pl-fe/hooks/use-instance'; import resizeImage from 'pl-fe/utils/resize-image'; import type { CreateGroupParams } from 'pl-api'; @@ -26,7 +27,7 @@ interface IDetailsStep { const DetailsStep: React.FC = ({ params, onChange }) => { const intl = useIntl(); - const { data: instance } = useInstance(); + const instance = useInstance(); const { display_name: displayName = '', @@ -36,7 +37,7 @@ const DetailsStep: React.FC = ({ params, onChange }) => { const avatarSrc = usePreview(params.avatar); const headerSrc = usePreview(params.header); - const attachmentTypes = useInstance().data.configuration.media_attachments.supported_mime_types + const attachmentTypes = useAppSelector(state => state.instance.configuration.media_attachments.supported_mime_types) ?.filter((type) => type.startsWith('image/')) .join(','); diff --git a/packages/pl-fe/src/features/ui/components/modals/report-modal/index.tsx b/packages/pl-fe/src/features/ui/components/modals/report-modal/index.tsx index c8f203e56..e949a7b9f 100644 --- a/packages/pl-fe/src/features/ui/components/modals/report-modal/index.tsx +++ b/packages/pl-fe/src/features/ui/components/modals/report-modal/index.tsx @@ -5,7 +5,6 @@ import { blockAccount } from 'pl-fe/actions/accounts'; import { submitReport, ReportableEntities } from 'pl-fe/actions/reports'; import { fetchAccountTimeline } from 'pl-fe/actions/timelines'; import { useAccount } from 'pl-fe/api/hooks/accounts/use-account'; -import { useInstance } from 'pl-fe/api/hooks/instance/use-instance'; import AttachmentThumbs from 'pl-fe/components/attachment-thumbs'; import StatusContent from 'pl-fe/components/status-content'; import Modal from 'pl-fe/components/ui/modal'; @@ -15,6 +14,7 @@ import Text from 'pl-fe/components/ui/text'; import AccountContainer from 'pl-fe/containers/account-container'; import { useAppDispatch } from 'pl-fe/hooks/use-app-dispatch'; import { useAppSelector } from 'pl-fe/hooks/use-app-selector'; +import { useInstance } from 'pl-fe/hooks/use-instance'; import ConfirmationStep from './steps/confirmation-step'; import OtherActionsStep from './steps/other-actions-step'; @@ -83,7 +83,7 @@ const ReportModal: React.FC = ({ onClose, acc const [block, setBlock] = useState(false); const [isSubmitting, setIsSubmitting] = useState(false); - const { rules } = useInstance().data; + const { rules } = useInstance(); const [ruleIds, setRuleIds] = useState>([]); const [selectedStatusIds, setSelectedStatusIds] = useState(statusIds); const [comment, setComment] = useState(''); diff --git a/packages/pl-fe/src/features/ui/components/modals/report-modal/steps/reason-step.tsx b/packages/pl-fe/src/features/ui/components/modals/report-modal/steps/reason-step.tsx index 3e9fa59c4..fd4b9ac86 100644 --- a/packages/pl-fe/src/features/ui/components/modals/report-modal/steps/reason-step.tsx +++ b/packages/pl-fe/src/features/ui/components/modals/report-modal/steps/reason-step.tsx @@ -2,11 +2,11 @@ import clsx from 'clsx'; import React, { useEffect, useRef, useState } from 'react'; import { defineMessages, useIntl } from 'react-intl'; -import { useInstance } from 'pl-fe/api/hooks/instance/use-instance'; import FormGroup from 'pl-fe/components/ui/form-group'; import Stack from 'pl-fe/components/ui/stack'; import Text from 'pl-fe/components/ui/text'; import Textarea from 'pl-fe/components/ui/textarea'; +import { useInstance } from 'pl-fe/hooks/use-instance'; import type { Account } from 'pl-fe/normalizers/account'; @@ -33,7 +33,7 @@ const ReasonStep: React.FC = ({ comment, setComment, ruleIds, setRu const [isNearBottom, setNearBottom] = useState(false); const [isNearTop, setNearTop] = useState(true); - const { rules } = useInstance().data; + const { rules } = useInstance(); const shouldRequireRule = rules.length > 0; const handleCommentChange = (event: React.ChangeEvent) => { diff --git a/packages/pl-fe/src/features/ui/components/modals/unauthorized-modal.tsx b/packages/pl-fe/src/features/ui/components/modals/unauthorized-modal.tsx index 7bda58852..2fb49f939 100644 --- a/packages/pl-fe/src/features/ui/components/modals/unauthorized-modal.tsx +++ b/packages/pl-fe/src/features/ui/components/modals/unauthorized-modal.tsx @@ -3,7 +3,6 @@ import { defineMessages, useIntl, FormattedMessage } from 'react-intl'; import { useHistory } from 'react-router-dom'; import { remoteInteraction } from 'pl-fe/actions/interactions'; -import { useInstance } from 'pl-fe/api/hooks/instance/use-instance'; import Button from 'pl-fe/components/ui/button'; import Form from 'pl-fe/components/ui/form'; import Input from 'pl-fe/components/ui/input'; @@ -13,6 +12,7 @@ import Text from 'pl-fe/components/ui/text'; import { useAppDispatch } from 'pl-fe/hooks/use-app-dispatch'; import { useAppSelector } from 'pl-fe/hooks/use-app-selector'; import { useFeatures } from 'pl-fe/hooks/use-features'; +import { useInstance } from 'pl-fe/hooks/use-instance'; import { useRegistrationStatus } from 'pl-fe/hooks/use-registration-status'; import { selectAccount } from 'pl-fe/selectors'; import toast from 'pl-fe/toast'; @@ -40,7 +40,7 @@ const UnauthorizedModal: React.FC = ({ const intl = useIntl(); const history = useHistory(); const dispatch = useAppDispatch(); - const { data: instance } = useInstance(); + const instance = useInstance(); const { isOpen } = useRegistrationStatus(); const username = useAppSelector(state => selectAccount(state, accountId!)?.display_name); diff --git a/packages/pl-fe/src/features/ui/components/panels/instance-info-panel.tsx b/packages/pl-fe/src/features/ui/components/panels/instance-info-panel.tsx index b88fe2203..3273c4fe7 100644 --- a/packages/pl-fe/src/features/ui/components/panels/instance-info-panel.tsx +++ b/packages/pl-fe/src/features/ui/components/panels/instance-info-panel.tsx @@ -2,7 +2,6 @@ import React from 'react'; import { useIntl, defineMessages } from 'react-intl'; import { pinHost, unpinHost } from 'pl-fe/actions/remote-timeline'; -import { useInstance } from 'pl-fe/api/hooks/instance/use-instance'; import Widget from 'pl-fe/components/ui/widget'; import { useAppDispatch } from 'pl-fe/hooks/use-app-dispatch'; import { useAppSelector } from 'pl-fe/hooks/use-app-selector'; @@ -27,9 +26,8 @@ const InstanceInfoPanel: React.FC = ({ host }) => { const dispatch = useAppDispatch(); const settings = useSettings(); + const remoteInstance: any = useAppSelector(state => getRemoteInstance(state, host)); const pinned = settings.remote_timeline.pinnedHosts.includes(host); - const { data: instance } = useInstance(); - const remoteInstance = useAppSelector(state => getRemoteInstance(state, host, instance)); const handlePinHost = () => { if (!pinned) { diff --git a/packages/pl-fe/src/features/ui/components/panels/instance-moderation-panel.tsx b/packages/pl-fe/src/features/ui/components/panels/instance-moderation-panel.tsx index f344f5d48..e0c55aa00 100644 --- a/packages/pl-fe/src/features/ui/components/panels/instance-moderation-panel.tsx +++ b/packages/pl-fe/src/features/ui/components/panels/instance-moderation-panel.tsx @@ -1,7 +1,6 @@ import React from 'react'; import { useIntl, defineMessages, FormattedMessage } from 'react-intl'; -import { useInstance } from 'pl-fe/api/hooks/instance/use-instance'; import DropdownMenu from 'pl-fe/components/dropdown-menu'; import Widget from 'pl-fe/components/ui/widget'; import InstanceRestrictions from 'pl-fe/features/federation-restrictions/components/instance-restrictions'; @@ -26,9 +25,8 @@ const InstanceModerationPanel: React.FC = ({ host }) = const intl = useIntl(); const { openModal } = useModalsStore(); - const { data: instance } = useInstance(); const { account } = useOwnAccount(); - const remoteInstance = useAppSelector(state => getRemoteInstance(state, host, instance)); + const remoteInstance = useAppSelector(state => getRemoteInstance(state, host)); const handleEditFederation = () => { openModal('EDIT_FEDERATION', { host }); diff --git a/packages/pl-fe/src/features/ui/components/panels/promo-panel.tsx b/packages/pl-fe/src/features/ui/components/panels/promo-panel.tsx index 165517d23..80eef9584 100644 --- a/packages/pl-fe/src/features/ui/components/panels/promo-panel.tsx +++ b/packages/pl-fe/src/features/ui/components/panels/promo-panel.tsx @@ -1,15 +1,15 @@ import React from 'react'; -import { useInstance } from 'pl-fe/api/hooks/instance/use-instance'; import ForkAwesomeIcon from 'pl-fe/components/fork-awesome-icon'; import List, { ListItem } from 'pl-fe/components/list'; import HStack from 'pl-fe/components/ui/hstack'; import Widget from 'pl-fe/components/ui/widget'; +import { useInstance } from 'pl-fe/hooks/use-instance'; import { usePlFeConfig } from 'pl-fe/hooks/use-pl-fe-config'; import { useSettings } from 'pl-fe/hooks/use-settings'; const PromoPanel: React.FC = () => { - const { data: instance } = useInstance(); + const instance = useInstance(); const { promoPanel } = usePlFeConfig(); const { locale } = useSettings(); diff --git a/packages/pl-fe/src/features/ui/components/panels/sign-up-panel.tsx b/packages/pl-fe/src/features/ui/components/panels/sign-up-panel.tsx index cb265daa2..201f3f4d7 100644 --- a/packages/pl-fe/src/features/ui/components/panels/sign-up-panel.tsx +++ b/packages/pl-fe/src/features/ui/components/panels/sign-up-panel.tsx @@ -3,7 +3,7 @@ import { FormattedMessage } from 'react-intl'; import { Redirect } from 'react-router-dom'; import { logIn, switchAccount, verifyCredentials } from 'pl-fe/actions/auth'; -import { useInstance } from 'pl-fe/api/hooks/instance/use-instance'; +import { fetchInstance } from 'pl-fe/actions/instance'; import Button from 'pl-fe/components/ui/button'; import Stack from 'pl-fe/components/ui/stack'; import Text from 'pl-fe/components/ui/text'; @@ -12,6 +12,7 @@ import OtpAuthForm from 'pl-fe/features/auth-login/components/otp-auth-form'; import ExternalLoginForm from 'pl-fe/features/external-login/components/external-login-form'; import { useAppDispatch } from 'pl-fe/hooks/use-app-dispatch'; import { useAppSelector } from 'pl-fe/hooks/use-app-selector'; +import { useInstance } from 'pl-fe/hooks/use-instance'; import { useRegistrationStatus } from 'pl-fe/hooks/use-registration-status'; import { getRedirectUrl } from 'pl-fe/utils/redirect'; import { isStandalone } from 'pl-fe/utils/state'; @@ -20,7 +21,7 @@ import type { PlfeResponse } from 'pl-fe/api'; const SignUpPanel = () => { const dispatch = useAppDispatch(); - const { data: instance } = useInstance(); + const instance = useInstance(); const { isOpen } = useRegistrationStatus(); const me = useAppSelector((state) => state.me); const standalone = useAppSelector(isStandalone); @@ -41,6 +42,11 @@ const SignUpPanel = () => { const { username, password } = getFormData(event.target as HTMLFormElement); dispatch(logIn(username, password)) .then(({ access_token }) => dispatch(verifyCredentials(access_token as string))) + // Refetch the instance for authenticated fetch + .then(async (account) => { + await dispatch(fetchInstance()); + return account; + }) .then((account: { id: string }) => { if (typeof me === 'string') { dispatch(switchAccount(account.id)); diff --git a/packages/pl-fe/src/features/ui/index.tsx b/packages/pl-fe/src/features/ui/index.tsx index dbe28f08b..05b8bc729 100644 --- a/packages/pl-fe/src/features/ui/index.tsx +++ b/packages/pl-fe/src/features/ui/index.tsx @@ -12,7 +12,6 @@ import { expandNotifications } from 'pl-fe/actions/notifications'; import { register as registerPushNotifications } from 'pl-fe/actions/push-notifications/registerer'; import { fetchScheduledStatuses } from 'pl-fe/actions/scheduled-statuses'; import { fetchHomeTimeline } from 'pl-fe/actions/timelines'; -import { useInstance } from 'pl-fe/api/hooks/instance/use-instance'; import { useUserStream } from 'pl-fe/api/hooks/streaming/use-user-stream'; import SidebarNavigation from 'pl-fe/components/sidebar-navigation'; import ThumbNavigation from 'pl-fe/components/thumb-navigation'; @@ -21,6 +20,7 @@ import { useAppDispatch } from 'pl-fe/hooks/use-app-dispatch'; import { useAppSelector } from 'pl-fe/hooks/use-app-selector'; import { useDraggedFiles } from 'pl-fe/hooks/use-dragged-files'; import { useFeatures } from 'pl-fe/hooks/use-features'; +import { useInstance } from 'pl-fe/hooks/use-instance'; import { useLoggedIn } from 'pl-fe/hooks/use-logged-in'; import { useOwnAccount } from 'pl-fe/hooks/use-own-account'; import { usePlFeConfig } from 'pl-fe/hooks/use-pl-fe-config'; @@ -41,6 +41,7 @@ import RemoteInstanceLayout from 'pl-fe/layouts/remote-instance-layout'; import SearchLayout from 'pl-fe/layouts/search-layout'; import StatusLayout from 'pl-fe/layouts/status-layout'; import { useUiStore } from 'pl-fe/stores/ui'; +import { getVapidKey } from 'pl-fe/utils/auth'; import { isStandalone } from 'pl-fe/utils/state'; import BackgroundShapes from './components/background-shapes'; @@ -145,14 +146,13 @@ import { WrappedRoute } from './util/react-router-helpers'; // Dummy import, to make sure that ends up in the application bundle. // Without this it ends up in ~8 very commonly used bundles. import 'pl-fe/components/status'; -import { useVapidKey } from 'pl-fe/hooks/use-vapid-key'; interface ISwitchingColumnsArea { children: React.ReactNode; } const SwitchingColumnsArea: React.FC = ({ children }) => { - const { data: instance } = useInstance(); + const instance = useInstance(); const features = useFeatures(); const { search } = useLocation(); const { isLoggedIn } = useLoggedIn(); @@ -361,7 +361,7 @@ const UI: React.FC = ({ children }) => { const me = useAppSelector(state => state.me); const { account } = useOwnAccount(); const features = useFeatures(); - const vapidKey = useVapidKey(); + const vapidKey = useAppSelector(state => getVapidKey(state)); const { isDropdownMenuOpen } = useUiStore(); const standalone = useAppSelector(isStandalone); @@ -447,7 +447,7 @@ const UI: React.FC = ({ children }) => { }, [!!account]); useEffect(() => { - dispatch(registerPushNotifications(vapidKey)); + dispatch(registerPushNotifications()); }, [vapidKey]); // Wait for login to succeed or fail diff --git a/packages/pl-fe/src/hooks/use-features.ts b/packages/pl-fe/src/hooks/use-features.ts index 81fb49024..0b6560f76 100644 --- a/packages/pl-fe/src/hooks/use-features.ts +++ b/packages/pl-fe/src/hooks/use-features.ts @@ -1,8 +1,7 @@ import { Features } from 'pl-api'; -import { useInstance } from 'pl-fe/api/hooks/instance/use-instance'; - import { useAppSelector } from './use-app-selector'; +import { useInstance } from './use-instance'; /** Get features for the current instance. */ const useFeatures = (): Features => { diff --git a/packages/pl-fe/src/hooks/use-instance.ts b/packages/pl-fe/src/hooks/use-instance.ts new file mode 100644 index 000000000..4c94a4ab2 --- /dev/null +++ b/packages/pl-fe/src/hooks/use-instance.ts @@ -0,0 +1,6 @@ +import { useAppSelector } from './use-app-selector'; + +/** Get the Instance for the current backend. */ +const useInstance = () => useAppSelector((state) => state.instance); + +export { useInstance }; diff --git a/packages/pl-fe/src/hooks/use-registration-status.ts b/packages/pl-fe/src/hooks/use-registration-status.ts index 8ab5d48ab..aa4700e24 100644 --- a/packages/pl-fe/src/hooks/use-registration-status.ts +++ b/packages/pl-fe/src/hooks/use-registration-status.ts @@ -1,9 +1,8 @@ -import { useInstance } from 'pl-fe/api/hooks/instance/use-instance'; - import { useFeatures } from './use-features'; +import { useInstance } from './use-instance'; const useRegistrationStatus = () => { - const { data: instance } = useInstance(); + const instance = useInstance(); const features = useFeatures(); return { diff --git a/packages/pl-fe/src/hooks/use-vapid-key.ts b/packages/pl-fe/src/hooks/use-vapid-key.ts deleted file mode 100644 index b52879aed..000000000 --- a/packages/pl-fe/src/hooks/use-vapid-key.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { useInstance } from 'pl-fe/api/hooks/instance/use-instance'; - -import { useAppSelector } from './use-app-selector'; - -const useVapidKey = () => { - const { data: instance } = useInstance(); - - return useAppSelector((state) => instance.configuration.vapid.public_key || state.auth.app?.vapid_key); -}; - -export { useVapidKey }; diff --git a/packages/pl-fe/src/init/pl-fe-load.tsx b/packages/pl-fe/src/init/pl-fe-load.tsx index bbe56dbbd..cfcc6be64 100644 --- a/packages/pl-fe/src/init/pl-fe-load.tsx +++ b/packages/pl-fe/src/init/pl-fe-load.tsx @@ -1,9 +1,9 @@ import React, { useState, useEffect } from 'react'; import { IntlProvider } from 'react-intl'; +import { fetchInstance } from 'pl-fe/actions/instance'; import { fetchMe } from 'pl-fe/actions/me'; import { loadPlFeConfig } from 'pl-fe/actions/pl-fe'; -import { useInstance } from 'pl-fe/api/hooks/instance/use-instance'; import LoadingScreen from 'pl-fe/components/loading-screen'; import { useAppDispatch } from 'pl-fe/hooks/use-app-dispatch'; import { useAppSelector } from 'pl-fe/hooks/use-app-selector'; @@ -17,6 +17,8 @@ const loadInitial = () => { return async(dispatch, getState) => { // Await for authenticated fetch await dispatch(fetchMe()); + // Await for feature detection + await dispatch(fetchInstance()); // Await for configuration await dispatch(loadPlFeConfig()); }; @@ -29,7 +31,6 @@ interface IPlFeLoad { /** Initial data loader. */ const PlFeLoad: React.FC = ({ children }) => { const dispatch = useAppDispatch(); - const { isLoading: isLoadingInstance } = useInstance(); const me = useAppSelector(state => state.me); const { account } = useOwnAccount(); @@ -45,7 +46,6 @@ const PlFeLoad: React.FC = ({ children }) => { me && !account, !isLoaded, localeLoading, - isLoadingInstance, ].some(Boolean); // Load the user's locale diff --git a/packages/pl-fe/src/initial-state.ts b/packages/pl-fe/src/initial-state.ts deleted file mode 100644 index 9dcdce221..000000000 --- a/packages/pl-fe/src/initial-state.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { decodeFromMarkup, pleromaDecoder } from './actions/preload'; - -let initialState: Record = {}; - -try { - initialState = decodeFromMarkup('initial-results', pleromaDecoder); -} catch (e) { - // -} - -export { initialState }; diff --git a/packages/pl-fe/src/layouts/remote-instance-layout.tsx b/packages/pl-fe/src/layouts/remote-instance-layout.tsx index 4ecc060a6..424f903aa 100644 --- a/packages/pl-fe/src/layouts/remote-instance-layout.tsx +++ b/packages/pl-fe/src/layouts/remote-instance-layout.tsx @@ -10,7 +10,6 @@ import { import { useAppSelector } from 'pl-fe/hooks/use-app-selector'; import { useOwnAccount } from 'pl-fe/hooks/use-own-account'; import { federationRestrictionsDisclosed } from 'pl-fe/utils/state'; -import { useInstance } from 'pl-fe/api/hooks/instance/use-instance'; interface IRemoteInstanceLayout { params?: { @@ -24,8 +23,7 @@ const RemoteInstanceLayout: React.FC = ({ children, param const host = params!.instance!; const { account } = useOwnAccount(); - const { data: instance } = useInstance(); - const disclosed = federationRestrictionsDisclosed(instance); + const disclosed = useAppSelector(federationRestrictionsDisclosed); return ( <> diff --git a/packages/pl-fe/src/reducers/compose.ts b/packages/pl-fe/src/reducers/compose.ts index 853904fd2..d68a931bb 100644 --- a/packages/pl-fe/src/reducers/compose.ts +++ b/packages/pl-fe/src/reducers/compose.ts @@ -1,5 +1,7 @@ import { create } from 'mutative'; +import { type CredentialAccount, type Instance, type MediaAttachment, type Tag } from 'pl-api'; +import { INSTANCE_FETCH_SUCCESS, type InstanceAction } from 'pl-fe/actions/instance'; import { isNativeEmoji, type Emoji } from 'pl-fe/features/emoji'; import { tagHistory } from 'pl-fe/settings'; @@ -65,7 +67,6 @@ import { FE_NAME } from '../actions/settings'; import { TIMELINE_DELETE, type TimelineAction } from '../actions/timelines'; import { unescapeHTML } from '../utils/html'; -import type { CredentialAccount, MediaAttachment, Tag } from 'pl-api'; import type { Language } from 'pl-fe/features/preferences'; import type { Account } from 'pl-fe/normalizers/account'; import type { Status } from 'pl-fe/normalizers/status'; @@ -309,11 +310,11 @@ const importAccount = (compose: Compose, account: CredentialAccount) => { // } // }; -// const updateDefaultContentType = (compose: Compose, instance: Instance) => { -// const postFormats = instance.pleroma.metadata.post_formats; +const updateDefaultContentType = (compose: Compose, instance: Instance) => { + const postFormats = instance.pleroma.metadata.post_formats; -// compose.content_type = postFormats.includes(compose.content_type) ? compose.content_type : postFormats.includes('text/markdown') ? 'text/markdown' : postFormats[0]; -// }; + compose.content_type = postFormats.includes(compose.content_type) ? compose.content_type : postFormats.includes('text/markdown') ? 'text/markdown' : postFormats[0]; +}; const updateCompose = (state: State, key: string, updater: (compose: Compose) => void) => create(state, draft => { @@ -326,7 +327,7 @@ const initialState: State = { default: newCompose({ idempotencyKey: crypto.randomUUID(), resetFileKey: getResetFileKey() }), }; -const compose = (state = initialState, action: ComposeAction | EventsAction | MeAction | TimelineAction): State => { +const compose = (state = initialState, action: ComposeAction | EventsAction | InstanceAction | MeAction | TimelineAction): State => { switch (action.type) { case COMPOSE_TYPE_CHANGE: return updateCompose(state, action.composeId, compose => { @@ -687,6 +688,8 @@ const compose = (state = initialState, action: ComposeAction | EventsAction | Me return updateCompose(state, action.composeId, compose => { compose.federated = !compose.federated; }); + case INSTANCE_FETCH_SUCCESS: + return updateCompose(state, 'default', (compose) => updateDefaultContentType(compose, action.instance)); default: return state; } diff --git a/packages/pl-fe/src/reducers/index.ts b/packages/pl-fe/src/reducers/index.ts index c26ad4915..945556710 100644 --- a/packages/pl-fe/src/reducers/index.ts +++ b/packages/pl-fe/src/reducers/index.ts @@ -18,6 +18,7 @@ import domain_lists from './domain-lists'; import draft_statuses from './draft-statuses'; import filters from './filters'; import followed_tags from './followed-tags'; +import instance from './instance'; import listAdder from './list-adder'; import listEditor from './list-editor'; import lists from './lists'; @@ -53,6 +54,7 @@ const reducers = { entities, filters, followed_tags, + instance, listAdder, listEditor, lists, @@ -85,8 +87,8 @@ const logOut = (state: AppState): ReturnType => { const newState = rootReducer(undefined, { type: '' }); - const { plfe, custom_emojis, auth } = state; - return { ...newState, plfe, custom_emojis, auth }; + const { instance, plfe, custom_emojis, auth } = state; + return { ...newState, instance, plfe, custom_emojis, auth }; }; const rootReducer: typeof appReducer = (state, action) => { diff --git a/packages/pl-fe/src/reducers/instance.ts b/packages/pl-fe/src/reducers/instance.ts index 96312b8c3..9d4475dc5 100644 --- a/packages/pl-fe/src/reducers/instance.ts +++ b/packages/pl-fe/src/reducers/instance.ts @@ -1,8 +1,102 @@ -import { instanceSchema } from 'pl-api'; +import { create } from 'mutative'; +import { type Instance, instanceSchema, PleromaConfig } from 'pl-api'; import * as v from 'valibot'; -const initialState = v.parse(instanceSchema, {}); +import { ADMIN_CONFIG_UPDATE_REQUEST, ADMIN_CONFIG_UPDATE_SUCCESS, type AdminActions } from 'pl-fe/actions/admin'; +import { INSTANCE_FETCH_FAIL, INSTANCE_FETCH_SUCCESS, type InstanceAction } from 'pl-fe/actions/instance'; +import { PLEROMA_PRELOAD_IMPORT, type PreloadAction } from 'pl-fe/actions/preload'; +import KVStore from 'pl-fe/storage/kv-store'; +import ConfigDB from 'pl-fe/utils/config-db'; -const instance = () => initialState; +const initialState: State = v.parse(instanceSchema, {}); +type State = Instance; + +const preloadImport = (state: State, action: Record, path: string) => { + const instance = action.data[path]; + return instance ? v.parse(instanceSchema, instance) : state; +}; + +const getConfigValue = (instanceConfig: Array, key: string) => { + const v = instanceConfig + .find(value => value?.tuple?.[0] === key); + + return v ? v?.tuple?.[1] : undefined; +}; + +const importConfigs = (state: State, configs: PleromaConfig['configs']) => { + // FIXME: This is pretty hacked together. Need to make a cleaner map. + const config = ConfigDB.find(configs, ':pleroma', ':instance'); + const simplePolicy = ConfigDB.toSimplePolicy(configs); + + if (!config && !simplePolicy) return state; + + if (config) { + const value = config.value || []; + const registrationsOpen = getConfigValue(value, ':registrations_open') as boolean | undefined; + const approvalRequired = getConfigValue(value, ':account_approval_required') as boolean | undefined; + + state.registrations = { + enabled: registrationsOpen ?? state.registrations.enabled, + approval_required: approvalRequired ?? state.registrations.approval_required, + }; + } + + if (simplePolicy) { + state.pleroma.metadata.federation.mrf_simple = simplePolicy; + } +}; + +const handleAuthFetch = (state: State) => { + // Authenticated fetch is enabled, so make the instance appear censored + return { + ...state, + title: state.title || '██████', + description: state.description || '████████████', + }; +}; + +const getHost = (instance: { domain: string }) => { + const domain = instance.domain; + try { + return new URL(domain).host; + } catch { + try { + return new URL(`https://${domain}`).host; + } catch { + return null; + } + } +}; + +const persistInstance = (instance: { domain: string }, host: string | null = getHost(instance)) => { + if (host) { + KVStore.setItem(`instance:${host}`, instance).catch(console.error); + } +}; + +const handleInstanceFetchFail = (state: State, error: any) => { + if (error.response?.status === 401) { + return handleAuthFetch(state); + } else { + return state; + } +}; + +const instance = (state = initialState, action: AdminActions | InstanceAction | PreloadAction): State => { + switch (action.type) { + case PLEROMA_PRELOAD_IMPORT: + return create(state, (draft) => preloadImport(draft, action, '/api/v1/instance')); + case INSTANCE_FETCH_SUCCESS: + persistInstance(action.instance); + return action.instance; + case INSTANCE_FETCH_FAIL: + return handleInstanceFetchFail(state, action.error); + case ADMIN_CONFIG_UPDATE_REQUEST: + case ADMIN_CONFIG_UPDATE_SUCCESS: + return create(state, (draft) => importConfigs(draft, action.configs)); + default: + return state; + } +}; export { instance as default }; diff --git a/packages/pl-fe/src/reducers/meta.ts b/packages/pl-fe/src/reducers/meta.ts index 4ab9d37e1..78e5e9f3b 100644 --- a/packages/pl-fe/src/reducers/meta.ts +++ b/packages/pl-fe/src/reducers/meta.ts @@ -1,10 +1,20 @@ -import type { AnyAction } from 'redux'; +import { INSTANCE_FETCH_FAIL, type InstanceAction } from 'pl-fe/actions/instance'; const initialState = { /** Whether /api/v1/instance 404'd (and we should display the external auth form). */ instance_fetch_failed: false, }; -const meta = (state = initialState, action: AnyAction): typeof initialState => state; +const meta = (state = initialState, action: InstanceAction): typeof initialState => { + switch (action.type) { + case INSTANCE_FETCH_FAIL: + if ((action.error as any)?.response?.status === 404) { + return { instance_fetch_failed: true }; + } + return state; + default: + return state; + } +}; export { meta as default }; diff --git a/packages/pl-fe/src/selectors/index.ts b/packages/pl-fe/src/selectors/index.ts index dd538d5ce..1eddc1584 100644 --- a/packages/pl-fe/src/selectors/index.ts +++ b/packages/pl-fe/src/selectors/index.ts @@ -8,7 +8,7 @@ import { validId } from 'pl-fe/utils/auth'; import ConfigDB from 'pl-fe/utils/config-db'; import { shouldFilter } from 'pl-fe/utils/timelines'; -import type { Account as BaseAccount, Filter, Instance, MediaAttachment, NotificationGroup, Relationship } from 'pl-api'; +import type { Account as BaseAccount, Filter, MediaAttachment, NotificationGroup, Relationship } from 'pl-api'; import type { EntityStore } from 'pl-fe/entity-store/types'; import type { Account } from 'pl-fe/normalizers/account'; import type { Group } from 'pl-fe/normalizers/group'; @@ -275,7 +275,7 @@ const makeGetOtherAccounts = () => createSelector([ const getSimplePolicy = createSelector([ (state: RootState) => state.admin.configs, - (_state: RootState, instance: Instance) => instance.pleroma.metadata.federation.mrf_simple, + (state: RootState) => state.instance.pleroma.metadata.federation.mrf_simple, ], (configs, instancePolicy) => ({ ...instancePolicy, ...ConfigDB.toSimplePolicy(configs), @@ -291,8 +291,8 @@ type HostFederation = { [key in keyof MRFSimple]: boolean; }; -const getRemoteInstanceFederation = (state: RootState, host: string, instance: Instance): HostFederation => { - const simplePolicy = getSimplePolicy(state, instance); +const getRemoteInstanceFederation = (state: RootState, host: string): HostFederation => { + const simplePolicy = getSimplePolicy(state); return Object.fromEntries( Object.entries(simplePolicy).map(([key, hosts]) => [key, hosts.includes(host)]), diff --git a/packages/pl-fe/src/utils/auth.ts b/packages/pl-fe/src/utils/auth.ts index 8bd27659e..59cd8e545 100644 --- a/packages/pl-fe/src/utils/auth.ts +++ b/packages/pl-fe/src/utils/auth.ts @@ -56,6 +56,10 @@ const getAuthUserUrl = (state: RootState) => { ].filter(url => url).find(isURL); }; +/** Get the VAPID public key. */ +const getVapidKey = (state: RootState) => + state.auth.app?.vapid_key || state.instance.configuration.vapid.public_key; + const getMeUrl = (state: RootState) => selectOwnAccount(state)?.url; export { @@ -67,5 +71,6 @@ export { getAccessToken, getAuthUserId, getAuthUserUrl, + getVapidKey, getMeUrl, }; diff --git a/packages/pl-fe/src/utils/scopes.ts b/packages/pl-fe/src/utils/scopes.ts index 966b146ff..bfaf61d22 100644 --- a/packages/pl-fe/src/utils/scopes.ts +++ b/packages/pl-fe/src/utils/scopes.ts @@ -1,16 +1,15 @@ import { getFeatures, PLEROMA, TOKI, type Instance } from 'pl-api'; -import * as BuildConfig from 'pl-fe/build-config'; -import { queryClient } from 'pl-fe/queries/client'; +import type { RootState } from 'pl-fe/store'; /** * Get the OAuth scopes to use for login & signup. * Mastodon will refuse scopes it doesn't know, so care is needed. */ -const getInstanceScopes = (instance?: Instance) => { - const software = instance ? getFeatures(instance).version.software : null; +const getInstanceScopes = (instance: Instance) => { + const v = getFeatures(instance).version; - switch (software) { + switch (v.software) { case TOKI: return 'read write follow push write:bites'; case PLEROMA: @@ -21,11 +20,7 @@ const getInstanceScopes = (instance?: Instance) => { }; /** Convenience function to get scopes from instance in store. */ -const getScopes = (baseURL = BuildConfig.BACKEND_URL || '') => { - const instance = queryClient.getQueryData(['instance', 'instanceInformation', baseURL]); - - return getInstanceScopes(instance); -}; +const getScopes = (state: RootState) => getInstanceScopes(state.instance); export { getInstanceScopes, diff --git a/packages/pl-fe/src/utils/state.ts b/packages/pl-fe/src/utils/state.ts index 5ec11d05a..f461bff42 100644 --- a/packages/pl-fe/src/utils/state.ts +++ b/packages/pl-fe/src/utils/state.ts @@ -9,15 +9,14 @@ import { isPrerendered } from 'pl-fe/precheck'; import { selectOwnAccount } from 'pl-fe/selectors'; import { isURL } from 'pl-fe/utils/auth'; -import type { Instance } from 'pl-api'; import type { RootState } from 'pl-fe/store'; /** Whether to display the fqn instead of the acct. */ const displayFqn = (state: RootState): boolean => getPlFeConfig(state).displayFqn; /** Whether the instance exposes instance blocks through the API. */ -const federationRestrictionsDisclosed = (instance: Instance): boolean => - !!instance.pleroma.metadata.federation.mrf_policies; +const federationRestrictionsDisclosed = (state: RootState): boolean => + !!state.instance.pleroma.metadata.federation.mrf_policies; /** * Determine whether pl-fe is running in standalone mode. From e1f80fd96f4a7d24bf7a7ec199653c52f3eaa021 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?marcin=20miko=C5=82ajczak?= Date: Sat, 30 Nov 2024 12:22:49 +0000 Subject: [PATCH 08/76] Translated using Weblate (Polish) Currently translated at 98.7% (1606 of 1627 strings) Translation: pl-fe/pl-fe Translate-URL: https://hosted.weblate.org/projects/pl-fe/pl-fe/pl/ --- packages/pl-fe/src/locales/pl.json | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/packages/pl-fe/src/locales/pl.json b/packages/pl-fe/src/locales/pl.json index 46611b016..58a452c85 100644 --- a/packages/pl-fe/src/locales/pl.json +++ b/packages/pl-fe/src/locales/pl.json @@ -432,6 +432,7 @@ "compose.submit_success": "Twój wpis został wysłany", "compose_event.create": "Utwórz", "compose_event.edit_success": "Wydarzenie zostało zedytowane", + "compose_event.fetch_fail": "Nie udało się uzyskać informacji o edytowanym wydarzeniu", "compose_event.fields.approval_required": "Chcę ręcznie zatwierdzać prośby o dołączenie", "compose_event.fields.banner_hint": "PNG, GIF lub JPG. Zalecany jest poziomy format.", "compose_event.fields.banner_label": "Baner wydarzenia", @@ -455,6 +456,7 @@ "compose_event.tabs.pending": "Zarządzaj prośbami", "compose_event.update": "Aktualizuj", "compose_event.upload_banner": "Wyślij obraz", + "compose_form.approval_required": "Odpowiedź musi zostać zatwierdzona przez jej autora.", "compose_form.content_type.change": "Zmień typ treści", "compose_form.direct_message_warning": "Ten wpis będzie widoczny tylko dla wszystkich wspomnianych użytkowników.", "compose_form.event_placeholder": "Napisz w tym wydarzeniu", @@ -877,6 +879,7 @@ "groups.empty.title": "Brak grup", "groups.pending.count": "{number, plural, one {# oczekujące zgłoszenie} few {# oczekujące zgłoszenia} other {# oczekujących zgłoszeń}}", "hashtag.follow": "Obserwuj hashtagi", + "hashtags.and_other": "…i {count, plural, other {# więcej}}", "home.column_settings.show_reblogs": "Pokazuj podbicia", "home.column_settings.show_replies": "Pokazuj odpowiedzi", "icon_button.icons": "Ikony", @@ -921,6 +924,11 @@ "interaction_policies.title.unlisted.can_reblog": "Kto może podbić niewidoczny wpis?", "interaction_policies.title.unlisted.can_reply": "Kto może odpowiedzieć na niewidoczny wpis?", "interaction_policies.update": "Aktualizuj", + "interaction_request.authorize": "Akceptuj", + "interaction_request.favourite": "{name} chce polubić Twój wpis", + "interaction_request.reblog": "{name} chce podbić Twój wpis", + "interaction_request.reject": "Odrzuć", + "interaction_request.reply": "{name} chce odpowiedzieć na Twój wpis wpis", "interactions_circle.compose": "Udostępnij", "interactions_circle.confirmation_heading": "Czy chcesz wygenerować krąg interakcji dla użytkownika @{username}?", "interactions_circle.download": "Pobierz", @@ -1249,6 +1257,7 @@ "preferences.fields.display_media.default": "Ukrywaj media oznaczone jako wrażliwe", "preferences.fields.display_media.hide_all": "Ukrywaj wszystkie media", "preferences.fields.display_media.show_all": "Pokazuj wszystkie media", + "preferences.fields.implicit_addressing_label": "Uwzględnij wzmianki w treści wpisu, gdy odpowiadasz", "preferences.fields.known_languages_label": "Języki, które znasz", "preferences.fields.language_label": "Język", "preferences.fields.media_display_label": "Wyświetlanie zawartości multimedialnej", @@ -1265,6 +1274,7 @@ "preferences.notifications.advanced": "Pokazuj wszystkie kategorie powiadomień", "preferences.options.content_type_html": "HTML", "preferences.options.content_type_markdown": "Markdown", + "preferences.options.content_type_mfm": "MFM", "preferences.options.content_type_plaintext": "Czysty tekst", "preferences.options.content_type_wysiwyg": "WYSIWYG", "preferences.options.privacy_followers_only": "Tylko dla obserwujących", @@ -1439,6 +1449,7 @@ "status.add_known_language": "Nie tłumacz automatycznie wpisów w języku {language}.", "status.admin_account": "Moderuj @{name}", "status.admin_status": "Otwórz ten wpis w interfejsie moderacyjnym", + "status.application_name": "Wysłano z {name}", "status.approval.pending": "Oczekuje na zatwierdzenie", "status.approval.rejected": "Odrzucono", "status.bookmark": "Dodaj do zakładek", @@ -1465,6 +1476,12 @@ "status.group": "Napisano w {group}", "status.group_mod_delete": "Usuń wpis z grupy", "status.hide_translation": "Ukryj tłumaczenie", + "status.interaction_policy.favourite.approval_required": "Autor musi zatwierdzić Twoje polubienie.", + "status.interaction_policy.favourite.followers_only": "Tylko osoby obserwjące autora mogą to polubić.", + "status.interaction_policy.favourite.following_only": "Tylko osoby obserwowane przez autora mogą to polubić.", + "status.interaction_policy.favourite.header": "Autor ogranicza, kto może polubić ten wpis.", + "status.interaction_policy.favourite.mentioned_only": "Tylko osoby wspomniane przez autora mogą to polubić.", + "status.interaction_policy.favourite.mutuals_only": "Tylko osoby wzajemnie obserwujące się z autorem mogą to polubić.", "status.interactions.dislikes": "{count, plural, one {Negatywna reakcja} other {Negatywnych reakcji}}", "status.interactions.favourites": "{count, plural, one {Polubienie} few {Polubienia} other {Polubień}}", "status.interactions.quotes": "{count, plural, one {Cytat} few {Cytaty} other {Cytatów}}", @@ -1511,7 +1528,7 @@ "status.title": "Wpis", "status.title_direct": "Wiadomość bezpośrednia", "status.translate": "Przetłumacz wpis", - "status.translated_from_with": "Przetłumaczono z {lang} z użyciem {provider}", + "status.translated_from_with": "Przetłumaczono z {lang} {provider}", "status.translating": "Tłumaczenie…", "status.unbookmark": "Usuń z zakładek", "status.unbookmarked": "Usunięto z zakładek.", From 22f0f09ce6412880e884832e2f21c26a19e76256 Mon Sep 17 00:00:00 2001 From: mkljczk Date: Wed, 4 Dec 2024 12:02:55 +0100 Subject: [PATCH 09/76] pl-api: update feature definitions for iceshrimp net Signed-off-by: mkljczk --- packages/pl-api/lib/features.ts | 21 +++++++++++++++++++++ packages/pl-api/package.json | 2 +- packages/pl-fe/package.json | 2 +- packages/pl-fe/yarn.lock | 8 ++++---- 4 files changed, 27 insertions(+), 6 deletions(-) diff --git a/packages/pl-api/lib/features.ts b/packages/pl-api/lib/features.ts index 7c97b291d..d261f3b18 100644 --- a/packages/pl-api/lib/features.ts +++ b/packages/pl-api/lib/features.ts @@ -257,6 +257,7 @@ const getFeatures = (instance: Instance) => { announcements: any([ v.software === FIREFISH, v.software === ICESHRIMP, + v.software === ICESHRIMP_NET, v.software === MASTODON, v.software === PLEROMA, v.software === TAKAHE && gte(v.version, '0.7.0'), @@ -283,6 +284,7 @@ const getFeatures = (instance: Instance) => { * see POST /api/v1/bite */ bites: any([ + v.software === ICESHRIMP_NET, v.software === TOKI, instance.api_versions['bites.pleroma.pl-api'] >= 1, ]), @@ -309,6 +311,7 @@ const getFeatures = (instance: Instance) => { v.software === FIREFISH, v.software === GOTOSOCIAL, v.software === ICESHRIMP, + v.software === ICESHRIMP_NET, v.software === FRIENDICA, v.software === MASTODON, v.software === MITRA && gte(v.version, '3.3.0'), @@ -325,6 +328,7 @@ const getFeatures = (instance: Instance) => { bots: any([ v.software === GOTOSOCIAL, v.software === ICESHRIMP, + v.software === ICESHRIMP_NET, v.software === MASTODON, v.software === PLEROMA, ]), @@ -359,6 +363,7 @@ const getFeatures = (instance: Instance) => { v.software === FRIENDICA, v.software === GOTOSOCIAL && gte(v.version, '0.17.0'), v.software === ICESHRIMP, + v.software === ICESHRIMP_NET, v.software === MASTODON, v.software === PIXELFED, v.software === PLEROMA, @@ -439,6 +444,7 @@ const getFeatures = (instance: Instance) => { v.software === FRIENDICA, v.software === GOTOSOCIAL, v.software === ICESHRIMP, + v.software === ICESHRIMP_NET, v.software === MASTODON, v.software === MITRA, v.software === PIXELFED, @@ -455,6 +461,7 @@ const getFeatures = (instance: Instance) => { v.software === FIREFISH, v.software === FRIENDICA && gte(v.version, '2022.12.0'), v.software === ICESHRIMP, + v.software === ICESHRIMP_NET, v.software === MASTODON, v.software === MITRA, v.software === TAKAHE && gte(v.version, '0.8.0'), @@ -527,6 +534,7 @@ const getFeatures = (instance: Instance) => { v.software === FRIENDICA, v.software === GOTOSOCIAL, v.software === ICESHRIMP, + v.software === ICESHRIMP_NET, v.software === MASTODON, v.software === TAKAHE && gte(v.version, '0.6.1'), v.software === TOKI, @@ -563,6 +571,7 @@ const getFeatures = (instance: Instance) => { */ filtersV2: any([ v.software === GOTOSOCIAL && gte(v.version, '0.16.0'), + v.software === ICESHRIMP_NET, v.software === MASTODON, ]), @@ -624,6 +633,7 @@ const getFeatures = (instance: Instance) => { */ frontendConfigurations: any([ v.software === DITTO, + v.software === ICESHRIMP_NET, v.software === PLEROMA, ]), @@ -750,6 +760,7 @@ const getFeatures = (instance: Instance) => { v.software === FRIENDICA, v.software === GOTOSOCIAL, v.software === ICESHRIMP, + v.software === ICESHRIMP_NET, v.software === MASTODON, v.software === PLEROMA, ]), @@ -820,6 +831,7 @@ const getFeatures = (instance: Instance) => { mediaV2: any([ v.software === FIREFISH, v.software === ICESHRIMP, + v.software === ICESHRIMP_NET, v.software === MASTODON, v.software === MITRA, v.software === PLEROMA, @@ -850,6 +862,7 @@ const getFeatures = (instance: Instance) => { v.software === FRIENDICA, v.software === GOTOSOCIAL && gte(v.version, '0.16.0'), v.software === ICESHRIMP, + v.software === ICESHRIMP_NET, v.software === MASTODON, v.software === MITRA, v.software === PIXELFED, @@ -865,6 +878,7 @@ const getFeatures = (instance: Instance) => { v.software === FIREFISH, v.software === GOTOSOCIAL && gte(v.version, '0.16.0'), v.software === ICESHRIMP, + v.software === ICESHRIMP_NET, v.software === MASTODON, v.software === PLEROMA, v.software === TAKAHE, @@ -903,6 +917,7 @@ const getFeatures = (instance: Instance) => { notificationsIncludeTypes: any([ v.software === FIREFISH, v.software === ICESHRIMP, + v.software === ICESHRIMP_NET, v.software === MASTODON, v.software === PLEROMA && gte(v.version, '2.5.0'), v.software === TAKAHE && gte(v.version, '0.6.2'), @@ -965,6 +980,7 @@ const getFeatures = (instance: Instance) => { polls: any([ v.software === FIREFISH, v.software === ICESHRIMP, + v.software === ICESHRIMP_NET, v.software === MASTODON, v.software === TAKAHE && gte(v.version, '0.8.0'), v.software === GOTOSOCIAL, @@ -1014,6 +1030,7 @@ const getFeatures = (instance: Instance) => { v.software === DITTO, v.software === GOTOSOCIAL, v.software === ICESHRIMP, + v.software === ICESHRIMP_NET, v.software === MASTODON, v.software === MITRA, v.software === PLEROMA, @@ -1037,6 +1054,7 @@ const getFeatures = (instance: Instance) => { v.software === FRIENDICA, v.software === GOTOSOCIAL, v.software === ICESHRIMP, + v.software === ICESHRIMP_NET, v.software === MASTODON, v.software === PLEROMA, v.software === TAKAHE, @@ -1048,6 +1066,7 @@ const getFeatures = (instance: Instance) => { * @see POST /api/v1/statuses */ quotePosts: any([ + v.software === ICESHRIMP_NET, v.software === FRIENDICA && gte(v.version, '2023.3.0'), v.software === PLEROMA && [REBASED, AKKOMA].includes(v.build!) && gte(v.version, '2.5.0'), instance.api_versions['quote_posting.pleroma.pl-api'] >= 1, @@ -1059,6 +1078,7 @@ const getFeatures = (instance: Instance) => { * @see POST /api/v1/statuses/:id/reblog */ reblogVisibility: any([ + v.software === ICESHRIMP_NET, v.software === MASTODON, v.software === PLEROMA, ]), @@ -1074,6 +1094,7 @@ const getFeatures = (instance: Instance) => { * @see POST /api/v1/accounts/:id/remove_from_followers */ removeFromFollowers: any([ + v.software === ICESHRIMP_NET, v.software === MASTODON, v.software === PLEROMA && gte(v.version, '2.5.0'), v.software === PLEROMA && v.build === AKKOMA, diff --git a/packages/pl-api/package.json b/packages/pl-api/package.json index 61b7cfa3b..ba5889eb6 100644 --- a/packages/pl-api/package.json +++ b/packages/pl-api/package.json @@ -1,6 +1,6 @@ { "name": "pl-api", - "version": "1.0.0-rc.1", + "version": "1.0.0-rc.2", "type": "module", "homepage": "https://github.com/mkljczk/pl-fe/tree/develop/packages/pl-api", "repository": { diff --git a/packages/pl-fe/package.json b/packages/pl-fe/package.json index f35a39463..efde17797 100644 --- a/packages/pl-fe/package.json +++ b/packages/pl-fe/package.json @@ -101,7 +101,7 @@ "multiselect-react-dropdown": "^2.0.25", "mutative": "^1.0.11", "path-browserify": "^1.0.1", - "pl-api": "^1.0.0-rc.1", + "pl-api": "^1.0.0-rc.2", "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 12ac9f078..2d57e6849 100644 --- a/packages/pl-fe/yarn.lock +++ b/packages/pl-fe/yarn.lock @@ -7620,10 +7620,10 @@ pkg-dir@^4.1.0: dependencies: find-up "^4.0.0" -pl-api@^1.0.0-rc.1: - version "1.0.0-rc.1" - resolved "https://registry.yarnpkg.com/pl-api/-/pl-api-1.0.0-rc.1.tgz#e5b1ead42230ed86e57ebaf020f3a2114da3bce0" - integrity sha512-bwV831HoATajRlmZg4USIzQvHgZC9MBAg0/sN/T5uXrM5tcUzfM+qU5ZQIzk+r5gSQ0ZCwqkjbajvhbn9tRcBA== +pl-api@^1.0.0-rc.2: + version "1.0.0-rc.2" + resolved "https://registry.yarnpkg.com/pl-api/-/pl-api-1.0.0-rc.2.tgz#e6fb11b11bae2464974a88cce19901f458ef07e7" + integrity sha512-iF+NLNGkng/CTOyH84+0UJOWm02zB/MA7t6U9Wpu/QIMqqqjMPuwl6jcF9JhbB/V6TcBegzHZcmjUViz3zQxeA== dependencies: blurhash "^2.0.5" http-link-header "^1.1.3" From 32fed66477b5f07864162e21ea37353577ddc14a Mon Sep 17 00:00:00 2001 From: mkljczk Date: Wed, 4 Dec 2024 16:56:32 +0100 Subject: [PATCH 10/76] pl-fe: migrate about page to tanstack query Signed-off-by: mkljczk --- packages/pl-fe/src/actions/about.test.ts | 44 --------------- packages/pl-fe/src/actions/about.ts | 55 ------------------- .../src/api/hooks/pl-fe/use-about-page.ts | 19 +++++++ packages/pl-fe/src/api/index.ts | 2 +- packages/pl-fe/src/features/about/index.tsx | 24 +++----- 5 files changed, 27 insertions(+), 117 deletions(-) delete mode 100644 packages/pl-fe/src/actions/about.test.ts delete mode 100644 packages/pl-fe/src/actions/about.ts create mode 100644 packages/pl-fe/src/api/hooks/pl-fe/use-about-page.ts diff --git a/packages/pl-fe/src/actions/about.test.ts b/packages/pl-fe/src/actions/about.test.ts deleted file mode 100644 index edc1c939c..000000000 --- a/packages/pl-fe/src/actions/about.test.ts +++ /dev/null @@ -1,44 +0,0 @@ -// import MockAdapter from 'axios-mock-adapter'; -import { Map as ImmutableMap } from 'immutable'; - -// import { staticClient } from 'pl-fe/api'; -import { mockStore } from 'pl-fe/jest/test-helpers'; - -import { - FETCH_ABOUT_PAGE_REQUEST, - // FETCH_ABOUT_PAGE_SUCCESS, - FETCH_ABOUT_PAGE_FAIL, - fetchAboutPage, -} from './about'; - -describe('fetchAboutPage()', () => { - // it('creates the expected actions on success', () => { - - // const mock = new MockAdapter(staticClient); - - // mock.onGet('/instance/about/index.html') - // .reply(200, '

Hello world

'); - - // const expectedActions = [ - // { type: FETCH_ABOUT_PAGE_REQUEST, slug: 'index' }, - // { type: FETCH_ABOUT_PAGE_SUCCESS, slug: 'index', html: '

Hello world

' }, - // ]; - // const store = mockStore(ImmutableMap()); - - // return store.dispatch(fetchAboutPage()).then(() => { - // expect(store.getActions()).toEqual(expectedActions); - // }); - // }); - - it('creates the expected actions on failure', () => { - const expectedActions = [ - { type: FETCH_ABOUT_PAGE_REQUEST, slug: 'asdf' }, - { type: FETCH_ABOUT_PAGE_FAIL, slug: 'asdf', error: new Error('Request failed with status code 404') }, - ]; - const store = mockStore(ImmutableMap()); - - return store.dispatch(fetchAboutPage('asdf')).catch(() => { - expect(store.getActions()).toEqual(expectedActions); - }); - }); -}); diff --git a/packages/pl-fe/src/actions/about.ts b/packages/pl-fe/src/actions/about.ts deleted file mode 100644 index abc74c13b..000000000 --- a/packages/pl-fe/src/actions/about.ts +++ /dev/null @@ -1,55 +0,0 @@ -import { staticFetch } from '../api'; - -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; - -interface FetchAboutPageRequestAction { - type: typeof FETCH_ABOUT_PAGE_REQUEST; - slug: string; - locale?: string; -} - -interface FetchAboutPageSuccessAction { - type: typeof FETCH_ABOUT_PAGE_SUCCESS; - slug: string; - locale?: string; - html: string; -} - -interface FetchAboutPageFailAction { - type: typeof FETCH_ABOUT_PAGE_FAIL; - slug: string; - locale?: string; - error: unknown; -} - -const fetchAboutPage = (slug = 'index', locale?: string) => (dispatch: AppDispatch, getState: () => RootState) => { - dispatch({ type: FETCH_ABOUT_PAGE_REQUEST, slug, locale }); - - const filename = `${slug}${locale ? `.${locale}` : ''}.html`; - return staticFetch(`/instance/about/${filename}`) - .then(({ data: html }) => { - dispatch({ type: FETCH_ABOUT_PAGE_SUCCESS, slug, locale, html }); - return html; - }) - .catch(error => { - dispatch({ type: FETCH_ABOUT_PAGE_FAIL, slug, locale, error }); - throw error; - }); -}; - -type AboutAction = - | FetchAboutPageRequestAction - | FetchAboutPageSuccessAction - | FetchAboutPageFailAction; - -export { - fetchAboutPage, - FETCH_ABOUT_PAGE_REQUEST, - FETCH_ABOUT_PAGE_SUCCESS, - FETCH_ABOUT_PAGE_FAIL, - type AboutAction, -}; diff --git a/packages/pl-fe/src/api/hooks/pl-fe/use-about-page.ts b/packages/pl-fe/src/api/hooks/pl-fe/use-about-page.ts new file mode 100644 index 000000000..0f79f3761 --- /dev/null +++ b/packages/pl-fe/src/api/hooks/pl-fe/use-about-page.ts @@ -0,0 +1,19 @@ +import { useQuery } from '@tanstack/react-query'; + +import { staticFetch } from 'pl-fe/api'; + +const fetchAboutPage = async (slug: string, locale?: string) => { + const filename = `${slug}${locale ? `.${locale}` : ''}.html`; + + const { data } = await staticFetch(`/instance/about/${filename}`); + + return data; +}; + +const useAboutPage = (slug = 'index', locale?: string) => + useQuery({ + queryKey: ['pl-fe', 'aboutPages', slug, locale], + queryFn: () => fetchAboutPage(slug, locale), + }); + +export { useAboutPage }; diff --git a/packages/pl-fe/src/api/index.ts b/packages/pl-fe/src/api/index.ts index 819ba870d..efd01cce9 100644 --- a/packages/pl-fe/src/api/index.ts +++ b/packages/pl-fe/src/api/index.ts @@ -14,7 +14,7 @@ type PlfeResponse = Response & { data: string; json: T }; * No authorization is needed. */ const staticFetch = (input: URL | RequestInfo, init?: RequestInit | undefined) => { - const fullPath = buildFullPath(input.toString(), BuildConfig.FE_SUBDIRECTORY); + const fullPath = buildFullPath(input.toString(), BuildConfig.BACKEND_URL); return fetch(fullPath, init).then(async (response) => { if (!response.ok) throw { response }; diff --git a/packages/pl-fe/src/features/about/index.tsx b/packages/pl-fe/src/features/about/index.tsx index 71e3fd66c..a952f27eb 100644 --- a/packages/pl-fe/src/features/about/index.tsx +++ b/packages/pl-fe/src/features/about/index.tsx @@ -1,11 +1,10 @@ -import React, { useEffect, useState } from 'react'; +import React, { useState } from 'react'; import { FormattedMessage } from 'react-intl'; import { useParams } from 'react-router-dom'; -import { fetchAboutPage } from 'pl-fe/actions/about'; +import { useAboutPage } from 'pl-fe/api/hooks/pl-fe/use-about-page'; import { Navlinks } from 'pl-fe/components/navlinks'; import Card from 'pl-fe/components/ui/card'; -import { useAppDispatch } from 'pl-fe/hooks/use-app-dispatch'; import { usePlFeConfig } from 'pl-fe/hooks/use-pl-fe-config'; import { useSettings } from 'pl-fe/hooks/use-settings'; @@ -13,30 +12,21 @@ import { languages } from '../preferences'; /** Displays arbitrary user-uploaded HTML on a page at `/about/:slug` */ const AboutPage: React.FC = () => { - const dispatch = useAppDispatch(); - const { slug } = useParams<{ slug?: string }>(); + const { slug = 'index' } = useParams<{ slug?: string }>(); const settings = useSettings(); const plFeConfig = usePlFeConfig(); - const [pageHtml, setPageHtml] = useState(''); const [locale, setLocale] = useState(settings.locale); const { aboutPages } = plFeConfig; - const page = aboutPages[slug || 'about']; + const page = aboutPages[slug]; const defaultLocale = page?.defaultLocale; const pageLocales = page?.locales || []; + const fetchLocale = Boolean(page && locale !== defaultLocale && pageLocales.includes(locale)); - useEffect(() => { - const fetchLocale = Boolean(page && locale !== defaultLocale && pageLocales.includes(locale)); - dispatch(fetchAboutPage(slug, fetchLocale ? locale : undefined)).then(html => { - setPageHtml(html); - }).catch(error => { - // TODO: Better error handling. 404 page? - setPageHtml('

Page not found

'); - }); - }, [locale, slug]); + const { data: pageHtml } = useAboutPage(slug, fetchLocale ? locale : undefined); const alsoAvailable = (defaultLocale) && (
@@ -67,7 +57,7 @@ const AboutPage: React.FC = () => {
-
+ {pageHtml &&
} {alsoAvailable}
From 200fc5a5cc7d69bd6863555d0234751d64a0ea41 Mon Sep 17 00:00:00 2001 From: mkljczk Date: Wed, 4 Dec 2024 17:03:34 +0100 Subject: [PATCH 11/76] pl-fe: remove unused Signed-off-by: mkljczk --- packages/pl-fe/heroku.yml | 3 --- 1 file changed, 3 deletions(-) delete mode 100644 packages/pl-fe/heroku.yml diff --git a/packages/pl-fe/heroku.yml b/packages/pl-fe/heroku.yml deleted file mode 100644 index 8eec25b9c..000000000 --- a/packages/pl-fe/heroku.yml +++ /dev/null @@ -1,3 +0,0 @@ -build: - docker: - web: Dockerfile From 615f2cb0cccd920cbc59c8c146d831e23ca60890 Mon Sep 17 00:00:00 2001 From: mkljczk Date: Wed, 4 Dec 2024 17:07:05 +0100 Subject: [PATCH 12/76] pl-fe: cleanup Signed-off-by: mkljczk --- .../components/draft-status-action-bar.tsx | 25 ++++++++----------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/packages/pl-fe/src/features/draft-statuses/components/draft-status-action-bar.tsx b/packages/pl-fe/src/features/draft-statuses/components/draft-status-action-bar.tsx index 0f25abb70..20a4f7be7 100644 --- a/packages/pl-fe/src/features/draft-statuses/components/draft-status-action-bar.tsx +++ b/packages/pl-fe/src/features/draft-statuses/components/draft-status-action-bar.tsx @@ -31,20 +31,17 @@ const DraftStatusActionBar: React.FC = ({ source, status const dispatch = useAppDispatch(); const handleCancelClick = () => { - dispatch((_, getState) => { - - const deleteModal = settings.deleteModal; - if (!deleteModal) { - dispatch(cancelDraftStatus(source.draft_id)); - } else { - openModal('CONFIRM', { - heading: intl.formatMessage(messages.deleteHeading), - message: intl.formatMessage(messages.deleteMessage), - confirm: intl.formatMessage(messages.deleteConfirm), - onConfirm: () => dispatch(cancelDraftStatus(source.draft_id)), - }); - } - }); + const deleteModal = settings.deleteModal; + if (!deleteModal) { + dispatch(cancelDraftStatus(source.draft_id)); + } else { + openModal('CONFIRM', { + heading: intl.formatMessage(messages.deleteHeading), + message: intl.formatMessage(messages.deleteMessage), + confirm: intl.formatMessage(messages.deleteConfirm), + onConfirm: () => dispatch(cancelDraftStatus(source.draft_id)), + }); + } }; const handleEditClick = () => { From 7a85ef413b445e1f0f9ee9992e708b5c7d135382 Mon Sep 17 00:00:00 2001 From: mkljczk Date: Wed, 4 Dec 2024 17:08:11 +0100 Subject: [PATCH 13/76] pl-fe: cleanup Signed-off-by: mkljczk --- .../scheduled-status-action-bar.tsx | 25 ++++++++----------- .../src/features/status/components/thread.tsx | 18 ++++++------- 2 files changed, 19 insertions(+), 24 deletions(-) diff --git a/packages/pl-fe/src/features/scheduled-statuses/components/scheduled-status-action-bar.tsx b/packages/pl-fe/src/features/scheduled-statuses/components/scheduled-status-action-bar.tsx index 3f3e20124..e656a95b1 100644 --- a/packages/pl-fe/src/features/scheduled-statuses/components/scheduled-status-action-bar.tsx +++ b/packages/pl-fe/src/features/scheduled-statuses/components/scheduled-status-action-bar.tsx @@ -29,20 +29,17 @@ const ScheduledStatusActionBar: React.FC = ({ status const { settings } = useSettingsStore(); const handleCancelClick = () => { - dispatch((_, getState) => { - - const deleteModal = settings.deleteModal; - if (!deleteModal) { - dispatch(cancelScheduledStatus(status.id)); - } else { - openModal('CONFIRM', { - heading: intl.formatMessage(messages.deleteHeading), - message: intl.formatMessage(messages.deleteMessage), - confirm: intl.formatMessage(messages.deleteConfirm), - onConfirm: () => dispatch(cancelScheduledStatus(status.id)), - }); - } - }); + const deleteModal = settings.deleteModal; + if (!deleteModal) { + dispatch(cancelScheduledStatus(status.id)); + } else { + openModal('CONFIRM', { + heading: intl.formatMessage(messages.deleteHeading), + message: intl.formatMessage(messages.deleteMessage), + confirm: intl.formatMessage(messages.deleteConfirm), + onConfirm: () => dispatch(cancelScheduledStatus(status.id)), + }); + } }; return ( diff --git a/packages/pl-fe/src/features/status/components/thread.tsx b/packages/pl-fe/src/features/status/components/thread.tsx index 8272561c6..0bd25a125 100644 --- a/packages/pl-fe/src/features/status/components/thread.tsx +++ b/packages/pl-fe/src/features/status/components/thread.tsx @@ -143,18 +143,16 @@ const Thread: React.FC = ({ const handleModalReblog = (status: Pick) => dispatch(reblog(status)); const handleReblogClick = (status: SelectedStatus, e?: React.MouseEvent) => { - dispatch((_, getState) => { - const boostModal = settings.boostModal; - if (status.reblogged) { - dispatch(unreblog(status)); + const boostModal = settings.boostModal; + if (status.reblogged) { + dispatch(unreblog(status)); + } else { + if ((e && e.shiftKey) || !boostModal) { + handleModalReblog(status); } else { - if ((e && e.shiftKey) || !boostModal) { - handleModalReblog(status); - } else { - openModal('BOOST', { statusId: status.id, onReblog: handleModalReblog }); - } + openModal('BOOST', { statusId: status.id, onReblog: handleModalReblog }); } - }); + } }; const handleMentionClick = (account: Pick) => dispatch(mentionCompose(account)); From edf831bed9e696c559b5eea469ecde6b3f399ec4 Mon Sep 17 00:00:00 2001 From: mkljczk Date: Wed, 4 Dec 2024 17:13:02 +0100 Subject: [PATCH 14/76] fix remember language/emoji use Signed-off-by: mkljczk --- packages/pl-fe/src/actions/compose.ts | 9 ++++---- packages/pl-fe/src/actions/emojis.ts | 21 ------------------- packages/pl-fe/src/actions/languages.ts | 16 -------------- .../editor/plugins/autosuggest-plugin.tsx | 9 ++++++-- .../components/emoji-picker-dropdown.tsx | 8 ++++--- 5 files changed, 17 insertions(+), 46 deletions(-) delete mode 100644 packages/pl-fe/src/actions/emojis.ts delete mode 100644 packages/pl-fe/src/actions/languages.ts diff --git a/packages/pl-fe/src/actions/compose.ts b/packages/pl-fe/src/actions/compose.ts index 3d8fb8fed..ca0fdf661 100644 --- a/packages/pl-fe/src/actions/compose.ts +++ b/packages/pl-fe/src/actions/compose.ts @@ -13,10 +13,9 @@ import { useSettingsStore } from 'pl-fe/stores/settings'; import toast from 'pl-fe/toast'; import { isLoggedIn } from 'pl-fe/utils/auth'; -import { chooseEmoji } from './emojis'; import { importEntities } from './importer'; -import { rememberLanguageUse } from './languages'; import { uploadFile, updateMedia } from './media'; +import { saveSettings } from './settings'; import { createStatus } from './statuses'; import type { EditorState } from 'lexical'; @@ -384,7 +383,8 @@ const submitCompose = (composeId: string, opts: SubmitComposeOpts = {}) => useModalsStore.getState().closeModal('COMPOSE'); if (compose.language && !statusId) { - dispatch(rememberLanguageUse(compose.language)); + useSettingsStore.getState().rememberLanguageUse(compose.language); + dispatch(saveSettings()); } const idempotencyKey = compose.idempotencyKey; @@ -686,7 +686,8 @@ const selectComposeSuggestion = (composeId: string, position: number, token: str completion = isNativeEmoji(suggestion) ? suggestion.native : suggestion.colons; startPosition = position - 1; - dispatch(chooseEmoji(suggestion)); + useSettingsStore.getState().rememberEmojiUse(suggestion); + dispatch(saveSettings()); } else if (typeof suggestion === 'string' && suggestion[0] === '#') { completion = suggestion; startPosition = position - 1; diff --git a/packages/pl-fe/src/actions/emojis.ts b/packages/pl-fe/src/actions/emojis.ts deleted file mode 100644 index b4b949314..000000000 --- a/packages/pl-fe/src/actions/emojis.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { saveSettings } from './settings'; - -import type { Emoji } from 'pl-fe/features/emoji'; -import type { AppDispatch } from 'pl-fe/store'; - -const EMOJI_CHOOSE = 'EMOJI_CHOOSE'; - -const chooseEmoji = (emoji: Emoji) => - (dispatch: AppDispatch) => { - dispatch({ - type: EMOJI_CHOOSE, - emoji, - }); - - dispatch(saveSettings()); - }; - -export { - EMOJI_CHOOSE, - chooseEmoji, -}; diff --git a/packages/pl-fe/src/actions/languages.ts b/packages/pl-fe/src/actions/languages.ts deleted file mode 100644 index fe26a5345..000000000 --- a/packages/pl-fe/src/actions/languages.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { saveSettings } from './settings'; - -import type { AppDispatch } from 'pl-fe/store'; - -const LANGUAGE_USE = 'LANGUAGE_USE' as const; - -const rememberLanguageUse = (language: string) => (dispatch: AppDispatch) => { - dispatch({ - type: LANGUAGE_USE, - language, - }); - - dispatch(saveSettings()); -}; - -export { LANGUAGE_USE, rememberLanguageUse }; diff --git a/packages/pl-fe/src/features/compose/editor/plugins/autosuggest-plugin.tsx b/packages/pl-fe/src/features/compose/editor/plugins/autosuggest-plugin.tsx index ee270402a..1784eb7ae 100644 --- a/packages/pl-fe/src/features/compose/editor/plugins/autosuggest-plugin.tsx +++ b/packages/pl-fe/src/features/compose/editor/plugins/autosuggest-plugin.tsx @@ -33,11 +33,12 @@ import React, { import ReactDOM from 'react-dom'; import { clearComposeSuggestions, fetchComposeSuggestions } from 'pl-fe/actions/compose'; -import { chooseEmoji } from 'pl-fe/actions/emojis'; +import { saveSettings } from 'pl-fe/actions/settings'; import AutosuggestEmoji from 'pl-fe/components/autosuggest-emoji'; import { useAppDispatch } from 'pl-fe/hooks/use-app-dispatch'; import { useCompose } from 'pl-fe/hooks/use-compose'; import { selectAccount } from 'pl-fe/selectors'; +import { useSettingsStore } from 'pl-fe/stores/settings'; import { textAtCursorMatchesToken } from 'pl-fe/utils/suggestions'; import AutosuggestAccount from '../../components/autosuggest-account'; @@ -285,6 +286,7 @@ const AutosuggestPlugin = ({ suggestionsHidden, setSuggestionsHidden, }: AutosuggestPluginProps): JSX.Element | null => { + const { rememberEmojiUse } = useSettingsStore(); const { suggestions } = useCompose(composeId); const dispatch = useAppDispatch(); @@ -324,7 +326,10 @@ const AutosuggestPlugin = ({ if (typeof suggestion === 'object') { if (!suggestion.id) return; - dispatch(chooseEmoji(suggestion)); + + rememberEmojiUse(suggestion); + dispatch(saveSettings()); + replaceMatch($createEmojiNode(suggestion)); } else if (suggestion[0] === '#') { (node as TextNode).setTextContent(`${suggestion} `); diff --git a/packages/pl-fe/src/features/emoji/components/emoji-picker-dropdown.tsx b/packages/pl-fe/src/features/emoji/components/emoji-picker-dropdown.tsx index a43f076ef..3209af4e5 100644 --- a/packages/pl-fe/src/features/emoji/components/emoji-picker-dropdown.tsx +++ b/packages/pl-fe/src/features/emoji/components/emoji-picker-dropdown.tsx @@ -2,13 +2,13 @@ import React, { useEffect, useState, useLayoutEffect, Suspense, useMemo } from ' import { defineMessages, useIntl } from 'react-intl'; import { createSelector } from 'reselect'; -import { chooseEmoji } from 'pl-fe/actions/emojis'; -import { changeSetting } from 'pl-fe/actions/settings'; +import { changeSetting, saveSettings } from 'pl-fe/actions/settings'; import { useAppDispatch } from 'pl-fe/hooks/use-app-dispatch'; import { useAppSelector } from 'pl-fe/hooks/use-app-selector'; import { useSettings } from 'pl-fe/hooks/use-settings'; import { useTheme } from 'pl-fe/hooks/use-theme'; import { RootState } from 'pl-fe/store'; +import { useSettingsStore } from 'pl-fe/stores/settings'; import { buildCustomEmojis } from '../../emoji'; import { EmojiPicker } from '../../ui/util/async-components'; @@ -128,6 +128,7 @@ const EmojiPickerDropdown: React.FC = ({ const dispatch = useAppDispatch(); const title = intl.formatMessage(messages.emoji); const theme = useTheme(); + const { rememberEmojiUse } = useSettingsStore(); const customEmojis = useAppSelector((state) => getCustomEmojis(state)); @@ -156,7 +157,8 @@ const EmojiPickerDropdown: React.FC = ({ } as CustomEmoji; } - dispatch(chooseEmoji(pickedEmoji)); + rememberEmojiUse(pickedEmoji); + dispatch(saveSettings()); if (onPickEmoji) { onPickEmoji(pickedEmoji); From 90f17de808ec17bc2c463487319ac8692500e6b4 Mon Sep 17 00:00:00 2001 From: mkljczk Date: Wed, 4 Dec 2024 17:31:04 +0100 Subject: [PATCH 15/76] pl-fe: refactor, remove unused exports, migrate event participants list to tanstack query Signed-off-by: mkljczk --- packages/pl-fe/src/actions/admin.ts | 6 -- packages/pl-fe/src/actions/aliases.ts | 1 - packages/pl-fe/src/actions/auth.ts | 1 - packages/pl-fe/src/actions/compose.ts | 18 ---- packages/pl-fe/src/actions/events.ts | 88 ------------------- .../account-lists/use-event-participations.ts | 21 +++++ .../api/hooks/statuses/use-status-quotes.ts | 2 +- .../pl-fe/src/api/normalizers/minify-list.ts | 27 ++++++ .../pl-fe/src/api/normalizers/status-list.ts | 17 ---- .../modals/event-participants-modal.tsx | 25 ++---- packages/pl-fe/src/reducers/compose.ts | 16 +--- packages/pl-fe/src/reducers/user-lists.ts | 6 -- 12 files changed, 57 insertions(+), 171 deletions(-) create mode 100644 packages/pl-fe/src/api/hooks/account-lists/use-event-participations.ts create mode 100644 packages/pl-fe/src/api/normalizers/minify-list.ts delete mode 100644 packages/pl-fe/src/api/normalizers/status-list.ts diff --git a/packages/pl-fe/src/actions/admin.ts b/packages/pl-fe/src/actions/admin.ts index ee97042b0..4d45f307f 100644 --- a/packages/pl-fe/src/actions/admin.ts +++ b/packages/pl-fe/src/actions/admin.ts @@ -410,13 +410,7 @@ export { approveUser, deleteStatus, toggleStatusSensitivity, - tagUser, - untagUser, - setTags, setBadges, - promoteToAdmin, - promoteToModerator, - demoteToUser, setRole, setUserIndexQuery, fetchUserIndex, diff --git a/packages/pl-fe/src/actions/aliases.ts b/packages/pl-fe/src/actions/aliases.ts index 764363007..1efef7f2a 100644 --- a/packages/pl-fe/src/actions/aliases.ts +++ b/packages/pl-fe/src/actions/aliases.ts @@ -163,7 +163,6 @@ export { ALIASES_REMOVE_FAIL, fetchAliases, fetchAliasesSuggestions, - fetchAliasesSuggestionsReady, clearAliasesSuggestions, changeAliasesSuggestions, addToAliases, diff --git a/packages/pl-fe/src/actions/auth.ts b/packages/pl-fe/src/actions/auth.ts index a0d6da0bc..8f2a2c678 100644 --- a/packages/pl-fe/src/actions/auth.ts +++ b/packages/pl-fe/src/actions/auth.ts @@ -376,7 +376,6 @@ export { messages, otpVerify, verifyCredentials, - rememberAuthAccount, loadCredentials, logIn, logOut, diff --git a/packages/pl-fe/src/actions/compose.ts b/packages/pl-fe/src/actions/compose.ts index ca0fdf661..417e0a2f7 100644 --- a/packages/pl-fe/src/actions/compose.ts +++ b/packages/pl-fe/src/actions/compose.ts @@ -65,8 +65,6 @@ const COMPOSE_LANGUAGE_ADD = 'COMPOSE_LANGUAGE_ADD' as const; const COMPOSE_LANGUAGE_DELETE = 'COMPOSE_LANGUAGE_DELETE' as const; const COMPOSE_FEDERATED_CHANGE = 'COMPOSE_FEDERATED_CHANGE' as const; -const COMPOSE_EMOJI_INSERT = 'COMPOSE_EMOJI_INSERT' as const; - const COMPOSE_UPLOAD_CHANGE_REQUEST = 'COMPOSE_UPLOAD_UPDATE_REQUEST' as const; const COMPOSE_UPLOAD_CHANGE_SUCCESS = 'COMPOSE_UPLOAD_UPDATE_SUCCESS' as const; const COMPOSE_UPLOAD_CHANGE_FAIL = 'COMPOSE_UPLOAD_UPDATE_FAIL' as const; @@ -784,13 +782,6 @@ const deleteComposeLanguage = (composeId: string, value: Language) => ({ value, }); -const insertEmojiCompose = (composeId: string, position: number, emoji: Emoji, needsSpace: boolean) => ({ - type: COMPOSE_EMOJI_INSERT, - composeId, - position, - emoji, - needsSpace, -}); const addPoll = (composeId: string) => ({ type: COMPOSE_POLL_ADD, @@ -978,7 +969,6 @@ type ComposeAction = | ReturnType | ReturnType | ReturnType - | ReturnType | ReturnType | ReturnType | ReturnType @@ -1029,7 +1019,6 @@ export { COMPOSE_MODIFIED_LANGUAGE_CHANGE, COMPOSE_LANGUAGE_ADD, COMPOSE_LANGUAGE_DELETE, - COMPOSE_EMOJI_INSERT, COMPOSE_UPLOAD_CHANGE_REQUEST, COMPOSE_UPLOAD_CHANGE_SUCCESS, COMPOSE_UPLOAD_CHANGE_FAIL, @@ -1051,7 +1040,6 @@ export { COMPOSE_ADD_SUGGESTED_LANGUAGE, COMPOSE_FEDERATED_CHANGE, setComposeToStatus, - changeCompose, replyCompose, cancelReplyCompose, quoteCompose, @@ -1060,7 +1048,6 @@ export { mentionCompose, directCompose, directComposeById, - handleComposeSubmit, submitCompose, uploadFile, uploadCompose, @@ -1071,11 +1058,7 @@ export { groupComposeModal, clearComposeSuggestions, fetchComposeSuggestions, - readyComposeSuggestionsEmojis, - readyComposeSuggestionsAccounts, selectComposeSuggestion, - updateSuggestionTags, - updateTagHistory, changeComposeSpoilerness, changeComposeContentType, changeComposeSpoilerText, @@ -1084,7 +1067,6 @@ export { changeComposeModifiedLanguage, addComposeLanguage, deleteComposeLanguage, - insertEmojiCompose, addPoll, removePoll, addSchedule, diff --git a/packages/pl-fe/src/actions/events.ts b/packages/pl-fe/src/actions/events.ts index 944528869..a67b69cb7 100644 --- a/packages/pl-fe/src/actions/events.ts +++ b/packages/pl-fe/src/actions/events.ts @@ -21,14 +21,6 @@ const EVENT_LEAVE_REQUEST = 'EVENT_LEAVE_REQUEST' as const; const EVENT_LEAVE_SUCCESS = 'EVENT_LEAVE_SUCCESS' as const; const EVENT_LEAVE_FAIL = 'EVENT_LEAVE_FAIL' as const; -const EVENT_PARTICIPATIONS_FETCH_REQUEST = 'EVENT_PARTICIPATIONS_FETCH_REQUEST' as const; -const EVENT_PARTICIPATIONS_FETCH_SUCCESS = 'EVENT_PARTICIPATIONS_FETCH_SUCCESS' as const; -const EVENT_PARTICIPATIONS_FETCH_FAIL = 'EVENT_PARTICIPATIONS_FETCH_FAIL' as const; - -const EVENT_PARTICIPATIONS_EXPAND_REQUEST = 'EVENT_PARTICIPATIONS_EXPAND_REQUEST' as const; -const EVENT_PARTICIPATIONS_EXPAND_SUCCESS = 'EVENT_PARTICIPATIONS_EXPAND_SUCCESS' as const; -const EVENT_PARTICIPATIONS_EXPAND_FAIL = 'EVENT_PARTICIPATIONS_EXPAND_FAIL' as const; - const EVENT_PARTICIPATION_REQUESTS_FETCH_REQUEST = 'EVENT_PARTICIPATION_REQUESTS_FETCH_REQUEST' as const; const EVENT_PARTICIPATION_REQUESTS_FETCH_SUCCESS = 'EVENT_PARTICIPATION_REQUESTS_FETCH_SUCCESS' as const; const EVENT_PARTICIPATION_REQUESTS_FETCH_FAIL = 'EVENT_PARTICIPATION_REQUESTS_FETCH_FAIL' as const; @@ -221,72 +213,6 @@ const leaveEventFail = (error: unknown, statusId: string, previousState: Exclude previousState, }); -const fetchEventParticipations = (statusId: string) => - (dispatch: AppDispatch, getState: () => RootState) => { - dispatch(fetchEventParticipationsRequest(statusId)); - - return getClient(getState).events.getEventParticipations(statusId).then(response => { - dispatch(importEntities({ accounts: response.items })); - return dispatch(fetchEventParticipationsSuccess(statusId, response.items, response.next)); - }).catch(error => { - dispatch(fetchEventParticipationsFail(statusId, error)); - }); - }; - -const fetchEventParticipationsRequest = (statusId: string) => ({ - type: EVENT_PARTICIPATIONS_FETCH_REQUEST, - statusId, -}); - -const fetchEventParticipationsSuccess = (statusId: string, accounts: Array, next: (() => Promise>) | null) => ({ - type: EVENT_PARTICIPATIONS_FETCH_SUCCESS, - statusId, - accounts, - next, -}); - -const fetchEventParticipationsFail = (statusId: string, error: unknown) => ({ - type: EVENT_PARTICIPATIONS_FETCH_FAIL, - statusId, - error, -}); - -const expandEventParticipations = (statusId: string) => - (dispatch: AppDispatch, getState: () => RootState) => { - const next = getState().user_lists.event_participations[statusId]?.next || null; - - if (next === null) { - return dispatch(noOp); - } - - dispatch(expandEventParticipationsRequest(statusId)); - - return next().then(response => { - dispatch(importEntities({ accounts: response.items })); - return dispatch(expandEventParticipationsSuccess(statusId, response.items, response.next)); - }).catch(error => { - dispatch(expandEventParticipationsFail(statusId, error)); - }); - }; - -const expandEventParticipationsRequest = (statusId: string) => ({ - type: EVENT_PARTICIPATIONS_EXPAND_REQUEST, - statusId, -}); - -const expandEventParticipationsSuccess = (statusId: string, accounts: Array, next: (() => Promise>) | null) => ({ - type: EVENT_PARTICIPATIONS_EXPAND_SUCCESS, - statusId, - accounts, - next, -}); - -const expandEventParticipationsFail = (statusId: string, error: unknown) => ({ - type: EVENT_PARTICIPATIONS_EXPAND_FAIL, - statusId, - error, -}); - const fetchEventParticipationRequests = (statusId: string) => (dispatch: AppDispatch, getState: () => RootState) => { dispatch(fetchEventParticipationRequestsRequest(statusId)); @@ -499,12 +425,6 @@ type EventsAction = | ReturnType | ReturnType | ReturnType - | ReturnType - | ReturnType - | ReturnType - | ReturnType - | ReturnType - | ReturnType | ReturnType | ReturnType | ReturnType @@ -538,12 +458,6 @@ export { EVENT_LEAVE_REQUEST, EVENT_LEAVE_SUCCESS, EVENT_LEAVE_FAIL, - EVENT_PARTICIPATIONS_FETCH_REQUEST, - EVENT_PARTICIPATIONS_FETCH_SUCCESS, - EVENT_PARTICIPATIONS_FETCH_FAIL, - EVENT_PARTICIPATIONS_EXPAND_REQUEST, - EVENT_PARTICIPATIONS_EXPAND_SUCCESS, - EVENT_PARTICIPATIONS_EXPAND_FAIL, EVENT_PARTICIPATION_REQUESTS_FETCH_REQUEST, EVENT_PARTICIPATION_REQUESTS_FETCH_SUCCESS, EVENT_PARTICIPATION_REQUESTS_FETCH_FAIL, @@ -567,8 +481,6 @@ export { submitEvent, joinEvent, leaveEvent, - fetchEventParticipations, - expandEventParticipations, fetchEventParticipationRequests, expandEventParticipationRequests, authorizeEventParticipationRequest, diff --git a/packages/pl-fe/src/api/hooks/account-lists/use-event-participations.ts b/packages/pl-fe/src/api/hooks/account-lists/use-event-participations.ts new file mode 100644 index 000000000..231e8516f --- /dev/null +++ b/packages/pl-fe/src/api/hooks/account-lists/use-event-participations.ts @@ -0,0 +1,21 @@ + +import { useInfiniteQuery } from '@tanstack/react-query'; + +import { minifyAccountList } from 'pl-fe/api/normalizers/minify-list'; +import { useClient } from 'pl-fe/hooks/use-client'; + +import type { PaginatedResponse } from 'pl-api'; + +const useEventParticipations = (statusId: string) => { + const client = useClient(); + + return useInfiniteQuery({ + queryKey: ['accountsLists', 'eventParticipations', statusId], + queryFn: ({ pageParam }) => pageParam.next?.() || client.events.getEventParticipations(statusId).then(minifyAccountList), + initialPageParam: { previous: null, next: null, items: [], partial: false } as PaginatedResponse, + getNextPageParam: (page) => page.next ? page : undefined, + select: (data) => data.pages.map(page => page.items).flat(), + }); +}; + +export { useEventParticipations }; diff --git a/packages/pl-fe/src/api/hooks/statuses/use-status-quotes.ts b/packages/pl-fe/src/api/hooks/statuses/use-status-quotes.ts index 0fc0d9edd..cb214dd13 100644 --- a/packages/pl-fe/src/api/hooks/statuses/use-status-quotes.ts +++ b/packages/pl-fe/src/api/hooks/statuses/use-status-quotes.ts @@ -1,6 +1,6 @@ import { useInfiniteQuery } from '@tanstack/react-query'; -import { minifyStatusList } from 'pl-fe/api/normalizers/status-list'; +import { minifyStatusList } from 'pl-fe/api/normalizers/minify-list'; import { useClient } from 'pl-fe/hooks/use-client'; import type { PaginatedResponse } from 'pl-api'; diff --git a/packages/pl-fe/src/api/normalizers/minify-list.ts b/packages/pl-fe/src/api/normalizers/minify-list.ts new file mode 100644 index 000000000..2a430be56 --- /dev/null +++ b/packages/pl-fe/src/api/normalizers/minify-list.ts @@ -0,0 +1,27 @@ +import { Account, PaginatedResponse, Status } from 'pl-api'; + +import { importEntities } from 'pl-fe/actions/importer'; +import { store } from 'pl-fe/store'; + +const minifyList = ({ previous, next, items, ...response }: PaginatedResponse, minifier: (value: T1) => T2, importer?: (items: Array) => void): PaginatedResponse => { + importer?.(items); + + return { + ...response, + previous: previous ? () => previous().then((list) => minifyList(list, minifier, importer)) : null, + next: next ? () => next().then((list) => minifyList(list, minifier, importer)) : null, + items: items.map(minifier), + }; +}; + +const minifyStatusList = (response: PaginatedResponse): PaginatedResponse => + minifyList(response, (status) => status.id, (statuses) => { + store.dispatch(importEntities({ statuses }) as any); + }); + +const minifyAccountList = (response: PaginatedResponse): PaginatedResponse => + minifyList(response, (account) => account.id, (accounts) => { + store.dispatch(importEntities({ accounts }) as any); + }); + +export { minifyList, minifyAccountList, minifyStatusList }; diff --git a/packages/pl-fe/src/api/normalizers/status-list.ts b/packages/pl-fe/src/api/normalizers/status-list.ts deleted file mode 100644 index 9e8333462..000000000 --- a/packages/pl-fe/src/api/normalizers/status-list.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { PaginatedResponse, Status } from 'pl-api'; - -import { importEntities } from 'pl-fe/actions/importer'; -import { store } from 'pl-fe/store'; - -const minifyStatusList = ({ previous, next, items, ...response }: PaginatedResponse): PaginatedResponse => { - store.dispatch(importEntities({ statuses: items }) as any); - - return { - ...response, - previous: previous ? () => previous().then(minifyStatusList) : null, - next: next ? () => next().then(minifyStatusList) : null, - items: items.map(status => status.id), - }; -}; - -export { minifyStatusList }; diff --git a/packages/pl-fe/src/features/ui/components/modals/event-participants-modal.tsx b/packages/pl-fe/src/features/ui/components/modals/event-participants-modal.tsx index e8586a13a..adb1d9377 100644 --- a/packages/pl-fe/src/features/ui/components/modals/event-participants-modal.tsx +++ b/packages/pl-fe/src/features/ui/components/modals/event-participants-modal.tsx @@ -1,13 +1,11 @@ -import React, { useEffect } from 'react'; +import React from 'react'; import { FormattedMessage } from 'react-intl'; -import { fetchEventParticipations } from 'pl-fe/actions/events'; +import { useEventParticipations } from 'pl-fe/api/hooks/account-lists/use-event-participations'; import ScrollableList from 'pl-fe/components/scrollable-list'; import Modal from 'pl-fe/components/ui/modal'; import Spinner from 'pl-fe/components/ui/spinner'; import AccountContainer from 'pl-fe/containers/account-container'; -import { useAppDispatch } from 'pl-fe/hooks/use-app-dispatch'; -import { useAppSelector } from 'pl-fe/hooks/use-app-selector'; import type { BaseModalProps } from '../modal-root'; @@ -16,17 +14,7 @@ interface EventParticipantsModalProps { } const EventParticipantsModal: React.FC = ({ onClose, statusId }) => { - const dispatch = useAppDispatch(); - - const accountIds = useAppSelector((state) => state.user_lists.event_participations[statusId]?.items); - - const fetchData = () => { - dispatch(fetchEventParticipations(statusId)); - }; - - useEffect(() => { - fetchData(); - }, []); + const { data: accountIds, isLoading, hasNextPage, fetchNextPage } = useEventParticipations(statusId); const onClickClose = () => { onClose('EVENT_PARTICIPANTS'); @@ -45,10 +33,11 @@ const EventParticipantsModal: React.FC fetchNextPage({ cancelRefetch: false })} > - {accountIds.map(id => - , - )} + {accountIds.map(id => )} ); } diff --git a/packages/pl-fe/src/reducers/compose.ts b/packages/pl-fe/src/reducers/compose.ts index d68a931bb..effcc87a6 100644 --- a/packages/pl-fe/src/reducers/compose.ts +++ b/packages/pl-fe/src/reducers/compose.ts @@ -2,7 +2,6 @@ import { create } from 'mutative'; import { type CredentialAccount, type Instance, type MediaAttachment, type Tag } from 'pl-api'; import { INSTANCE_FETCH_SUCCESS, type InstanceAction } from 'pl-fe/actions/instance'; -import { isNativeEmoji, type Emoji } from 'pl-fe/features/emoji'; import { tagHistory } from 'pl-fe/settings'; import { @@ -36,7 +35,6 @@ import { COMPOSE_LANGUAGE_ADD, COMPOSE_LANGUAGE_DELETE, COMPOSE_ADD_SUGGESTED_LANGUAGE, - COMPOSE_EMOJI_INSERT, COMPOSE_UPLOAD_CHANGE_REQUEST, COMPOSE_UPLOAD_CHANGE_SUCCESS, COMPOSE_UPLOAD_CHANGE_FAIL, @@ -67,6 +65,7 @@ import { FE_NAME } from '../actions/settings'; import { TIMELINE_DELETE, type TimelineAction } from '../actions/timelines'; import { unescapeHTML } from '../utils/html'; +import type { Emoji } from 'pl-fe/features/emoji'; import type { Language } from 'pl-fe/features/preferences'; import type { Account } from 'pl-fe/normalizers/account'; import type { Status } from 'pl-fe/normalizers/status'; @@ -245,17 +244,6 @@ const updateSuggestionTags = (compose: Compose, token: string, tags: Tag[]) => { compose.suggestion_token = token; }; -const insertEmoji = (compose: Compose, position: number, emojiData: Emoji, needsSpace: boolean) => { - const oldText = compose.text; - const emojiText = isNativeEmoji(emojiData) ? emojiData.native : emojiData.colons; - const emoji = needsSpace ? ' ' + emojiText : emojiText; - - compose.text = `${oldText.slice(0, position)}${emoji} ${oldText.slice(position)}`; - compose.focusDate = new Date(); - compose.caretPosition = position + emoji.length + 1; - compose.idempotencyKey = crypto.randomUUID(); -}; - const privacyPreference = (a: string, b: string) => { const order = ['public', 'unlisted', 'mutuals_only', 'private', 'direct', 'local']; @@ -513,8 +501,6 @@ const compose = (state = initialState, action: ComposeAction | EventsAction | In compose.quote = null; } }); - case COMPOSE_EMOJI_INSERT: - return updateCompose(state, action.composeId, compose => insertEmoji(compose, action.position, action.emoji, action.needsSpace)); case COMPOSE_UPLOAD_CHANGE_SUCCESS: return updateCompose(state, action.composeId, compose => { compose.is_changing_upload = false; diff --git a/packages/pl-fe/src/reducers/user-lists.ts b/packages/pl-fe/src/reducers/user-lists.ts index d443593d8..c76e41889 100644 --- a/packages/pl-fe/src/reducers/user-lists.ts +++ b/packages/pl-fe/src/reducers/user-lists.ts @@ -10,8 +10,6 @@ import { type AccountsAction, } from 'pl-fe/actions/accounts'; import { - EVENT_PARTICIPATIONS_EXPAND_SUCCESS, - EVENT_PARTICIPATIONS_FETCH_SUCCESS, EVENT_PARTICIPATION_REQUESTS_EXPAND_SUCCESS, EVENT_PARTICIPATION_REQUESTS_FETCH_SUCCESS, EVENT_PARTICIPATION_REQUEST_AUTHORIZE_SUCCESS, @@ -182,10 +180,6 @@ const userLists = (state = initialState, action: AccountsAction | EventsAction | return normalizeList(state, ['birthday_reminders', action.accountId], action.accounts); case FAMILIAR_FOLLOWERS_FETCH_SUCCESS: return normalizeList(state, ['familiar_followers', action.accountId], action.accounts); - case EVENT_PARTICIPATIONS_FETCH_SUCCESS: - return normalizeList(state, ['event_participations', action.statusId], action.accounts, action.next); - case EVENT_PARTICIPATIONS_EXPAND_SUCCESS: - return appendToList(state, ['event_participations', action.statusId], action.accounts, action.next); case EVENT_PARTICIPATION_REQUESTS_FETCH_SUCCESS: return create(state, (draft) => { draft.event_participation_requests[action.statusId] = { From 443e15c591ef37d1f61de7cac359bae705390379 Mon Sep 17 00:00:00 2001 From: mkljczk Date: Wed, 4 Dec 2024 17:58:20 +0100 Subject: [PATCH 16/76] pl-fe: migrate event participation requests to tanstack query Signed-off-by: mkljczk --- packages/pl-fe/src/actions/events.ts | 178 +----------------- packages/pl-fe/src/actions/export-data.ts | 2 +- .../use-event-participation-requests.ts | 62 ++++++ .../account-lists/use-event-participations.ts | 2 +- .../tabs/manage-pending-participants.tsx | 46 ++--- packages/pl-fe/src/reducers/user-lists.ts | 52 +---- 6 files changed, 79 insertions(+), 263 deletions(-) create mode 100644 packages/pl-fe/src/api/hooks/account-lists/use-event-participation-requests.ts diff --git a/packages/pl-fe/src/actions/events.ts b/packages/pl-fe/src/actions/events.ts index a67b69cb7..e6d49d556 100644 --- a/packages/pl-fe/src/actions/events.ts +++ b/packages/pl-fe/src/actions/events.ts @@ -6,7 +6,7 @@ import toast from 'pl-fe/toast'; 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'; +import type { CreateEventParams, Location, MediaAttachment, PaginatedResponse, Status } from 'pl-api'; import type { AppDispatch, RootState } from 'pl-fe/store'; const EVENT_SUBMIT_REQUEST = 'EVENT_SUBMIT_REQUEST' as const; @@ -21,22 +21,6 @@ const EVENT_LEAVE_REQUEST = 'EVENT_LEAVE_REQUEST' as const; const EVENT_LEAVE_SUCCESS = 'EVENT_LEAVE_SUCCESS' as const; const EVENT_LEAVE_FAIL = 'EVENT_LEAVE_FAIL' as const; -const EVENT_PARTICIPATION_REQUESTS_FETCH_REQUEST = 'EVENT_PARTICIPATION_REQUESTS_FETCH_REQUEST' as const; -const EVENT_PARTICIPATION_REQUESTS_FETCH_SUCCESS = 'EVENT_PARTICIPATION_REQUESTS_FETCH_SUCCESS' as const; -const EVENT_PARTICIPATION_REQUESTS_FETCH_FAIL = 'EVENT_PARTICIPATION_REQUESTS_FETCH_FAIL' as const; - -const EVENT_PARTICIPATION_REQUESTS_EXPAND_REQUEST = 'EVENT_PARTICIPATION_REQUESTS_EXPAND_REQUEST' as const; -const EVENT_PARTICIPATION_REQUESTS_EXPAND_SUCCESS = 'EVENT_PARTICIPATION_REQUESTS_EXPAND_SUCCESS' as const; -const EVENT_PARTICIPATION_REQUESTS_EXPAND_FAIL = 'EVENT_PARTICIPATION_REQUESTS_EXPAND_FAIL' as const; - -const EVENT_PARTICIPATION_REQUEST_AUTHORIZE_REQUEST = 'EVENT_PARTICIPATION_REQUEST_AUTHORIZE_REQUEST' as const; -const EVENT_PARTICIPATION_REQUEST_AUTHORIZE_SUCCESS = 'EVENT_PARTICIPATION_REQUEST_AUTHORIZE_SUCCESS' as const; -const EVENT_PARTICIPATION_REQUEST_AUTHORIZE_FAIL = 'EVENT_PARTICIPATION_REQUEST_AUTHORIZE_FAIL' as const; - -const EVENT_PARTICIPATION_REQUEST_REJECT_REQUEST = 'EVENT_PARTICIPATION_REQUEST_REJECT_REQUEST' as const; -const EVENT_PARTICIPATION_REQUEST_REJECT_SUCCESS = 'EVENT_PARTICIPATION_REQUEST_REJECT_SUCCESS' as const; -const EVENT_PARTICIPATION_REQUEST_REJECT_FAIL = 'EVENT_PARTICIPATION_REQUEST_REJECT_FAIL' as const; - const EVENT_COMPOSE_CANCEL = 'EVENT_COMPOSE_CANCEL' as const; const EVENT_FORM_SET = 'EVENT_FORM_SET' as const; @@ -213,136 +197,6 @@ const leaveEventFail = (error: unknown, statusId: string, previousState: Exclude previousState, }); -const fetchEventParticipationRequests = (statusId: string) => - (dispatch: AppDispatch, getState: () => RootState) => { - dispatch(fetchEventParticipationRequestsRequest(statusId)); - - return getClient(getState).events.getEventParticipationRequests(statusId).then(response => { - dispatch(importEntities({ accounts: response.items.map(({ account }) => account) })); - return dispatch(fetchEventParticipationRequestsSuccess(statusId, response.items, response.next)); - }).catch(error => { - dispatch(fetchEventParticipationRequestsFail(statusId, error)); - }); - }; - -const fetchEventParticipationRequestsRequest = (statusId: string) => ({ - type: EVENT_PARTICIPATION_REQUESTS_FETCH_REQUEST, - statusId, -}); - -const fetchEventParticipationRequestsSuccess = (statusId: string, participations: Array<{ - account: Account; - participation_message: string; -}>, next: (() => Promise>) | null) => ({ - type: EVENT_PARTICIPATION_REQUESTS_FETCH_SUCCESS, - statusId, - participations, - next, -}); - -const fetchEventParticipationRequestsFail = (statusId: string, error: unknown) => ({ - type: EVENT_PARTICIPATION_REQUESTS_FETCH_FAIL, - statusId, - error, -}); - -const expandEventParticipationRequests = (statusId: string) => - (dispatch: AppDispatch, getState: () => RootState) => { - const next = getState().user_lists.event_participation_requests[statusId]?.next || null; - - if (next === null) { - return dispatch(noOp); - } - - dispatch(expandEventParticipationRequestsRequest(statusId)); - - return next().then(response => { - dispatch(importEntities({ accounts: response.items.map(({ account }) => account) })); - return dispatch(expandEventParticipationRequestsSuccess(statusId, response.items, response.next)); - }).catch(error => { - dispatch(expandEventParticipationRequestsFail(statusId, error)); - }); - }; - -const expandEventParticipationRequestsRequest = (statusId: string) => ({ - type: EVENT_PARTICIPATION_REQUESTS_EXPAND_REQUEST, - statusId, -}); - -const expandEventParticipationRequestsSuccess = (statusId: string, participations: Array<{ - account: Account; - participation_message: string; -}>, next: (() => Promise>) | null) => ({ - type: EVENT_PARTICIPATION_REQUESTS_EXPAND_SUCCESS, - statusId, - participations, - next, -}); - -const expandEventParticipationRequestsFail = (statusId: string, error: unknown) => ({ - type: EVENT_PARTICIPATION_REQUESTS_EXPAND_FAIL, - statusId, - error, -}); - -const authorizeEventParticipationRequest = (statusId: string, accountId: string) => - (dispatch: AppDispatch, getState: () => RootState) => { - dispatch(authorizeEventParticipationRequestRequest(statusId, accountId)); - - return getClient(getState).events.acceptEventParticipationRequest(statusId, accountId).then(() => { - dispatch(authorizeEventParticipationRequestSuccess(statusId, accountId)); - toast.success(messages.authorized); - }).catch(error => dispatch(authorizeEventParticipationRequestFail(statusId, accountId, error))); - }; - -const authorizeEventParticipationRequestRequest = (statusId: string, accountId: string) => ({ - type: EVENT_PARTICIPATION_REQUEST_AUTHORIZE_REQUEST, - statusId, - accountId, -}); - -const authorizeEventParticipationRequestSuccess = (statusId: string, accountId: string) => ({ - type: EVENT_PARTICIPATION_REQUEST_AUTHORIZE_SUCCESS, - statusId, - accountId, -}); - -const authorizeEventParticipationRequestFail = (statusId: string, accountId: string, error: unknown) => ({ - type: EVENT_PARTICIPATION_REQUEST_AUTHORIZE_FAIL, - statusId, - accountId, - error, -}); - -const rejectEventParticipationRequest = (statusId: string, accountId: string) => - (dispatch: AppDispatch, getState: () => RootState) => { - dispatch(rejectEventParticipationRequestRequest(statusId, accountId)); - - return getClient(getState).events.rejectEventParticipationRequest(statusId, accountId).then(() => { - dispatch(rejectEventParticipationRequestSuccess(statusId, accountId)); - toast.success(messages.rejected); - }).catch(error => dispatch(rejectEventParticipationRequestFail(statusId, accountId, error))); - }; - -const rejectEventParticipationRequestRequest = (statusId: string, accountId: string) => ({ - type: EVENT_PARTICIPATION_REQUEST_REJECT_REQUEST, - statusId, - accountId, -}); - -const rejectEventParticipationRequestSuccess = (statusId: string, accountId: string) => ({ - type: EVENT_PARTICIPATION_REQUEST_REJECT_SUCCESS, - statusId, - accountId, -}); - -const rejectEventParticipationRequestFail = (statusId: string, accountId: string, error: unknown) => ({ - type: EVENT_PARTICIPATION_REQUEST_REJECT_FAIL, - statusId, - accountId, - error, -}); - const fetchEventIcs = (statusId: string) => (dispatch: AppDispatch, getState: () => RootState) => getClient(getState).events.getEventIcs(statusId); @@ -425,20 +279,6 @@ type EventsAction = | ReturnType | ReturnType | ReturnType - | ReturnType - | ReturnType - | ReturnType - | ReturnType - | ReturnType - | ReturnType - | ReturnType - | ReturnType - | ReturnType - | ReturnType - | ReturnType - | ReturnType - | ReturnType - | ReturnType | ReturnType | EventFormSetAction | { type: typeof RECENT_EVENTS_FETCH_REQUEST } @@ -458,18 +298,6 @@ export { EVENT_LEAVE_REQUEST, EVENT_LEAVE_SUCCESS, EVENT_LEAVE_FAIL, - EVENT_PARTICIPATION_REQUESTS_FETCH_REQUEST, - EVENT_PARTICIPATION_REQUESTS_FETCH_SUCCESS, - EVENT_PARTICIPATION_REQUESTS_FETCH_FAIL, - EVENT_PARTICIPATION_REQUESTS_EXPAND_REQUEST, - EVENT_PARTICIPATION_REQUESTS_EXPAND_SUCCESS, - EVENT_PARTICIPATION_REQUESTS_EXPAND_FAIL, - EVENT_PARTICIPATION_REQUEST_AUTHORIZE_REQUEST, - EVENT_PARTICIPATION_REQUEST_AUTHORIZE_SUCCESS, - EVENT_PARTICIPATION_REQUEST_AUTHORIZE_FAIL, - EVENT_PARTICIPATION_REQUEST_REJECT_REQUEST, - EVENT_PARTICIPATION_REQUEST_REJECT_SUCCESS, - EVENT_PARTICIPATION_REQUEST_REJECT_FAIL, EVENT_COMPOSE_CANCEL, EVENT_FORM_SET, RECENT_EVENTS_FETCH_REQUEST, @@ -481,10 +309,6 @@ export { submitEvent, joinEvent, leaveEvent, - fetchEventParticipationRequests, - expandEventParticipationRequests, - authorizeEventParticipationRequest, - rejectEventParticipationRequest, fetchEventIcs, cancelEventCompose, initEventEdit, diff --git a/packages/pl-fe/src/actions/export-data.ts b/packages/pl-fe/src/actions/export-data.ts index 9c28c1911..5f1d2b24e 100644 --- a/packages/pl-fe/src/actions/export-data.ts +++ b/packages/pl-fe/src/actions/export-data.ts @@ -33,7 +33,7 @@ type ExportDataAction = { | typeof EXPORT_BLOCKS_SUCCESS | typeof EXPORT_MUTES_SUCCESS; } | { - type: typeof EXPORT_FOLLOWS_FAIL + type: typeof EXPORT_FOLLOWS_FAIL | typeof EXPORT_BLOCKS_FAIL | typeof EXPORT_MUTES_FAIL; error?: unknown; diff --git a/packages/pl-fe/src/api/hooks/account-lists/use-event-participation-requests.ts b/packages/pl-fe/src/api/hooks/account-lists/use-event-participation-requests.ts new file mode 100644 index 000000000..da221cbcd --- /dev/null +++ b/packages/pl-fe/src/api/hooks/account-lists/use-event-participation-requests.ts @@ -0,0 +1,62 @@ + +import { InfiniteData, useInfiniteQuery, useMutation } from '@tanstack/react-query'; + +import { importEntities } from 'pl-fe/actions/importer'; +import { minifyList } from 'pl-fe/api/normalizers/minify-list'; +import { useClient } from 'pl-fe/hooks/use-client'; +import { queryClient } from 'pl-fe/queries/client'; +import { store } from 'pl-fe/store'; + +import type { PlApiClient } from 'pl-api'; + +const minifyRequestList = (response: Awaited)['events']['getEventParticipationRequests']>>) => + minifyList( + response, + ({ account, participation_message }) => ({ account_id: account.id, participation_message }), + (requests) => store.dispatch(importEntities({ accounts: requests.map(request => request.account) }) as any), + ); + +type MinifiedRequestList = ReturnType + +const removeRequest = (statusId: string, accountId: string) => + queryClient.setQueryData>(['accountsLists', 'eventParticipationRequests', statusId], (data) => data ? { + ...data, + pages: data.pages.map(({ items, ...page }) => ({ ...page, items: items.filter(({ account_id }) => account_id !== accountId) })), + } : undefined); + +const useEventParticipationRequests = (statusId: string) => { + const client = useClient(); + + return useInfiniteQuery({ + queryKey: ['accountsLists', 'eventParticipationRequests', statusId], + queryFn: ({ pageParam }) => pageParam.next?.() || client.events.getEventParticipationRequests(statusId).then(minifyRequestList), + initialPageParam: { previous: null, next: null, items: [], partial: false } as MinifiedRequestList, + getNextPageParam: (page) => page.next ? page : undefined, + select: (data) => data.pages.map(page => page.items).flat(), + }); +}; + +const useAcceptEventParticipationRequestMutation = (statusId: string, accountId: string) => { + const client = useClient(); + + return useMutation({ + mutationKey: ['accountsLists', 'eventParticipationRequests', statusId, accountId], + mutationFn: () => client.events.acceptEventParticipationRequest(statusId, accountId), + onSettled: () => removeRequest(statusId, accountId), + }); +}; + +const useRejectEventParticipationRequestMutation = (statusId: string, accountId: string) => { + const client = useClient(); + + return useMutation({ + mutationKey: ['accountsLists', 'eventParticipationRequests', statusId, accountId], + mutationFn: () => client.events.rejectEventParticipationRequest(statusId, accountId), + onSettled: () => removeRequest(statusId, accountId), + }); +}; +export { + useEventParticipationRequests, + useAcceptEventParticipationRequestMutation, + useRejectEventParticipationRequestMutation, +}; diff --git a/packages/pl-fe/src/api/hooks/account-lists/use-event-participations.ts b/packages/pl-fe/src/api/hooks/account-lists/use-event-participations.ts index 231e8516f..33d63dc1b 100644 --- a/packages/pl-fe/src/api/hooks/account-lists/use-event-participations.ts +++ b/packages/pl-fe/src/api/hooks/account-lists/use-event-participations.ts @@ -11,7 +11,7 @@ const useEventParticipations = (statusId: string) => { return useInfiniteQuery({ queryKey: ['accountsLists', 'eventParticipations', statusId], - queryFn: ({ pageParam }) => pageParam.next?.() || client.events.getEventParticipations(statusId).then(minifyAccountList), + queryFn: ({ pageParam }) => pageParam.next?.() || client.events.getEventParticipations(statusId).then(minifyAccountList), initialPageParam: { previous: null, next: null, items: [], partial: false } as PaginatedResponse, getNextPageParam: (page) => page.next ? page : undefined, select: (data) => data.pages.map(page => page.items).flat(), diff --git a/packages/pl-fe/src/features/compose-event/tabs/manage-pending-participants.tsx b/packages/pl-fe/src/features/compose-event/tabs/manage-pending-participants.tsx index 90ffeac59..d7ecea40a 100644 --- a/packages/pl-fe/src/features/compose-event/tabs/manage-pending-participants.tsx +++ b/packages/pl-fe/src/features/compose-event/tabs/manage-pending-participants.tsx @@ -1,20 +1,13 @@ -import React, { useEffect } from 'react'; +import React from 'react'; import { defineMessages, FormattedMessage, useIntl } from 'react-intl'; -import { - fetchEventParticipationRequests, - rejectEventParticipationRequest, - authorizeEventParticipationRequest, - cancelEventCompose, -} from 'pl-fe/actions/events'; +import { useAcceptEventParticipationRequestMutation, useEventParticipationRequests } from 'pl-fe/api/hooks/account-lists/use-event-participation-requests'; import ScrollableList from 'pl-fe/components/scrollable-list'; import Button from 'pl-fe/components/ui/button'; import HStack from 'pl-fe/components/ui/hstack'; import Spinner from 'pl-fe/components/ui/spinner'; import Stack from 'pl-fe/components/ui/stack'; import AccountContainer from 'pl-fe/containers/account-container'; -import { useAppDispatch } from 'pl-fe/hooks/use-app-dispatch'; -import { useAppSelector } from 'pl-fe/hooks/use-app-selector'; const messages = defineMessages({ authorize: { id: 'compose_event.participation_requests.authorize', defaultMessage: 'Authorize' }, @@ -29,15 +22,9 @@ interface IAccount { const Account: React.FC = ({ eventId, id, participationMessage }) => { const intl = useIntl(); - const dispatch = useAppDispatch(); - const handleAuthorize = () => { - dispatch(authorizeEventParticipationRequest(eventId, id)); - }; - - const handleReject = () => { - dispatch(rejectEventParticipationRequest(eventId, id)); - }; + const { mutate: acceptEventParticipationRequest } = useAcceptEventParticipationRequestMutation(eventId, id); + const { mutate: rejectEventParticipationRequest } = useAcceptEventParticipationRequestMutation(eventId, id); return ( = ({ eventId, id, participationMessage }) => { theme='secondary' size='sm' text={intl.formatMessage(messages.authorize)} - onClick={handleAuthorize} + onClick={() => acceptEventParticipationRequest()} />
-
+
diff --git a/packages/pl-fe/src/features/status/components/thread-status.tsx b/packages/pl-fe/src/features/status/components/thread-status.tsx index 0d9495d78..18cceb488 100644 --- a/packages/pl-fe/src/features/status/components/thread-status.tsx +++ b/packages/pl-fe/src/features/status/components/thread-status.tsx @@ -26,12 +26,7 @@ const ThreadStatus: React.FC = (props): JSX.Element => { if (isDeleted) { return (
- +
); } diff --git a/packages/pl-fe/src/features/status/components/thread.tsx b/packages/pl-fe/src/features/status/components/thread.tsx index 4f8bbda1b..1a2f4e77f 100644 --- a/packages/pl-fe/src/features/status/components/thread.tsx +++ b/packages/pl-fe/src/features/status/components/thread.tsx @@ -329,7 +329,7 @@ const Thread: React.FC = ({ const focusedStatus = (
{status.deleted ? ( - + ) : (
Date: Thu, 5 Dec 2024 16:13:32 +0100 Subject: [PATCH 63/76] recommend tailwind css vscode extension Signed-off-by: mkljczk --- .vscode/extensions.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.vscode/extensions.json b/.vscode/extensions.json index d1762aa9a..33be54684 100644 --- a/.vscode/extensions.json +++ b/.vscode/extensions.json @@ -4,6 +4,6 @@ "bradlc.vscode-tailwindcss", "stylelint.vscode-stylelint", "wix.vscode-import-cost", - "redhat.vscode-yaml" + "bradlc.vscode-tailwindcss" ] } From 6687a12f01841b77167184747a53affb7a398603 Mon Sep 17 00:00:00 2001 From: mkljczk Date: Thu, 5 Dec 2024 16:14:05 +0100 Subject: [PATCH 64/76] pl-fe: update verified badge styles Signed-off-by: mkljczk --- packages/pl-fe/src/features/account/components/header.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/pl-fe/src/features/account/components/header.tsx b/packages/pl-fe/src/features/account/components/header.tsx index 201a526c1..4847b75fd 100644 --- a/packages/pl-fe/src/features/account/components/header.tsx +++ b/packages/pl-fe/src/features/account/components/header.tsx @@ -657,7 +657,7 @@ const Header: React.FC = ({ account }) => { /> {account.verified && ( -
+
)} From 4c0bd101c57e857ac392db1cf556f936750cae58 Mon Sep 17 00:00:00 2001 From: mkljczk Date: Thu, 5 Dec 2024 16:14:28 +0100 Subject: [PATCH 65/76] pl-fe: make search input focusable by hotkeys again Signed-off-by: mkljczk --- packages/pl-fe/src/components/autosuggest-account-input.tsx | 1 + packages/pl-fe/src/components/search-input.tsx | 1 + 2 files changed, 2 insertions(+) diff --git a/packages/pl-fe/src/components/autosuggest-account-input.tsx b/packages/pl-fe/src/components/autosuggest-account-input.tsx index aa75dae6f..fadff8f28 100644 --- a/packages/pl-fe/src/components/autosuggest-account-input.tsx +++ b/packages/pl-fe/src/components/autosuggest-account-input.tsx @@ -11,6 +11,7 @@ import type { InputThemes } from 'pl-fe/components/ui/input'; const noOp = () => { }; interface IAutosuggestAccountInput { + id?: string; onChange: React.ChangeEventHandler; onSelected: (accountId: string) => void; autoFocus?: boolean; diff --git a/packages/pl-fe/src/components/search-input.tsx b/packages/pl-fe/src/components/search-input.tsx index 11460b297..36e571bf6 100644 --- a/packages/pl-fe/src/components/search-input.tsx +++ b/packages/pl-fe/src/components/search-input.tsx @@ -78,6 +78,7 @@ const SearchInput = () => {
Date: Thu, 5 Dec 2024 16:31:23 +0100 Subject: [PATCH 66/76] pl-fe: optimize initial js size Signed-off-by: mkljczk --- .../pl-fe/src/components/account-hover-card.tsx | 2 +- packages/pl-fe/src/components/account.tsx | 2 +- .../announcements/announcements-panel.tsx | 2 +- .../src/components/announcements/reaction.tsx | 4 ++-- .../pl-fe/src/components/autosuggest-input.tsx | 2 +- packages/pl-fe/src/components/avatar-stack.tsx | 2 +- packages/pl-fe/src/components/big-card.tsx | 2 +- .../dropdown-menu/dropdown-menu-item.tsx | 4 ++-- .../components/dropdown-menu/dropdown-menu.tsx | 4 ++-- packages/pl-fe/src/components/event-preview.tsx | 4 ++-- packages/pl-fe/src/components/group-card.tsx | 4 ++-- .../components/groups/popover/group-popover.tsx | 4 ++-- packages/pl-fe/src/components/hashtags-bar.tsx | 2 +- .../pl-fe/src/components/landing-gradient.tsx | 2 +- packages/pl-fe/src/components/link.tsx | 2 +- packages/pl-fe/src/components/list.tsx | 2 +- packages/pl-fe/src/components/mention.tsx | 2 +- packages/pl-fe/src/components/modal-root.tsx | 2 +- packages/pl-fe/src/components/navlinks.tsx | 2 +- packages/pl-fe/src/components/parsed-content.tsx | 2 +- .../pl-fe/src/components/pending-items-row.tsx | 2 +- .../pl-fe/src/components/polls/poll-option.tsx | 10 +++++----- packages/pl-fe/src/components/radio.tsx | 2 +- .../pl-fe/src/components/scroll-top-button.tsx | 2 +- packages/pl-fe/src/components/sidebar-menu.tsx | 12 ++++++------ .../pl-fe/src/components/site-error-boundary.tsx | 8 ++++---- .../src/components/status-action-button.tsx | 2 +- .../pl-fe/src/components/status-hover-card.tsx | 2 +- packages/pl-fe/src/components/status-mention.tsx | 2 +- .../src/components/status-reactions-bar.tsx | 2 +- .../src/components/status-reply-mentions.tsx | 2 +- packages/pl-fe/src/components/status.tsx | 4 ++-- .../src/components/statuses/status-info.tsx | 2 +- .../pl-fe/src/components/thumb-navigation.tsx | 6 +++--- packages/pl-fe/src/components/trending-link.tsx | 2 +- packages/pl-fe/src/components/ui/accordion.tsx | 2 +- packages/pl-fe/src/components/ui/card.tsx | 2 +- packages/pl-fe/src/components/ui/checkbox.tsx | 2 +- packages/pl-fe/src/components/ui/counter.tsx | 2 +- packages/pl-fe/src/components/ui/divider.tsx | 4 ++-- packages/pl-fe/src/components/ui/form-group.tsx | 4 ++-- packages/pl-fe/src/components/ui/icon-button.tsx | 2 +- .../src/components/ui/inline-multiselect.tsx | 4 ++-- packages/pl-fe/src/components/ui/input.tsx | 4 ++-- packages/pl-fe/src/components/ui/layout.tsx | 2 +- packages/pl-fe/src/components/ui/modal.tsx | 8 ++++---- packages/pl-fe/src/components/ui/popover.tsx | 4 ++-- .../pl-fe/src/components/ui/progress-bar.tsx | 4 ++-- packages/pl-fe/src/components/ui/select.tsx | 2 +- packages/pl-fe/src/components/ui/slider.tsx | 6 +++--- packages/pl-fe/src/components/ui/tabs.tsx | 4 ++-- packages/pl-fe/src/components/ui/tag-input.tsx | 2 +- packages/pl-fe/src/components/ui/tag.tsx | 2 +- packages/pl-fe/src/components/ui/textarea.tsx | 2 +- packages/pl-fe/src/components/ui/toast.tsx | 8 ++++---- packages/pl-fe/src/components/ui/toggle.tsx | 2 +- packages/pl-fe/src/components/ui/widget.tsx | 2 +- .../pl-fe/src/components/verification-badge.tsx | 4 ++-- packages/pl-fe/src/features/about/index.tsx | 2 +- .../account-timeline/components/moved-note.tsx | 2 +- .../src/features/account/components/header.tsx | 8 ++++---- .../pl-fe/src/features/admin/announcements.tsx | 2 +- .../src/features/admin/components/report.tsx | 2 +- packages/pl-fe/src/features/admin/domains.tsx | 2 +- packages/pl-fe/src/features/admin/relays.tsx | 2 +- packages/pl-fe/src/features/admin/rules.tsx | 2 +- .../src/features/aliases/components/search.tsx | 2 +- packages/pl-fe/src/features/audio/index.tsx | 4 ++-- .../auth-login/components/consumers-list.tsx | 2 +- .../pl-fe/src/features/auth-token-list/index.tsx | 2 +- packages/pl-fe/src/features/backups/index.tsx | 2 +- .../features/chats/components/chat-composer.tsx | 4 ++-- .../features/chats/components/chat-list-item.tsx | 4 ++-- .../src/features/chats/components/chat-list.tsx | 4 ++-- .../chats/components/chat-page/chat-page.tsx | 6 +++--- .../chats/components/chat-pending-upload.tsx | 2 +- .../chats/components/chat-search/results.tsx | 4 ++-- .../features/chats/components/chat-textarea.tsx | 16 ++++++++-------- .../features/chats/components/chat-upload.tsx | 4 ++-- .../components/chat-widget/chat-pane-header.tsx | 2 +- .../components/chat-widget/chat-settings.tsx | 6 +++--- .../chats/components/chat-widget/chat-window.tsx | 2 +- .../chat-widget/headers/chat-search-header.tsx | 2 +- .../src/features/chats/components/ui/pane.tsx | 2 +- packages/pl-fe/src/features/circle/index.tsx | 2 +- .../compose-event/components/upload-button.tsx | 2 +- .../features/compose-event/tabs/edit-event.tsx | 4 ++-- .../features/compose/components/compose-form.tsx | 2 +- .../compose/components/language-dropdown.tsx | 2 +- .../compose/components/reply-indicator.tsx | 2 +- .../compose/components/reply-mentions.tsx | 2 +- .../plugins/floating-link-editor-plugin.tsx | 2 +- .../floating-text-format-toolbar-plugin.tsx | 4 ++-- .../crypto-donate/components/crypto-address.tsx | 3 +-- .../components/detailed-crypto-address.tsx | 3 +-- .../directory/components/account-card.tsx | 4 ++-- .../edit-profile/components/avatar-picker.tsx | 2 +- .../edit-profile/components/header-picker.tsx | 2 +- .../pl-fe/src/features/embedded-status/index.tsx | 2 +- .../features/event/components/event-header.tsx | 6 +++--- .../src/features/event/event-discussion.tsx | 2 +- .../src/features/event/event-information.tsx | 4 ++-- packages/pl-fe/src/features/filters/index.tsx | 2 +- .../features/group/components/group-header.tsx | 8 ++++---- .../pl-fe/src/features/group/group-timeline.tsx | 2 +- .../src/features/hashtag-timeline/index.tsx | 2 +- .../pl-fe/src/features/home-timeline/index.tsx | 2 +- .../src/features/interaction-requests/index.tsx | 6 +++--- .../landing-timeline/components/logo-text.tsx | 2 +- packages/pl-fe/src/features/migration/index.tsx | 2 +- .../notifications/components/notification.tsx | 2 +- .../pl-fe/src/features/notifications/index.tsx | 2 +- .../onboarding/steps/avatar-selection-step.tsx | 2 +- .../features/onboarding/steps/completed-step.tsx | 2 +- .../steps/cover-photo-selection-step.tsx | 4 ++-- .../features/onboarding/steps/fediverse-step.tsx | 6 +++--- .../onboarding/steps/suggested-accounts-step.tsx | 2 +- .../pl-fe-config/components/icon-picker-menu.tsx | 4 ++-- .../pl-fe-config/components/site-preview.tsx | 2 +- .../components/placeholder-avatar.tsx | 4 ++-- .../placeholder/components/placeholder-card.tsx | 2 +- .../components/placeholder-chat-message.tsx | 4 ++-- .../components/placeholder-display-name.tsx | 2 +- .../components/placeholder-event-header.tsx | 2 +- .../components/placeholder-event-preview.tsx | 4 ++-- .../components/placeholder-group-card.tsx | 4 ++-- .../components/placeholder-group-search.tsx | 2 +- .../components/placeholder-hashtag.tsx | 2 +- .../components/placeholder-media-gallery.tsx | 2 +- .../components/placeholder-notification.tsx | 2 +- .../placeholder-sidebar-suggestions.tsx | 2 +- .../components/placeholder-sidebar-trends.tsx | 2 +- .../components/placeholder-status-content.tsx | 2 +- .../pl-fe/src/features/public-timeline/index.tsx | 2 +- .../components/pinned-hosts-picker.tsx | 2 +- .../src/features/search/components/search.tsx | 2 +- .../status/components/detailed-status.tsx | 2 +- .../features/status/components/thread-status.tsx | 2 +- .../src/features/status/components/thread.tsx | 6 +++--- .../features/ui/components/background-shapes.tsx | 2 +- .../features/ui/components/column-forbidden.tsx | 2 +- .../components/modals/compare-history-modal.tsx | 2 +- .../ui/components/modals/compose-modal.tsx | 2 +- .../ui/components/modals/dropdown-menu-modal.tsx | 2 +- .../modals/edit-bookmark-folder-modal.tsx | 2 +- .../ui/components/modals/hotkeys-modal.tsx | 2 +- .../steps/confirmation-step.tsx | 6 +++--- .../report-modal/steps/confirmation-step.tsx | 2 +- .../modals/report-modal/steps/reason-step.tsx | 2 +- .../features/ui/components/profile-dropdown.tsx | 6 +++--- packages/pl-fe/src/features/ui/index.tsx | 2 +- .../src/features/ui/util/async-components.ts | 2 ++ packages/pl-fe/src/features/video/index.tsx | 2 +- packages/pl-fe/src/init/pl-fe-head.tsx | 2 +- packages/pl-fe/src/layouts/chats-layout.tsx | 2 +- packages/pl-fe/src/layouts/home-layout.tsx | 4 ++-- packages/pl-fe/src/layouts/landing-layout.tsx | 2 +- packages/pl-fe/vite.config.ts | 2 +- 158 files changed, 242 insertions(+), 242 deletions(-) diff --git a/packages/pl-fe/src/components/account-hover-card.tsx b/packages/pl-fe/src/components/account-hover-card.tsx index 1286f798a..5c721f950 100644 --- a/packages/pl-fe/src/components/account-hover-card.tsx +++ b/packages/pl-fe/src/components/account-hover-card.tsx @@ -124,7 +124,7 @@ const AccountHoverCard: React.FC = ({ visible = true }) => { onMouseEnter={handleMouseEnter} onMouseLeave={handleMouseLeave} > - + = ({ account, disabled }) => { return ( diff --git a/packages/pl-fe/src/components/autosuggest-input.tsx b/packages/pl-fe/src/components/autosuggest-input.tsx index 1fc057963..5756a59be 100644 --- a/packages/pl-fe/src/components/autosuggest-input.tsx +++ b/packages/pl-fe/src/components/autosuggest-input.tsx @@ -217,7 +217,7 @@ const AutosuggestInput: React.FC = ({ return menu.map((item, i) => ( = ({ accountIds, limit = 3 }) => { style={{ zIndex: limit - i }} > = ({ title, subtitle, children }) => ( -
+
{title} {subtitle && {subtitle}} diff --git a/packages/pl-fe/src/components/dropdown-menu/dropdown-menu-item.tsx b/packages/pl-fe/src/components/dropdown-menu/dropdown-menu-item.tsx index 8e0390a8d..3e7e4b268 100644 --- a/packages/pl-fe/src/components/dropdown-menu/dropdown-menu-item.tsx +++ b/packages/pl-fe/src/components/dropdown-menu/dropdown-menu-item.tsx @@ -100,7 +100,7 @@ const DropdownMenuItem = ({ index, item, onClick, autoFocus, onSetTab }: IDropdo } return ( -
  • +
  • { } const getClassName = () => { - const className = clsx('z-[1001] bg-white py-1 shadow-lg ease-in-out focus:outline-none black:bg-black no-reduce-motion:transition-all dark:bg-gray-900 dark:ring-2 dark:ring-primary-700', { + const className = clsx('black:bg-black no-reduce-motion:transition-all dark:ring-primary-700 z-[1001] bg-white py-1 shadow-lg ease-in-out focus:outline-none dark:bg-gray-900 dark:ring-2', { 'rounded-md min-w-56 max-w-sm duration-100': true, 'no-reduce-motion:scale-0': !(isDisplayed && isOpen), 'scale-100': isDisplayed && isOpen, @@ -371,7 +371,7 @@ const DropdownMenu = (props: IDropdownMenu) => {
  • diff --git a/packages/pl-fe/src/components/event-preview.tsx b/packages/pl-fe/src/components/event-preview.tsx index 3d457cbad..ae33e35ac 100644 --- a/packages/pl-fe/src/components/event-preview.tsx +++ b/packages/pl-fe/src/components/event-preview.tsx @@ -54,11 +54,11 @@ const EventPreview: React.FC = ({ status, className, hideAction, )); return ( -
    +
    {floatingAction && action}
    -
    +
    {banner && {intl.formatMessage(messages.eventBanner)}}
    diff --git a/packages/pl-fe/src/components/group-card.tsx b/packages/pl-fe/src/components/group-card.tsx index 1a384169a..db067ebf1 100644 --- a/packages/pl-fe/src/components/group-card.tsx +++ b/packages/pl-fe/src/components/group-card.tsx @@ -19,11 +19,11 @@ interface IGroupCard { const GroupCard: React.FC = ({ group }) => ( {/* Group Cover Image */} - + { content={ {/* Group Cover Image */} - + {group.header && ( = ({ hashtags }) => { key={hashtag} to={`/tags/${hashtag}`} onClick={(e) => e.stopPropagation()} - className='flex items-center rounded-sm bg-gray-100 px-1.5 py-1 text-center text-xs font-medium text-primary-600 black:bg-primary-900 dark:bg-primary-700 dark:text-white' + className='text-primary-600 black:bg-primary-900 dark:bg-primary-700 flex items-center rounded-sm bg-gray-100 px-1.5 py-1 text-center text-xs font-medium dark:text-white' > #{hashtag} diff --git a/packages/pl-fe/src/components/landing-gradient.tsx b/packages/pl-fe/src/components/landing-gradient.tsx index 7bf75dc11..0e582c7dd 100644 --- a/packages/pl-fe/src/components/landing-gradient.tsx +++ b/packages/pl-fe/src/components/landing-gradient.tsx @@ -2,7 +2,7 @@ import React from 'react'; /** Fullscreen gradient used as a backdrop to public pages. */ const LandingGradient: React.FC = () => ( -
    +
    ); export { LandingGradient as default }; diff --git a/packages/pl-fe/src/components/link.tsx b/packages/pl-fe/src/components/link.tsx index 413061279..7516ce49f 100644 --- a/packages/pl-fe/src/components/link.tsx +++ b/packages/pl-fe/src/components/link.tsx @@ -4,7 +4,7 @@ import { Link as Comp, LinkProps } from 'react-router-dom'; const Link = (props: LinkProps) => ( ); diff --git a/packages/pl-fe/src/components/list.tsx b/packages/pl-fe/src/components/list.tsx index d5881ff4b..b125be4d1 100644 --- a/packages/pl-fe/src/components/list.tsx +++ b/packages/pl-fe/src/components/list.tsx @@ -56,7 +56,7 @@ const ListItem: React.FC = ({ className, label, hint, children, to, h return null; }), [children, domId]); - const classNames = clsx('flex items-center justify-between overflow-hidden bg-gradient-to-r from-gradient-start/20 to-gradient-end/20 first:rounded-t-lg last:rounded-b-lg dark:from-gradient-start/10 dark:to-gradient-end/10', + const classNames = clsx('from-gradient-start/20 to-gradient-end/20 dark:from-gradient-start/10 dark:to-gradient-end/10 flex items-center justify-between overflow-hidden bg-gradient-to-r first:rounded-t-lg last:rounded-b-lg', className, { 'px-4 py-2': size === 'md', diff --git a/packages/pl-fe/src/components/mention.tsx b/packages/pl-fe/src/components/mention.tsx index 68bcabb39..56310296b 100644 --- a/packages/pl-fe/src/components/mention.tsx +++ b/packages/pl-fe/src/components/mention.tsx @@ -23,7 +23,7 @@ const Mention: React.FC = ({ mention: { acct, username }, disabled }) diff --git a/packages/pl-fe/src/components/modal-root.tsx b/packages/pl-fe/src/components/modal-root.tsx index be0eb10fc..a6dfa527c 100644 --- a/packages/pl-fe/src/components/modal-root.tsx +++ b/packages/pl-fe/src/components/modal-root.tsx @@ -205,7 +205,7 @@ const ModalRoot: React.FC = ({ children, onCancel, onClose, type })