th: live from new york it's friday night

various critical fixes (pls don't report this to NVD)
This commit is contained in:
Kouhai 2024-02-01 00:46:38 -08:00
parent e9dbe31776
commit c1910db65f
14 changed files with 973 additions and 951 deletions

File diff suppressed because one or more lines are too long

893
.yarn/releases/yarn-4.1.0.cjs vendored Executable file

File diff suppressed because one or more lines are too long

View file

@ -1,9 +1,9 @@
enableGlobalCache: true enableGlobalCache: true
nodeLinker: node-modules
yarnPath: .yarn/releases/yarn-3.4.1.cjs
logFilters: logFilters:
- code: YN0013 - code: YN0013
level: ${YARN_NOISE_LOG_CODE_LEVEL:-info} level: "${YARN_NOISE_LOG_CODE_LEVEL:-info}"
nodeLinker: node-modules
yarnPath: .yarn/releases/yarn-4.1.0.cjs

View file

@ -189,7 +189,7 @@ RUN \
--mount=type=cache,id=corepack-cache-${TARGETPLATFORM},target=/usr/local/share/.cache/corepack,sharing=locked \ --mount=type=cache,id=corepack-cache-${TARGETPLATFORM},target=/usr/local/share/.cache/corepack,sharing=locked \
--mount=type=cache,id=yarn-cache-${TARGETPLATFORM},target=/usr/local/share/.cache/yarn,sharing=locked \ --mount=type=cache,id=yarn-cache-${TARGETPLATFORM},target=/usr/local/share/.cache/yarn,sharing=locked \
# Install Node packages # Install Node packages
yarn workspaces focus --production @mastodon/mastodon; yarn workspaces focus --production @mastodon/mastodon
# Create temporary assets build layer from build layer # Create temporary assets build layer from build layer
FROM build as precompiler FROM build as precompiler

View file

@ -363,8 +363,7 @@ class StatusActionBar extends ImmutablePureComponent {
/> />
<IconButton className={classNames('status__action-bar-button', { reblogPrivate })} disabled={!publicStatus && !reblogPrivate} active={status.get('reblogged')} title={reblogTitle} icon={reblogIcon} iconComponent={reblogIconComponent} onClick={this.handleReblogClick} counter={withCounters ? status.get('reblogs_count') : undefined} /> <IconButton className={classNames('status__action-bar-button', { reblogPrivate })} disabled={!publicStatus && !reblogPrivate} active={status.get('reblogged')} title={reblogTitle} icon={reblogIcon} iconComponent={reblogIconComponent} onClick={this.handleReblogClick} counter={withCounters ? status.get('reblogs_count') : undefined} />
{/* FIXME: this is hilariously broken :( */} <IconButton className={classNames('status__action-bar-button', { reblogPrivate })} disabled={!publicStatus && !reblogPrivate} /* active={status.get('reblogged')} */ title={quoteTitle} icon={quoteIcon} iconComponent={quoteIconComponent} onClick={this.handleQuoteClick} />
<IconButton className={classNames('status__action-bar-button', { reblogPrivate })} disabled={true /* !publicStatus && !reblogPrivate */} /* active={status.get('reblogged')} */ title={quoteTitle} icon={quoteIcon} iconComponent={quoteIconComponent} onClick={this.handleQuoteClick} />
<IconButton className='status__action-bar-button star-icon' animate active={status.get('favourited')} title={intl.formatMessage(messages.favourite)} icon='star' iconComponent={status.get('favourited') ? StarIcon : StarBorderIcon} onClick={this.handleFavouriteClick} counter={withCounters ? status.get('favourites_count') : undefined} /> <IconButton className='status__action-bar-button star-icon' animate active={status.get('favourited')} title={intl.formatMessage(messages.favourite)} icon='star' iconComponent={status.get('favourited') ? StarIcon : StarBorderIcon} onClick={this.handleFavouriteClick} counter={withCounters ? status.get('favourites_count') : undefined} />
<IconButton className='status__action-bar-button bookmark-icon' disabled={!signedIn} active={status.get('bookmarked')} title={intl.formatMessage(messages.bookmark)} icon='bookmark' iconComponent={status.get('bookmarked') ? BookmarkIcon : BookmarkBorderIcon} onClick={this.handleBookmarkClick} /> <IconButton className='status__action-bar-button bookmark-icon' disabled={!signedIn} active={status.get('bookmarked')} title={intl.formatMessage(messages.bookmark)} icon='bookmark' iconComponent={status.get('bookmarked') ? BookmarkIcon : BookmarkBorderIcon} onClick={this.handleBookmarkClick} />

View file

@ -372,17 +372,17 @@ class StatusContent extends PureComponent {
let quoteStatusDisplayName = { __html: quoteStatusAccount.get('display_name_html') }; let quoteStatusDisplayName = { __html: quoteStatusAccount.get('display_name_html') };
quote = ( quote = (
<div class="status__quote"> <div className='status__quote'>
<blockquote> <blockquote>
<bdi> <bdi>
<span class="quote-display-name"> <span className='quote-display-name'>
<Icon <Icon
fixedWidth fixedWidth
icon='quote-right' icon='quote-right'
id='quote-right' id='quote-right'
aria-hidden='true' aria-hidden='true'
key='icon-quote-right' /> key='icon-quote-right' />
<strong class="display-name__html"> <strong className='display-name__html'>
<a onClick={this.handleAccountClick} href={quoteStatus.getIn(['account', 'url'])} dangerouslySetInnerHTML={quoteStatusDisplayName} /> <a onClick={this.handleAccountClick} href={quoteStatus.getIn(['account', 'url'])} dangerouslySetInnerHTML={quoteStatusDisplayName} />
</strong> </strong>
</span> </span>

View file

@ -1,15 +1,20 @@
// Package imports. // Package imports.
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import React from 'react';
import ImmutablePropTypes from 'react-immutable-proptypes';
import { defineMessages, injectIntl } from 'react-intl'; import { defineMessages, injectIntl } from 'react-intl';
import ImmutablePropTypes from 'react-immutable-proptypes';
import ImmutablePureComponent from 'react-immutable-pure-component'; import ImmutablePureComponent from 'react-immutable-pure-component';
// Components.
import AccountContainer from 'flavours/glitch/containers/account_container'; import CloseIcon from '@/material-icons/400-24px/close.svg?react';
import { Icon } from 'flavours/glitch/components/icon';
import { IconButton } from 'flavours/glitch/components/icon_button';
import AttachmentList from 'flavours/glitch/components/attachment_list'; import AttachmentList from 'flavours/glitch/components/attachment_list';
import { WithOptionalRouterPropTypes, withOptionalRouter } from 'flavours/glitch/utils/react_router';
import { Avatar } from '../../../components/avatar';
import { DisplayName } from '../../../components/display_name';
import { Icon } from '../../../components/icon';
import { IconButton } from '../../../components/icon_button';
// Messages. // Messages.
const messages = defineMessages({ const messages = defineMessages({
@ -19,19 +24,23 @@ const messages = defineMessages({
}, },
}); });
class QuoteIndicator extends ImmutablePureComponent { class QuoteIndicator extends ImmutablePureComponent {
static propTypes = { static propTypes = {
status: ImmutablePropTypes.map, status: ImmutablePropTypes.map,
intl: PropTypes.object.isRequired,
onCancel: PropTypes.func, onCancel: PropTypes.func,
intl: PropTypes.object.isRequired,
...WithOptionalRouterPropTypes,
}; };
handleClick = () => { handleClick = () => {
const { onCancel } = this.props; this.props.onCancel();
if (onCancel) { };
onCancel();
handleAccountClick = (e) => {
if (e.button === 0 && !(e.ctrlKey || e.metaKey)) {
e.preventDefault();
this.props.history?.push(`/@${this.props.status.getIn(['account', 'acct'])}`);
} }
} }
@ -43,40 +52,28 @@ class QuoteIndicator extends ImmutablePureComponent {
return null; return null;
} }
const account = status.get('account'); const content = { __html: status.get('contentHtml') };
const content = status.get('content');
const attachments = status.get('media_attachments');
// The result. // The result.
return ( return (
<article className='quote-indicator'> <article className='quote-indicator'>
<header className='quote-indicator__header'> <header className='quote-indicator__header'>
<IconButton <div className='quote-indicator__cancel'>
className='quote-indicator__cancel' <IconButton title={intl.formatMessage(messages.cancel)} icon='times' iconComponent={CloseIcon} onClick={this.handleClick} inverted />
icon='times' </div>
onClick={this.handleClick}
title={intl.formatMessage(messages.cancel)} <a href={status.getIn(['account', 'url'])} onClick={this.handleAccountClick} className='quote-indicator__display-name' target='_blank' rel='noopener noreferrer'>
inverted <div className='quote-indicator__display-avatar'><Avatar account={status.get('account')} size={24} /></div>
/> <DisplayName account={status.get('account')} inline />
<Icon </a>
className='quote-indicator__cancel icon-button inverted'
icon='quote-right'
id='quote-right' />
{account && (
<AccountContainer
id={account}
small
/>
)}
</header> </header>
<div
className='quote-indicator__content icon-button translate' <div className='quote-indicator__content translate' dangerouslySetInnerHTML={content} />
dangerouslySetInnerHTML={{ __html: content || '' }}
/> {status.get('media_attachments').size > 0 && (
{attachments.size > 0 && (
<AttachmentList <AttachmentList
compact compact
media={attachments} media={status.get('media_attachments')}
/> />
)} )}
</article> </article>
@ -85,4 +82,4 @@ class QuoteIndicator extends ImmutablePureComponent {
} }
export default injectIntl(QuoteIndicator) export default withOptionalRouter(injectIntl(QuoteIndicator));

View file

@ -54,9 +54,6 @@ class ReplyIndicator extends ImmutablePureComponent {
<div className='reply-indicator__cancel'> <div className='reply-indicator__cancel'>
<IconButton title={intl.formatMessage(messages.cancel)} icon='times' iconComponent={CloseIcon} onClick={this.handleClick} inverted /> <IconButton title={intl.formatMessage(messages.cancel)} icon='times' iconComponent={CloseIcon} onClick={this.handleClick} inverted />
</div> </div>
<div className='quote-indicator__cancel'>
<Icon className='icon-button inverted' id='reply' />
</div>
<a href={status.getIn(['account', 'url'])} onClick={this.handleAccountClick} className='reply-indicator__display-name' target='_blank' rel='noopener noreferrer'> <a href={status.getIn(['account', 'url'])} onClick={this.handleAccountClick} className='reply-indicator__display-name' target='_blank' rel='noopener noreferrer'>
<div className='reply-indicator__display-avatar'><Avatar account={status.get('account')} size={24} /></div> <div className='reply-indicator__display-avatar'><Avatar account={status.get('account')} size={24} /></div>

View file

@ -1,14 +1,18 @@
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { cancelQuoteCompose } from 'flavours/glitch/actions/compose'; import { cancelQuoteCompose } from 'flavours/glitch/actions/compose';
import { makeGetStatus } from '../../../selectors';
import QuoteIndicator from '../components/quote_indicator'; import QuoteIndicator from '../components/quote_indicator';
const makeMapStateToProps = () => { const makeMapStateToProps = () => {
const getStatus = makeGetStatus();
const mapStateToProps = state => { const mapStateToProps = state => {
const statusId = state.getIn(['compose', 'quote_id']); const statusId = state.getIn(['compose', 'quote_id'], null);
const editing = false; const editing = false;
return { return {
status: state.getIn(['statuses', statusId]), status: getStatus(state, { id: statusId }),
editing, editing,
}; };
}; };

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 -960 960 960" width="24"><path d="m228-240 92-160q-66 0-113-47t-47-113q0-66 47-113t113-47q66 0 113 47t47 113q0 23-5.5 42.5T458-480L320-240h-92Zm360 0 92-160q-66 0-113-47t-47-113q0-66 47-113t113-47q66 0 113 47t47 113q0 23-5.5 42.5T818-480L680-240h-92Z"/></svg>

After

Width:  |  Height:  |  Size: 322 B

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 -960 960 960" width="24"><path d="m228-240 92-160q-66 0-113-47t-47-113q0-66 47-113t113-47q66 0 113 47t47 113q0 23-5.5 42.5T458-480L320-240h-92Zm360 0 92-160q-66 0-113-47t-47-113q0-66 47-113t113-47q66 0 113 47t47 113q0 23-5.5 42.5T818-480L680-240h-92ZM320-500q25 0 42.5-17.5T380-560q0-25-17.5-42.5T320-620q-25 0-42.5 17.5T260-560q0 25 17.5 42.5T320-500Zm360 0q25 0 42.5-17.5T740-560q0-25-17.5-42.5T680-620q-25 0-42.5 17.5T620-560q0 25 17.5 42.5T680-500Zm0-60Zm-360 0Z"/></svg>

After

Width:  |  Height:  |  Size: 538 B

View file

@ -180,11 +180,11 @@ class Status < ApplicationRecord
quote: [ quote: [
:application, :application,
:tags, :tags,
:preview_cards,
:media_attachments, :media_attachments,
:conversation, :conversation,
:status_stat, :status_stat,
:preloadable_poll, :preloadable_poll,
preview_cards_status: [:preview_card],
account: [:account_stat, :user], account: [:account_stat, :user],
active_mentions: { account: :account_stat }, active_mentions: { account: :account_stat },
], ],

View file

@ -1,35 +1,38 @@
.status.quote-status{ dataurl: ActivityPub::TagManager.instance.url_for(status) } .status.quote-status{ dataurl: ActivityPub::TagManager.instance.url_for(status) }
= link_to ActivityPub::TagManager.instance.url_for(status.account), class: 'status__display-name u-url', target: stream_link_target, rel: 'noopener' do = link_to ActivityPub::TagManager.instance.url_for(status.account), class: 'status__display-name u-url', target: stream_link_target, rel: 'noopener noreferrer' do
.status__avatar .status__avatar
%div %div
= image_tag status.account.avatar_static_url, width: 18, height: 18, alt: '', class: 'u-photo account__avatar' - if prefers_autoplay?
= image_tag status.account.avatar_original_url, alt: '', class: 'u-photo account__avatar'
- else
= image_tag status.account.avatar_static_url, alt: '', class: 'u-photo account__avatar'
%span.display-name %span.display-name
%bdi %bdi
%strong.display-name__html.p-name.emojify= display_name(status.account, custom_emojify: true) %strong.display-name__html.p-name.emojify= display_name(status.account, custom_emojify: true, autoplay: prefers_autoplay?)
&nbsp; &nbsp;
%span.display-name__account %span.display-name__account
= acct(status.account) = acct(status.account)
= fa_icon('lock') if status.account.locked? = fa_icon('lock') if status.account.locked?
.status__content.emojify< .status__content.emojify{ data: ({ spoiler: current_account&.user&.setting_expand_spoilers ? 'expanded' : 'folded' } if status.spoiler_text?) }<
- if status.spoiler_text?
%p{ style: ('margin-bottom: 0' unless current_account&.user&.setting_expand_spoilers) }<
%span.p-summary> #{Formatter.instance.format_spoiler(status)}&nbsp;
%button.status__content__spoiler-link= t('statuses.show_more')
.e-content{ lang: status.language, style: "display: #{!current_account&.user&.setting_expand_spoilers && status.spoiler_text? ? 'none' : 'block'}" }
= Formatter.instance.format_in_quote(status, custom_emojify: true)
- if !status.media_attachments.empty? - if status.spoiler_text?
- if status.media_attachments.first.video? %p<
- video = status.media_attachments.first %span.p-summary> #{prerender_custom_emojis(h(status.spoiler_text), status.emojis)}&nbsp;
= react_component :video, src: video.file.url(:original), preview: video.file.url(:small), blurhash: video.blurhash, sensitive: (!current_account&.user&.show_all_media? && status.sensitive?) || current_account&.user&.hide_all_media?, width: 610, height: 343, inline: true, alt: video.description, quote: true do %button.status__content__spoiler-link= t('statuses.show_more')
= render partial: 'statuses/attachment_list', locals: { attachments: status.media_attachments } .e-content{ lang: status.language }<
- elsif status.media_attachments.first.audio? = prerender_custom_emojis(status_content_format(status), status.emojis)
- audio = status.media_attachments.first
= react_component :audio, src: audio.file.url(:original), height: 60, alt: audio.description, duration: audio.file.meta.dig(:original, :duration) do - if status.preloadable_poll
= render partial: 'statuses/attachment_list', locals: { attachments: status.media_attachments } = render_poll_component(status)
- if !status.ordered_media_attachments.empty?
- if status.ordered_media_attachments.first.video?
= render_video_component(status, width: 610, height: 343)
- elsif status.ordered_media_attachments.first.audio?
= render_audio_component(status, width: 610, height: 343)
- else - else
= react_component :media_gallery, height: 343, sensitive: (!current_account&.user&.show_all_media? && status.sensitive?) || current_account&.user&.hide_all_media?, autoPlayGif: current_account&.user&.setting_auto_play_gif, media: status.media_attachments.map { |a| ActiveModelSerializers::SerializableResource.new(a, serializer: REST::MediaAttachmentSerializer).as_json }, quote: true do = render_media_gallery_component(status, height: 343)
= render partial: 'statuses/attachment_list', locals: { attachments: status.media_attachments }
- elsif status.preview_card - elsif status.preview_card
= react_component :card, maxDescription: 10, card: ActiveModelSerializers::SerializableResource.new(status.preview_card, serializer: REST::PreviewCardSerializer).as_json, quote: true = render_card_component(status)

View file

@ -1,7 +1,7 @@
{ {
"name": "@mastodon/mastodon", "name": "@mastodon/mastodon",
"license": "AGPL-3.0-or-later", "license": "AGPL-3.0-or-later",
"packageManager": "yarn@4.0.2", "packageManager": "yarn@4.1.0",
"engines": { "engines": {
"node": ">=18" "node": ">=18"
}, },