Merge remote-tracking branch 'soapbox/develop' into translations

Signed-off-by: marcin mikołajczak <git@mkljczk.pl>
environments/review-translatio-h7npbq/deployments/1298
marcin mikołajczak 2022-11-05 17:37:36 +01:00
commit 1526ccaa2e
9 zmienionych plików z 68 dodań i 21 usunięć

Wyświetl plik

@ -11,7 +11,7 @@ import { getFilters, regexFromFilters } from 'soapbox/selectors';
import { isLoggedIn } from 'soapbox/utils/auth'; import { isLoggedIn } from 'soapbox/utils/auth';
import { getFeatures, parseVersion, PLEROMA } from 'soapbox/utils/features'; import { getFeatures, parseVersion, PLEROMA } from 'soapbox/utils/features';
import { unescapeHTML } from 'soapbox/utils/html'; import { unescapeHTML } from 'soapbox/utils/html';
import { NOTIFICATION_TYPES } from 'soapbox/utils/notification'; import { EXCLUDE_TYPES, NOTIFICATION_TYPES } from 'soapbox/utils/notification';
import { joinPublicPath } from 'soapbox/utils/static'; import { joinPublicPath } from 'soapbox/utils/static';
import { fetchRelationships } from './accounts'; import { fetchRelationships } from './accounts';
@ -195,7 +195,9 @@ const expandNotifications = ({ maxId }: Record<string, any> = {}, done: () => an
if (activeFilter === 'all') { if (activeFilter === 'all') {
if (features.notificationsIncludeTypes) { if (features.notificationsIncludeTypes) {
params.types = NOTIFICATION_TYPES; params.types = NOTIFICATION_TYPES.filter(type => !EXCLUDE_TYPES.includes(type as any));
} else {
params.exclude_types = EXCLUDE_TYPES;
} }
} else { } else {
if (features.notificationsIncludeTypes) { if (features.notificationsIncludeTypes) {

Wyświetl plik

@ -40,6 +40,8 @@ interface IHStack {
space?: keyof typeof spaces space?: keyof typeof spaces
/** Whether to let the flexbox grow. */ /** Whether to let the flexbox grow. */
grow?: boolean grow?: boolean
/** HTML element to use for container. */
element?: keyof JSX.IntrinsicElements,
/** Extra CSS styles for the <div> */ /** Extra CSS styles for the <div> */
style?: React.CSSProperties style?: React.CSSProperties
/** Whether to let the flexbox wrap onto multiple lines. */ /** Whether to let the flexbox wrap onto multiple lines. */
@ -48,10 +50,12 @@ interface IHStack {
/** Horizontal row of child elements. */ /** Horizontal row of child elements. */
const HStack = forwardRef<HTMLDivElement, IHStack>((props, ref) => { const HStack = forwardRef<HTMLDivElement, IHStack>((props, ref) => {
const { space, alignItems, grow, justifyContent, wrap, className, ...filteredProps } = props; const { space, alignItems, justifyContent, className, grow, element = 'div', wrap, ...filteredProps } = props;
const Elem = element as 'div';
return ( return (
<div <Elem
{...filteredProps} {...filteredProps}
ref={ref} ref={ref}
className={classNames('flex', { className={classNames('flex', {

Wyświetl plik

@ -26,24 +26,28 @@ const alignItemsOptions = {
}; };
interface IStack extends React.HTMLAttributes<HTMLDivElement> { interface IStack extends React.HTMLAttributes<HTMLDivElement> {
/** Size of the gap between elements. */
space?: keyof typeof spaces
/** Horizontal alignment of children. */ /** Horizontal alignment of children. */
alignItems?: keyof typeof alignItemsOptions alignItems?: keyof typeof alignItemsOptions
/** Extra class names on the element. */
className?: string
/** Vertical alignment of children. */ /** Vertical alignment of children. */
justifyContent?: keyof typeof justifyContentOptions justifyContent?: keyof typeof justifyContentOptions
/** Extra class names on the <div> element. */ /** Size of the gap between elements. */
className?: string space?: keyof typeof spaces
/** Whether to let the flexbox grow. */ /** Whether to let the flexbox grow. */
grow?: boolean grow?: boolean
/** HTML element to use for container. */
element?: keyof JSX.IntrinsicElements,
} }
/** Vertical stack of child elements. */ /** Vertical stack of child elements. */
const Stack = React.forwardRef<HTMLDivElement, IStack>((props, ref: React.LegacyRef<HTMLDivElement> | undefined) => { const Stack = React.forwardRef<HTMLDivElement, IStack>((props, ref: React.LegacyRef<HTMLDivElement> | undefined) => {
const { space, alignItems, justifyContent, className, grow, ...filteredProps } = props; const { space, alignItems, justifyContent, className, grow, element = 'div', ...filteredProps } = props;
const Elem = element as 'div';
return ( return (
<div <Elem
{...filteredProps} {...filteredProps}
ref={ref} ref={ref}
className={classNames('flex flex-col', { className={classNames('flex flex-col', {

Wyświetl plik

@ -1,26 +1,45 @@
import React, { useEffect } from 'react'; import React, { useEffect } from 'react';
import { defineMessages, FormattedDate, useIntl } from 'react-intl'; import { defineMessages, FormattedDate, useIntl } from 'react-intl';
import { openModal } from 'soapbox/actions/modals';
import { fetchOAuthTokens, revokeOAuthTokenById } from 'soapbox/actions/security'; import { fetchOAuthTokens, revokeOAuthTokenById } from 'soapbox/actions/security';
import { Button, Card, CardBody, CardHeader, CardTitle, Column, Spinner, Stack, Text } from 'soapbox/components/ui'; import { Button, Card, CardBody, CardHeader, CardTitle, Column, Spinner, Stack, Text } from 'soapbox/components/ui';
import { useAppDispatch, useAppSelector } from 'soapbox/hooks'; import { useAppDispatch, useAppSelector } from 'soapbox/hooks';
import { Token } from 'soapbox/reducers/security'; import { Token } from 'soapbox/reducers/security';
import type { Map as ImmutableMap } from 'immutable';
const messages = defineMessages({ const messages = defineMessages({
header: { id: 'security.headers.tokens', defaultMessage: 'Sessions' }, header: { id: 'security.headers.tokens', defaultMessage: 'Sessions' },
revoke: { id: 'security.tokens.revoke', defaultMessage: 'Revoke' }, revoke: { id: 'security.tokens.revoke', defaultMessage: 'Revoke' },
revokeSessionHeading: { id: 'confirmations.revoke_session.heading', defaultMessage: 'Revoke current session' },
revokeSessionMessage: { id: 'confirmations.revoke_session.message', defaultMessage: 'You are about to revoke your current session. You will be signed out.' },
revokeSessionConfirm: { id: 'confirmations.revoke_session.confirm', defaultMessage: 'Revoke' },
}); });
interface IAuthToken { interface IAuthToken {
token: Token, token: Token,
isCurrent: boolean,
} }
const AuthToken: React.FC<IAuthToken> = ({ token }) => { const AuthToken: React.FC<IAuthToken> = ({ token, isCurrent }) => {
const dispatch = useAppDispatch(); const dispatch = useAppDispatch();
const intl = useIntl(); const intl = useIntl();
const handleRevoke = () => { const handleRevoke = () => {
dispatch(revokeOAuthTokenById(token.id)); if (isCurrent)
dispatch(openModal('CONFIRM', {
icon: require('@tabler/icons/alert-triangle.svg'),
heading: intl.formatMessage(messages.revokeSessionHeading),
message: intl.formatMessage(messages.revokeSessionMessage),
confirm: intl.formatMessage(messages.revokeSessionConfirm),
onConfirm: () => {
dispatch(revokeOAuthTokenById(token.id));
},
}));
else {
dispatch(revokeOAuthTokenById(token.id));
}
}; };
return ( return (
@ -42,7 +61,7 @@ const AuthToken: React.FC<IAuthToken> = ({ token }) => {
</Stack> </Stack>
<div className='flex justify-end'> <div className='flex justify-end'>
<Button theme='primary' onClick={handleRevoke}> <Button theme={isCurrent ? 'danger' : 'primary'} onClick={handleRevoke}>
{intl.formatMessage(messages.revoke)} {intl.formatMessage(messages.revoke)}
</Button> </Button>
</div> </div>
@ -55,6 +74,11 @@ const AuthTokenList: React.FC = () => {
const dispatch = useAppDispatch(); const dispatch = useAppDispatch();
const intl = useIntl(); const intl = useIntl();
const tokens = useAppSelector(state => state.security.get('tokens').reverse()); const tokens = useAppSelector(state => state.security.get('tokens').reverse());
const currentTokenId = useAppSelector(state => {
const currentToken = state.auth.get('tokens').valueSeq().find((token: ImmutableMap<string, any>) => token.get('me') === state.auth.get('me'));
return currentToken?.get('id');
});
useEffect(() => { useEffect(() => {
dispatch(fetchOAuthTokens()); dispatch(fetchOAuthTokens());
@ -63,7 +87,7 @@ const AuthTokenList: React.FC = () => {
const body = tokens ? ( const body = tokens ? (
<div className='grid grid-cols-1 sm:grid-cols-2 gap-4'> <div className='grid grid-cols-1 sm:grid-cols-2 gap-4'>
{tokens.map((token) => ( {tokens.map((token) => (
<AuthToken key={token.id} token={token} /> <AuthToken key={token.id} token={token} isCurrent={token.id === currentTokenId} />
))} ))}
</div> </div>
) : <Spinner />; ) : <Spinner />;

Wyświetl plik

@ -132,7 +132,7 @@ const ComposeForm = <ID extends string>({ id, shouldCondense, autoFocus, clickab
setComposeFocused(true); setComposeFocused(true);
}; };
const handleSubmit = () => { const handleSubmit = (e?: React.FormEvent<Element>) => {
if (text !== autosuggestTextareaRef.current?.textarea?.value) { if (text !== autosuggestTextareaRef.current?.textarea?.value) {
// Something changed the text inside the textarea (e.g. browser extensions like Grammarly) // Something changed the text inside the textarea (e.g. browser extensions like Grammarly)
// Update the state to match the current text // Update the state to match the current text
@ -142,6 +142,10 @@ const ComposeForm = <ID extends string>({ id, shouldCondense, autoFocus, clickab
// Submit disabled: // Submit disabled:
const fulltext = [spoilerText, countableText(text)].join(''); const fulltext = [spoilerText, countableText(text)].join('');
if (e) {
e.preventDefault();
}
if (isSubmitting || isUploading || isChangingUpload || length(fulltext) > maxTootChars || (fulltext.length !== 0 && fulltext.trim().length === 0 && !anyMedia)) { if (isSubmitting || isUploading || isChangingUpload || length(fulltext) > maxTootChars || (fulltext.length !== 0 && fulltext.trim().length === 0 && !anyMedia)) {
return; return;
} }
@ -261,7 +265,7 @@ const ComposeForm = <ID extends string>({ id, shouldCondense, autoFocus, clickab
} }
return ( return (
<Stack className='w-full' space={4} ref={formRef} onClick={handleClick}> <Stack className='w-full' space={4} ref={formRef} onClick={handleClick} element='form' onSubmit={handleSubmit}>
{scheduledStatusCount > 0 && ( {scheduledStatusCount > 0 && (
<Warning <Warning
message={( message={(
@ -339,7 +343,7 @@ const ComposeForm = <ID extends string>({ id, shouldCondense, autoFocus, clickab
</div> </div>
)} )}
<Button theme='primary' text={publishText} onClick={handleSubmit} disabled={disabledButton} /> <Button type='submit' theme='primary' text={publishText} disabled={disabledButton} />
</div> </div>
</div> </div>
</Stack> </Stack>

Wyświetl plik

@ -168,7 +168,7 @@ const PollForm: React.FC<IPollForm> = ({ composeId }) => {
<Divider /> <Divider />
<button onClick={handleToggleMultiple} className='text-left'> <button type='button' onClick={handleToggleMultiple} className='text-left'>
<HStack alignItems='center' justifyContent='between'> <HStack alignItems='center' justifyContent='between'>
<Stack> <Stack>
<Text weight='medium'> <Text weight='medium'>
@ -197,7 +197,7 @@ const PollForm: React.FC<IPollForm> = ({ composeId }) => {
{/* Remove Poll */} {/* Remove Poll */}
<div className='text-center'> <div className='text-center'>
<button className='text-danger-500' onClick={onRemovePoll}> <button type='button' className='text-danger-500' onClick={onRemovePoll}>
{intl.formatMessage(messages.removePoll)} {intl.formatMessage(messages.removePoll)}
</button> </button>
</div> </div>

Wyświetl plik

@ -68,7 +68,7 @@ const SpoilerInput = React.forwardRef<AutosuggestInput, ISpoilerInput>(({
/> />
<div className='text-center'> <div className='text-center'>
<button className='text-danger-500' onClick={handleRemove}> <button type='button' className='text-danger-500' onClick={handleRemove}>
{intl.formatMessage(messages.remove)} {intl.formatMessage(messages.remove)}
</button> </button>
</div> </div>
@ -77,4 +77,4 @@ const SpoilerInput = React.forwardRef<AutosuggestInput, ISpoilerInput>(({
); );
}); });
export default SpoilerInput; export default SpoilerInput;

Wyświetl plik

@ -39,6 +39,8 @@ const ProfileDropdown: React.FC<IProfileDropdown> = ({ account, children }) => {
const features = useFeatures(); const features = useFeatures();
const intl = useIntl(); const intl = useIntl();
useAppSelector((state) => console.log(state.auth.toJS()));
const authUsers = useAppSelector((state) => state.auth.get('users')); const authUsers = useAppSelector((state) => state.auth.get('users'));
const otherAccounts = useAppSelector((state) => authUsers.map((authUser: any) => getAccount(state, authUser.get('id')))); const otherAccounts = useAppSelector((state) => authUsers.map((authUser: any) => getAccount(state, authUser.get('id'))));

Wyświetl plik

@ -14,6 +14,12 @@ const NOTIFICATION_TYPES = [
'update', 'update',
] as const; ] as const;
/** Notification types to exclude from the "All" filter by default. */
const EXCLUDE_TYPES = [
'pleroma:chat_mention',
'chat', // TruthSocial
] as const;
type NotificationType = typeof NOTIFICATION_TYPES[number]; type NotificationType = typeof NOTIFICATION_TYPES[number];
/** Ensure the Notification is a valid, known type. */ /** Ensure the Notification is a valid, known type. */
@ -21,6 +27,7 @@ const validType = (type: string): type is NotificationType => NOTIFICATION_TYPES
export { export {
NOTIFICATION_TYPES, NOTIFICATION_TYPES,
EXCLUDE_TYPES,
NotificationType, NotificationType,
validType, validType,
}; };