Merge commit 'f16f8b51b863d3fcadd17753004adbf8962ead01' into glitch-soc/merge-upstream

Conflicts:
- `yarn.lock`:
  Upstream updated a dependency adjacent to one that is only in glitch-soc.
  Updated as upstream did.
This commit is contained in:
Claire 2025-08-19 18:42:01 +02:00
commit 71cee3e472
39 changed files with 278 additions and 152 deletions

View File

@ -17,11 +17,11 @@ ARG RUBY_VERSION="3.4.5"
# # Node.js version to use in base image, change with [--build-arg NODE_MAJOR_VERSION="20"] # # Node.js version to use in base image, change with [--build-arg NODE_MAJOR_VERSION="20"]
# renovate: datasource=node-version depName=node # renovate: datasource=node-version depName=node
ARG NODE_MAJOR_VERSION="22" ARG NODE_MAJOR_VERSION="22"
# Debian image to use for base image, change with [--build-arg DEBIAN_VERSION="bookworm"] # Debian image to use for base image, change with [--build-arg DEBIAN_VERSION="trixie"]
ARG DEBIAN_VERSION="bookworm" ARG DEBIAN_VERSION="trixie"
# Node.js image to use for base image based on combined variables (ex: 20-bookworm-slim) # Node.js image to use for base image based on combined variables (ex: 20-trixie-slim)
FROM ${BASE_REGISTRY}/node:${NODE_MAJOR_VERSION}-${DEBIAN_VERSION}-slim AS node FROM ${BASE_REGISTRY}/node:${NODE_MAJOR_VERSION}-${DEBIAN_VERSION}-slim AS node
# Ruby image to use for base image based on combined variables (ex: 3.4.x-slim-bookworm) # Ruby image to use for base image based on combined variables (ex: 3.4.x-slim-trixie)
FROM ${BASE_REGISTRY}/ruby:${RUBY_VERSION}-slim-${DEBIAN_VERSION} AS ruby FROM ${BASE_REGISTRY}/ruby:${RUBY_VERSION}-slim-${DEBIAN_VERSION} AS ruby
# Resulting version string is vX.X.X-MASTODON_VERSION_PRERELEASE+MASTODON_VERSION_METADATA # Resulting version string is vX.X.X-MASTODON_VERSION_PRERELEASE+MASTODON_VERSION_METADATA
@ -96,9 +96,6 @@ RUN \
# Set /opt/mastodon as working directory # Set /opt/mastodon as working directory
WORKDIR /opt/mastodon WORKDIR /opt/mastodon
# Add backport repository for some specific packages where we need the latest version
RUN echo 'deb http://deb.debian.org/debian bookworm-backports main' >> /etc/apt/sources.list
# hadolint ignore=DL3008,DL3005 # hadolint ignore=DL3008,DL3005
RUN \ RUN \
# Mount Apt cache and lib directories from Docker buildx caches # Mount Apt cache and lib directories from Docker buildx caches
@ -161,11 +158,11 @@ RUN \
libexif-dev \ libexif-dev \
libexpat1-dev \ libexpat1-dev \
libgirepository1.0-dev \ libgirepository1.0-dev \
libheif-dev/bookworm-backports \ libheif-dev \
libhwy-dev \
libimagequant-dev \ libimagequant-dev \
libjpeg62-turbo-dev \ libjpeg62-turbo-dev \
liblcms2-dev \ liblcms2-dev \
liborc-dev \
libspng-dev \ libspng-dev \
libtiff-dev \ libtiff-dev \
libwebp-dev \ libwebp-dev \
@ -209,7 +206,7 @@ FROM build AS ffmpeg
# ffmpeg version to compile, change with [--build-arg FFMPEG_VERSION="7.0.x"] # ffmpeg version to compile, change with [--build-arg FFMPEG_VERSION="7.0.x"]
# renovate: datasource=repology depName=ffmpeg packageName=openpkg_current/ffmpeg # renovate: datasource=repology depName=ffmpeg packageName=openpkg_current/ffmpeg
ARG FFMPEG_VERSION=7.1 ARG FFMPEG_VERSION=7.1.1
# ffmpeg download URL, change with [--build-arg FFMPEG_URL="https://ffmpeg.org/releases"] # ffmpeg download URL, change with [--build-arg FFMPEG_URL="https://ffmpeg.org/releases"]
ARG FFMPEG_URL=https://ffmpeg.org/releases ARG FFMPEG_URL=https://ffmpeg.org/releases
@ -327,28 +324,28 @@ RUN \
# Apt update install non-dev versions of necessary components # Apt update install non-dev versions of necessary components
apt-get install -y --no-install-recommends \ apt-get install -y --no-install-recommends \
libexpat1 \ libexpat1 \
libglib2.0-0 \ libglib2.0-0t64 \
libicu72 \ libicu76 \
libidn12 \ libidn12 \
libpq5 \ libpq5 \
libreadline8 \ libreadline8t64 \
libssl3 \ libssl3t64 \
libyaml-0-2 \ libyaml-0-2 \
# libvips components # libvips components
libcgif0 \ libcgif0 \
libexif12 \ libexif12 \
libheif1/bookworm-backports \ libheif1 \
libhwy1t64 \
libimagequant0 \ libimagequant0 \
libjpeg62-turbo \ libjpeg62-turbo \
liblcms2-2 \ liblcms2-2 \
liborc-0.4-0 \
libspng0 \ libspng0 \
libtiff6 \ libtiff6 \
libwebp7 \ libwebp7 \
libwebpdemux2 \ libwebpdemux2 \
libwebpmux3 \ libwebpmux3 \
# ffmpeg components # ffmpeg components
libdav1d6 \ libdav1d7 \
libmp3lame0 \ libmp3lame0 \
libopencore-amrnb0 \ libopencore-amrnb0 \
libopencore-amrwb0 \ libopencore-amrwb0 \
@ -358,9 +355,9 @@ RUN \
libvorbis0a \ libvorbis0a \
libvorbisenc2 \ libvorbisenc2 \
libvorbisfile3 \ libvorbisfile3 \
libvpx7 \ libvpx9 \
libx264-164 \ libx264-164 \
libx265-199 \ libx265-215 \
; ;
# Copy Mastodon sources into final layer # Copy Mastodon sources into final layer

View File

@ -102,7 +102,7 @@ gem 'rdf-normalize', '~> 0.5'
gem 'prometheus_exporter', '~> 2.2', require: false gem 'prometheus_exporter', '~> 2.2', require: false
gem 'opentelemetry-api', '~> 1.5.0' gem 'opentelemetry-api', '~> 1.6.0'
group :opentelemetry do group :opentelemetry do
gem 'opentelemetry-exporter-otlp', '~> 0.30.0', require: false gem 'opentelemetry-exporter-otlp', '~> 0.30.0', require: false

View File

@ -497,7 +497,7 @@ GEM
openssl (3.3.0) openssl (3.3.0)
openssl-signature_algorithm (1.3.0) openssl-signature_algorithm (1.3.0)
openssl (> 2.0) openssl (> 2.0)
opentelemetry-api (1.5.0) opentelemetry-api (1.6.0)
opentelemetry-common (0.22.0) opentelemetry-common (0.22.0)
opentelemetry-api (~> 1.0) opentelemetry-api (~> 1.0)
opentelemetry-exporter-otlp (0.30.0) opentelemetry-exporter-otlp (0.30.0)
@ -589,7 +589,7 @@ GEM
opentelemetry-instrumentation-base (~> 0.23.0) opentelemetry-instrumentation-base (~> 0.23.0)
opentelemetry-registry (0.4.0) opentelemetry-registry (0.4.0)
opentelemetry-api (~> 1.1) opentelemetry-api (~> 1.1)
opentelemetry-sdk (1.8.0) opentelemetry-sdk (1.8.1)
opentelemetry-api (~> 1.1) opentelemetry-api (~> 1.1)
opentelemetry-common (~> 0.20) opentelemetry-common (~> 0.20)
opentelemetry-registry (~> 0.2) opentelemetry-registry (~> 0.2)
@ -625,7 +625,7 @@ GEM
premailer (~> 1.7, >= 1.7.9) premailer (~> 1.7, >= 1.7.9)
prettyprint (0.2.0) prettyprint (0.2.0)
prism (1.4.0) prism (1.4.0)
prometheus_exporter (2.2.0) prometheus_exporter (2.3.0)
webrick webrick
propshaft (1.2.1) propshaft (1.2.1)
actionpack (>= 7.0.0) actionpack (>= 7.0.0)
@ -1025,7 +1025,7 @@ DEPENDENCIES
omniauth-rails_csrf_protection (~> 1.0) omniauth-rails_csrf_protection (~> 1.0)
omniauth-saml (~> 2.0) omniauth-saml (~> 2.0)
omniauth_openid_connect (~> 0.8.0) omniauth_openid_connect (~> 0.8.0)
opentelemetry-api (~> 1.5.0) opentelemetry-api (~> 1.6.0)
opentelemetry-exporter-otlp (~> 0.30.0) opentelemetry-exporter-otlp (~> 0.30.0)
opentelemetry-instrumentation-active_job (~> 0.8.0) opentelemetry-instrumentation-active_job (~> 0.8.0)
opentelemetry-instrumentation-active_model_serializers (~> 0.22.0) opentelemetry-instrumentation-active_model_serializers (~> 0.22.0)

View File

