Merge remote-tracking branch 'origin/main' into no-untranslated-jsx
This commit is contained in:
commit
fb5003682f
|
@ -133,7 +133,7 @@
|
||||||
"no-irregular-whitespace": "error",
|
"no-irregular-whitespace": "error",
|
||||||
"no-loop-func": "error",
|
"no-loop-func": "error",
|
||||||
"no-mixed-spaces-and-tabs": "error",
|
"no-mixed-spaces-and-tabs": "error",
|
||||||
"no-nested-ternary": "warn",
|
"no-nested-ternary": "error",
|
||||||
"no-restricted-imports": [
|
"no-restricted-imports": [
|
||||||
"error",
|
"error",
|
||||||
{
|
{
|
||||||
|
|
|
@ -27,10 +27,10 @@ function logInNostr(pubkey: string) {
|
||||||
secret,
|
secret,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
dispatch(setNostrPubkey(undefined));
|
|
||||||
|
|
||||||
const { access_token } = dispatch(authLoggedIn(token));
|
const { access_token } = dispatch(authLoggedIn(token));
|
||||||
return await dispatch(verifyCredentials(access_token as string));
|
await dispatch(verifyCredentials(access_token as string));
|
||||||
|
|
||||||
|
dispatch(setNostrPubkey(undefined));
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -241,7 +241,8 @@ const saveSettings = (opts?: SettingOpts) =>
|
||||||
const getLocale = (state: RootState, fallback = 'en') => {
|
const getLocale = (state: RootState, fallback = 'en') => {
|
||||||
const localeWithVariant = (getSettings(state).get('locale') as string).replace('_', '-');
|
const localeWithVariant = (getSettings(state).get('locale') as string).replace('_', '-');
|
||||||
const locale = localeWithVariant.split('-')[0];
|
const locale = localeWithVariant.split('-')[0];
|
||||||
return Object.keys(messages).includes(localeWithVariant) ? localeWithVariant : Object.keys(messages).includes(locale) ? locale : fallback;
|
const fallbackLocale = Object.keys(messages).includes(locale) ? locale : fallback;
|
||||||
|
return Object.keys(messages).includes(localeWithVariant) ? localeWithVariant : fallbackLocale;
|
||||||
};
|
};
|
||||||
|
|
||||||
type SettingsAction =
|
type SettingsAction =
|
||||||
|
|
|
@ -2,7 +2,7 @@ import { NRelay, NRelay1, NostrSigner } from '@nostrify/nostrify';
|
||||||
import React, { createContext, useContext, useState, useEffect, useMemo } from 'react';
|
import React, { createContext, useContext, useState, useEffect, useMemo } from 'react';
|
||||||
|
|
||||||
import { NKeys } from 'soapbox/features/nostr/keys';
|
import { NKeys } from 'soapbox/features/nostr/keys';
|
||||||
import { useAppSelector, useOwnAccount } from 'soapbox/hooks';
|
import { useAppSelector } from 'soapbox/hooks';
|
||||||
import { useInstance } from 'soapbox/hooks/useInstance';
|
import { useInstance } from 'soapbox/hooks/useInstance';
|
||||||
|
|
||||||
interface NostrContextType {
|
interface NostrContextType {
|
||||||
|
@ -25,13 +25,11 @@ export const NostrProvider: React.FC<NostrProviderProps> = ({ children }) => {
|
||||||
const [relay, setRelay] = useState<NRelay1>();
|
const [relay, setRelay] = useState<NRelay1>();
|
||||||
const [isRelayOpen, setIsRelayOpen] = useState(false);
|
const [isRelayOpen, setIsRelayOpen] = useState(false);
|
||||||
|
|
||||||
const { account } = useOwnAccount();
|
|
||||||
|
|
||||||
const url = instance.nostr?.relay;
|
const url = instance.nostr?.relay;
|
||||||
const accountPubkey = useAppSelector((state) => state.meta.pubkey ?? account?.nostr.pubkey);
|
const accountPubkey = useAppSelector(({ meta, auth }) => meta.pubkey ?? auth.users.get(auth.me!)?.id);
|
||||||
|
|
||||||
const signer = useMemo(
|
const signer = useMemo(
|
||||||
() => (accountPubkey ? NKeys.get(accountPubkey) : undefined) ?? window.nostr,
|
() => accountPubkey ? NKeys.get(accountPubkey) ?? window.nostr : undefined,
|
||||||
[accountPubkey, window.nostr],
|
[accountPubkey, window.nostr],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -51,7 +51,9 @@ const Domain: React.FC<IDomain> = ({ domain }) => {
|
||||||
}));
|
}));
|
||||||
};
|
};
|
||||||
|
|
||||||
const domainState = domain.last_checked_at ? (domain.resolves ? 'active' : 'error') : 'pending';
|
const resolveState = domain.resolves ? 'active' : 'error';
|
||||||
|
const domainState = domain.last_checked_at ? resolveState : 'pending';
|
||||||
|
|
||||||
const domainStateLabel = {
|
const domainStateLabel = {
|
||||||
active: <FormattedMessage id='admin.domains.resolve.success_label' defaultMessage='Resolves correctly' />,
|
active: <FormattedMessage id='admin.domains.resolve.success_label' defaultMessage='Resolves correctly' />,
|
||||||
error: <FormattedMessage id='admin.domains.resolve.fail_label' defaultMessage='Not resolving' />,
|
error: <FormattedMessage id='admin.domains.resolve.fail_label' defaultMessage='Not resolving' />,
|
||||||
|
|
|
@ -141,13 +141,19 @@ const RegistrationForm: React.FC<IRegistrationForm> = ({ inviteToken }) => {
|
||||||
/></p>}
|
/></p>}
|
||||||
</>);
|
</>);
|
||||||
|
|
||||||
|
const confirmationHeading = needsConfirmation
|
||||||
|
? intl.formatMessage(messages.needsConfirmationHeader)
|
||||||
|
: undefined;
|
||||||
|
|
||||||
|
const approvalHeading = needsApproval
|
||||||
|
? intl.formatMessage(messages.needsApprovalHeader)
|
||||||
|
: undefined;
|
||||||
|
|
||||||
|
const heading = confirmationHeading || approvalHeading;
|
||||||
|
|
||||||
dispatch(openModal('CONFIRM', {
|
dispatch(openModal('CONFIRM', {
|
||||||
icon: require('@tabler/icons/outline/check.svg'),
|
icon: require('@tabler/icons/outline/check.svg'),
|
||||||
heading: needsConfirmation
|
heading: heading,
|
||||||
? intl.formatMessage(messages.needsConfirmationHeader)
|
|
||||||
: needsApproval
|
|
||||||
? intl.formatMessage(messages.needsApprovalHeader)
|
|
||||||
: undefined,
|
|
||||||
message,
|
message,
|
||||||
confirm: intl.formatMessage(messages.close),
|
confirm: intl.formatMessage(messages.close),
|
||||||
}));
|
}));
|
||||||
|
|
|
@ -88,12 +88,14 @@ const Backups = () => {
|
||||||
</Card>
|
</Card>
|
||||||
);
|
);
|
||||||
|
|
||||||
const body = showLoading ? <Spinner /> : backups.isEmpty() ? emptyMessage : (
|
const backupsContent = backups.isEmpty() ? emptyMessage : (
|
||||||
<div className='mb-4 grid grid-cols-1 gap-4 sm:grid-cols-2'>
|
<div className='mb-4 grid grid-cols-1 gap-4 sm:grid-cols-2'>
|
||||||
{backups.map((backup) => <Backup key={backup.id} backup={backup} />)}
|
{backups.map((backup) => <Backup key={backup.id} backup={backup} />)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const body = showLoading ? <Spinner /> : backupsContent;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Column label={intl.formatMessage(messages.heading)}>
|
<Column label={intl.formatMessage(messages.heading)}>
|
||||||
{body}
|
{body}
|
||||||
|
|
|
@ -70,7 +70,17 @@ const Filters = () => {
|
||||||
emptyMessage={emptyMessage}
|
emptyMessage={emptyMessage}
|
||||||
itemClassName='pb-4 last:pb-0'
|
itemClassName='pb-4 last:pb-0'
|
||||||
>
|
>
|
||||||
{filters.map((filter) => (
|
{filters.map((filter) => {
|
||||||
|
|
||||||
|
const truthMessageFilter = filter.filter_action === 'hide' ?
|
||||||
|
<FormattedMessage id='filters.filters_list_hide_completely' defaultMessage='Hide content' /> :
|
||||||
|
<FormattedMessage id='filters.filters_list_warn' defaultMessage='Display warning' />;
|
||||||
|
|
||||||
|
const falseMessageFilter = (filter.filter_action === 'hide' ?
|
||||||
|
<FormattedMessage id='filters.filters_list_drop' defaultMessage='Drop' /> :
|
||||||
|
<FormattedMessage id='filters.filters_list_hide' defaultMessage='Hide' />);
|
||||||
|
|
||||||
|
return (
|
||||||
<div key={filter.id} className='rounded-lg bg-gray-100 p-4 dark:bg-primary-800'>
|
<div key={filter.id} className='rounded-lg bg-gray-100 p-4 dark:bg-primary-800'>
|
||||||
<Stack space={2}>
|
<Stack space={2}>
|
||||||
<Stack className='grow' space={1}>
|
<Stack className='grow' space={1}>
|
||||||
|
@ -86,13 +96,7 @@ const Filters = () => {
|
||||||
</Text>
|
</Text>
|
||||||
<HStack space={4} wrap>
|
<HStack space={4} wrap>
|
||||||
<Text weight='medium'>
|
<Text weight='medium'>
|
||||||
{filtersV2 ? (
|
{filtersV2 ? truthMessageFilter : falseMessageFilter}
|
||||||
filter.filter_action === 'hide' ?
|
|
||||||
<FormattedMessage id='filters.filters_list_hide_completely' defaultMessage='Hide content' /> :
|
|
||||||
<FormattedMessage id='filters.filters_list_warn' defaultMessage='Display warning' />
|
|
||||||
) : (filter.filter_action === 'hide' ?
|
|
||||||
<FormattedMessage id='filters.filters_list_drop' defaultMessage='Drop' /> :
|
|
||||||
<FormattedMessage id='filters.filters_list_hide' defaultMessage='Hide' />)}
|
|
||||||
</Text>
|
</Text>
|
||||||
{filter.expires_at && (
|
{filter.expires_at && (
|
||||||
<Text weight='medium'>
|
<Text weight='medium'>
|
||||||
|
@ -113,7 +117,9 @@ const Filters = () => {
|
||||||
</HStack>
|
</HStack>
|
||||||
</Stack>
|
</Stack>
|
||||||
</div>
|
</div>
|
||||||
))}
|
);
|
||||||
|
},
|
||||||
|
)}
|
||||||
</ScrollableList>
|
</ScrollableList>
|
||||||
</Column>
|
</Column>
|
||||||
);
|
);
|
||||||
|
|
|
@ -121,7 +121,7 @@ const AccountModerationModal: React.FC<IAccountModerationModal> = ({ onClose, ac
|
||||||
</OutlineBox>
|
</OutlineBox>
|
||||||
|
|
||||||
<List>
|
<List>
|
||||||
{(ownAccount.admin && account.local) && (
|
{(ownAccount.admin && (account.local || features.nostr)) && (
|
||||||
<ListItem label={<FormattedMessage id='account_moderation_modal.fields.account_role' defaultMessage='Staff level' />}>
|
<ListItem label={<FormattedMessage id='account_moderation_modal.fields.account_role' defaultMessage='Staff level' />}>
|
||||||
<div className='w-auto'>
|
<div className='w-auto'>
|
||||||
<StaffRolePicker account={account} />
|
<StaffRolePicker account={account} />
|
||||||
|
|
|
@ -22,6 +22,8 @@ const CaptchaModal: React.FC<ICaptchaModal> = ({ onClose }) => {
|
||||||
xPosition,
|
xPosition,
|
||||||
} = useCaptcha();
|
} = useCaptcha();
|
||||||
|
|
||||||
|
const messageButton = tryAgain ? <FormattedMessage id='nostr_signup.captcha_try_again_button' defaultMessage='Try again' /> : <FormattedMessage id='nostr_signup.captcha_check_button' defaultMessage='Check' />;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Modal
|
<Modal
|
||||||
title={<FormattedMessage id='nostr_signup.captcha_title' defaultMessage='Human Verification' />} width='sm'
|
title={<FormattedMessage id='nostr_signup.captcha_title' defaultMessage='Human Verification' />} width='sm'
|
||||||
|
@ -46,10 +48,7 @@ const CaptchaModal: React.FC<ICaptchaModal> = ({ onClose }) => {
|
||||||
>
|
>
|
||||||
{isSubmitting ? (
|
{isSubmitting ? (
|
||||||
<FormattedMessage id='nostr_signup.captcha_check_button.checking' defaultMessage='Checking…' />
|
<FormattedMessage id='nostr_signup.captcha_check_button.checking' defaultMessage='Checking…' />
|
||||||
) : (tryAgain ?
|
) : messageButton}
|
||||||
<FormattedMessage id='nostr_signup.captcha_try_again_button' defaultMessage='Try again' /> :
|
|
||||||
<FormattedMessage id='nostr_signup.captcha_check_button' defaultMessage='Check' />
|
|
||||||
)}
|
|
||||||
</Button>
|
</Button>
|
||||||
<Button onClick={loadCaptcha}>
|
<Button onClick={loadCaptcha}>
|
||||||
<FormattedMessage id='nostr_signup.captcha_reset_button' defaultMessage='Reset puzzle' />
|
<FormattedMessage id='nostr_signup.captcha_reset_button' defaultMessage='Reset puzzle' />
|
||||||
|
|
|
@ -44,9 +44,11 @@ const SoapboxLoad: React.FC<ISoapboxLoad> = ({ children }) => {
|
||||||
const [localeLoading, setLocaleLoading] = useState(true);
|
const [localeLoading, setLocaleLoading] = useState(true);
|
||||||
const [isLoaded, setIsLoaded] = useState(false);
|
const [isLoaded, setIsLoaded] = useState(false);
|
||||||
|
|
||||||
const { hasNostr, isRelayOpen } = useNostr();
|
const { hasNostr, isRelayOpen, signer } = useNostr();
|
||||||
const { isSubscribed } = useSignerStream();
|
const { isSubscribed } = useSignerStream();
|
||||||
|
|
||||||
|
const nostrLoading = Boolean(hasNostr && signer && (!isRelayOpen || !isSubscribed));
|
||||||
|
|
||||||
/** Whether to display a loading indicator. */
|
/** Whether to display a loading indicator. */
|
||||||
const showLoading = [
|
const showLoading = [
|
||||||
me === null,
|
me === null,
|
||||||
|
@ -55,7 +57,7 @@ const SoapboxLoad: React.FC<ISoapboxLoad> = ({ children }) => {
|
||||||
localeLoading,
|
localeLoading,
|
||||||
instance.isLoading,
|
instance.isLoading,
|
||||||
swUpdating,
|
swUpdating,
|
||||||
hasNostr && me && (!isRelayOpen || !isSubscribed),
|
nostrLoading,
|
||||||
].some(Boolean);
|
].some(Boolean);
|
||||||
|
|
||||||
// Load the user's locale
|
// Load the user's locale
|
||||||
|
@ -68,14 +70,14 @@ const SoapboxLoad: React.FC<ISoapboxLoad> = ({ children }) => {
|
||||||
|
|
||||||
// Load initial data from the API
|
// Load initial data from the API
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!instance.isLoading) {
|
if (!instance.isLoading && !nostrLoading) {
|
||||||
dispatch(loadInitial()).then(() => {
|
dispatch(loadInitial()).then(() => {
|
||||||
setIsLoaded(true);
|
setIsLoaded(true);
|
||||||
}).catch(() => {
|
}).catch(() => {
|
||||||
setIsLoaded(true);
|
setIsLoaded(true);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}, [instance.isLoading]);
|
}, [instance.isLoading, nostrLoading]);
|
||||||
|
|
||||||
// intl is part of loading.
|
// intl is part of loading.
|
||||||
// It's important nothing in here depends on intl.
|
// It's important nothing in here depends on intl.
|
||||||
|
|
|
@ -33,12 +33,18 @@ export const AdminAccountRecord = ImmutableRecord({
|
||||||
|
|
||||||
const normalizePleromaAccount = (account: ImmutableMap<string, any>) => {
|
const normalizePleromaAccount = (account: ImmutableMap<string, any>) => {
|
||||||
if (!account.get('account')) {
|
if (!account.get('account')) {
|
||||||
|
|
||||||
|
const isAdmin = account.getIn(['roles', 'admin']);
|
||||||
|
const isModerator = account.getIn(['roles', 'moderator']) ? 'moderator' : null;
|
||||||
|
|
||||||
|
const accountRole = isAdmin ? 'admin' : isModerator;
|
||||||
|
|
||||||
return account.withMutations(account => {
|
return account.withMutations(account => {
|
||||||
account.set('approved', account.get('is_approved'));
|
account.set('approved', account.get('is_approved'));
|
||||||
account.set('confirmed', account.get('is_confirmed'));
|
account.set('confirmed', account.get('is_confirmed'));
|
||||||
account.set('disabled', !account.get('is_active'));
|
account.set('disabled', !account.get('is_active'));
|
||||||
account.set('invite_request', account.get('registration_reason'));
|
account.set('invite_request', account.get('registration_reason'));
|
||||||
account.set('role', account.getIn(['roles', 'admin']) ? 'admin' : (account.getIn(['roles', 'moderator']) ? 'moderator' : null));
|
account.set('role', accountRole);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue