mirror of
https://github.com/mastodon/mastodon.git
synced 2025-09-06 18:01:05 +00:00
Fix error alerts for deleted quotes (#35918)
Some checks are pending
Check i18n / check-i18n (push) Waiting to run
Chromatic / Run Chromatic (push) Waiting to run
CodeQL / Analyze (javascript) (push) Waiting to run
CodeQL / Analyze (ruby) (push) Waiting to run
Check formatting / lint (push) Waiting to run
JavaScript Linting / lint (push) Waiting to run
Ruby Linting / lint (push) Waiting to run
JavaScript Testing / test (push) Waiting to run
Historical data migration test / test (14-alpine) (push) Waiting to run
Historical data migration test / test (15-alpine) (push) Waiting to run
Historical data migration test / test (16-alpine) (push) Waiting to run
Historical data migration test / test (17-alpine) (push) Waiting to run
Ruby Testing / build (production) (push) Waiting to run
Ruby Testing / build (test) (push) Waiting to run
Ruby Testing / test (.ruby-version) (push) Blocked by required conditions
Ruby Testing / test (3.2) (push) Blocked by required conditions
Ruby Testing / test (3.3) (push) Blocked by required conditions
Ruby Testing / ImageMagick tests (.ruby-version) (push) Blocked by required conditions
Ruby Testing / ImageMagick tests (3.2) (push) Blocked by required conditions
Ruby Testing / ImageMagick tests (3.3) (push) Blocked by required conditions
Ruby Testing / End to End testing (.ruby-version) (push) Blocked by required conditions
Ruby Testing / End to End testing (3.2) (push) Blocked by required conditions
Ruby Testing / End to End testing (3.3) (push) Blocked by required conditions
Ruby Testing / Elastic Search integration testing (.ruby-version, docker.elastic.co/elasticsearch/elasticsearch:7.17.13) (push) Blocked by required conditions
Ruby Testing / Elastic Search integration testing (.ruby-version, docker.elastic.co/elasticsearch/elasticsearch:8.10.2) (push) Blocked by required conditions
Ruby Testing / Elastic Search integration testing (.ruby-version, opensearchproject/opensearch:2) (push) Blocked by required conditions
Ruby Testing / Elastic Search integration testing (3.2, docker.elastic.co/elasticsearch/elasticsearch:7.17.13) (push) Blocked by required conditions
Ruby Testing / Elastic Search integration testing (3.3, docker.elastic.co/elasticsearch/elasticsearch:7.17.13) (push) Blocked by required conditions
Some checks are pending
Check i18n / check-i18n (push) Waiting to run
Chromatic / Run Chromatic (push) Waiting to run
CodeQL / Analyze (javascript) (push) Waiting to run
CodeQL / Analyze (ruby) (push) Waiting to run
Check formatting / lint (push) Waiting to run
JavaScript Linting / lint (push) Waiting to run
Ruby Linting / lint (push) Waiting to run
JavaScript Testing / test (push) Waiting to run
Historical data migration test / test (14-alpine) (push) Waiting to run
Historical data migration test / test (15-alpine) (push) Waiting to run
Historical data migration test / test (16-alpine) (push) Waiting to run
Historical data migration test / test (17-alpine) (push) Waiting to run
Ruby Testing / build (production) (push) Waiting to run
Ruby Testing / build (test) (push) Waiting to run
Ruby Testing / test (.ruby-version) (push) Blocked by required conditions
Ruby Testing / test (3.2) (push) Blocked by required conditions
Ruby Testing / test (3.3) (push) Blocked by required conditions
Ruby Testing / ImageMagick tests (.ruby-version) (push) Blocked by required conditions
Ruby Testing / ImageMagick tests (3.2) (push) Blocked by required conditions
Ruby Testing / ImageMagick tests (3.3) (push) Blocked by required conditions
Ruby Testing / End to End testing (.ruby-version) (push) Blocked by required conditions
Ruby Testing / End to End testing (3.2) (push) Blocked by required conditions
Ruby Testing / End to End testing (3.3) (push) Blocked by required conditions
Ruby Testing / Elastic Search integration testing (.ruby-version, docker.elastic.co/elasticsearch/elasticsearch:7.17.13) (push) Blocked by required conditions
Ruby Testing / Elastic Search integration testing (.ruby-version, docker.elastic.co/elasticsearch/elasticsearch:8.10.2) (push) Blocked by required conditions
Ruby Testing / Elastic Search integration testing (.ruby-version, opensearchproject/opensearch:2) (push) Blocked by required conditions
Ruby Testing / Elastic Search integration testing (3.2, docker.elastic.co/elasticsearch/elasticsearch:7.17.13) (push) Blocked by required conditions
Ruby Testing / Elastic Search integration testing (3.3, docker.elastic.co/elasticsearch/elasticsearch:7.17.13) (push) Blocked by required conditions
This commit is contained in:
parent
6ad0ddebe4
commit
4180f754d0
|
@ -3,7 +3,7 @@ import { browserHistory } from 'mastodon/components/router';
|
||||||
import api from '../api';
|
import api from '../api';
|
||||||
|
|
||||||
import { ensureComposeIsVisible, setComposeToStatus } from './compose';
|
import { ensureComposeIsVisible, setComposeToStatus } from './compose';
|
||||||
import { importFetchedStatus, importFetchedStatuses, importFetchedAccount } from './importer';
|
import { importFetchedStatus, importFetchedAccount } from './importer';
|
||||||
import { fetchContext } from './statuses_typed';
|
import { fetchContext } from './statuses_typed';
|
||||||
import { deleteFromTimelines } from './timelines';
|
import { deleteFromTimelines } from './timelines';
|
||||||
|
|
||||||
|
@ -48,7 +48,18 @@ export function fetchStatusRequest(id, skipLoading) {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function fetchStatus(id, forceFetch = false, alsoFetchContext = true) {
|
/**
|
||||||
|
* @param {string} id
|
||||||
|
* @param {Object} [options]
|
||||||
|
* @param {boolean} [options.forceFetch]
|
||||||
|
* @param {boolean} [options.alsoFetchContext]
|
||||||
|
* @param {string | null | undefined} [options.parentQuotePostId]
|
||||||
|
*/
|
||||||
|
export function fetchStatus(id, {
|
||||||
|
forceFetch = false,
|
||||||
|
alsoFetchContext = true,
|
||||||
|
parentQuotePostId,
|
||||||
|
} = {}) {
|
||||||
return (dispatch, getState) => {
|
return (dispatch, getState) => {
|
||||||
const skipLoading = !forceFetch && getState().getIn(['statuses', id], null) !== null;
|
const skipLoading = !forceFetch && getState().getIn(['statuses', id], null) !== null;
|
||||||
|
|
||||||
|
@ -66,7 +77,7 @@ export function fetchStatus(id, forceFetch = false, alsoFetchContext = true) {
|
||||||
dispatch(importFetchedStatus(response.data));
|
dispatch(importFetchedStatus(response.data));
|
||||||
dispatch(fetchStatusSuccess(skipLoading));
|
dispatch(fetchStatusSuccess(skipLoading));
|
||||||
}).catch(error => {
|
}).catch(error => {
|
||||||
dispatch(fetchStatusFail(id, error, skipLoading));
|
dispatch(fetchStatusFail(id, error, skipLoading, parentQuotePostId));
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -78,11 +89,12 @@ export function fetchStatusSuccess(skipLoading) {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function fetchStatusFail(id, error, skipLoading) {
|
export function fetchStatusFail(id, error, skipLoading, parentQuotePostId) {
|
||||||
return {
|
return {
|
||||||
type: STATUS_FETCH_FAIL,
|
type: STATUS_FETCH_FAIL,
|
||||||
id,
|
id,
|
||||||
error,
|
error,
|
||||||
|
parentQuotePostId,
|
||||||
skipLoading,
|
skipLoading,
|
||||||
skipAlert: true,
|
skipAlert: true,
|
||||||
};
|
};
|
||||||
|
|
|
@ -32,9 +32,7 @@ const QuoteWrapper: React.FC<{
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const NestedQuoteLink: React.FC<{
|
const NestedQuoteLink: React.FC<{ status: Status }> = ({ status }) => {
|
||||||
status: Status;
|
|
||||||
}> = ({ status }) => {
|
|
||||||
const accountId = status.get('account') as string;
|
const accountId = status.get('account') as string;
|
||||||
const account = useAppSelector((state) =>
|
const account = useAppSelector((state) =>
|
||||||
accountId ? state.accounts.get(accountId) : undefined,
|
accountId ? state.accounts.get(accountId) : undefined,
|
||||||
|
@ -66,6 +64,7 @@ type GetStatusSelector = (
|
||||||
interface QuotedStatusProps {
|
interface QuotedStatusProps {
|
||||||
quote: QuoteMap;
|
quote: QuoteMap;
|
||||||
contextType?: string;
|
contextType?: string;
|
||||||
|
parentQuotePostId?: string | null;
|
||||||
variant?: 'full' | 'link';
|
variant?: 'full' | 'link';
|
||||||
nestingLevel?: number;
|
nestingLevel?: number;
|
||||||
onQuoteCancel?: () => void; // Used for composer.
|
onQuoteCancel?: () => void; // Used for composer.
|
||||||
|
@ -74,23 +73,35 @@ interface QuotedStatusProps {
|
||||||
export const QuotedStatus: React.FC<QuotedStatusProps> = ({
|
export const QuotedStatus: React.FC<QuotedStatusProps> = ({
|
||||||
quote,
|
quote,
|
||||||
contextType,
|
contextType,
|
||||||
|
parentQuotePostId,
|
||||||
nestingLevel = 1,
|
nestingLevel = 1,
|
||||||
variant = 'full',
|
variant = 'full',
|
||||||
onQuoteCancel,
|
onQuoteCancel,
|
||||||
}) => {
|
}) => {
|
||||||
const dispatch = useAppDispatch();
|
const dispatch = useAppDispatch();
|
||||||
|
const quoteState = useAppSelector((state) =>
|
||||||
|
parentQuotePostId
|
||||||
|
? state.statuses.getIn([parentQuotePostId, 'quote', 'state'])
|
||||||
|
: quote.get('state'),
|
||||||
|
);
|
||||||
|
|
||||||
const quotedStatusId = quote.get('quoted_status');
|
const quotedStatusId = quote.get('quoted_status');
|
||||||
const quoteState = quote.get('state');
|
|
||||||
const status = useAppSelector((state) =>
|
const status = useAppSelector((state) =>
|
||||||
quotedStatusId ? state.statuses.get(quotedStatusId) : undefined,
|
quotedStatusId ? state.statuses.get(quotedStatusId) : undefined,
|
||||||
);
|
);
|
||||||
const isQuoteLoaded = !!status && !status.get('isLoading');
|
|
||||||
|
const shouldLoadQuote = !status?.get('isLoading') && quoteState !== 'deleted';
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!isQuoteLoaded && quotedStatusId) {
|
if (shouldLoadQuote && quotedStatusId) {
|
||||||
dispatch(fetchStatus(quotedStatusId));
|
dispatch(
|
||||||
|
fetchStatus(quotedStatusId, {
|
||||||
|
parentQuotePostId,
|
||||||
|
alsoFetchContext: false,
|
||||||
|
}),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}, [isQuoteLoaded, quotedStatusId, dispatch]);
|
}, [shouldLoadQuote, quotedStatusId, parentQuotePostId, dispatch]);
|
||||||
|
|
||||||
// In order to find out whether the quoted post should be completely hidden
|
// In order to find out whether the quoted post should be completely hidden
|
||||||
// due to a matching filter, we run it through the selector used by `status_container`.
|
// due to a matching filter, we run it through the selector used by `status_container`.
|
||||||
|
@ -175,6 +186,7 @@ export const QuotedStatus: React.FC<QuotedStatusProps> = ({
|
||||||
{canRenderChildQuote && (
|
{canRenderChildQuote && (
|
||||||
<QuotedStatus
|
<QuotedStatus
|
||||||
quote={childQuote}
|
quote={childQuote}
|
||||||
|
parentQuotePostId={quotedStatusId}
|
||||||
contextType={contextType}
|
contextType={contextType}
|
||||||
variant={
|
variant={
|
||||||
nestingLevel === MAX_QUOTE_POSTS_NESTING_LEVEL ? 'link' : 'full'
|
nestingLevel === MAX_QUOTE_POSTS_NESTING_LEVEL ? 'link' : 'full'
|
||||||
|
@ -210,7 +222,11 @@ export const StatusQuoteManager = (props: StatusQuoteManagerProps) => {
|
||||||
if (quote) {
|
if (quote) {
|
||||||
return (
|
return (
|
||||||
<StatusContainer {...props}>
|
<StatusContainer {...props}>
|
||||||
<QuotedStatus quote={quote} contextType={props.contextType} />
|
<QuotedStatus
|
||||||
|
quote={quote}
|
||||||
|
parentQuotePostId={status?.get('id') as string}
|
||||||
|
contextType={props.contextType}
|
||||||
|
/>
|
||||||
</StatusContainer>
|
</StatusContainer>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,7 +32,7 @@ const Embed: React.FC<{ id: string }> = ({ id }) => {
|
||||||
const dispatchRenderSignal = useRenderSignal();
|
const dispatchRenderSignal = useRenderSignal();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
dispatch(fetchStatus(id, false, false));
|
dispatch(fetchStatus(id, { alsoFetchContext: false }));
|
||||||
}, [dispatch, id]);
|
}, [dispatch, id]);
|
||||||
|
|
||||||
const handleToggleHidden = useCallback(() => {
|
const handleToggleHidden = useCallback(() => {
|
||||||
|
|
|
@ -399,7 +399,10 @@ export const DetailedStatus: React.FC<{
|
||||||
{hashtagBar}
|
{hashtagBar}
|
||||||
|
|
||||||
{status.get('quote') && (
|
{status.get('quote') && (
|
||||||
<QuotedStatus quote={status.get('quote')} />
|
<QuotedStatus
|
||||||
|
quote={status.get('quote')}
|
||||||
|
parentQuotePostId={status.get('id')}
|
||||||
|
/>
|
||||||
)}
|
)}
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
|
|
@ -38,7 +38,7 @@ class FilterModal extends ImmutablePureComponent {
|
||||||
|
|
||||||
handleSuccess = () => {
|
handleSuccess = () => {
|
||||||
const { dispatch, statusId } = this.props;
|
const { dispatch, statusId } = this.props;
|
||||||
dispatch(fetchStatus(statusId, true));
|
dispatch(fetchStatus(statusId, {forceFetch: true}));
|
||||||
this.setState({ isSubmitting: false, isSubmitted: true, step: 'submitted' });
|
this.setState({ isSubmitting: false, isSubmitted: true, step: 'submitted' });
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -90,8 +90,15 @@ export default function statuses(state = initialState, action) {
|
||||||
switch(action.type) {
|
switch(action.type) {
|
||||||
case STATUS_FETCH_REQUEST:
|
case STATUS_FETCH_REQUEST:
|
||||||
return state.setIn([action.id, 'isLoading'], true);
|
return state.setIn([action.id, 'isLoading'], true);
|
||||||
case STATUS_FETCH_FAIL:
|
case STATUS_FETCH_FAIL: {
|
||||||
|
if (action.parentQuotePostId && action.error.status === 404) {
|
||||||
|
return state
|
||||||
|
.delete(action.id)
|
||||||
|
.setIn([action.parentQuotePostId, 'quote', 'state'], 'deleted')
|
||||||
|
} else {
|
||||||
return state.delete(action.id);
|
return state.delete(action.id);
|
||||||
|
}
|
||||||
|
}
|
||||||
case STATUS_IMPORT:
|
case STATUS_IMPORT:
|
||||||
return importStatus(state, action.status);
|
return importStatus(state, action.status);
|
||||||
case STATUSES_IMPORT:
|
case STATUSES_IMPORT:
|
||||||
|
|
Loading…
Reference in New Issue
Block a user