@ -53,6 +53,7 @@ const AutosuggestTextarea = forwardRef(({
onFocus, onFocus,
autoFocus = true, autoFocus = true,
lang, lang,
className,
}, textareaRef) => { }, textareaRef) => {
const [suggestionsHidden, setSuggestionsHidden] = useState(true); const [suggestionsHidden, setSuggestionsHidden] = useState(true);
@ -192,7 +193,7 @@ const AutosuggestTextarea = forwardRef(({
}; };
return ( return (
<div className='autosuggest-textarea'> <div className={classNames('autosuggest-textarea', className)}>
<Textarea <Textarea
ref={textareaRef} ref={textareaRef}
className='autosuggest-textarea__textarea' className='autosuggest-textarea__textarea'

View File

@ -10,6 +10,7 @@ import ImmutablePureComponent from 'react-immutable-pure-component';
import AlternateEmailIcon from '@/material-icons/400-24px/alternate_email.svg?react'; import AlternateEmailIcon from '@/material-icons/400-24px/alternate_email.svg?react';
import RepeatIcon from '@/material-icons/400-24px/repeat.svg?react'; import RepeatIcon from '@/material-icons/400-24px/repeat.svg?react';
import CancelFillIcon from '@/material-icons/400-24px/cancel-fill.svg?react';
import { Hotkeys } from 'mastodon/components/hotkeys'; import { Hotkeys } from 'mastodon/components/hotkeys';
import { ContentWarning } from 'mastodon/components/content_warning'; import { ContentWarning } from 'mastodon/components/content_warning';
import { FilterWarning } from 'mastodon/components/filter_warning'; import { FilterWarning } from 'mastodon/components/filter_warning';
@ -34,6 +35,8 @@ import StatusActionBar from './status_action_bar';
import StatusContent from './status_content'; import StatusContent from './status_content';
import { StatusThreadLabel } from './status_thread_label'; import { StatusThreadLabel } from './status_thread_label';
import { VisibilityIcon } from './visibility_icon'; import { VisibilityIcon } from './visibility_icon';
import { IconButton } from './icon_button';
const domParser = new DOMParser(); const domParser = new DOMParser();
export const textForScreenReader = (intl, status, rebloggedByText = false) => { export const textForScreenReader = (intl, status, rebloggedByText = false) => {
@ -75,6 +78,7 @@ const messages = defineMessages({
private_short: { id: 'privacy.private.short', defaultMessage: 'Followers' }, private_short: { id: 'privacy.private.short', defaultMessage: 'Followers' },
direct_short: { id: 'privacy.direct.short', defaultMessage: 'Specific people' }, direct_short: { id: 'privacy.direct.short', defaultMessage: 'Specific people' },
edited: { id: 'status.edited', defaultMessage: 'Edited {date}' }, edited: { id: 'status.edited', defaultMessage: 'Edited {date}' },
quote_cancel: { id: 'status.quote.cancel', defaultMessage: 'Cancel quote' },
}); });
class Status extends ImmutablePureComponent { class Status extends ImmutablePureComponent {
@ -126,6 +130,7 @@ class Status extends ImmutablePureComponent {
inUse: PropTypes.bool, inUse: PropTypes.bool,
available: PropTypes.bool, available: PropTypes.bool,
}), }),
contextType: PropTypes.string,
...WithOptionalRouterPropTypes, ...WithOptionalRouterPropTypes,
}; };
@ -359,6 +364,10 @@ class Status extends ImmutablePureComponent {
this.setState(state => ({ ...state, showDespiteFilter: !state.showDespiteFilter })); this.setState(state => ({ ...state, showDespiteFilter: !state.showDespiteFilter }));
}; };
handleQuoteCancel = () => {
this.props.onQuoteCancel?.();
}
_properStatus () { _properStatus () {
const { status } = this.props; const { status } = this.props;
@ -573,6 +582,16 @@ class Status extends ImmutablePureComponent {
<DisplayName account={status.get('account')} /> <DisplayName account={status.get('account')} />
</Link> </Link>
{this.props.contextType === 'compose' && isQuotedPost && (
<IconButton
onClick={this.handleQuoteCancel}
className='status__quote-cancel'
title={intl.formatMessage(messages.quote_cancel)}
icon="cancel-fill"
iconComponent={CancelFillIcon}
/>
)}
</div> </div>
{matchedFilters && <FilterWarning title={matchedFilters.join(', ')} expanded={this.state.showDespiteFilter} onClick={this.handleFilterToggle} />} {matchedFilters && <FilterWarning title={matchedFilters.join(', ')} expanded={this.state.showDespiteFilter} onClick={this.handleFilterToggle} />}

View File

@ -44,6 +44,7 @@ import {
import Status from '../components/status'; import Status from '../components/status';
import { deleteModal } from '../initial_state'; import { deleteModal } from '../initial_state';
import { makeGetStatus, makeGetPictureInPicture } from '../selectors'; import { makeGetStatus, makeGetPictureInPicture } from '../selectors';
import { quoteComposeCancel } from '../actions/compose_typed';
const makeMapStateToProps = () => { const makeMapStateToProps = () => {
const getStatus = makeGetStatus(); const getStatus = makeGetStatus();
@ -111,6 +112,12 @@ 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']) }}));
}, },

View File

@ -31,6 +31,7 @@ import { PollForm } from "./poll_form";
import { ReplyIndicator } from './reply_indicator'; import { ReplyIndicator } from './reply_indicator';
import { UploadForm } from './upload_form'; import { UploadForm } from './upload_form';
import { Warning } from './warning'; import { Warning } from './warning';
import { ComposeQuotedStatus } from './quoted_post';
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';
@ -258,6 +259,11 @@ class ComposeForm extends ImmutablePureComponent {
<div className={classNames('compose-form__highlightable', { active: highlighted })} ref={this.setRef}> <div className={classNames('compose-form__highlightable', { active: highlighted })} ref={this.setRef}>
<EditIndicator /> <EditIndicator />
<div className='compose-form__dropdowns'>
<PrivacyDropdownContainer disabled={this.props.isEditing} />
<LanguageDropdown />
</div>
{this.props.spoiler && ( {this.props.spoiler && (
<div className='spoiler-input'> <div className='spoiler-input'>
<div className='spoiler-input__border' /> <div className='spoiler-input__border' />
@ -284,11 +290,6 @@ class ComposeForm extends ImmutablePureComponent {
</div> </div>
)} )}
<div className='compose-form__dropdowns'>
<PrivacyDropdownContainer disabled={this.props.isEditing} />
<LanguageDropdown />
</div>
<AutosuggestTextarea <AutosuggestTextarea
ref={this.textareaRef} ref={this.textareaRef}
placeholder={intl.formatMessage(messages.placeholder)} placeholder={intl.formatMessage(messages.placeholder)}
@ -304,10 +305,12 @@ class ComposeForm extends ImmutablePureComponent {
onPaste={onPaste} onPaste={onPaste}
autoFocus={autoFocus} autoFocus={autoFocus}
lang={this.props.lang} lang={this.props.lang}
className='compose-form__input'
/> />
<UploadForm /> <UploadForm />
<PollForm /> <PollForm />
<ComposeQuotedStatus />
<div className='compose-form__footer'> <div className='compose-form__footer'>
<div className='compose-form__actions'> <div className='compose-form__actions'>

View File

@ -0,0 +1,27 @@
import { useMemo } from 'react';
import type { FC } from 'react';
import { Map } from 'immutable';
import { QuotedStatus } from '@/mastodon/components/status_quoted';
import { useAppSelector } from '@/mastodon/store';
export const ComposeQuotedStatus: FC = () => {
const quotedStatusId = useAppSelector(
(state) => state.compose.get('quoted_status_id') as string | null,
);
const quote = useMemo(
() =>
quotedStatusId
? Map<'state' | 'quoted_status', string>([
['state', 'accepted'],
['quoted_status', quotedStatusId],
])
: null,
[quotedStatusId],
);
if (!quote) {
return null;
}
return <QuotedStatus quote={quote} contextType='compose' />;
};

View File

@ -3,10 +3,16 @@ import { connect } from 'react-redux';
import { addPoll, removePoll } from '../../../actions/compose'; import { addPoll, removePoll } from '../../../actions/compose';
import PollButton from '../components/poll_button'; import PollButton from '../components/poll_button';
const mapStateToProps = state => ({ const mapStateToProps = state => {
disabled: state.getIn(['compose', 'is_uploading']) || (state.getIn(['compose', 'media_attachments']).size > 0), const readyAttachmentsSize = state.compose.get('media_attachments').size ?? 0;
active: state.getIn(['compose', 'poll']) !== null, const hasAttachments = readyAttachmentsSize > 0 || !!state.compose.get('is_uploading');
}); const hasQuote = !!state.compose.get('quoted_status_id');
return ({
disabled: hasAttachments || hasQuote,
active: state.getIn(['compose', 'poll']) !== null,
});
};
const mapDispatchToProps = dispatch => ({ const mapDispatchToProps = dispatch => ({

View File

@ -11,9 +11,10 @@ const mapStateToProps = state => {
const attachmentsSize = readyAttachmentsSize + pendingAttachmentsSize; const attachmentsSize = readyAttachmentsSize + pendingAttachmentsSize;
const isOverLimit = attachmentsSize > state.getIn(['server', 'server', 'configuration', 'statuses', 'max_media_attachments'])-1; const isOverLimit = attachmentsSize > state.getIn(['server', 'server', 'configuration', 'statuses', 'max_media_attachments'])-1;
const hasVideoOrAudio = state.getIn(['compose', 'media_attachments']).some(m => ['video', 'audio'].includes(m.get('type'))); const hasVideoOrAudio = state.getIn(['compose', 'media_attachments']).some(m => ['video', 'audio'].includes(m.get('type')));
const hasQuote = !!state.compose.get('quoted_status_id');
return { return {
disabled: isPoll || isUploading || isOverLimit || hasVideoOrAudio, disabled: isPoll || isUploading || isOverLimit || hasVideoOrAudio || hasQuote,
resetFileKey: state.getIn(['compose', 'resetFileKey']), resetFileKey: state.getIn(['compose', 'resetFileKey']),
}; };
}; };

View File

@ -864,6 +864,7 @@
"status.mute": "@{name} - səssizə al", "status.mute": "@{name} - səssizə al",
"status.mute_conversation": "Danışığın səsini kəs", "status.mute_conversation": "Danışığın səsini kəs",
"status.open": "Bu göndərişi genişləndir", "status.open": "Bu göndərişi genişləndir",
"status.pin": "Profildə sanc",
"status.quote_error.filtered": "Bəzi filtrlərinizə görə gizlidir", "status.quote_error.filtered": "Bəzi filtrlərinizə görə gizlidir",
"status.quote_error.not_available": "Göndəriş əlçatmazdır", "status.quote_error.not_available": "Göndəriş əlçatmazdır",
"status.quote_error.pending_approval": "Göndəriş gözləmədədir", "status.quote_error.pending_approval": "Göndəriş gözləmədədir",
@ -893,6 +894,7 @@
"status.translated_from_with": "{provider} ilə {lang} dilindən tərcümə edilib", "status.translated_from_with": "{provider} ilə {lang} dilindən tərcümə edilib",
"status.uncached_media_warning": "Önizləmə mövcud deyil", "status.uncached_media_warning": "Önizləmə mövcud deyil",
"status.unmute_conversation": "Danışığın səsini aç", "status.unmute_conversation": "Danışığın səsini aç",
"status.unpin": "Profil sancağı götür",
"subscribed_languages.lead": "Dəyişiklikdən sonra əsas ekran və siyahı zaman xəttinizdə yalnız seçdiyiniz dillərdəki göndərişlər görünəcək. Bütün dillərdə göndəriş almaq üçün heç birini seçməyin.", "subscribed_languages.lead": "Dəyişiklikdən sonra əsas ekran və siyahı zaman xəttinizdə yalnız seçdiyiniz dillərdəki göndərişlər görünəcək. Bütün dillərdə göndəriş almaq üçün heç birini seçməyin.",
"subscribed_languages.save": "Dəyişiklikləri saxla", "subscribed_languages.save": "Dəyişiklikləri saxla",
"subscribed_languages.target": "{target} üçün abunə olunmuş dilləri dəyişdir", "subscribed_languages.target": "{target} üçün abunə olunmuş dilləri dəyişdir",

View File

@ -879,6 +879,7 @@
"status.mute_conversation": "Silencia la conversa", "status.mute_conversation": "Silencia la conversa",
"status.open": "Amplia el tut", "status.open": "Amplia el tut",
"status.pin": "Fixa en el perfil", "status.pin": "Fixa en el perfil",
"status.quote.cancel": "Canceŀlar la citació",
"status.quote_error.filtered": "No es mostra a causa d'un dels vostres filtres", "status.quote_error.filtered": "No es mostra a causa d'un dels vostres filtres",
"status.quote_error.not_available": "Publicació no disponible", "status.quote_error.not_available": "Publicació no disponible",
"status.quote_error.pending_approval": "Publicació pendent", "status.quote_error.pending_approval": "Publicació pendent",

View File

@ -63,7 +63,7 @@
"account.mute_short": "Stummschalten", "account.mute_short": "Stummschalten",
"account.muted": "Stummgeschaltet", "account.muted": "Stummgeschaltet",
"account.muting": "Stummgeschaltet", "account.muting": "Stummgeschaltet",
"account.mutual": "Ihr folgt euch", "account.mutual": "Ihr folgt einander",
"account.no_bio": "Keine Beschreibung verfügbar.", "account.no_bio": "Keine Beschreibung verfügbar.",
"account.open_original_page": "Ursprüngliche Seite öffnen", "account.open_original_page": "Ursprüngliche Seite öffnen",
"account.posts": "Beiträge", "account.posts": "Beiträge",
@ -880,6 +880,7 @@
"status.mute_conversation": "Unterhaltung stummschalten", "status.mute_conversation": "Unterhaltung stummschalten",
"status.open": "Beitrag öffnen", "status.open": "Beitrag öffnen",
"status.pin": "Im Profil anheften", "status.pin": "Im Profil anheften",
"status.quote.cancel": "Zitat abbrechen",
"status.quote_error.filtered": "Ausgeblendet wegen eines deiner Filter", "status.quote_error.filtered": "Ausgeblendet wegen eines deiner Filter",
"status.quote_error.not_available": "Beitrag nicht verfügbar", "status.quote_error.not_available": "Beitrag nicht verfügbar",
"status.quote_error.pending_approval": "Beitragsveröffentlichung ausstehend", "status.quote_error.pending_approval": "Beitragsveröffentlichung ausstehend",

View File

@ -880,6 +880,7 @@
"status.mute_conversation": "Mute conversation", "status.mute_conversation": "Mute conversation",
"status.open": "Expand this post", "status.open": "Expand this post",
"status.pin": "Pin on profile", "status.pin": "Pin on profile",
"status.quote.cancel": "Cancel quote",
"status.quote_error.filtered": "Hidden due to one of your filters", "status.quote_error.filtered": "Hidden due to one of your filters",
"status.quote_error.not_available": "Post unavailable", "status.quote_error.not_available": "Post unavailable",
"status.quote_error.pending_approval": "Post pending", "status.quote_error.pending_approval": "Post pending",

View File

@ -880,6 +880,7 @@
"status.mute_conversation": "Silenciar conversación", "status.mute_conversation": "Silenciar conversación",
"status.open": "Expandir este mensaje", "status.open": "Expandir este mensaje",
"status.pin": "Fijar en el perfil", "status.pin": "Fijar en el perfil",
"status.quote.cancel": "Cancelar cita",
"status.quote_error.filtered": "Oculto debido a uno de tus filtros", "status.quote_error.filtered": "Oculto debido a uno de tus filtros",
"status.quote_error.not_available": "Mensaje no disponible", "status.quote_error.not_available": "Mensaje no disponible",
"status.quote_error.pending_approval": "Mensaje pendiente", "status.quote_error.pending_approval": "Mensaje pendiente",

View File

@ -880,6 +880,7 @@
"status.mute_conversation": "Silenciar conversación", "status.mute_conversation": "Silenciar conversación",
"status.open": "Expandir estado", "status.open": "Expandir estado",
"status.pin": "Fijar", "status.pin": "Fijar",
"status.quote.cancel": "Cancelar cita",
"status.quote_error.filtered": "Oculto debido a uno de tus filtros", "status.quote_error.filtered": "Oculto debido a uno de tus filtros",
"status.quote_error.not_available": "Publicación no disponible", "status.quote_error.not_available": "Publicación no disponible",
"status.quote_error.pending_approval": "Publicación pendiente", "status.quote_error.pending_approval": "Publicación pendiente",

View File

@ -880,6 +880,7 @@
"status.mute_conversation": "Silenciar conversación", "status.mute_conversation": "Silenciar conversación",
"status.open": "Expandir publicación", "status.open": "Expandir publicación",
"status.pin": "Fijar", "status.pin": "Fijar",
"status.quote.cancel": "Cancelar cita",
"status.quote_error.filtered": "Oculto debido a uno de tus filtros", "status.quote_error.filtered": "Oculto debido a uno de tus filtros",
"status.quote_error.not_available": "Publicación no disponible", "status.quote_error.not_available": "Publicación no disponible",
"status.quote_error.pending_approval": "Publicación pendiente", "status.quote_error.pending_approval": "Publicación pendiente",

View File

@ -880,6 +880,7 @@
"status.mute_conversation": "Mykistä keskustelu", "status.mute_conversation": "Mykistä keskustelu",
"status.open": "Laajenna julkaisu", "status.open": "Laajenna julkaisu",
"status.pin": "Kiinnitä profiiliin", "status.pin": "Kiinnitä profiiliin",
"status.quote.cancel": "Peruuta lainaus",
"status.quote_error.filtered": "Piilotettu jonkin asettamasi suodattimen takia", "status.quote_error.filtered": "Piilotettu jonkin asettamasi suodattimen takia",
"status.quote_error.not_available": "Julkaisu ei saatavilla", "status.quote_error.not_available": "Julkaisu ei saatavilla",
"status.quote_error.pending_approval": "Julkaisu odottaa", "status.quote_error.pending_approval": "Julkaisu odottaa",

View File

@ -880,6 +880,7 @@
"status.mute_conversation": "Doyv samrøðu", "status.mute_conversation": "Doyv samrøðu",
"status.open": "Víðka henda postin", "status.open": "Víðka henda postin",
"status.pin": "Ger fastan í vangan", "status.pin": "Ger fastan í vangan",
"status.quote.cancel": "Ógilda sitat",
"status.quote_error.filtered": "Eitt av tínum filtrum fjalir hetta", "status.quote_error.filtered": "Eitt av tínum filtrum fjalir hetta",
"status.quote_error.not_available": "Postur ikki tøkur", "status.quote_error.not_available": "Postur ikki tøkur",
"status.quote_error.pending_approval": "Postur bíðar", "status.quote_error.pending_approval": "Postur bíðar",

View File

@ -880,6 +880,7 @@
"status.mute_conversation": "Silenciar conversa", "status.mute_conversation": "Silenciar conversa",
"status.open": "Estender esta publicación", "status.open": "Estender esta publicación",
"status.pin": "Fixar no perfil", "status.pin": "Fixar no perfil",
"status.quote.cancel": "Cancelar a cita",
"status.quote_error.filtered": "Oculto debido a un dos teus filtros", "status.quote_error.filtered": "Oculto debido a un dos teus filtros",
"status.quote_error.not_available": "Publicación non dispoñible", "status.quote_error.not_available": "Publicación non dispoñible",
"status.quote_error.pending_approval": "Publicación pendente", "status.quote_error.pending_approval": "Publicación pendente",

View File

@ -880,6 +880,7 @@
"status.mute_conversation": "השתקת שיחה", "status.mute_conversation": "השתקת שיחה",
"status.open": "הרחבת הודעה זו", "status.open": "הרחבת הודעה זו",
"status.pin": "הצמדה לפרופיל שלי", "status.pin": "הצמדה לפרופיל שלי",
"status.quote.cancel": "ביטול הודעת ציטוט",
"status.quote_error.filtered": "מוסתר בהתאם לסננים שלך", "status.quote_error.filtered": "מוסתר בהתאם לסננים שלך",
"status.quote_error.not_available": "ההודעה לא זמינה", "status.quote_error.not_available": "ההודעה לא זמינה",
"status.quote_error.pending_approval": "ההודעה בהמתנה לאישור", "status.quote_error.pending_approval": "ההודעה בהמתנה לאישור",

View File

@ -880,6 +880,7 @@
"status.mute_conversation": "Þagga niður í samtali", "status.mute_conversation": "Þagga niður í samtali",
"status.open": "Opna þessa færslu", "status.open": "Opna þessa færslu",
"status.pin": "Festa á notandasnið", "status.pin": "Festa á notandasnið",
"status.quote.cancel": "Hætta við tilvitnun",
"status.quote_error.filtered": "Falið vegna einnar síu sem er virk", "status.quote_error.filtered": "Falið vegna einnar síu sem er virk",
"status.quote_error.not_available": "Færsla ekki tiltæk", "status.quote_error.not_available": "Færsla ekki tiltæk",
"status.quote_error.pending_approval": "Færsla í bið", "status.quote_error.pending_approval": "Færsla í bið",
@ -964,6 +965,11 @@
"video.volume_up": "Hækka hljóðstyrk", "video.volume_up": "Hækka hljóðstyrk",
"visibility_modal.button_title": "Stilla sýnileika", "visibility_modal.button_title": "Stilla sýnileika",
"visibility_modal.header": "Sýnileiki og gagnvirkni", "visibility_modal.header": "Sýnileiki og gagnvirkni",
"visibility_modal.helper.direct_quoting": "Ekki er hægt að vitna í einkaspjall.",
"visibility_modal.helper.privacy_editing": "Ekki er hægt að breyta sýnileika birtra færslna.",
"visibility_modal.helper.private_quoting": "Ekki er hægt að vitna í færslur sem eingöngu eru til fylgjenda.",
"visibility_modal.helper.unlisted_quoting": "Þegar fólk vitnar í þig verða færslurnar þeirr einnig faldar á vinsældatímalínum.",
"visibility_modal.instructions": "Stýrðu hverjir geta átt við þessa færslu. Víðværar stillingar finnast undir <link>Kjörstillingar > Annað</link>.",
"visibility_modal.privacy_label": "Persónuvernd", "visibility_modal.privacy_label": "Persónuvernd",
"visibility_modal.quote_followers": "Einungis fylgjendur", "visibility_modal.quote_followers": "Einungis fylgjendur",
"visibility_modal.quote_label": "Breyttu því hver getur tilvitnað", "visibility_modal.quote_label": "Breyttu því hver getur tilvitnað",

View File

@ -603,6 +603,7 @@
"notification.label.mention": "Упоминание", "notification.label.mention": "Упоминание",
"notification.label.private_mention": "Личное упоминание", "notification.label.private_mention": "Личное упоминание",
"notification.label.private_reply": "Приватный ответ", "notification.label.private_reply": "Приватный ответ",
"notification.label.quote": "{name} процитировал(а) ваш пост",
"notification.label.reply": "Ответ", "notification.label.reply": "Ответ",
"notification.mention": "Упоминание", "notification.mention": "Упоминание",
"notification.mentioned_you": "{name} упомянул(а) вас", "notification.mentioned_you": "{name} упомянул(а) вас",
@ -660,6 +661,7 @@
"notifications.column_settings.mention": "Вас упомянули в посте:", "notifications.column_settings.mention": "Вас упомянули в посте:",
"notifications.column_settings.poll": "Опрос, в котором вы приняли участие, завершился:", "notifications.column_settings.poll": "Опрос, в котором вы приняли участие, завершился:",
"notifications.column_settings.push": "Push-уведомления", "notifications.column_settings.push": "Push-уведомления",
"notifications.column_settings.quote": "Ваш пост процитировали:",
"notifications.column_settings.reblog": "Ваш пост продвинули:", "notifications.column_settings.reblog": "Ваш пост продвинули:",
"notifications.column_settings.show": "Отображать в списке", "notifications.column_settings.show": "Отображать в списке",
"notifications.column_settings.sound": "Проигрывать звук", "notifications.column_settings.sound": "Проигрывать звук",
@ -851,7 +853,7 @@
"status.cancel_reblog_private": "Отменить продвижение", "status.cancel_reblog_private": "Отменить продвижение",
"status.cannot_reblog": "Этот пост не может быть продвинут", "status.cannot_reblog": "Этот пост не может быть продвинут",
"status.context.load_new_replies": "Доступны новые ответы", "status.context.load_new_replies": "Доступны новые ответы",
"status.context.loading": "Проверяем, есть ли еще ответы", "status.context.loading": "Проверяем, есть ли ещё ответы",
"status.continued_thread": "Продолжение предыдущего поста", "status.continued_thread": "Продолжение предыдущего поста",
"status.copy": "Скопировать ссылку на пост", "status.copy": "Скопировать ссылку на пост",
"status.delete": "Удалить", "status.delete": "Удалить",
@ -879,6 +881,8 @@
"status.pin": "Закрепить в профиле", "status.pin": "Закрепить в профиле",
"status.quote_error.filtered": "Скрыто одним из ваших фильтров", "status.quote_error.filtered": "Скрыто одним из ваших фильтров",
"status.quote_error.not_available": "Пост недоступен", "status.quote_error.not_available": "Пост недоступен",
"status.quote_error.pending_approval": "Пост ожидает подтверждения",
"status.quote_error.pending_approval_popout.title": "Цитирование ещё не подтверждено? Не беспокойтесь",
"status.read_more": "Читать далее", "status.read_more": "Читать далее",
"status.reblog": "Продвинуть", "status.reblog": "Продвинуть",
"status.reblog_private": "Продвинуть для своей аудитории", "status.reblog_private": "Продвинуть для своей аудитории",

View File

@ -880,6 +880,7 @@
"status.mute_conversation": "Tắt thông báo", "status.mute_conversation": "Tắt thông báo",
"status.open": "Mở tút", "status.open": "Mở tút",
"status.pin": "Ghim lên hồ sơ", "status.pin": "Ghim lên hồ sơ",
"status.quote.cancel": "Bỏ trích dẫn",
"status.quote_error.filtered": "Bị ẩn vì một bộ lọc của bạn", "status.quote_error.filtered": "Bị ẩn vì một bộ lọc của bạn",
"status.quote_error.not_available": "Tút không khả dụng", "status.quote_error.not_available": "Tút không khả dụng",
"status.quote_error.pending_approval": "Tút đang chờ duyệt", "status.quote_error.pending_approval": "Tút đang chờ duyệt",

View File

@ -240,6 +240,8 @@
"confirmations.remove_from_followers.confirm": "移除关注者", "confirmations.remove_from_followers.confirm": "移除关注者",
"confirmations.remove_from_followers.message": "{name} 将停止关注您。您确定要继续吗?", "confirmations.remove_from_followers.message": "{name} 将停止关注您。您确定要继续吗?",
"confirmations.remove_from_followers.title": "移除关注者?", "confirmations.remove_from_followers.title": "移除关注者?",
"confirmations.revoke_quote.confirm": "移除嘟文",
"confirmations.revoke_quote.title": "移除嘟文?",
"confirmations.unfollow.confirm": "取消关注", "confirmations.unfollow.confirm": "取消关注",
"confirmations.unfollow.message": "你确定要取消关注 {name} 吗?", "confirmations.unfollow.message": "你确定要取消关注 {name} 吗?",
"confirmations.unfollow.title": "确定要取消关注用户?", "confirmations.unfollow.title": "确定要取消关注用户?",
@ -491,6 +493,7 @@
"keyboard_shortcuts.translate": "翻译嘟文", "keyboard_shortcuts.translate": "翻译嘟文",
"keyboard_shortcuts.unfocus": "取消输入/搜索", "keyboard_shortcuts.unfocus": "取消输入/搜索",
"keyboard_shortcuts.up": "在列表中让光标上移", "keyboard_shortcuts.up": "在列表中让光标上移",
"learn_more_link.got_it": "明白了",
"lightbox.close": "关闭", "lightbox.close": "关闭",
"lightbox.next": "下一个", "lightbox.next": "下一个",
"lightbox.previous": "上一个", "lightbox.previous": "上一个",
@ -861,6 +864,7 @@
"status.mute_conversation": "关闭此对话的通知", "status.mute_conversation": "关闭此对话的通知",
"status.open": "展开嘟文", "status.open": "展开嘟文",
"status.pin": "在个人资料页面置顶", "status.pin": "在个人资料页面置顶",
"status.quote.cancel": "取消引用",
"status.quote_error.filtered": "已根据你的筛选器过滤", "status.quote_error.filtered": "已根据你的筛选器过滤",
"status.read_more": "查看更多", "status.read_more": "查看更多",
"status.reblog": "转嘟", "status.reblog": "转嘟",

View File

@ -880,6 +880,7 @@
"status.mute_conversation": "靜音對話", "status.mute_conversation": "靜音對話",
"status.open": "展開此嘟文", "status.open": "展開此嘟文",
"status.pin": "釘選至個人檔案頁面", "status.pin": "釘選至個人檔案頁面",
"status.quote.cancel": "取消引用嘟文",
"status.quote_error.filtered": "由於您的過濾器,該嘟文被隱藏", "status.quote_error.filtered": "由於您的過濾器,該嘟文被隱藏",
"status.quote_error.not_available": "無法取得該嘟文", "status.quote_error.not_available": "無法取得該嘟文",
"status.quote_error.pending_approval": "嘟文正在發送中", "status.quote_error.pending_approval": "嘟文正在發送中",

View File

@ -331,8 +331,16 @@ export const composeReducer = (state = initialState, action) => {
return state.set('is_changing_upload', false); return state.set('is_changing_upload', false);
} else if (quoteComposeByStatus.match(action)) { } else if (quoteComposeByStatus.match(action)) {
const status = action.payload; const status = action.payload;
if (status.getIn(['quote_approval', 'current_user']) === 'automatic') { if (
return state.set('quoted_status_id', status.get('id')); status.getIn(['quote_approval', 'current_user']) === 'automatic' &&
state.get('media_attachments').size === 0 &&
!state.get('is_uploading') &&
!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);

View File

@ -15,7 +15,7 @@ export const getFilters = createSelector(
(_, { contextType }: { contextType: string }) => contextType, (_, { contextType }: { contextType: string }) => contextType,
], ],
(filters, contextType) => { (filters, contextType) => {
if (!contextType) { if (!contextType || contextType === 'compose') {
return null; return null;
} }

View File

@ -129,7 +129,7 @@ export function createAppThunk<Arg = void, Returned = void, ExtraArg = unknown>(
}, },
})); }));
return Object.assign({}, action, actionCreator); return Object.assign(actionCreator, action);
} }
const createBaseAsyncThunk = rtkCreateAsyncThunk.withTypes<AppThunkConfig>(); const createBaseAsyncThunk = rtkCreateAsyncThunk.withTypes<AppThunkConfig>();

View File

@ -656,19 +656,12 @@ body > [data-popper-placement] {
background: url('@/images/warning-stripes.svg') repeat-y; background: url('@/images/warning-stripes.svg') repeat-y;
width: 5px; width: 5px;
flex: 0 0 auto; flex: 0 0 auto;
&:first-child {
border-start-start-radius: 4px;
}
&:last-child {
border-start-end-radius: 4px;
}
} }
.autosuggest-input { .autosuggest-input {
flex: 1 1 auto; flex: 1 1 auto;
border-bottom: 1px solid var(--background-border-color); border: 1px solid var(--background-border-color);
border-width: 1px 0;
} }
} }
@ -946,6 +939,24 @@ body > [data-popper-placement] {
} }
} }
} }
.status__quote {
margin: 0 8px;
max-height: 220px;
overflow: hidden;
// Override .status__content .status__content__text.status__content__text--visible
.status__content__text.status__content__text {
display: -webkit-box;
}
.status__content__text {
-webkit-line-clamp: 4;
line-clamp: 4;
-webkit-box-orient: vertical;
overflow: hidden;
}
}
} }
.dropdown-button { .dropdown-button {
@ -1583,6 +1594,7 @@ body > [data-popper-placement] {
align-items: center; align-items: center;
gap: 10px; gap: 10px;
overflow: hidden; overflow: hidden;
flex-grow: 1;
.display-name { .display-name {
bdi { bdi {
@ -1599,6 +1611,11 @@ body > [data-popper-placement] {
} }
} }
.status__quote-cancel {
align-self: self-start;
order: 5;
}
.status__info { .status__info {
font-size: 15px; font-size: 15px;
padding-bottom: 10px; padding-bottom: 10px;

View File

@ -21,8 +21,9 @@ class Scheduler::SelfDestructScheduler
def sidekiq_overwhelmed? def sidekiq_overwhelmed?
redis_mem_info = Sidekiq.default_configuration.redis_info redis_mem_info = Sidekiq.default_configuration.redis_info
maxmemory = [redis_mem_info['maxmemory'].to_f, redis_mem_info['total_system_memory'].to_f].filter(&:positive?).min
Sidekiq::Stats.new.enqueued > MAX_ENQUEUED || redis_mem_info['used_memory'].to_f > redis_mem_info['total_system_memory'].to_f * MAX_REDIS_MEM_USAGE Sidekiq::Stats.new.enqueued > MAX_ENQUEUED || redis_mem_info['used_memory'].to_f > maxmemory * MAX_REDIS_MEM_USAGE
end end
def delete_accounts! def delete_accounts!

View File

@ -1930,7 +1930,7 @@ cy:
last_active: Yn weithgar ddiwethaf last_active: Yn weithgar ddiwethaf
most_recent: Y diweddaraf most_recent: Y diweddaraf
moved: Wedi symud moved: Wedi symud
mutual: Cydfudd mutual: Yn Gyffredin
primary: Cynradd primary: Cynradd
relationship: Perthynas relationship: Perthynas
remove_selected_domains: Tynnu'r holl ddilynwyr o'r parthau a ddewiswyd remove_selected_domains: Tynnu'r holl ddilynwyr o'r parthau a ddewiswyd

View File

@ -2059,12 +2059,12 @@ ru:
enabled: Двухфакторная аутентификация включена enabled: Двухфакторная аутентификация включена
enabled_success: Двухфакторная аутентификация настроена enabled_success: Двухфакторная аутентификация настроена
generate_recovery_codes: Сгенерировать резервные коды generate_recovery_codes: Сгенерировать резервные коды
lost_recovery_codes: Коды восстановления позволяются войти в учётную запись в случае утери смартфона. Если вы потеряли свои коды восстановления, вы можете создать новые здесь. Прошлые коды работать перестанут. lost_recovery_codes: Резервные коды позволят вам восстановить доступ к своей учётной записи в случае потери смартфона. Если вы потеряли свои резервные коды, просто создайте новые. Ваши старые коды будут аннулированы.
methods: Способы подтверждения входа methods: Способы подтверждения входа
otp: Приложение-аутентификатор otp: Приложение-аутентификатор
recovery_codes: Резервные коды recovery_codes: Резервные коды
recovery_codes_regenerated: Коды восстановления успешно сгенерированы recovery_codes_regenerated: Новые резервные коды сгенерированы
recovery_instructions_html: 'Пожалуйста, сохраните коды ниже в надёжном месте: они понадобятся, чтобы войти в учётную запись, если вы потеряете доступ к своему смартфону. Вы можете вручную переписать их, распечатать и спрятать среди важных документов или, например, в любимой книжке. <strong>Каждый код действителен только один раз</strong>.' recovery_instructions_html: Если случится так, что у вас не будет доступа к смартфону, резервные коды позволят вам восстановить доступ к своей учётной записи. <strong>Храните резервные коды в надёжном месте.</strong> К примеру, вы можете распечатать их и убрать туда, где лежат другие важные документы.
webauthn: Электронные ключи webauthn: Электронные ключи
user_mailer: user_mailer:
announcement_published: announcement_published:
@ -2083,16 +2083,16 @@ ru:
subtitle: Ваша апелляция отклонена. subtitle: Ваша апелляция отклонена.
title: Обжалование отклонено title: Обжалование отклонено
backup_ready: backup_ready:
explanation: Вы запросили полное резервное копирование вашей учетной записи Mastodon. explanation: Вы запросили экспорт данных своей учётной записи Mastodon.
extra: Теперь он готов к загрузке! extra: Теперь ваш архив готов и доступен для скачивания!
subject: Ваш архив готов к загрузке subject: Ваш архив готов к загрузке
title: Архив ваших данных готов title: Экспорт данных
failed_2fa: failed_2fa:
details: 'Вот подробности попытки регистрации:' details: 'Вот подробности попытки входа:'
explanation: Кто-то пытался войти в вашу учетную запись, но указал неверный второй фактор аутентификации. explanation: Кто-то пытался войти в вашу учётную запись, но не смог подтвердить вход при помощи второго фактора.
further_actions_html: Если это не вы, мы рекомендуем %{action} немедленно принять меры, так как он может быть скомпрометирован. further_actions_html: Если это были не вы, рекомендуем немедленно %{action}, так как он мог быть скомпрометирован.
subject: Сбой двухфакторной аутентификации subject: Неудачная попытка подтверждения входа
title: Сбой двухфакторной аутентификации title: Неудачная попытка подтверждения входа
suspicious_sign_in: suspicious_sign_in:
change_password: сменить пароль change_password: сменить пароль
details: 'Подробности о новом входе:' details: 'Подробности о новом входе:'
@ -2146,58 +2146,45 @@ ru:
apps_step: Загрузите наши официальные приложения. apps_step: Загрузите наши официальные приложения.
apps_title: Приложения Mastodon apps_title: Приложения Mastodon
checklist_subtitle: 'Давайте начнем знакомство с этим новым социальным рубежом:' checklist_subtitle: 'Давайте начнем знакомство с этим новым социальным рубежом:'
checklist_title: Приветственный контрольный список
edit_profile_action: Персонализация edit_profile_action: Персонализация
edit_profile_step: Усильте взаимодействие, заполнив полный профиль.
edit_profile_title: Персонализируйте свой профиль edit_profile_title: Персонализируйте свой профиль
explanation: Вот несколько советов для новичков explanation: Вот несколько советов для новичков
feature_action: Подробнее feature_action: Подробнее
feature_audience: Mastodon предоставляет вам уникальную возможность управлять своей аудиторией без посредников. Mastodon, развернутый на вашей собственной инфраструктуре, позволяет вам следить и быть преследуемым с любого другого сервера Mastodon в Интернете и не контролируется никем, кроме вас.
feature_audience_title: Создайте уверенную аудиторию
feature_control: Вы сами знаете, что хотите видеть в своей ленте. Никаких алгоритмов или рекламы, чтобы тратить ваше время. Следите за любым человеком на любом сервере Mastodon с одного аккаунта и получайте его сообщения в хронологическом порядке, а также сделайте свой уголок интернета немного больше похожим на себя. feature_control: Вы сами знаете, что хотите видеть в своей ленте. Никаких алгоритмов или рекламы, чтобы тратить ваше время. Следите за любым человеком на любом сервере Mastodon с одного аккаунта и получайте его сообщения в хронологическом порядке, а также сделайте свой уголок интернета немного больше похожим на себя.
feature_control_title: Контролируйте свой график
feature_creativity: Mastodon поддерживает аудио-, видео- и фотопосты, описания доступности, опросы, предупреждения о содержании, анимированные аватары, пользовательские emojis, управление обрезкой миниатюр и многое другое, чтобы помочь вам выразить себя в Интернете. Публикуете ли вы свои работы, музыку или подкаст, Mastodon всегда готов помочь вам. feature_creativity: Mastodon поддерживает аудио-, видео- и фотопосты, описания доступности, опросы, предупреждения о содержании, анимированные аватары, пользовательские emojis, управление обрезкой миниатюр и многое другое, чтобы помочь вам выразить себя в Интернете. Публикуете ли вы свои работы, музыку или подкаст, Mastodon всегда готов помочь вам.
feature_creativity_title: Непревзойденная креативность feature_creativity_title: Непревзойденная креативность
feature_moderation: Mastodon возвращает принятие решений в ваши руки. Каждый сервер создает свои собственные правила и нормы, которые соблюдаются локально, а не сверху вниз, как в корпоративных социальных сетях, что позволяет наиболее гибко реагировать на потребности различных групп людей. Присоединяйтесь к серверу с правилами, с которыми вы согласны, или создайте свой собственный. feature_moderation: Mastodon возвращает принятие решений в ваши руки. Каждый сервер создает свои собственные правила и нормы, которые соблюдаются локально, а не сверху вниз, как в корпоративных социальных сетях, что позволяет наиболее гибко реагировать на потребности различных групп людей. Присоединяйтесь к серверу с правилами, с которыми вы согласны, или создайте свой собственный.
feature_moderation_title: Модерирование, каким оно должно быть feature_moderation_title: Модерирование, каким оно должно быть
follow_action: Следуйте за
follow_step: Следить за интересными людьми - вот что такое Mastodon.
follow_title: Персонализируйте свою домашнюю ленту follow_title: Персонализируйте свою домашнюю ленту
follows_subtitle: Следите за известными аккаунтами
follows_title: За кем следить
follows_view_more: Посмотреть больше людей, за которыми стоит следить
hashtags_recent_count: hashtags_recent_count:
few: "%{people} человека за последние 2 дня" few: "%{people} человека за последние 2 дня"
many: "%{people} человек за последние 2 дня" many: "%{people} человек за последние 2 дня"
one: "%{people} человек за последние 2 дня" one: "%{people} человек за последние 2 дня"
other: "%{people} человек за последние 2 дня" other: "%{people} человек за последние 2 дня"
hashtags_subtitle: Изучите, что было в тренде за последние 2 дня hashtags_subtitle: Изучите, что было в тренде за последние 2 дня
hashtags_title: Модные хэштеги
hashtags_view_more: Посмотреть другие трендовые хэштеги hashtags_view_more: Посмотреть другие трендовые хэштеги
post_action: Составить post_action: Составить
post_step: Поприветствуйте мир с помощью текста, фотографий, видео или опросов. post_step: Поприветствуйте мир с помощью текста, фотографий, видео или опросов.
post_title: Сделайте свой первый пост post_title: Сделайте свой первый пост
share_step: Пусть ваши друзья знают, как найти вас на Mastodon. share_step: Пусть ваши друзья знают, как найти вас на Mastodon.
share_title: Поделитесь информацией о компании Mastodon
sign_in_action: Зарегистрироваться
subject: Добро пожаловать в Mastodon subject: Добро пожаловать в Mastodon
title: Добро пожаловать на борт, %{name}! title: Добро пожаловать на борт, %{name}!
users: users:
follow_limit_reached: Вы не можете подписаться больше, чем на %{limit} человек follow_limit_reached: Вы можете подписаться не больше чем на %{limit} человек
go_to_sso_account_settings: Перейти к настройкам сторонних аккаунтов учетной записи go_to_sso_account_settings: Перейти к настройкам сторонних аккаунтов учетной записи
invalid_otp_token: Введен неверный код двухфакторной аутентификации invalid_otp_token: Введён неверный код двухфакторной аутентификации
otp_lost_help_html: Если Вы потеряли доступ к обоим, свяжитесь с %{email} otp_lost_help_html: Если вы утратили доступ и к приложению-аутентификатору, и к резервным кодам, свяжитесь с %{email}
rate_limited: Слишком много попыток аутентификации, повторите попытку позже. rate_limited: Слишком много попыток аутентификации, попробуйте позже.
seamless_external_login: Вы вошли в систему через внешнюю службу, поэтому настройки пароля и электронной почты недоступны. seamless_external_login: Вы вошли в систему через внешнюю службу, поэтому настройки пароля и электронной почты недоступны.
signed_in_as: 'Выполнен вход под именем:' signed_in_as: Выполнен вход в учётную запись
verification: verification:
extra_instructions_html: <strong>Подсказка:</strong> Ссылка на вашем сайте может быть невидимой. Важной частью является <code>rel="me"</code>, который предотвращает выдачу себя за другое лицо на сайтах с пользовательским контентом. Вы даже можете использовать тег <code>link</code> в заголовке страницы вместо <code>a</code>, но HTML должен быть доступен без выполнения JavaScript. extra_instructions_html: <strong>Подсказка:</strong> Ссылка на вашем сайте может быть невидимой. Ключевое значение имеет атрибут <code>rel="me"</code>, который не даёт выдать себя за другое лицо на сайтах, где контент создают сами пользователи. Вместо тега <code>a</code> можно использовать тег <code>link</code> в <code>head</code>-секции страницы, но необходимо, чтобы HTML-код был доступен без выполнения JavaScript.
here_is_how: Вот как here_is_how: Как это делается?
hint_html: "<strong>Подтверждение личности на Mastodon доступно каждому.</strong> Основано на открытых веб-стандартах, отныне и навсегда бесплатно. Всё, что вам нужно, - это персональный сайт, по которому вас узнают. Когда вы ссылаетесь на этот сайт из своего профиля, мы проверим, что сайт ссылается на ваш профиль, и отобразим на нём визуальный индикатор." hint_html: "<strong>Подтверждение личности в Mastodon доступно каждому.</strong> Оно предоставляется на основе открытых веб-стандартов, бесплатно навсегда. Всё, что вам нужно, — это личный веб-сайт, по которому другие люди смогут вас узнать. После того как вы разместите ссылку на этот сайт в своём профиле, мы убедимся, что сайт в свою очередь ссылается на ваш профиль, и затем напротив ссылки появится визуальный индикатор."
instructions_html: Скопируйте и вставьте код ниже в HTML вашего сайта. Затем, добавьте адрес вашего веб сайта в одно из дополнительных полей на вкладке "Редактировать профиль" и сохраните изменения. instructions_html: Скопируйте и вставьте следующий код в HTML-разметку вашего сайта. Затем добавьте адрес вашего веб-сайта в одно из дополнительных полей на вкладке «Данные профиля» и сохраните изменения.
verification: Верификация ссылок verification: Верификация
verified_links: Ваши ссылки подтверждения verified_links: Верифицированные ссылки
website_verification: Проверка веб-сайта website_verification: Верификация по веб-сайту
webauthn_credentials: webauthn_credentials:
add: Добавить новый электронный ключ add: Добавить новый электронный ключ
create: create:

View File

@ -56,6 +56,7 @@ ru:
scopes: Выберите, какие API приложение сможет использовать. Разрешения верхнего уровня имплицитно включают в себя все разрешения более низких уровней. scopes: Выберите, какие API приложение сможет использовать. Разрешения верхнего уровня имплицитно включают в себя все разрешения более низких уровней.
setting_aggregate_reblogs: Не показывать новые продвижения постов, которые уже были недавно продвинуты (применяется только к будущим продвижениям) setting_aggregate_reblogs: Не показывать новые продвижения постов, которые уже были недавно продвинуты (применяется только к будущим продвижениям)
setting_always_send_emails: По умолчанию уведомления не доставляются по электронной почте, пока вы активно используете Mastodon setting_always_send_emails: По умолчанию уведомления не доставляются по электронной почте, пока вы активно используете Mastodon
setting_default_quote_policy: Эта настройка будет применена только к постам, созданным в следующей версии Mastodon, но вы можете заранее определить свои предпочтения.
setting_default_sensitive: Медиа деликатного характера скрыты по умолчанию и могут быть показаны по нажатию на них setting_default_sensitive: Медиа деликатного характера скрыты по умолчанию и могут быть показаны по нажатию на них
setting_display_media_default: Скрывать медиа деликатного характера setting_display_media_default: Скрывать медиа деликатного характера
setting_display_media_hide_all: Скрывать все медиа setting_display_media_hide_all: Скрывать все медиа
@ -148,6 +149,11 @@ ru:
min_age: Не меньше минимального возраста, требуемого по закону в вашей юрисдикции. min_age: Не меньше минимального возраста, требуемого по закону в вашей юрисдикции.
user: user:
chosen_languages: Отметьте языки, на которых вы желаете видеть посты в публичных лентах. Оставьте выбор пустым, чтобы не фильтровать посты по языку chosen_languages: Отметьте языки, на которых вы желаете видеть посты в публичных лентах. Оставьте выбор пустым, чтобы не фильтровать посты по языку
date_of_birth:
few: Для регистрации на %{domain} нужно убедиться, что вам не меньше %{count} лет. Мы не храним введённые здесь данные.
many: Для регистрации на %{domain} нужно убедиться, что вам не меньше %{count} лет. Мы не храним введённые здесь данные.
one: Для регистрации на %{domain} нужно убедиться, что вам не меньше %{count} года. Мы не храним введённые здесь данные.
other: Для регистрации на %{domain} нужно убедиться, что вам не меньше %{count} лет. Мы не храним введённые здесь данные.
role: Роль определяет, какими правами обладает пользователь. role: Роль определяет, какими правами обладает пользователь.
user_role: user_role:
color: Цвет, который будет использоваться для роли в интерфейсе (UI), как RGB в формате HEX color: Цвет, который будет использоваться для роли в интерфейсе (UI), как RGB в формате HEX

View File

@ -0,0 +1,13 @@
# frozen_string_literal: true
class UpdateQuoteIndex < ActiveRecord::Migration[8.0]
disable_ddl_transaction!
def change
add_index :quotes, [:account_id, :quoted_account_id, :id], algorithm: :concurrently
remove_index :quotes, [:account_id, :quoted_account_id]
add_index :quotes, [:quoted_status_id, :id], algorithm: :concurrently
remove_index :quotes, [:quoted_status_id]
end
end

View File

@ -10,7 +10,7 @@
# #
# It's strongly recommended that you check this file into your version control system. # It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema[8.0].define(version: 2025_08_05_075010) do ActiveRecord::Schema[8.0].define(version: 2025_08_19_100545) do
# These are extensions that must be enabled in order to support this database # These are extensions that must be enabled in order to support this database
enable_extension "pg_catalog.plpgsql" enable_extension "pg_catalog.plpgsql"
@ -926,11 +926,11 @@ ActiveRecord::Schema[8.0].define(version: 2025_08_05_075010) do
t.datetime "created_at", null: false t.datetime "created_at", null: false
t.datetime "updated_at", null: false t.datetime "updated_at", null: false
t.boolean "legacy", default: false, null: false t.boolean "legacy", default: false, null: false
t.index ["account_id", "quoted_account_id"], name: "index_quotes_on_account_id_and_quoted_account_id" t.index ["account_id", "quoted_account_id", "id"], name: "index_quotes_on_account_id_and_quoted_account_id_and_id"
t.index ["activity_uri"], name: "index_quotes_on_activity_uri", unique: true, where: "(activity_uri IS NOT NULL)" t.index ["activity_uri"], name: "index_quotes_on_activity_uri", unique: true, where: "(activity_uri IS NOT NULL)"
t.index ["approval_uri"], name: "index_quotes_on_approval_uri", where: "(approval_uri IS NOT NULL)" t.index ["approval_uri"], name: "index_quotes_on_approval_uri", where: "(approval_uri IS NOT NULL)"
t.index ["quoted_account_id"], name: "index_quotes_on_quoted_account_id" t.index ["quoted_account_id"], name: "index_quotes_on_quoted_account_id"
t.index ["quoted_status_id"], name: "index_quotes_on_quoted_status_id" t.index ["quoted_status_id", "id"], name: "index_quotes_on_quoted_status_id_and_id"
t.index ["status_id"], name: "index_quotes_on_status_id", unique: true t.index ["status_id"], name: "index_quotes_on_status_id", unique: true
end end

View File

@ -130,14 +130,19 @@ RSpec.describe 'Settings applications page' do
describe 'Regenerating an app token' do describe 'Regenerating an app token' do
it 'updates the app token' do it 'updates the app token' do
visit settings_application_path(application) expect { visit settings_application_path(application) }
.to change(user_application_token, :first).from(be_nil).to(be_present)
expect { regenerate_token } expect { regenerate_token }
.to(change { user.token_for_app(application) }) .to(change { user_application_token.first.token })
expect(page) expect(page)
.to have_content(I18n.t('applications.token_regenerated')) .to have_content(I18n.t('applications.token_regenerated'))
end end
def user_application_token
Doorkeeper::AccessToken.where(application:).where(resource_owner_id: user)
end
def regenerate_token def regenerate_token
click_on I18n.t('applications.regenerate_token') click_on I18n.t('applications.regenerate_token')
end end

View File

@ -11,9 +11,9 @@ ARG BASE_REGISTRY="docker.io"
# Node version to use in base image, change with [--build-arg NODE_MAJOR_VERSION="20"] # Node version to use in base image, change with [--build-arg NODE_MAJOR_VERSION="20"]
# renovate: datasource=node-version depName=node # renovate: datasource=node-version depName=node
ARG NODE_MAJOR_VERSION="22" ARG NODE_MAJOR_VERSION="22"
# Debian image to use for base image, change with [--build-arg DEBIAN_VERSION="bookworm"] # Debian image to use for base image, change with [--build-arg DEBIAN_VERSION="trixie"]
ARG DEBIAN_VERSION="bookworm" ARG DEBIAN_VERSION="trixie"
# Node image to use for base image based on combined variables (ex: 20-bookworm-slim) # Node image to use for base image based on combined variables (ex: 20-trixie-slim)
FROM ${BASE_REGISTRY}/node:${NODE_MAJOR_VERSION}-${DEBIAN_VERSION}-slim AS streaming FROM ${BASE_REGISTRY}/node:${NODE_MAJOR_VERSION}-${DEBIAN_VERSION}-slim AS streaming
# Resulting version string is vX.X.X-MASTODON_VERSION_PRERELEASE+MASTODON_VERSION_METADATA # Resulting version string is vX.X.X-MASTODON_VERSION_PRERELEASE+MASTODON_VERSION_METADATA

112
yarn.lock
View File

@ -73,39 +73,39 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"@babel/core@npm:^7.18.9, @babel/core@npm:^7.21.3, @babel/core@npm:^7.24.4, @babel/core@npm:^7.26.10, @babel/core@npm:^7.28.0": "@babel/core@npm:^7.18.9, @babel/core@npm:^7.21.3, @babel/core@npm:^7.24.4, @babel/core@npm:^7.26.10, @babel/core@npm:^7.28.0, @babel/core@npm:^7.28.3":
version: 7.28.0 version: 7.28.3
resolution: "@babel/core@npm:7.28.0" resolution: "@babel/core@npm:7.28.3"
dependencies: dependencies:
"@ampproject/remapping": "npm:^2.2.0" "@ampproject/remapping": "npm:^2.2.0"
"@babel/code-frame": "npm:^7.27.1" "@babel/code-frame": "npm:^7.27.1"
"@babel/generator": "npm:^7.28.0" "@babel/generator": "npm:^7.28.3"
"@babel/helper-compilation-targets": "npm:^7.27.2" "@babel/helper-compilation-targets": "npm:^7.27.2"
"@babel/helper-module-transforms": "npm:^7.27.3" "@babel/helper-module-transforms": "npm:^7.28.3"
"@babel/helpers": "npm:^7.27.6" "@babel/helpers": "npm:^7.28.3"
"@babel/parser": "npm:^7.28.0" "@babel/parser": "npm:^7.28.3"
"@babel/template": "npm:^7.27.2" "@babel/template": "npm:^7.27.2"
"@babel/traverse": "npm:^7.28.0" "@babel/traverse": "npm:^7.28.3"
"@babel/types": "npm:^7.28.0" "@babel/types": "npm:^7.28.2"
convert-source-map: "npm:^2.0.0" convert-source-map: "npm:^2.0.0"
debug: "npm:^4.1.0" debug: "npm:^4.1.0"
gensync: "npm:^1.0.0-beta.2" gensync: "npm:^1.0.0-beta.2"
json5: "npm:^2.2.3" json5: "npm:^2.2.3"
semver: "npm:^6.3.1" semver: "npm:^6.3.1"
checksum: 10c0/423302e7c721e73b1c096217880272e02020dfb697a55ccca60ad01bba90037015f84d0c20c6ce297cf33a19bb704bc5c2b3d3095f5284dfa592bd1de0b9e8c3 checksum: 10c0/e6b3eb830c4b93f5a442b305776df1cd2bb4fafa4612355366f67c764f3e54a69d45b84def77fb2d4fd83439102667b0a92c3ea2838f678733245b748c602a7b
languageName: node languageName: node
linkType: hard linkType: hard
"@babel/generator@npm:^7.28.0": "@babel/generator@npm:^7.28.3":
version: 7.28.0 version: 7.28.3
resolution: "@babel/generator@npm:7.28.0" resolution: "@babel/generator@npm:7.28.3"
dependencies: dependencies:
"@babel/parser": "npm:^7.28.0" "@babel/parser": "npm:^7.28.3"
"@babel/types": "npm:^7.28.0" "@babel/types": "npm:^7.28.2"
"@jridgewell/gen-mapping": "npm:^0.3.12" "@jridgewell/gen-mapping": "npm:^0.3.12"
"@jridgewell/trace-mapping": "npm:^0.3.28" "@jridgewell/trace-mapping": "npm:^0.3.28"
jsesc: "npm:^3.0.2" jsesc: "npm:^3.0.2"
checksum: 10c0/1b3d122268ea3df50fde707ad864d9a55c72621357d5cebb972db3dd76859c45810c56e16ad23123f18f80cc2692f5a015d2858361300f0f224a05dc43d36a92 checksum: 10c0/0ff58bcf04f8803dcc29479b547b43b9b0b828ec1ee0668e92d79f9e90f388c28589056637c5ff2fd7bcf8d153c990d29c448d449d852bf9d1bc64753ca462bc
languageName: node languageName: node
linkType: hard linkType: hard
@ -203,16 +203,16 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"@babel/helper-module-transforms@npm:^7.27.1, @babel/helper-module-transforms@npm:^7.27.3": "@babel/helper-module-transforms@npm:^7.27.1, @babel/helper-module-transforms@npm:^7.28.3":
version: 7.27.3 version: 7.28.3
resolution: "@babel/helper-module-transforms@npm:7.27.3" resolution: "@babel/helper-module-transforms@npm:7.28.3"
dependencies: dependencies:
"@babel/helper-module-imports": "npm:^7.27.1" "@babel/helper-module-imports": "npm:^7.27.1"
"@babel/helper-validator-identifier": "npm:^7.27.1" "@babel/helper-validator-identifier": "npm:^7.27.1"
"@babel/traverse": "npm:^7.27.3" "@babel/traverse": "npm:^7.28.3"
peerDependencies: peerDependencies:
"@babel/core": ^7.0.0 "@babel/core": ^7.0.0
checksum: 10c0/fccb4f512a13b4c069af51e1b56b20f54024bcf1591e31e978a30f3502567f34f90a80da6a19a6148c249216292a8074a0121f9e52602510ef0f32dbce95ca01 checksum: 10c0/549be62515a6d50cd4cfefcab1b005c47f89bd9135a22d602ee6a5e3a01f27571868ada10b75b033569f24dc4a2bb8d04bfa05ee75c16da7ade2d0db1437fcdb
languageName: node languageName: node
linkType: hard linkType: hard
@ -300,24 +300,24 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"@babel/helpers@npm:^7.27.6": "@babel/helpers@npm:^7.28.3":
version: 7.27.6 version: 7.28.3
resolution: "@babel/helpers@npm:7.27.6" resolution: "@babel/helpers@npm:7.28.3"
dependencies: dependencies:
"@babel/template": "npm:^7.27.2" "@babel/template": "npm:^7.27.2"
"@babel/types": "npm:^7.27.6" "@babel/types": "npm:^7.28.2"
checksum: 10c0/448bac96ef8b0f21f2294a826df9de6bf4026fd023f8a6bb6c782fe3e61946801ca24381490b8e58d861fee75cd695a1882921afbf1f53b0275ee68c938bd6d3 checksum: 10c0/03a8f94135415eec62d37be9c62c63908f2d5386c7b00e04545de4961996465775330e3eb57717ea7451e19b0e24615777ebfec408c2adb1df3b10b4df6bf1ce
languageName: node languageName: node
linkType: hard linkType: hard
"@babel/parser@npm:^7.1.0, @babel/parser@npm:^7.20.7, @babel/parser@npm:^7.25.4, @babel/parser@npm:^7.27.2, @babel/parser@npm:^7.28.0": "@babel/parser@npm:^7.1.0, @babel/parser@npm:^7.20.7, @babel/parser@npm:^7.25.4, @babel/parser@npm:^7.27.2, @babel/parser@npm:^7.28.3":
version: 7.28.0 version: 7.28.3
resolution: "@babel/parser@npm:7.28.0" resolution: "@babel/parser@npm:7.28.3"
dependencies: dependencies:
"@babel/types": "npm:^7.28.0" "@babel/types": "npm:^7.28.2"
bin: bin:
parser: ./bin/babel-parser.js parser: ./bin/babel-parser.js
checksum: 10c0/c2ef81d598990fa949d1d388429df327420357cb5200271d0d0a2784f1e6d54afc8301eb8bdf96d8f6c77781e402da93c7dc07980fcc136ac5b9d5f1fce701b5 checksum: 10c0/1f41eb82623b0ca0f94521b57f4790c6c457cd922b8e2597985b36bdec24114a9ccf54640286a760ceb60f11fe9102d192bf60477aee77f5d45f1029b9b72729
languageName: node languageName: node
linkType: hard linkType: hard
@ -1179,22 +1179,22 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"@babel/traverse@npm:^7.18.9, @babel/traverse@npm:^7.26.10, @babel/traverse@npm:^7.27.1, @babel/traverse@npm:^7.27.3, @babel/traverse@npm:^7.28.0": "@babel/traverse@npm:^7.18.9, @babel/traverse@npm:^7.26.10, @babel/traverse@npm:^7.27.1, @babel/traverse@npm:^7.28.0, @babel/traverse@npm:^7.28.3":
version: 7.28.0 version: 7.28.3
resolution: "@babel/traverse@npm:7.28.0" resolution: "@babel/traverse@npm:7.28.3"
dependencies: dependencies:
"@babel/code-frame": "npm:^7.27.1" "@babel/code-frame": "npm:^7.27.1"
"@babel/generator": "npm:^7.28.0" "@babel/generator": "npm:^7.28.3"
"@babel/helper-globals": "npm:^7.28.0" "@babel/helper-globals": "npm:^7.28.0"
"@babel/parser": "npm:^7.28.0" "@babel/parser": "npm:^7.28.3"
"@babel/template": "npm:^7.27.2" "@babel/template": "npm:^7.27.2"
"@babel/types": "npm:^7.28.0" "@babel/types": "npm:^7.28.2"
debug: "npm:^4.3.1" debug: "npm:^4.3.1"
checksum: 10c0/32794402457827ac558173bcebdcc0e3a18fa339b7c41ca35621f9f645f044534d91bb923ff385f5f960f2e495f56ce18d6c7b0d064d2f0ccb55b285fa6bc7b9 checksum: 10c0/26e95b29a46925b7b41255e03185b7e65b2c4987e14bbee7bbf95867fb19c69181f301bbe1c7b201d4fe0cce6aa0cbea0282dad74b3a0fef3d9058f6c76fdcb3
languageName: node languageName: node
linkType: hard linkType: hard
"@babel/types@npm:^7.0.0, @babel/types@npm:^7.18.9, @babel/types@npm:^7.20.7, @babel/types@npm:^7.21.3, @babel/types@npm:^7.25.4, @babel/types@npm:^7.26.10, @babel/types@npm:^7.27.1, @babel/types@npm:^7.27.3, @babel/types@npm:^7.27.6, @babel/types@npm:^7.28.0, @babel/types@npm:^7.4.4": "@babel/types@npm:^7.0.0, @babel/types@npm:^7.18.9, @babel/types@npm:^7.20.7, @babel/types@npm:^7.21.3, @babel/types@npm:^7.25.4, @babel/types@npm:^7.26.10, @babel/types@npm:^7.27.1, @babel/types@npm:^7.27.3, @babel/types@npm:^7.28.2, @babel/types@npm:^7.4.4":
version: 7.28.2 version: 7.28.2
resolution: "@babel/types@npm:7.28.2" resolution: "@babel/types@npm:7.28.2"
dependencies: dependencies:
@ -3212,10 +3212,10 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"@rolldown/pluginutils@npm:1.0.0-beta.30": "@rolldown/pluginutils@npm:1.0.0-beta.32":
version: 1.0.0-beta.30 version: 1.0.0-beta.32
resolution: "@rolldown/pluginutils@npm:1.0.0-beta.30" resolution: "@rolldown/pluginutils@npm:1.0.0-beta.32"
checksum: 10c0/aff8b532cb9d82d94c9a4101fa12ecb10620ad47d52dbb9135a5c65bde1ad19895b41026b821f4d607083699239a5d0010198401b6a6a54ab6a10d0015302768 checksum: 10c0/ba3582fc3c35c8eb57b0df2d22d0733b1be83d37edcc258203364773f094f58fc0cb7a056d604603573a69dd0105a466506cad467f59074e1e53d0dc26191f06
languageName: node languageName: node
linkType: hard linkType: hard
@ -4714,18 +4714,18 @@ __metadata:
linkType: hard linkType: hard
"@vitejs/plugin-react@npm:^5.0.0": "@vitejs/plugin-react@npm:^5.0.0":
version: 5.0.0 version: 5.0.1
resolution: "@vitejs/plugin-react@npm:5.0.0" resolution: "@vitejs/plugin-react@npm:5.0.1"
dependencies: dependencies:
"@babel/core": "npm:^7.28.0" "@babel/core": "npm:^7.28.3"
"@babel/plugin-transform-react-jsx-self": "npm:^7.27.1" "@babel/plugin-transform-react-jsx-self": "npm:^7.27.1"
"@babel/plugin-transform-react-jsx-source": "npm:^7.27.1" "@babel/plugin-transform-react-jsx-source": "npm:^7.27.1"
"@rolldown/pluginutils": "npm:1.0.0-beta.30" "@rolldown/pluginutils": "npm:1.0.0-beta.32"
"@types/babel__core": "npm:^7.20.5" "@types/babel__core": "npm:^7.20.5"
react-refresh: "npm:^0.17.0" react-refresh: "npm:^0.17.0"
peerDependencies: peerDependencies:
vite: ^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 vite: ^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0
checksum: 10c0/e5813839d319ab5dc1b90cab40b6c08388f26e456166ba9df10ffc3c3f4ecc594cec06715b5c93390bba56140ca5f68a18f2233f7d275d77e5bbfeb979e4fd9b checksum: 10c0/2641171beedfc38edc5671abb47706906f9af2a79a6dfff4e946106c9550de4f83ccae41c164f3ee26a3edf07127ecc0e415fe5cddbf7abc71fbb2540016c27d
languageName: node languageName: node
linkType: hard linkType: hard
@ -7387,15 +7387,15 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"fdir@npm:^6.4.4, fdir@npm:^6.4.6": "fdir@npm:^6.4.4, fdir@npm:^6.5.0":
version: 6.4.6 version: 6.5.0
resolution: "fdir@npm:6.4.6" resolution: "fdir@npm:6.5.0"
peerDependencies: peerDependencies:
picomatch: ^3 || ^4 picomatch: ^3 || ^4
peerDependenciesMeta: peerDependenciesMeta:
picomatch: picomatch:
optional: true optional: true
checksum: 10c0/45b559cff889934ebb8bc498351e5acba40750ada7e7d6bde197768d2fa67c149be8ae7f8ff34d03f4e1eb20f2764116e56440aaa2f6689e9a4aa7ef06acafe9 checksum: 10c0/e345083c4306b3aed6cb8ec551e26c36bab5c511e99ea4576a16750ddc8d3240e63826cc624f5ae17ad4dc82e68a253213b60d556c11bfad064b7607847ed07f
languageName: node languageName: node
linkType: hard linkType: hard
@ -13899,11 +13899,11 @@ __metadata:
linkType: hard linkType: hard
"vite@npm:^5.0.0 || ^6.0.0 || ^7.0.0-0, vite@npm:^7.1.1": "vite@npm:^5.0.0 || ^6.0.0 || ^7.0.0-0, vite@npm:^7.1.1":
version: 7.1.2 version: 7.1.3
resolution: "vite@npm:7.1.2" resolution: "vite@npm:7.1.3"
dependencies: dependencies:
esbuild: "npm:^0.25.0" esbuild: "npm:^0.25.0"
fdir: "npm:^6.4.6" fdir: "npm:^6.5.0"
fsevents: "npm:~2.3.3" fsevents: "npm:~2.3.3"
picomatch: "npm:^4.0.3" picomatch: "npm:^4.0.3"
postcss: "npm:^8.5.6" postcss: "npm:^8.5.6"
@ -13949,7 +13949,7 @@ __metadata:
optional: true optional: true
bin: bin:
vite: bin/vite.js vite: bin/vite.js
checksum: 10c0/4ed825b20bc0f49db99cd382de9506b2721ccd47dcebd4a68e0ef65e3cdd2347fded52b306c34178308e0fd7fe78fd5ff517623002cb00710182ad3012c92ced checksum: 10c0/a0aa418beab80673dc9a3e9d1fa49472955d6ef9d41a4c9c6bd402953f411346f612864dae267adfb2bb8ceeb894482369316ffae5816c84fd45990e352b727d
languageName: node languageName: node
linkType: hard linkType: hard