mirror of
https://github.com/glitch-soc/mastodon.git
synced 2025-12-14 00:08:46 +00:00
[Glitch] Composer quote improvements
Port f85f0eee1b to glitch-soc
Co-authored-by: Claire <claire.github-309c@sitedethib.com>
Co-authored-by: diondiondion <mail@diondiondion.com>
Signed-off-by: Claire <claire.github-309c@sitedethib.com>
This commit is contained in:
@@ -89,6 +89,7 @@ export const COMPOSE_FOCUS = 'COMPOSE_FOCUS';
|
|||||||
const messages = defineMessages({
|
const messages = defineMessages({
|
||||||
uploadErrorLimit: { id: 'upload_error.limit', defaultMessage: 'File upload limit exceeded.' },
|
uploadErrorLimit: { id: 'upload_error.limit', defaultMessage: 'File upload limit exceeded.' },
|
||||||
uploadErrorPoll: { id: 'upload_error.poll', defaultMessage: 'File upload not allowed with polls.' },
|
uploadErrorPoll: { id: 'upload_error.poll', defaultMessage: 'File upload not allowed with polls.' },
|
||||||
|
uploadQuote: { id: 'upload_error.quote', defaultMessage: 'File upload not allowed with quotes.' },
|
||||||
open: { id: 'compose.published.open', defaultMessage: 'Open' },
|
open: { id: 'compose.published.open', defaultMessage: 'Open' },
|
||||||
published: { id: 'compose.published.body', defaultMessage: 'Post published.' },
|
published: { id: 'compose.published.body', defaultMessage: 'Post published.' },
|
||||||
saved: { id: 'compose.saved.body', defaultMessage: 'Post saved.' },
|
saved: { id: 'compose.saved.body', defaultMessage: 'Post saved.' },
|
||||||
@@ -154,7 +155,7 @@ export function resetCompose() {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export const focusCompose = (defaultText) => (dispatch, getState) => {
|
export const focusCompose = (defaultText = '') => (dispatch, getState) => {
|
||||||
dispatch({
|
dispatch({
|
||||||
type: COMPOSE_FOCUS,
|
type: COMPOSE_FOCUS,
|
||||||
defaultText,
|
defaultText,
|
||||||
@@ -336,6 +337,11 @@ export function doodleSet(options) {
|
|||||||
|
|
||||||
export function uploadCompose(files) {
|
export function uploadCompose(files) {
|
||||||
return function (dispatch, getState) {
|
return function (dispatch, getState) {
|
||||||
|
// Exit if there's a quote.
|
||||||
|
if (getState().compose.get('quoted_status_id')) {
|
||||||
|
dispatch(showAlert({ message: messages.uploadQuote }));
|
||||||
|
return;
|
||||||
|
}
|
||||||
const uploadLimit = getState().getIn(['server', 'server', 'configuration', 'statuses', 'max_media_attachments']);
|
const uploadLimit = getState().getIn(['server', 'server', 'configuration', 'statuses', 'max_media_attachments']);
|
||||||
const media = getState().getIn(['compose', 'media_attachments']);
|
const media = getState().getIn(['compose', 'media_attachments']);
|
||||||
const pending = getState().getIn(['compose', 'pending_media_attachments']);
|
const pending = getState().getIn(['compose', 'pending_media_attachments']);
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
import { defineMessages } from 'react-intl';
|
||||||
|
|
||||||
import { createAction } from '@reduxjs/toolkit';
|
import { createAction } from '@reduxjs/toolkit';
|
||||||
import type { List as ImmutableList, Map as ImmutableMap } from 'immutable';
|
import type { List as ImmutableList, Map as ImmutableMap } from 'immutable';
|
||||||
|
|
||||||
@@ -12,7 +14,27 @@ import {
|
|||||||
import type { ApiQuotePolicy } from '../api_types/quotes';
|
import type { ApiQuotePolicy } from '../api_types/quotes';
|
||||||
import type { Status } from '../models/status';
|
import type { Status } from '../models/status';
|
||||||
|
|
||||||
import { ensureComposeIsVisible } from './compose';
|
import { showAlert } from './alerts';
|
||||||
|
import { focusCompose } from './compose';
|
||||||
|
|
||||||
|
const messages = defineMessages({
|
||||||
|
quoteErrorUpload: {
|
||||||
|
id: 'quote_error.upload',
|
||||||
|
defaultMessage: 'Quoting is not allowed with media attachments.',
|
||||||
|
},
|
||||||
|
quoteErrorPoll: {
|
||||||
|
id: 'quote_error.poll',
|
||||||
|
defaultMessage: 'Quoting is not allowed with polls.',
|
||||||
|
},
|
||||||
|
quoteErrorQuote: {
|
||||||
|
id: 'quote_error.quote',
|
||||||
|
defaultMessage: 'Only one quote at a time is allowed.',
|
||||||
|
},
|
||||||
|
quoteErrorUnauthorized: {
|
||||||
|
id: 'quote_error.unauthorized',
|
||||||
|
defaultMessage: 'You are not authorized to quote this post.',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
type SimulatedMediaAttachmentJSON = ApiMediaAttachmentJSON & {
|
type SimulatedMediaAttachmentJSON = ApiMediaAttachmentJSON & {
|
||||||
unattached?: boolean;
|
unattached?: boolean;
|
||||||
@@ -78,14 +100,43 @@ export const changeUploadCompose = createDataLoadingThunk(
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
export const quoteComposeByStatus = createAppThunk(
|
export const quoteCompose = createAppThunk(
|
||||||
'compose/quoteComposeStatus',
|
'compose/quoteComposeStatus',
|
||||||
(status: Status, { getState }) => {
|
(status: Status, { dispatch }) => {
|
||||||
ensureComposeIsVisible(getState);
|
dispatch(focusCompose());
|
||||||
return status;
|
return status;
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
export const quoteComposeByStatus = createAppThunk(
|
||||||
|
(status: Status, { dispatch, getState }) => {
|
||||||
|
const composeState = getState().compose;
|
||||||
|
const mediaAttachments = composeState.get('media_attachments');
|
||||||
|
|
||||||
|
if (composeState.get('poll')) {
|
||||||
|
dispatch(showAlert({ message: messages.quoteErrorPoll }));
|
||||||
|
} else if (
|
||||||
|
composeState.get('is_uploading') ||
|
||||||
|
(mediaAttachments &&
|
||||||
|
typeof mediaAttachments !== 'string' &&
|
||||||
|
typeof mediaAttachments !== 'number' &&
|
||||||
|
typeof mediaAttachments !== 'boolean' &&
|
||||||
|
mediaAttachments.size !== 0)
|
||||||
|
) {
|
||||||
|
dispatch(showAlert({ message: messages.quoteErrorUpload }));
|
||||||
|
} else if (composeState.get('quoted_status_id')) {
|
||||||
|
dispatch(showAlert({ message: messages.quoteErrorQuote }));
|
||||||
|
} else if (
|
||||||
|
status.getIn(['quote_approval', 'current_user']) !== 'automatic' &&
|
||||||
|
status.getIn(['quote_approval', 'current_user']) !== 'manual'
|
||||||
|
) {
|
||||||
|
dispatch(showAlert({ message: messages.quoteErrorUnauthorized }));
|
||||||
|
} else {
|
||||||
|
dispatch(quoteCompose(status));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
export const quoteComposeById = createAppThunk(
|
export const quoteComposeById = createAppThunk(
|
||||||
(statusId: string, { dispatch, getState }) => {
|
(statusId: string, { dispatch, getState }) => {
|
||||||
const status = getState().statuses.get(statusId);
|
const status = getState().statuses.get(statusId);
|
||||||
@@ -97,6 +148,6 @@ export const quoteComposeById = createAppThunk(
|
|||||||
|
|
||||||
export const quoteComposeCancel = createAction('compose/quoteComposeCancel');
|
export const quoteComposeCancel = createAction('compose/quoteComposeCancel');
|
||||||
|
|
||||||
export const setQuotePolicy = createAction<ApiQuotePolicy>(
|
export const setComposeQuotePolicy = createAction<ApiQuotePolicy>(
|
||||||
'compose/setQuotePolicy',
|
'compose/setQuotePolicy',
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -137,3 +137,9 @@ export interface ApiStatusSourceJSON {
|
|||||||
text: string;
|
text: string;
|
||||||
spoiler_text: string;
|
spoiler_text: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function isStatusVisibility(
|
||||||
|
visibility: string,
|
||||||
|
): visibility is StatusVisibility {
|
||||||
|
return ['public', 'unlisted', 'private', 'direct'].includes(visibility);
|
||||||
|
}
|
||||||
|
|||||||
@@ -110,6 +110,7 @@ class Status extends ImmutablePureComponent {
|
|||||||
onToggleCollapsed: PropTypes.func,
|
onToggleCollapsed: PropTypes.func,
|
||||||
onTranslate: PropTypes.func,
|
onTranslate: PropTypes.func,
|
||||||
onInteractionModal: PropTypes.func,
|
onInteractionModal: PropTypes.func,
|
||||||
|
onQuoteCancel: PropTypes.func,
|
||||||
muted: PropTypes.bool,
|
muted: PropTypes.bool,
|
||||||
hidden: PropTypes.bool,
|
hidden: PropTypes.bool,
|
||||||
unread: PropTypes.bool,
|
unread: PropTypes.bool,
|
||||||
@@ -727,7 +728,7 @@ class Status extends ImmutablePureComponent {
|
|||||||
</Permalink>
|
</Permalink>
|
||||||
|
|
||||||
|
|
||||||
{this.props.contextType === 'compose' && isQuotedPost ? (
|
{isQuotedPost && !!this.props.onQuoteCancel ? (
|
||||||
<IconButton
|
<IconButton
|
||||||
onClick={this.handleQuoteCancel}
|
onClick={this.handleQuoteCancel}
|
||||||
className='status__quote-cancel'
|
className='status__quote-cancel'
|
||||||
|
|||||||
@@ -63,12 +63,21 @@ type GetStatusSelector = (
|
|||||||
props: { id?: string | null; contextType?: string },
|
props: { id?: string | null; contextType?: string },
|
||||||
) => Status | null;
|
) => Status | null;
|
||||||
|
|
||||||
export const QuotedStatus: React.FC<{
|
interface QuotedStatusProps {
|
||||||
quote: QuoteMap;
|
quote: QuoteMap;
|
||||||
contextType?: string;
|
contextType?: string;
|
||||||
variant?: 'full' | 'link';
|
variant?: 'full' | 'link';
|
||||||
nestingLevel?: number;
|
nestingLevel?: number;
|
||||||
}> = ({ quote, contextType, nestingLevel = 1, variant = 'full' }) => {
|
onQuoteCancel?: () => void; // Used for composer.
|
||||||
|
}
|
||||||
|
|
||||||
|
export const QuotedStatus: React.FC<QuotedStatusProps> = ({
|
||||||
|
quote,
|
||||||
|
contextType,
|
||||||
|
nestingLevel = 1,
|
||||||
|
variant = 'full',
|
||||||
|
onQuoteCancel,
|
||||||
|
}) => {
|
||||||
const dispatch = useAppDispatch();
|
const dispatch = useAppDispatch();
|
||||||
const quotedStatusId = quote.get('quoted_status');
|
const quotedStatusId = quote.get('quoted_status');
|
||||||
const quoteState = quote.get('state');
|
const quoteState = quote.get('state');
|
||||||
@@ -160,6 +169,7 @@ export const QuotedStatus: React.FC<{
|
|||||||
id={quotedStatusId}
|
id={quotedStatusId}
|
||||||
contextType={contextType}
|
contextType={contextType}
|
||||||
avatarSize={32}
|
avatarSize={32}
|
||||||
|
onQuoteCancel={onQuoteCancel}
|
||||||
>
|
>
|
||||||
{canRenderChildQuote && (
|
{canRenderChildQuote && (
|
||||||
<QuotedStatus
|
<QuotedStatus
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ import Status from 'flavours/glitch/components/status';
|
|||||||
import { deleteModal } from 'flavours/glitch/initial_state';
|
import { deleteModal } from 'flavours/glitch/initial_state';
|
||||||
import { makeGetStatus, makeGetPictureInPicture } from 'flavours/glitch/selectors';
|
import { makeGetStatus, makeGetPictureInPicture } from 'flavours/glitch/selectors';
|
||||||
|
|
||||||
import { quoteComposeCancel } from '../actions/compose_typed';
|
import { setStatusQuotePolicy } from '../actions/statuses_typed';
|
||||||
|
|
||||||
const makeMapStateToProps = () => {
|
const makeMapStateToProps = () => {
|
||||||
const getStatus = makeGetStatus();
|
const getStatus = makeGetStatus();
|
||||||
@@ -121,18 +121,18 @@ const mapDispatchToProps = (dispatch, { contextType }) => ({
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
onQuoteCancel() {
|
|
||||||
if (contextType === 'compose') {
|
|
||||||
dispatch(quoteComposeCancel());
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
onRevokeQuote (status) {
|
onRevokeQuote (status) {
|
||||||
dispatch(openModal({ modalType: 'CONFIRM_REVOKE_QUOTE', modalProps: { statusId: status.get('id'), quotedStatusId: status.getIn(['quote', 'quoted_status']) }}));
|
dispatch(openModal({ modalType: 'CONFIRM_REVOKE_QUOTE', modalProps: { statusId: status.get('id'), quotedStatusId: status.getIn(['quote', 'quoted_status']) }}));
|
||||||
},
|
},
|
||||||
|
|
||||||
onQuotePolicyChange(status) {
|
onQuotePolicyChange(status) {
|
||||||
dispatch(openModal({ modalType: 'COMPOSE_PRIVACY', modalProps: { statusId: status.get('id') } }));
|
const statusId = status.get('id');
|
||||||
|
const handleChange = (_, quotePolicy) => {
|
||||||
|
dispatch(
|
||||||
|
setStatusQuotePolicy({ policy: quotePolicy, statusId }),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
dispatch(openModal({ modalType: 'COMPOSE_PRIVACY', modalProps: { statusId, onChange: handleChange } }));
|
||||||
},
|
},
|
||||||
|
|
||||||
onEdit (status) {
|
onEdit (status) {
|
||||||
|
|||||||
@@ -15,10 +15,8 @@ import { missingAltTextModal } from 'flavours/glitch/initial_state';
|
|||||||
import AutosuggestInput from 'flavours/glitch/components/autosuggest_input';
|
import AutosuggestInput from 'flavours/glitch/components/autosuggest_input';
|
||||||
import AutosuggestTextarea from 'flavours/glitch/components/autosuggest_textarea';
|
import AutosuggestTextarea from 'flavours/glitch/components/autosuggest_textarea';
|
||||||
import { Button } from 'flavours/glitch/components/button';
|
import { Button } from 'flavours/glitch/components/button';
|
||||||
import { LoadingIndicator } from 'flavours/glitch/components/loading_indicator';
|
|
||||||
import EmojiPickerDropdown from '../containers/emoji_picker_dropdown_container';
|
import EmojiPickerDropdown from '../containers/emoji_picker_dropdown_container';
|
||||||
import PollButtonContainer from '../containers/poll_button_container';
|
import PollButtonContainer from '../containers/poll_button_container';
|
||||||
import PrivacyDropdownContainer from '../containers/privacy_dropdown_container';
|
|
||||||
import SpoilerButtonContainer from '../containers/spoiler_button_container';
|
import SpoilerButtonContainer from '../containers/spoiler_button_container';
|
||||||
import UploadButtonContainer from '../containers/upload_button_container';
|
import UploadButtonContainer from '../containers/upload_button_container';
|
||||||
import { countableText } from '../util/counter';
|
import { countableText } from '../util/counter';
|
||||||
@@ -36,6 +34,7 @@ import { ThreadModeButton } from './thread_mode_button';
|
|||||||
import { UploadForm } from './upload_form';
|
import { UploadForm } from './upload_form';
|
||||||
import { Warning } from './warning';
|
import { Warning } from './warning';
|
||||||
import { ComposeQuotedStatus } from './quoted_post';
|
import { ComposeQuotedStatus } from './quoted_post';
|
||||||
|
import { VisibilityButton } from './visibility_button';
|
||||||
|
|
||||||
const allowedAroundShortCode = '><\u0085\u0020\u00a0\u1680\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\u2028\u2029\u0009\u000a\u000b\u000c\u000d';
|
const allowedAroundShortCode = '><\u0085\u0020\u00a0\u1680\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\u2028\u2029\u0009\u000a\u000b\u000c\u000d';
|
||||||
|
|
||||||
@@ -280,7 +279,7 @@ class ComposeForm extends ImmutablePureComponent {
|
|||||||
<EditIndicator />
|
<EditIndicator />
|
||||||
|
|
||||||
<div className='compose-form__dropdowns'>
|
<div className='compose-form__dropdowns'>
|
||||||
<PrivacyDropdownContainer disabled={this.props.isEditing} />
|
<VisibilityButton disabled={this.props.isEditing} />
|
||||||
<LanguageDropdown />
|
<LanguageDropdown />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -1,15 +1,17 @@
|
|||||||
import { useMemo } from 'react';
|
import { useCallback, useMemo } from 'react';
|
||||||
import type { FC } from 'react';
|
import type { FC } from 'react';
|
||||||
|
|
||||||
import { Map } from 'immutable';
|
import { Map } from 'immutable';
|
||||||
|
|
||||||
|
import { quoteComposeCancel } from '@/flavours/glitch/actions/compose_typed';
|
||||||
import { QuotedStatus } from '@/flavours/glitch/components/status_quoted';
|
import { QuotedStatus } from '@/flavours/glitch/components/status_quoted';
|
||||||
import { useAppSelector } from '@/flavours/glitch/store';
|
import { useAppDispatch, useAppSelector } from '@/flavours/glitch/store';
|
||||||
|
|
||||||
export const ComposeQuotedStatus: FC = () => {
|
export const ComposeQuotedStatus: FC = () => {
|
||||||
const quotedStatusId = useAppSelector(
|
const quotedStatusId = useAppSelector(
|
||||||
(state) => state.compose.get('quoted_status_id') as string | null,
|
(state) => state.compose.get('quoted_status_id') as string | null,
|
||||||
);
|
);
|
||||||
|
const isEditing = useAppSelector((state) => !!state.compose.get('id'));
|
||||||
const quote = useMemo(
|
const quote = useMemo(
|
||||||
() =>
|
() =>
|
||||||
quotedStatusId
|
quotedStatusId
|
||||||
@@ -20,8 +22,17 @@ export const ComposeQuotedStatus: FC = () => {
|
|||||||
: null,
|
: null,
|
||||||
[quotedStatusId],
|
[quotedStatusId],
|
||||||
);
|
);
|
||||||
|
const dispatch = useAppDispatch();
|
||||||
|
const handleQuoteCancel = useCallback(() => {
|
||||||
|
dispatch(quoteComposeCancel());
|
||||||
|
}, [dispatch]);
|
||||||
if (!quote) {
|
if (!quote) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return <QuotedStatus quote={quote} contextType='compose' />;
|
return (
|
||||||
|
<QuotedStatus
|
||||||
|
quote={quote}
|
||||||
|
onQuoteCancel={!isEditing ? handleQuoteCancel : undefined}
|
||||||
|
/>
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -0,0 +1,148 @@
|
|||||||
|
import { useCallback, useMemo } from 'react';
|
||||||
|
import type { FC } from 'react';
|
||||||
|
|
||||||
|
import { defineMessages, useIntl } from 'react-intl';
|
||||||
|
|
||||||
|
import classNames from 'classnames';
|
||||||
|
|
||||||
|
import { changeComposeVisibility } from '@/flavours/glitch/actions/compose';
|
||||||
|
import { setComposeQuotePolicy } from '@/flavours/glitch/actions/compose_typed';
|
||||||
|
import { openModal } from '@/flavours/glitch/actions/modal';
|
||||||
|
import type { ApiQuotePolicy } from '@/flavours/glitch/api_types/quotes';
|
||||||
|
import type { StatusVisibility } from '@/flavours/glitch/api_types/statuses';
|
||||||
|
import { Icon } from '@/flavours/glitch/components/icon';
|
||||||
|
import { useAppSelector, useAppDispatch } from '@/flavours/glitch/store';
|
||||||
|
import { isFeatureEnabled } from '@/flavours/glitch/utils/environment';
|
||||||
|
import AlternateEmailIcon from '@/material-icons/400-24px/alternate_email.svg?react';
|
||||||
|
import LockIcon from '@/material-icons/400-24px/lock.svg?react';
|
||||||
|
import PublicIcon from '@/material-icons/400-24px/public.svg?react';
|
||||||
|
import QuietTimeIcon from '@/material-icons/400-24px/quiet_time.svg?react';
|
||||||
|
|
||||||
|
import type { VisibilityModalCallback } from '../../ui/components/visibility_modal';
|
||||||
|
import PrivacyDropdownContainer from '../containers/privacy_dropdown_container';
|
||||||
|
|
||||||
|
import { messages as privacyMessages } from './privacy_dropdown';
|
||||||
|
|
||||||
|
const messages = defineMessages({
|
||||||
|
anyone_quote: {
|
||||||
|
id: 'privacy.quote.anyone',
|
||||||
|
defaultMessage: '{visibility}, anyone can quote',
|
||||||
|
},
|
||||||
|
limited_quote: {
|
||||||
|
id: 'privacy.quote.limited',
|
||||||
|
defaultMessage: '{visibility}, quotes limited',
|
||||||
|
},
|
||||||
|
disabled_quote: {
|
||||||
|
id: 'privacy.quote.disabled',
|
||||||
|
defaultMessage: '{visibility}, quotes disabled',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
interface PrivacyDropdownProps {
|
||||||
|
disabled?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const VisibilityButton: FC<PrivacyDropdownProps> = (props) => {
|
||||||
|
if (!isFeatureEnabled('outgoing_quotes')) {
|
||||||
|
return <PrivacyDropdownContainer {...props} />;
|
||||||
|
}
|
||||||
|
return <PrivacyModalButton {...props} />;
|
||||||
|
};
|
||||||
|
|
||||||
|
const visibilityOptions = {
|
||||||
|
public: {
|
||||||
|
icon: 'globe',
|
||||||
|
iconComponent: PublicIcon,
|
||||||
|
value: 'public',
|
||||||
|
text: privacyMessages.public_short,
|
||||||
|
},
|
||||||
|
unlisted: {
|
||||||
|
icon: 'unlock',
|
||||||
|
iconComponent: QuietTimeIcon,
|
||||||
|
value: 'unlisted',
|
||||||
|
text: privacyMessages.unlisted_short,
|
||||||
|
},
|
||||||
|
private: {
|
||||||
|
icon: 'lock',
|
||||||
|
iconComponent: LockIcon,
|
||||||
|
value: 'private',
|
||||||
|
text: privacyMessages.private_short,
|
||||||
|
},
|
||||||
|
direct: {
|
||||||
|
icon: 'at',
|
||||||
|
iconComponent: AlternateEmailIcon,
|
||||||
|
value: 'direct',
|
||||||
|
text: privacyMessages.direct_short,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const PrivacyModalButton: FC<PrivacyDropdownProps> = ({ disabled = false }) => {
|
||||||
|
const intl = useIntl();
|
||||||
|
|
||||||
|
const { visibility, quotePolicy } = useAppSelector((state) => ({
|
||||||
|
visibility: state.compose.get('privacy') as StatusVisibility,
|
||||||
|
quotePolicy: state.compose.get('quote_policy') as ApiQuotePolicy,
|
||||||
|
}));
|
||||||
|
|
||||||
|
const { icon, iconComponent } = useMemo(() => {
|
||||||
|
const option = visibilityOptions[visibility];
|
||||||
|
return { icon: option.icon, iconComponent: option.iconComponent };
|
||||||
|
}, [visibility]);
|
||||||
|
const text = useMemo(() => {
|
||||||
|
const visibilityText = intl.formatMessage(
|
||||||
|
visibilityOptions[visibility].text,
|
||||||
|
);
|
||||||
|
if (visibility === 'private' || visibility === 'direct') {
|
||||||
|
return visibilityText;
|
||||||
|
}
|
||||||
|
if (quotePolicy === 'nobody') {
|
||||||
|
return intl.formatMessage(messages.disabled_quote, {
|
||||||
|
visibility: visibilityText,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (quotePolicy !== 'public') {
|
||||||
|
return intl.formatMessage(messages.limited_quote, {
|
||||||
|
visibility: visibilityText,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return intl.formatMessage(messages.anyone_quote, {
|
||||||
|
visibility: visibilityText,
|
||||||
|
});
|
||||||
|
}, [quotePolicy, visibility, intl]);
|
||||||
|
|
||||||
|
const dispatch = useAppDispatch();
|
||||||
|
|
||||||
|
const handleChange: VisibilityModalCallback = useCallback(
|
||||||
|
(newVisibility, newQuotePolicy) => {
|
||||||
|
if (newVisibility !== visibility) {
|
||||||
|
dispatch(changeComposeVisibility(newVisibility));
|
||||||
|
}
|
||||||
|
if (newQuotePolicy !== quotePolicy) {
|
||||||
|
dispatch(setComposeQuotePolicy(newQuotePolicy));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[dispatch, quotePolicy, visibility],
|
||||||
|
);
|
||||||
|
|
||||||
|
const handleOpen = useCallback(() => {
|
||||||
|
dispatch(
|
||||||
|
openModal({
|
||||||
|
modalType: 'COMPOSE_PRIVACY',
|
||||||
|
modalProps: { onChange: handleChange },
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
}, [dispatch, handleChange]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<button
|
||||||
|
type='button'
|
||||||
|
title={intl.formatMessage(privacyMessages.change_privacy)}
|
||||||
|
onClick={handleOpen}
|
||||||
|
disabled={disabled}
|
||||||
|
className={classNames('dropdown-button')}
|
||||||
|
>
|
||||||
|
<Icon id={icon} icon={iconComponent} />
|
||||||
|
<span className='dropdown-button__label'>{text}</span>
|
||||||
|
</button>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
|
|
||||||
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
|
import { defineMessages, injectIntl } from 'react-intl';
|
||||||
|
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import { Helmet } from 'react-helmet';
|
import { Helmet } from 'react-helmet';
|
||||||
@@ -16,7 +16,6 @@ import VisibilityOffIcon from '@/material-icons/400-24px/visibility_off.svg?reac
|
|||||||
import { Hotkeys } from 'flavours/glitch/components/hotkeys';
|
import { Hotkeys } from 'flavours/glitch/components/hotkeys';
|
||||||
import { Icon } from 'flavours/glitch/components/icon';
|
import { Icon } from 'flavours/glitch/components/icon';
|
||||||
import { LoadingIndicator } from 'flavours/glitch/components/loading_indicator';
|
import { LoadingIndicator } from 'flavours/glitch/components/loading_indicator';
|
||||||
import { TimelineHint } from 'flavours/glitch/components/timeline_hint';
|
|
||||||
import ScrollContainer from 'flavours/glitch/containers/scroll_container';
|
import ScrollContainer from 'flavours/glitch/containers/scroll_container';
|
||||||
import BundleColumnError from 'flavours/glitch/features/ui/components/bundle_column_error';
|
import BundleColumnError from 'flavours/glitch/features/ui/components/bundle_column_error';
|
||||||
import { identityContextPropShape, withIdentity } from 'flavours/glitch/identity_context';
|
import { identityContextPropShape, withIdentity } from 'flavours/glitch/identity_context';
|
||||||
@@ -51,6 +50,7 @@ import {
|
|||||||
translateStatus,
|
translateStatus,
|
||||||
undoStatusTranslation,
|
undoStatusTranslation,
|
||||||
} from '../../actions/statuses';
|
} from '../../actions/statuses';
|
||||||
|
import { setStatusQuotePolicy } from '../../actions/statuses_typed';
|
||||||
import ColumnHeader from '../../components/column_header';
|
import ColumnHeader from '../../components/column_header';
|
||||||
import { textForScreenReader, defaultMediaVisibility } from '../../components/status';
|
import { textForScreenReader, defaultMediaVisibility } from '../../components/status';
|
||||||
import { StatusQuoteManager } from '../../components/status_quoted';
|
import { StatusQuoteManager } from '../../components/status_quoted';
|
||||||
@@ -296,8 +296,14 @@ class Status extends ImmutablePureComponent {
|
|||||||
};
|
};
|
||||||
|
|
||||||
handleQuotePolicyChange = (status) => {
|
handleQuotePolicyChange = (status) => {
|
||||||
|
const statusId = status.get('id');
|
||||||
const { dispatch } = this.props;
|
const { dispatch } = this.props;
|
||||||
dispatch(openModal({ modalType: 'COMPOSE_PRIVACY', modalProps: { statusId: status.get('id') } }));
|
const handleChange = (_, quotePolicy) => {
|
||||||
|
dispatch(
|
||||||
|
setStatusQuotePolicy({ policy: quotePolicy, statusId }),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
dispatch(openModal({ modalType: 'COMPOSE_PRIVACY', modalProps: { statusId, onChange: handleChange } }));
|
||||||
};
|
};
|
||||||
|
|
||||||
handleEditClick = (status) => {
|
handleEditClick = (status) => {
|
||||||
|
|||||||
@@ -1,25 +1,31 @@
|
|||||||
import { forwardRef, useCallback, useId, useMemo } from 'react';
|
import {
|
||||||
|
forwardRef,
|
||||||
|
useCallback,
|
||||||
|
useId,
|
||||||
|
useImperativeHandle,
|
||||||
|
useMemo,
|
||||||
|
useState,
|
||||||
|
} from 'react';
|
||||||
import type { FC } from 'react';
|
import type { FC } from 'react';
|
||||||
|
|
||||||
import { defineMessages, FormattedMessage, useIntl } from 'react-intl';
|
import { defineMessages, FormattedMessage, useIntl } from 'react-intl';
|
||||||
|
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
|
|
||||||
import { changeComposeVisibility } from '@/flavours/glitch/actions/compose';
|
|
||||||
import { setStatusQuotePolicy } from '@/flavours/glitch/actions/statuses_typed';
|
|
||||||
import type { ApiQuotePolicy } from '@/flavours/glitch/api_types/quotes';
|
import type { ApiQuotePolicy } from '@/flavours/glitch/api_types/quotes';
|
||||||
import { isQuotePolicy } from '@/flavours/glitch/api_types/quotes';
|
import { isQuotePolicy } from '@/flavours/glitch/api_types/quotes';
|
||||||
|
import { isStatusVisibility } from '@/flavours/glitch/api_types/statuses';
|
||||||
import type { StatusVisibility } from '@/flavours/glitch/api_types/statuses';
|
import type { StatusVisibility } from '@/flavours/glitch/api_types/statuses';
|
||||||
import { Dropdown } from '@/flavours/glitch/components/dropdown';
|
import { Dropdown } from '@/flavours/glitch/components/dropdown';
|
||||||
import type { SelectItem } from '@/flavours/glitch/components/dropdown_selector';
|
import type { SelectItem } from '@/flavours/glitch/components/dropdown_selector';
|
||||||
import { IconButton } from '@/flavours/glitch/components/icon_button';
|
import { IconButton } from '@/flavours/glitch/components/icon_button';
|
||||||
import { messages as privacyMessages } from '@/flavours/glitch/features/compose/components/privacy_dropdown';
|
import { messages as privacyMessages } from '@/flavours/glitch/features/compose/components/privacy_dropdown';
|
||||||
import {
|
import { createAppSelector, useAppSelector } from '@/flavours/glitch/store';
|
||||||
createAppSelector,
|
import AlternateEmailIcon from '@/material-icons/400-24px/alternate_email.svg?react';
|
||||||
useAppDispatch,
|
|
||||||
useAppSelector,
|
|
||||||
} from '@/flavours/glitch/store';
|
|
||||||
import CloseIcon from '@/material-icons/400-24px/close.svg?react';
|
import CloseIcon from '@/material-icons/400-24px/close.svg?react';
|
||||||
|
import LockIcon from '@/material-icons/400-24px/lock.svg?react';
|
||||||
|
import PublicIcon from '@/material-icons/400-24px/public.svg?react';
|
||||||
|
import QuietTimeIcon from '@/material-icons/400-24px/quiet_time.svg?react';
|
||||||
|
|
||||||
import type { BaseConfirmationModalProps } from './confirmation_modals/confirmation_modal';
|
import type { BaseConfirmationModalProps } from './confirmation_modals/confirmation_modal';
|
||||||
|
|
||||||
@@ -43,13 +49,26 @@ const messages = defineMessages({
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
export type VisibilityModalCallback = (
|
||||||
|
visibility: StatusVisibility,
|
||||||
|
quotePolicy: ApiQuotePolicy,
|
||||||
|
) => void;
|
||||||
|
|
||||||
interface VisibilityModalProps extends BaseConfirmationModalProps {
|
interface VisibilityModalProps extends BaseConfirmationModalProps {
|
||||||
statusId: string;
|
statusId?: string;
|
||||||
|
onChange: VisibilityModalCallback;
|
||||||
}
|
}
|
||||||
|
|
||||||
const selectStatusPolicy = createAppSelector(
|
const selectStatusPolicy = createAppSelector(
|
||||||
[(state) => state.statuses, (_state, statusId: string) => statusId],
|
[
|
||||||
(statuses, statusId) => {
|
(state) => state.statuses,
|
||||||
|
(_state, statusId?: string) => statusId,
|
||||||
|
(state) => state.compose.get('quote_policy') as ApiQuotePolicy,
|
||||||
|
],
|
||||||
|
(statuses, statusId, composeQuotePolicy) => {
|
||||||
|
if (!statusId) {
|
||||||
|
return composeQuotePolicy;
|
||||||
|
}
|
||||||
const status = statuses.get(statusId);
|
const status = statuses.get(statusId);
|
||||||
if (!status) {
|
if (!status) {
|
||||||
return 'public';
|
return 'public';
|
||||||
@@ -77,24 +96,25 @@ const selectStatusPolicy = createAppSelector(
|
|||||||
);
|
);
|
||||||
|
|
||||||
export const VisibilityModal: FC<VisibilityModalProps> = forwardRef(
|
export const VisibilityModal: FC<VisibilityModalProps> = forwardRef(
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
({ onClose, onChange, statusId }, ref) => {
|
||||||
({ onClose, statusId }, ref) => {
|
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
const currentVisibility = useAppSelector(
|
const currentVisibility = useAppSelector((state) =>
|
||||||
(state) =>
|
statusId
|
||||||
(state.statuses.getIn([statusId, 'visibility'], 'public') as
|
? ((state.statuses.getIn([statusId, 'visibility'], 'public') as
|
||||||
| StatusVisibility
|
| StatusVisibility
|
||||||
| undefined) ?? 'public',
|
| undefined) ?? 'public')
|
||||||
|
: (state.compose.get('privacy') as StatusVisibility),
|
||||||
);
|
);
|
||||||
const currentQuotePolicy = useAppSelector((state) =>
|
const currentQuotePolicy = useAppSelector((state) =>
|
||||||
selectStatusPolicy(state, statusId),
|
selectStatusPolicy(state, statusId),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const [visibility, setVisibility] = useState(currentVisibility);
|
||||||
|
const [quotePolicy, setQuotePolicy] = useState(currentQuotePolicy);
|
||||||
|
|
||||||
|
const disableVisibility = !!statusId;
|
||||||
const disableQuotePolicy =
|
const disableQuotePolicy =
|
||||||
currentVisibility === 'private' || currentVisibility === 'direct';
|
visibility === 'private' || visibility === 'direct';
|
||||||
const isSaving = useAppSelector(
|
|
||||||
(state) =>
|
|
||||||
state.statuses.getIn([statusId, 'isSavingQuotePolicy']) === true,
|
|
||||||
);
|
|
||||||
|
|
||||||
const visibilityItems = useMemo<SelectItem<StatusVisibility>[]>(
|
const visibilityItems = useMemo<SelectItem<StatusVisibility>[]>(
|
||||||
() => [
|
() => [
|
||||||
@@ -102,21 +122,30 @@ export const VisibilityModal: FC<VisibilityModalProps> = forwardRef(
|
|||||||
value: 'public',
|
value: 'public',
|
||||||
text: intl.formatMessage(privacyMessages.public_short),
|
text: intl.formatMessage(privacyMessages.public_short),
|
||||||
meta: intl.formatMessage(privacyMessages.public_long),
|
meta: intl.formatMessage(privacyMessages.public_long),
|
||||||
|
icon: 'globe',
|
||||||
|
iconComponent: PublicIcon,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
value: 'unlisted',
|
value: 'unlisted',
|
||||||
text: intl.formatMessage(privacyMessages.unlisted_short),
|
text: intl.formatMessage(privacyMessages.unlisted_short),
|
||||||
meta: intl.formatMessage(privacyMessages.unlisted_long),
|
meta: intl.formatMessage(privacyMessages.unlisted_long),
|
||||||
|
extra: intl.formatMessage(privacyMessages.unlisted_extra),
|
||||||
|
icon: 'unlock',
|
||||||
|
iconComponent: QuietTimeIcon,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
value: 'private',
|
value: 'private',
|
||||||
text: intl.formatMessage(privacyMessages.private_short),
|
text: intl.formatMessage(privacyMessages.private_short),
|
||||||
meta: intl.formatMessage(privacyMessages.private_long),
|
meta: intl.formatMessage(privacyMessages.private_long),
|
||||||
|
icon: 'lock',
|
||||||
|
iconComponent: LockIcon,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
value: 'direct',
|
value: 'direct',
|
||||||
text: intl.formatMessage(privacyMessages.direct_short),
|
text: intl.formatMessage(privacyMessages.direct_short),
|
||||||
meta: intl.formatMessage(privacyMessages.direct_long),
|
meta: intl.formatMessage(privacyMessages.direct_long),
|
||||||
|
icon: 'at',
|
||||||
|
iconComponent: AlternateEmailIcon,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
[intl],
|
[intl],
|
||||||
@@ -133,24 +162,27 @@ export const VisibilityModal: FC<VisibilityModalProps> = forwardRef(
|
|||||||
[intl],
|
[intl],
|
||||||
);
|
);
|
||||||
|
|
||||||
const dispatch = useAppDispatch();
|
const handleVisibilityChange = useCallback((value: string) => {
|
||||||
const handleVisibilityChange = useCallback(
|
if (isStatusVisibility(value)) {
|
||||||
(value: string) => {
|
setVisibility(value);
|
||||||
// Published statuses cannot change visibility.
|
}
|
||||||
if (statusId) {
|
}, []);
|
||||||
return;
|
const handleQuotePolicyChange = useCallback((value: string) => {
|
||||||
}
|
if (isQuotePolicy(value)) {
|
||||||
dispatch(changeComposeVisibility(value));
|
setQuotePolicy(value);
|
||||||
},
|
}
|
||||||
[dispatch, statusId],
|
}, []);
|
||||||
);
|
|
||||||
const handleQuotePolicyChange = useCallback(
|
// Save on close
|
||||||
(value: string) => {
|
useImperativeHandle(
|
||||||
if (isQuotePolicy(value) && !disableQuotePolicy) {
|
ref,
|
||||||
void dispatch(setStatusQuotePolicy({ policy: value, statusId }));
|
() => ({
|
||||||
}
|
getCloseConfirmationMessage() {
|
||||||
},
|
onChange(visibility, quotePolicy);
|
||||||
[disableQuotePolicy, dispatch, statusId],
|
return null;
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
[onChange, quotePolicy, visibility],
|
||||||
);
|
);
|
||||||
|
|
||||||
const privacyDropdownId = useId();
|
const privacyDropdownId = useId();
|
||||||
@@ -192,7 +224,7 @@ export const VisibilityModal: FC<VisibilityModalProps> = forwardRef(
|
|||||||
<label
|
<label
|
||||||
htmlFor={privacyDropdownId}
|
htmlFor={privacyDropdownId}
|
||||||
className={classNames('visibility-dropdown__label', {
|
className={classNames('visibility-dropdown__label', {
|
||||||
disabled: isSaving || !!statusId,
|
disabled: disableVisibility,
|
||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
<FormattedMessage
|
<FormattedMessage
|
||||||
@@ -203,10 +235,10 @@ export const VisibilityModal: FC<VisibilityModalProps> = forwardRef(
|
|||||||
<Dropdown
|
<Dropdown
|
||||||
items={visibilityItems}
|
items={visibilityItems}
|
||||||
classPrefix='visibility-dropdown'
|
classPrefix='visibility-dropdown'
|
||||||
current={currentVisibility}
|
current={visibility}
|
||||||
onChange={handleVisibilityChange}
|
onChange={handleVisibilityChange}
|
||||||
title={intl.formatMessage(privacyMessages.change_privacy)}
|
title={intl.formatMessage(privacyMessages.change_privacy)}
|
||||||
disabled={isSaving || !!statusId}
|
disabled={disableVisibility}
|
||||||
id={privacyDropdownId}
|
id={privacyDropdownId}
|
||||||
/>
|
/>
|
||||||
{!!statusId && (
|
{!!statusId && (
|
||||||
@@ -222,7 +254,7 @@ export const VisibilityModal: FC<VisibilityModalProps> = forwardRef(
|
|||||||
<label
|
<label
|
||||||
htmlFor={quoteDropdownId}
|
htmlFor={quoteDropdownId}
|
||||||
className={classNames('visibility-dropdown__label', {
|
className={classNames('visibility-dropdown__label', {
|
||||||
disabled: disableQuotePolicy || isSaving,
|
disabled: disableQuotePolicy,
|
||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
<FormattedMessage
|
<FormattedMessage
|
||||||
@@ -234,15 +266,12 @@ export const VisibilityModal: FC<VisibilityModalProps> = forwardRef(
|
|||||||
items={quoteItems}
|
items={quoteItems}
|
||||||
onChange={handleQuotePolicyChange}
|
onChange={handleQuotePolicyChange}
|
||||||
classPrefix='visibility-dropdown'
|
classPrefix='visibility-dropdown'
|
||||||
current={currentQuotePolicy}
|
current={quotePolicy}
|
||||||
title={intl.formatMessage(messages.buttonTitle)}
|
title={intl.formatMessage(messages.buttonTitle)}
|
||||||
disabled={disableQuotePolicy || isSaving}
|
disabled={disableQuotePolicy}
|
||||||
id={quoteDropdownId}
|
id={quoteDropdownId}
|
||||||
/>
|
/>
|
||||||
<QuotePolicyHelper
|
<QuotePolicyHelper policy={quotePolicy} visibility={visibility} />
|
||||||
policy={currentQuotePolicy}
|
|
||||||
visibility={currentVisibility}
|
|
||||||
/>
|
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -2,9 +2,9 @@ import { Map as ImmutableMap, List as ImmutableList, OrderedSet as ImmutableOrde
|
|||||||
|
|
||||||
import {
|
import {
|
||||||
changeUploadCompose,
|
changeUploadCompose,
|
||||||
quoteComposeByStatus,
|
quoteCompose,
|
||||||
quoteComposeCancel,
|
quoteComposeCancel,
|
||||||
setQuotePolicy,
|
setComposeQuotePolicy,
|
||||||
} from 'flavours/glitch/actions/compose_typed';
|
} from 'flavours/glitch/actions/compose_typed';
|
||||||
import { timelineDelete } from 'flavours/glitch/actions/timelines_typed';
|
import { timelineDelete } from 'flavours/glitch/actions/timelines_typed';
|
||||||
|
|
||||||
@@ -405,22 +405,15 @@ export const composeReducer = (state = initialState, action) => {
|
|||||||
return state.set('is_changing_upload', true);
|
return state.set('is_changing_upload', true);
|
||||||
} else if (changeUploadCompose.rejected.match(action)) {
|
} else if (changeUploadCompose.rejected.match(action)) {
|
||||||
return state.set('is_changing_upload', false);
|
return state.set('is_changing_upload', false);
|
||||||
} else if (quoteComposeByStatus.match(action)) {
|
} else if (quoteCompose.match(action)) {
|
||||||
const status = action.payload;
|
const status = action.payload;
|
||||||
if (
|
return state
|
||||||
status.getIn(['quote_approval', 'current_user']) === 'automatic' &&
|
.set('quoted_status_id', status.get('id'))
|
||||||
state.get('media_attachments').size === 0 &&
|
.set('spoiler', status.get('sensitive'))
|
||||||
!state.get('is_uploading') &&
|
.set('spoiler_text', status.get('spoiler_text'));
|
||||||
!state.get('poll')
|
|
||||||
) {
|
|
||||||
return state
|
|
||||||
.set('quoted_status_id', status.get('id'))
|
|
||||||
.set('spoiler', status.get('sensitive'))
|
|
||||||
.set('spoiler_text', status.get('spoiler_text'));
|
|
||||||
}
|
|
||||||
} else if (quoteComposeCancel.match(action)) {
|
} else if (quoteComposeCancel.match(action)) {
|
||||||
return state.set('quoted_status_id', null);
|
return state.set('quoted_status_id', null);
|
||||||
} else if (setQuotePolicy.match(action)) {
|
} else if (setComposeQuotePolicy.match(action)) {
|
||||||
return state.set('quote_policy', action.payload);
|
return state.set('quote_policy', action.payload);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -634,6 +627,7 @@ export const composeReducer = (state = initialState, action) => {
|
|||||||
map => map.merge(new ImmutableMap({ do_not_federate })),
|
map => map.merge(new ImmutableMap({ do_not_federate })),
|
||||||
);
|
);
|
||||||
map.set('id', null);
|
map.set('id', null);
|
||||||
|
map.set('quoted_status_id', action.status.getIn(['quote', 'quoted_status']));
|
||||||
// Mastodon-authored posts can be expected to have at most one automatic approval policy
|
// Mastodon-authored posts can be expected to have at most one automatic approval policy
|
||||||
map.set('quote_policy', action.status.getIn(['quote_approval', 'automatic', 0]) || 'nobody');
|
map.set('quote_policy', action.status.getIn(['quote_approval', 'automatic', 0]) || 'nobody');
|
||||||
|
|
||||||
@@ -671,6 +665,7 @@ export const composeReducer = (state = initialState, action) => {
|
|||||||
map.set('idempotencyKey', uuid());
|
map.set('idempotencyKey', uuid());
|
||||||
map.set('sensitive', action.status.get('sensitive'));
|
map.set('sensitive', action.status.get('sensitive'));
|
||||||
map.set('language', action.status.get('language'));
|
map.set('language', action.status.get('language'));
|
||||||
|
map.set('quoted_status_id', action.status.getIn(['quote', 'quoted_status']));
|
||||||
// Mastodon-authored posts can be expected to have at most one automatic approval policy
|
// Mastodon-authored posts can be expected to have at most one automatic approval policy
|
||||||
map.set('quote_policy', action.status.getIn(['quote_approval', 'automatic', 0]) || 'nobody');
|
map.set('quote_policy', action.status.getIn(['quote_approval', 'automatic', 0]) || 'nobody');
|
||||||
|
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ export const getFilters = createSelector(
|
|||||||
(_, { contextType }: { contextType: string }) => contextType,
|
(_, { contextType }: { contextType: string }) => contextType,
|
||||||
],
|
],
|
||||||
(filters, contextType) => {
|
(filters, contextType) => {
|
||||||
if (!contextType || contextType === 'compose') {
|
if (!contextType) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5644,7 +5644,10 @@ a.status-card {
|
|||||||
|
|
||||||
.privacy-dropdown__option__content,
|
.privacy-dropdown__option__content,
|
||||||
.privacy-dropdown__option__content strong,
|
.privacy-dropdown__option__content strong,
|
||||||
.privacy-dropdown__option__additional {
|
.privacy-dropdown__option__additional,
|
||||||
|
.visibility-dropdown__option__content,
|
||||||
|
.visibility-dropdown__option__content strong,
|
||||||
|
.visibility-dropdown__option__additional {
|
||||||
color: $primary-text-color;
|
color: $primary-text-color;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -5658,13 +5661,15 @@ a.status-card {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.privacy-dropdown__option__icon {
|
.privacy-dropdown__option__icon,
|
||||||
|
.visibility-dropdown__option__icon {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.privacy-dropdown__option__content {
|
.privacy-dropdown__option__content,
|
||||||
|
.visibility-dropdown__option__content {
|
||||||
flex: 1 1 auto;
|
flex: 1 1 auto;
|
||||||
color: $darker-text-color;
|
color: $darker-text-color;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user