nicolium: remove admin reducer
Signed-off-by: nicole mikołajczyk <git@mkljczk.pl>
This commit is contained in:
@ -10,52 +10,8 @@ import { filterBadges, getTagDiff } from '@/utils/badges';
|
||||
import type { AppDispatch, RootState } from '@/store';
|
||||
import type { PleromaConfig } from 'pl-api';
|
||||
|
||||
const ADMIN_CONFIG_FETCH_SUCCESS = 'ADMIN_CONFIG_FETCH_SUCCESS' as const;
|
||||
|
||||
const ADMIN_CONFIG_UPDATE_REQUEST = 'ADMIN_CONFIG_UPDATE_REQUEST' as const;
|
||||
const ADMIN_CONFIG_UPDATE_SUCCESS = 'ADMIN_CONFIG_UPDATE_SUCCESS' as const;
|
||||
|
||||
const fetchConfig = () => (dispatch: AppDispatch, getState: () => RootState) =>
|
||||
getClient(getState)
|
||||
.admin.config.getPleromaConfig()
|
||||
.then((data) => {
|
||||
dispatch<AdminActions>({
|
||||
type: ADMIN_CONFIG_FETCH_SUCCESS,
|
||||
configs: data.configs,
|
||||
needsReboot: data.need_reboot,
|
||||
});
|
||||
});
|
||||
|
||||
const updateConfig =
|
||||
(configs: PleromaConfig['configs']) => (dispatch: AppDispatch, getState: () => RootState) => {
|
||||
dispatch<AdminActions>({ type: ADMIN_CONFIG_UPDATE_REQUEST, configs });
|
||||
return getClient(getState)
|
||||
.admin.config.updatePleromaConfig(configs)
|
||||
.then((data) => {
|
||||
dispatch<AdminActions>({
|
||||
type: ADMIN_CONFIG_UPDATE_SUCCESS,
|
||||
configs: data.configs,
|
||||
needsReboot: data.need_reboot,
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
const updateFrontendConfig = (data: Record<string, any>) => (dispatch: AppDispatch) => {
|
||||
const params = [
|
||||
{
|
||||
group: ':pleroma',
|
||||
key: ':frontend_configurations',
|
||||
value: [
|
||||
{
|
||||
tuple: [':nicolium', data],
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
return dispatch(updateConfig(params));
|
||||
};
|
||||
|
||||
const deactivateUser =
|
||||
(accountId: string, report_id?: string) => (dispatch: AppDispatch, getState: () => RootState) => {
|
||||
const state = getState();
|
||||
@ -150,26 +106,14 @@ const redactStatus = (statusId: string) => (dispatch: AppDispatch, getState: ()
|
||||
});
|
||||
};
|
||||
|
||||
type AdminActions =
|
||||
| {
|
||||
type: typeof ADMIN_CONFIG_FETCH_SUCCESS;
|
||||
configs: PleromaConfig['configs'];
|
||||
needsReboot: boolean;
|
||||
}
|
||||
| { type: typeof ADMIN_CONFIG_UPDATE_REQUEST; configs: PleromaConfig['configs'] }
|
||||
| {
|
||||
type: typeof ADMIN_CONFIG_UPDATE_SUCCESS;
|
||||
configs: PleromaConfig['configs'];
|
||||
needsReboot: boolean;
|
||||
};
|
||||
type AdminActions = {
|
||||
type: typeof ADMIN_CONFIG_UPDATE_SUCCESS;
|
||||
configs: PleromaConfig['configs'];
|
||||
needsReboot: boolean;
|
||||
};
|
||||
|
||||
export {
|
||||
ADMIN_CONFIG_FETCH_SUCCESS,
|
||||
ADMIN_CONFIG_UPDATE_REQUEST,
|
||||
ADMIN_CONFIG_UPDATE_SUCCESS,
|
||||
fetchConfig,
|
||||
updateConfig,
|
||||
updateFrontendConfig,
|
||||
deactivateUser,
|
||||
deleteUser,
|
||||
deleteStatus,
|
||||
|
||||
@ -1,9 +1,7 @@
|
||||
import { mrfSimpleSchema, type MRFSimple } from '@/schemas/pleroma';
|
||||
import ConfigDB from '@/utils/config-db';
|
||||
|
||||
import { fetchConfig, updateConfig } from './admin';
|
||||
|
||||
import type { AppDispatch, RootState } from '@/store';
|
||||
import type { PleromaConfig } from 'pl-api';
|
||||
|
||||
const simplePolicyMerge = (
|
||||
simplePolicy: Partial<MRFSimple>,
|
||||
@ -32,15 +30,15 @@ const simplePolicyMerge = (
|
||||
]);
|
||||
};
|
||||
|
||||
const updateMrf =
|
||||
(host: string, restrictions: Record<string, any>) =>
|
||||
(dispatch: AppDispatch, getState: () => RootState) =>
|
||||
dispatch(fetchConfig()).then(() => {
|
||||
const configs = getState().admin.configs;
|
||||
const simplePolicy = ConfigDB.toSimplePolicy(configs);
|
||||
const merged = simplePolicyMerge(simplePolicy, host, restrictions);
|
||||
const config = ConfigDB.fromSimplePolicy(merged);
|
||||
return dispatch(updateConfig(config));
|
||||
});
|
||||
const getUpdatedMrf = (
|
||||
configs: PleromaConfig['configs'],
|
||||
host: string,
|
||||
restrictions: Record<string, any>,
|
||||
) => {
|
||||
const simplePolicy = ConfigDB.toSimplePolicy(configs);
|
||||
const merged = simplePolicyMerge(simplePolicy, host, restrictions);
|
||||
const config = ConfigDB.fromSimplePolicy(merged);
|
||||
return config;
|
||||
};
|
||||
|
||||
export { updateMrf };
|
||||
export { getUpdatedMrf };
|
||||
|
||||
@ -149,7 +149,9 @@ const DropdownNavigation: React.FC = React.memo((): React.JSX.Element | null =>
|
||||
const scheduledStatusCount =
|
||||
useInfiniteQuery(authenticatedScheduledStatusesCountQueryOptions).data ?? 0;
|
||||
const { data: draftCount = 0 } = useDraftStatusesCountQuery();
|
||||
// const dashboardCount = useAppSelector((state) => state.admin.openReports.count() + state.admin.awaitingApproval.count());
|
||||
// const { data: awaitingApprovalCount = 0 } = usePendingUsersCount();
|
||||
// const { data: pendingReportsCount = 0 } = usePendingReportsCount();
|
||||
// const dashboardCount = pendingReportsCount + awaitingApprovalCount;
|
||||
const [sidebarVisible, setSidebarVisible] = useState(isSidebarOpen);
|
||||
const touchStart = useRef(0);
|
||||
const touchEnd = useRef<number | null>(null);
|
||||
|
||||
@ -1,10 +1,9 @@
|
||||
import React from 'react';
|
||||
import { useIntl, defineMessages, FormattedMessage } from 'react-intl';
|
||||
|
||||
import { updateConfig } from '@/actions/admin';
|
||||
import { RadioGroup, RadioItem } from '@/components/ui/radio';
|
||||
import { useAppDispatch } from '@/hooks/use-app-dispatch';
|
||||
import { useInstance } from '@/hooks/use-instance';
|
||||
import { useUpdateAdminConfig } from '@/queries/admin/use-config';
|
||||
import toast from '@/toast';
|
||||
|
||||
import type { Instance } from 'pl-api';
|
||||
@ -45,18 +44,18 @@ const modeFromInstance = ({ registrations }: Instance): RegistrationMode => {
|
||||
/** Allows changing the registration mode of the instance, eg "open", "closed", "approval" */
|
||||
const RegistrationModePicker: React.FC = () => {
|
||||
const intl = useIntl();
|
||||
const dispatch = useAppDispatch();
|
||||
const instance = useInstance();
|
||||
const { mutate: updateConfig } = useUpdateAdminConfig();
|
||||
|
||||
const mode = modeFromInstance(instance);
|
||||
|
||||
const onChange: React.ChangeEventHandler<HTMLInputElement> = (e) => {
|
||||
const config = generateConfig(e.target.value as RegistrationMode);
|
||||
dispatch(updateConfig(config))
|
||||
.then(() => {
|
||||
updateConfig(config, {
|
||||
onSuccess: () => {
|
||||
toast.success(intl.formatMessage(messages.saved));
|
||||
})
|
||||
.catch(() => {});
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
|
||||
@ -2,19 +2,16 @@ import clsx from 'clsx';
|
||||
import React, { useState } from 'react';
|
||||
|
||||
import Icon from '@/components/icon';
|
||||
import { useAppSelector } from '@/hooks/use-app-selector';
|
||||
import { makeGetRemoteInstance } from '@/selectors';
|
||||
import { useRemoteInstance } from '@/selectors';
|
||||
|
||||
import InstanceRestrictions from './instance-restrictions';
|
||||
|
||||
const getRemoteInstance = makeGetRemoteInstance();
|
||||
|
||||
interface IRestrictedInstance {
|
||||
host: string;
|
||||
}
|
||||
|
||||
const RestrictedInstance: React.FC<IRestrictedInstance> = ({ host }) => {
|
||||
const remoteInstance = useAppSelector((state) => getRemoteInstance(state, host));
|
||||
const remoteInstance = useRemoteInstance(host);
|
||||
|
||||
const [expanded, setExpanded] = useState(false);
|
||||
|
||||
|
||||
@ -4,12 +4,9 @@ import { useIntl, defineMessages } from 'react-intl';
|
||||
import { pinHost, unpinHost } from '@/actions/remote-timeline';
|
||||
import Widget from '@/components/ui/widget';
|
||||
import { useAppDispatch } from '@/hooks/use-app-dispatch';
|
||||
import { useAppSelector } from '@/hooks/use-app-selector';
|
||||
import { makeGetRemoteInstance } from '@/selectors';
|
||||
import { useRemoteInstance } from '@/selectors';
|
||||
import { useSettings } from '@/stores/settings';
|
||||
|
||||
const getRemoteInstance = makeGetRemoteInstance();
|
||||
|
||||
const messages = defineMessages({
|
||||
pinHost: { id: 'remote_instance.pin_host', defaultMessage: 'Pin {host}' },
|
||||
unpinHost: { id: 'remote_instance.unpin_host', defaultMessage: 'Unpin {host}' },
|
||||
@ -26,7 +23,7 @@ const InstanceInfoPanel: React.FC<IInstanceInfoPanel> = ({ host }) => {
|
||||
const dispatch = useAppDispatch();
|
||||
|
||||
const settings = useSettings();
|
||||
const remoteInstance = useAppSelector((state) => getRemoteInstance(state, host));
|
||||
const remoteInstance = useRemoteInstance(host);
|
||||
const pinned = settings.remote_timeline.pinnedHosts.includes(host);
|
||||
|
||||
const handlePinHost = () => {
|
||||
|
||||
@ -4,13 +4,10 @@ import { useIntl, defineMessages, FormattedMessage } from 'react-intl';
|
||||
import DropdownMenu from '@/components/dropdown-menu';
|
||||
import Widget from '@/components/ui/widget';
|
||||
import InstanceRestrictions from '@/features/federation-restrictions/components/instance-restrictions';
|
||||
import { useAppSelector } from '@/hooks/use-app-selector';
|
||||
import { useOwnAccount } from '@/hooks/use-own-account';
|
||||
import { makeGetRemoteInstance } from '@/selectors';
|
||||
import { useRemoteInstance } from '@/selectors';
|
||||
import { useModalsActions } from '@/stores/modals';
|
||||
|
||||
const getRemoteInstance = makeGetRemoteInstance();
|
||||
|
||||
const messages = defineMessages({
|
||||
editFederation: { id: 'remote_instance.edit_federation', defaultMessage: 'Edit federation' },
|
||||
});
|
||||
@ -26,7 +23,7 @@ const InstanceModerationPanel: React.FC<IInstanceModerationPanel> = ({ host }) =
|
||||
const { openModal } = useModalsActions();
|
||||
|
||||
const { data: account } = useOwnAccount();
|
||||
const remoteInstance = useAppSelector((state) => getRemoteInstance(state, host));
|
||||
const remoteInstance = useRemoteInstance(host);
|
||||
|
||||
const handleEditFederation = () => {
|
||||
openModal('EDIT_FEDERATION', { host });
|
||||
|
||||
@ -3,7 +3,6 @@ import clsx from 'clsx';
|
||||
import React, { Suspense, useEffect, useRef } from 'react';
|
||||
import { Toaster } from 'react-hot-toast';
|
||||
|
||||
import { fetchConfig } from '@/actions/admin';
|
||||
import { register as registerPushNotifications } from '@/actions/push-notifications/registerer';
|
||||
import { useUserStream } from '@/api/hooks/streaming/use-user-stream';
|
||||
import SidebarNavigation from '@/components/navigation/sidebar-navigation';
|
||||
@ -17,6 +16,7 @@ import { useFeatures } from '@/hooks/use-features';
|
||||
import { useInstance } from '@/hooks/use-instance';
|
||||
import { useOwnAccount } from '@/hooks/use-own-account';
|
||||
import { prefetchFollowRequests } from '@/queries/accounts/use-follow-requests';
|
||||
import { useAdminConfig } from '@/queries/admin/use-config';
|
||||
import { queryClient } from '@/queries/client';
|
||||
import { prefetchCustomEmojis } from '@/queries/instance/use-custom-emojis';
|
||||
import { usePrefetchNotificationsMarker } from '@/queries/markers/use-markers';
|
||||
@ -26,10 +26,11 @@ import { scheduledStatusesQueryOptions } from '@/queries/statuses/scheduled-stat
|
||||
import { useShoutboxSubscription } from '@/stores/shoutbox';
|
||||
import { useIsDropdownMenuOpen } from '@/stores/ui';
|
||||
import { getVapidKey } from '@/utils/auth';
|
||||
import { isStandalone } from '@/utils/state';
|
||||
// Dummy import, to make sure that <Status /> ends up in the application bundle.
|
||||
// Without this it ends up in ~8 very commonly used bundles.
|
||||
import '@/components/statuses/status';
|
||||
import { isStandalone } from '@/utils/state';
|
||||
|
||||
import {
|
||||
ModalRoot,
|
||||
AccountHoverCard,
|
||||
@ -53,6 +54,7 @@ const UI: React.FC = React.memo(() => {
|
||||
const isDropdownMenuOpen = useIsDropdownMenuOpen();
|
||||
const standalone = useAppSelector(isStandalone);
|
||||
|
||||
useAdminConfig();
|
||||
useShoutboxSubscription();
|
||||
useFilters();
|
||||
usePrefetchNotifications();
|
||||
@ -87,10 +89,6 @@ const UI: React.FC = React.memo(() => {
|
||||
|
||||
prefetchCustomEmojis(client);
|
||||
|
||||
if (account.is_admin && features.pleromaAdminAccounts) {
|
||||
dispatch(fetchConfig());
|
||||
}
|
||||
|
||||
if (account.locked) {
|
||||
requestIdleCallback(() => prefetchFollowRequests(client), { timeout: 2000 });
|
||||
}
|
||||
|
||||
@ -1,13 +1,12 @@
|
||||
import React, { useState, useEffect, useCallback } from 'react';
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { defineMessages, FormattedMessage, useIntl } from 'react-intl';
|
||||
|
||||
import { updateMrf } from '@/actions/mrf';
|
||||
import { getUpdatedMrf } from '@/actions/mrf';
|
||||
import List, { ListItem } from '@/components/list';
|
||||
import Modal from '@/components/ui/modal';
|
||||
import Toggle from '@/components/ui/toggle';
|
||||
import { useAppDispatch } from '@/hooks/use-app-dispatch';
|
||||
import { useAppSelector } from '@/hooks/use-app-selector';
|
||||
import { makeGetRemoteInstance } from '@/selectors';
|
||||
import { useAdminConfig, useUpdateAdminConfig } from '@/queries/admin/use-config';
|
||||
import { useRemoteInstance } from '@/selectors';
|
||||
import toast from '@/toast';
|
||||
|
||||
import type { BaseModalProps } from '@/features/ui/components/modal-root';
|
||||
@ -37,10 +36,10 @@ const EditFederationModal: React.FC<BaseModalProps & EditFederationModalProps> =
|
||||
onClose,
|
||||
}) => {
|
||||
const intl = useIntl();
|
||||
const dispatch = useAppDispatch();
|
||||
|
||||
const getRemoteInstance = useCallback(makeGetRemoteInstance(), []);
|
||||
const remoteInstance = useAppSelector((state) => getRemoteInstance(state, host));
|
||||
const { data: config } = useAdminConfig();
|
||||
const remoteInstance = useRemoteInstance(host);
|
||||
const { mutate: updateConfig } = useUpdateAdminConfig();
|
||||
|
||||
const [data, setData] = useState<Record<string, any>>({});
|
||||
|
||||
@ -68,11 +67,11 @@ const EditFederationModal: React.FC<BaseModalProps & EditFederationModalProps> =
|
||||
};
|
||||
|
||||
const handleSubmit = () => {
|
||||
dispatch(updateMrf(host, data))
|
||||
.then(() => {
|
||||
updateConfig(getUpdatedMrf(config!.configs, host, data), {
|
||||
onSuccess: () => {
|
||||
toast.success(intl.formatMessage(messages.success, { host }));
|
||||
})
|
||||
.catch(() => {});
|
||||
},
|
||||
});
|
||||
|
||||
onClose('EDIT_FEDERATION');
|
||||
};
|
||||
|
||||
@ -3,7 +3,6 @@ import React, { useState, useEffect, useMemo } from 'react';
|
||||
import { defineMessages, useIntl, FormattedMessage } from 'react-intl';
|
||||
import * as v from 'valibot';
|
||||
|
||||
import { updateFrontendConfig } from '@/actions/admin';
|
||||
import { uploadMedia } from '@/actions/media';
|
||||
import List, { ListItem } from '@/components/list';
|
||||
import Accordion from '@/components/ui/accordion';
|
||||
@ -27,6 +26,7 @@ import ThemeSelector from '@/features/ui/components/theme-selector';
|
||||
import { useAppDispatch } from '@/hooks/use-app-dispatch';
|
||||
import { useAppSelector } from '@/hooks/use-app-selector';
|
||||
import { useFeatures } from '@/hooks/use-features';
|
||||
import { getUpdateFrontendConfigParams, useUpdateAdminConfig } from '@/queries/admin/use-config';
|
||||
import {
|
||||
cryptoAddressSchema,
|
||||
footerItemSchema,
|
||||
@ -69,8 +69,9 @@ const FrontendConfigEditor: React.FC = () => {
|
||||
const features = useFeatures();
|
||||
|
||||
const initialData = useAppSelector((state) => state.frontendConfig);
|
||||
console.log(initialData);
|
||||
const { mutate: updateConfig, isPending } = useUpdateAdminConfig();
|
||||
|
||||
const [isLoading, setLoading] = useState(false);
|
||||
const [data, setData] = useState(v.parse(frontendConfigSchema, initialData));
|
||||
const [jsonEditorExpanded, setJsonEditorExpanded] = useState(false);
|
||||
const [rawJSON, setRawJSON] = useState<string>(JSON.stringify(initialData, null, 2));
|
||||
@ -89,15 +90,11 @@ const FrontendConfigEditor: React.FC = () => {
|
||||
};
|
||||
|
||||
const handleSubmit: React.SubmitEventHandler<HTMLFormElement> = (e) => {
|
||||
dispatch(updateFrontendConfig(data))
|
||||
.then(() => {
|
||||
setLoading(false);
|
||||
updateConfig(getUpdateFrontendConfigParams(data), {
|
||||
onSuccess: () => {
|
||||
toast.success(intl.formatMessage(messages.saved));
|
||||
})
|
||||
.catch(() => {
|
||||
setLoading(false);
|
||||
});
|
||||
setLoading(true);
|
||||
},
|
||||
});
|
||||
e.preventDefault();
|
||||
};
|
||||
|
||||
@ -199,7 +196,7 @@ const FrontendConfigEditor: React.FC = () => {
|
||||
return (
|
||||
<Column label={intl.formatMessage(messages.heading)}>
|
||||
<Form onSubmit={handleSubmit}>
|
||||
<fieldset className='space-y-6' disabled={isLoading}>
|
||||
<fieldset className='space-y-6' disabled={isPending}>
|
||||
<SitePreview frontendConfig={frontendConfig} />
|
||||
|
||||
<CardHeader>
|
||||
|
||||
@ -2,7 +2,6 @@ import React, { useRef, useState } from 'react';
|
||||
import { defineMessages, FormattedMessage, useIntl } from 'react-intl';
|
||||
import * as v from 'valibot';
|
||||
|
||||
import { updateFrontendConfig } from '@/actions/admin';
|
||||
import { fetchFrontendConfig } from '@/actions/frontend-config';
|
||||
import { getHost } from '@/actions/instance';
|
||||
import DropdownMenu from '@/components/dropdown-menu';
|
||||
@ -17,6 +16,7 @@ import { useAppDispatch } from '@/hooks/use-app-dispatch';
|
||||
import { useAppSelector } from '@/hooks/use-app-selector';
|
||||
import { useFrontendConfig } from '@/hooks/use-frontend-config';
|
||||
import { normalizeColors } from '@/hooks/use-theme-css';
|
||||
import { getUpdateFrontendConfigParams, useUpdateAdminConfig } from '@/queries/admin/use-config';
|
||||
import { frontendConfigSchema } from '@/schemas/frontend-config';
|
||||
import toast from '@/toast';
|
||||
import { download } from '@/utils/download';
|
||||
@ -56,6 +56,7 @@ const ThemeEditorPage: React.FC = () => {
|
||||
const frontendConfig = useFrontendConfig();
|
||||
const host = useAppSelector((state) => getHost(state));
|
||||
const rawConfig = useAppSelector((state) => state.frontendConfig);
|
||||
const { mutate: updateConfig } = useUpdateAdminConfig();
|
||||
|
||||
const [colors, setColors] = useState(normalizeColors(frontendConfig));
|
||||
const [isDefault, setIsDefault] = useState(false);
|
||||
@ -97,14 +98,14 @@ const ThemeEditorPage: React.FC = () => {
|
||||
setTheme(normalizeColors(frontendConfig));
|
||||
};
|
||||
|
||||
const updateTheme = async () => {
|
||||
const updateTheme = () => {
|
||||
let params;
|
||||
if (isDefault) {
|
||||
params = { ...rawConfig, colors: undefined, brandColor: undefined, accentColor: undefined };
|
||||
} else {
|
||||
params = { ...rawConfig, colors };
|
||||
}
|
||||
await dispatch(updateFrontendConfig(params));
|
||||
return updateConfig(getUpdateFrontendConfigParams(params));
|
||||
};
|
||||
|
||||
const restoreDefaultTheme = () => {
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import React, { useState, useCallback } from 'react';
|
||||
import React, { useState } from 'react';
|
||||
import { defineMessages, FormattedMessage, useIntl } from 'react-intl';
|
||||
|
||||
import ScrollableList from '@/components/scrollable-list';
|
||||
@ -7,7 +7,7 @@ import Column from '@/components/ui/column';
|
||||
import RestrictedInstance from '@/features/federation-restrictions/components/restricted-instance';
|
||||
import { useAppSelector } from '@/hooks/use-app-selector';
|
||||
import { useInstance } from '@/hooks/use-instance';
|
||||
import { makeGetHosts } from '@/selectors';
|
||||
import { useHosts } from '@/selectors';
|
||||
import { federationRestrictionsDisclosed } from '@/utils/state';
|
||||
|
||||
const messages = defineMessages({
|
||||
@ -27,9 +27,7 @@ const FederationRestrictionsPage = () => {
|
||||
const intl = useIntl();
|
||||
const instance = useInstance();
|
||||
|
||||
const getHosts = useCallback(makeGetHosts(), []);
|
||||
|
||||
const hosts = useAppSelector((state) => getHosts(state));
|
||||
const hosts = useHosts();
|
||||
const disclosed = useAppSelector((state) => federationRestrictionsDisclosed(state));
|
||||
|
||||
const [explanationBoxExpanded, setExplanationBoxExpanded] = useState(true);
|
||||
|
||||
57
packages/nicolium/src/queries/admin/use-config.ts
Normal file
57
packages/nicolium/src/queries/admin/use-config.ts
Normal file
@ -0,0 +1,57 @@
|
||||
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
|
||||
|
||||
import { ADMIN_CONFIG_UPDATE_SUCCESS, type AdminActions } from '@/actions/admin';
|
||||
import { useAppDispatch } from '@/hooks/use-app-dispatch';
|
||||
import { useClient } from '@/hooks/use-client';
|
||||
import { useFeatures } from '@/hooks/use-features';
|
||||
import { useOwnAccount } from '@/hooks/use-own-account';
|
||||
|
||||
import { queryKeys } from '../keys';
|
||||
|
||||
const useAdminConfig = () => {
|
||||
const client = useClient();
|
||||
const features = useFeatures();
|
||||
const { data: ownAccount } = useOwnAccount();
|
||||
|
||||
return useQuery({
|
||||
queryKey: queryKeys.admin.config,
|
||||
queryFn: () => client.admin.config.getPleromaConfig(),
|
||||
enabled: ownAccount?.is_admin && features.pleromaAdminAccounts,
|
||||
});
|
||||
};
|
||||
|
||||
const useUpdateAdminConfig = () => {
|
||||
const client = useClient();
|
||||
const dispatch = useAppDispatch();
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
return useMutation({
|
||||
mutationFn: (params: Parameters<typeof client.admin.config.updatePleromaConfig>[0]) =>
|
||||
client.admin.config.updatePleromaConfig(params),
|
||||
retry: false,
|
||||
onSuccess: (data) => {
|
||||
dispatch<AdminActions>({
|
||||
type: ADMIN_CONFIG_UPDATE_SUCCESS,
|
||||
configs: data.configs,
|
||||
needsReboot: data.need_reboot,
|
||||
});
|
||||
queryClient.setQueryData(queryKeys.admin.config, data);
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
const getUpdateFrontendConfigParams = (data: any) => {
|
||||
return [
|
||||
{
|
||||
group: ':pleroma',
|
||||
key: ':frontend_configurations',
|
||||
value: [
|
||||
{
|
||||
tuple: [':nicolium', data],
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
};
|
||||
|
||||
export { useAdminConfig, useUpdateAdminConfig, getUpdateFrontendConfigParams };
|
||||
@ -53,6 +53,7 @@ import type {
|
||||
OauthToken,
|
||||
PaginatedResponse,
|
||||
PlApiClient,
|
||||
PleromaConfig,
|
||||
Poll,
|
||||
Relationship,
|
||||
RssFeed,
|
||||
@ -304,6 +305,7 @@ const groupRelationships = {
|
||||
|
||||
const admin = {
|
||||
root: ['admin'] as const,
|
||||
config: ['admin', 'config'] as TaggedKey<['admin', 'config'], PleromaConfig>,
|
||||
accounts: {
|
||||
root: ['admin', 'accounts'] as const,
|
||||
show: (accountId: string) => {
|
||||
|
||||
@ -20,9 +20,9 @@ import { useLoggedIn } from '@/hooks/use-logged-in';
|
||||
import { appendFollowRequest } from '@/queries/accounts/use-follow-requests';
|
||||
import { queryClient } from '@/queries/client';
|
||||
import { makePaginatedResponseQueryOptions } from '@/queries/utils/make-paginated-response-query-options';
|
||||
import { regexFromFilters } from '@/selectors';
|
||||
import { useSettingsStore } from '@/stores/settings';
|
||||
import { compareId } from '@/utils/comparators';
|
||||
import { regexFromFilters } from '@/utils/filters';
|
||||
import { unescapeHTML } from '@/utils/html';
|
||||
import { EXCLUDE_TYPES, NOTIFICATION_TYPES } from '@/utils/notification';
|
||||
import { play, soundCache } from '@/utils/sounds';
|
||||
|
||||
@ -1,38 +0,0 @@
|
||||
import { create } from 'mutative';
|
||||
|
||||
import {
|
||||
ADMIN_CONFIG_FETCH_SUCCESS,
|
||||
ADMIN_CONFIG_UPDATE_SUCCESS,
|
||||
// ADMIN_USER_DELETE_SUCCESS,
|
||||
type AdminActions,
|
||||
} from '@/actions/admin';
|
||||
|
||||
import type { Config } from '@/utils/config-db';
|
||||
|
||||
interface State {
|
||||
configs: Array<Config>;
|
||||
needsReboot: boolean;
|
||||
}
|
||||
|
||||
const initialState: State = {
|
||||
configs: [],
|
||||
needsReboot: false,
|
||||
};
|
||||
|
||||
const importConfigs = (state: State, configs: Array<Config>) => {
|
||||
state.configs = configs;
|
||||
};
|
||||
|
||||
const admin = (state = initialState, action: AdminActions): State => {
|
||||
switch (action.type) {
|
||||
case ADMIN_CONFIG_FETCH_SUCCESS:
|
||||
case ADMIN_CONFIG_UPDATE_SUCCESS:
|
||||
return create(state, (draft) => {
|
||||
importConfigs(draft, action.configs);
|
||||
});
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
};
|
||||
|
||||
export { admin as default };
|
||||
@ -23,7 +23,7 @@ const fallbackState: PartialFrontendConfig = {
|
||||
const updateFromAdmin = (state: Record<string, any>, configs: PleromaConfig['configs']) => {
|
||||
try {
|
||||
return ConfigDB.find(configs, ':pleroma', ':frontend_configurations')!.value.find(
|
||||
(value: Record<string, any>) => value.tuple?.[0] === ':pl_fe',
|
||||
(value: Record<string, any>) => value.tuple?.[0] === ':nicolium',
|
||||
).tuple?.[1];
|
||||
} catch {
|
||||
return state;
|
||||
@ -77,7 +77,7 @@ const frontendConfig = (
|
||||
case FRONTEND_CONFIG_REQUEST_FAIL:
|
||||
return { ...fallbackState, ...state };
|
||||
case ADMIN_CONFIG_UPDATE_SUCCESS:
|
||||
return parseFrontendConfig(updateFromAdmin(state, action.configs ?? [])) || state;
|
||||
return parseFrontendConfig(updateFromAdmin(state, action.configs)) || state;
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
|
||||
@ -3,7 +3,6 @@ import { combineReducers } from '@reduxjs/toolkit';
|
||||
import { AUTH_LOGGED_OUT } from '@/actions/auth';
|
||||
import * as BuildConfig from '@/build-config';
|
||||
|
||||
import admin from './admin';
|
||||
import auth from './auth';
|
||||
import frontendConfig from './frontend-config';
|
||||
import instance from './instance';
|
||||
@ -12,7 +11,6 @@ import meta from './meta';
|
||||
import pushNotifications from './push-notifications';
|
||||
|
||||
const reducers = {
|
||||
admin,
|
||||
auth,
|
||||
frontendConfig,
|
||||
instance,
|
||||
|
||||
@ -2,11 +2,7 @@ import { create } from 'mutative';
|
||||
import { type Instance, instanceSchema, type PleromaConfig } from 'pl-api';
|
||||
import * as v from 'valibot';
|
||||
|
||||
import {
|
||||
ADMIN_CONFIG_UPDATE_REQUEST,
|
||||
ADMIN_CONFIG_UPDATE_SUCCESS,
|
||||
type AdminActions,
|
||||
} from '@/actions/admin';
|
||||
import { ADMIN_CONFIG_UPDATE_SUCCESS, type AdminActions } from '@/actions/admin';
|
||||
import {
|
||||
INSTANCE_FETCH_FAIL,
|
||||
INSTANCE_FETCH_SUCCESS,
|
||||
@ -105,7 +101,6 @@ const instance = (
|
||||
return { fetched: true, ...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:
|
||||
|
||||
@ -1,35 +1,36 @@
|
||||
import { createSelector } from 'reselect';
|
||||
import { useQueryClient } from '@tanstack/react-query';
|
||||
|
||||
import { getAccounts } from '@/queries/accounts/selectors';
|
||||
import { useInstance } from '@/hooks/use-instance';
|
||||
import { useAdminConfig } from '@/queries/admin/use-config';
|
||||
import { queryKeys } from '@/queries/keys';
|
||||
import { getDomain } from '@/utils/accounts';
|
||||
import ConfigDB from '@/utils/config-db';
|
||||
import { regexFromFilters } from '@/utils/filters';
|
||||
|
||||
import type { MRFSimple } from '@/schemas/pleroma';
|
||||
import type { RootState } from '@/store';
|
||||
|
||||
const getSimplePolicy = createSelector(
|
||||
[
|
||||
(state: RootState) => state.admin.configs,
|
||||
(state: RootState) => state.instance.pleroma.metadata.federation.mrf_simple_info,
|
||||
],
|
||||
(configs, instancePolicy): MRFSimple => ({
|
||||
...instancePolicy,
|
||||
...ConfigDB.toSimplePolicy(configs),
|
||||
}),
|
||||
);
|
||||
|
||||
const getRemoteInstanceFavicon = (_state: RootState, host: string) => {
|
||||
const account = getAccounts().find((item) => item && getDomain(item) === host);
|
||||
return account?.favicon ?? null;
|
||||
};
|
||||
import type { Account } from 'pl-api';
|
||||
|
||||
type HostFederation = {
|
||||
[key in keyof MRFSimple]: boolean;
|
||||
};
|
||||
|
||||
const getRemoteInstanceFederation = (state: RootState, host: string): HostFederation => {
|
||||
const simplePolicy = getSimplePolicy(state);
|
||||
interface RemoteInstance {
|
||||
host: string;
|
||||
favicon: string | null;
|
||||
federation: HostFederation;
|
||||
}
|
||||
|
||||
const useSimplePolicy = () => {
|
||||
const { data: config } = useAdminConfig();
|
||||
const simplePolicy = useInstance().pleroma.metadata.federation.mrf_simple_info;
|
||||
|
||||
return {
|
||||
...simplePolicy,
|
||||
...ConfigDB.toSimplePolicy(config?.configs || []),
|
||||
};
|
||||
};
|
||||
|
||||
const useRemoteInstanceFederation = (host: string) => {
|
||||
const simplePolicy = useSimplePolicy();
|
||||
|
||||
return Object.fromEntries(
|
||||
Object.entries(simplePolicy).map(([key, hosts]) => [
|
||||
@ -39,33 +40,37 @@ const getRemoteInstanceFederation = (state: RootState, host: string): HostFedera
|
||||
) as HostFederation;
|
||||
};
|
||||
|
||||
const makeGetHosts = () =>
|
||||
createSelector([getSimplePolicy], (simplePolicy) => {
|
||||
const { accept, reject_deletes, report_removal, ...rest } = simplePolicy;
|
||||
const useRemoteInstanceFavicon = (host: string) => {
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
return [
|
||||
...new Set(Object.values(rest).reduce((acc, hosts) => (acc.push(...hosts), acc), [])),
|
||||
].toSorted();
|
||||
});
|
||||
|
||||
interface RemoteInstance {
|
||||
host: string;
|
||||
favicon: string | null;
|
||||
federation: HostFederation;
|
||||
}
|
||||
|
||||
const makeGetRemoteInstance = () =>
|
||||
createSelector(
|
||||
[
|
||||
(_state: RootState, host: string) => host,
|
||||
getRemoteInstanceFavicon,
|
||||
getRemoteInstanceFederation,
|
||||
],
|
||||
(host, favicon, federation): RemoteInstance => ({
|
||||
host,
|
||||
favicon,
|
||||
federation,
|
||||
}),
|
||||
return (
|
||||
queryClient
|
||||
.getQueriesData<Account>({ queryKey: queryKeys.accounts.root })
|
||||
.map(([, account]) => account)
|
||||
.find(
|
||||
(account): account is Account =>
|
||||
typeof account?.id === 'string' && getDomain(account) === host,
|
||||
)?.favicon ?? null
|
||||
);
|
||||
};
|
||||
|
||||
export { type RemoteInstance, regexFromFilters, makeGetHosts, makeGetRemoteInstance };
|
||||
const useRemoteInstance = (host: string) => {
|
||||
const federation = useRemoteInstanceFederation(host);
|
||||
const favicon = useRemoteInstanceFavicon(host);
|
||||
|
||||
return {
|
||||
host,
|
||||
favicon,
|
||||
federation,
|
||||
};
|
||||
};
|
||||
|
||||
const useHosts = () => {
|
||||
const simplePolicy = useSimplePolicy();
|
||||
|
||||
return [
|
||||
...new Set(Object.values(simplePolicy).reduce((acc, hosts) => (acc.push(...hosts), acc), [])),
|
||||
].toSorted();
|
||||
};
|
||||
|
||||
export { type RemoteInstance, useHosts, useRemoteInstance };
|
||||
|
||||
Reference in New Issue
Block a user