Merge pull request #1364 from ThibG/glitch-soc/merge-upstream

Merge upstream changes
shrike
ThibG 2020-06-26 16:36:55 +02:00 committed by GitHub
commit 10ede3eb27
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
58 changed files with 735 additions and 409 deletions

View File

@ -1,10 +1,10 @@
FROM ubuntu:18.04 as build-dep FROM ubuntu:20.04 as build-dep
# Use bash for the shell # Use bash for the shell
SHELL ["bash", "-c"] SHELL ["bash", "-c"]
# Install Node v12 (LTS) # Install Node v12 (LTS)
ENV NODE_VER="12.16.1" ENV NODE_VER="12.16.3"
RUN ARCH= && \ RUN ARCH= && \
dpkgArch="$(dpkg --print-architecture)" && \ dpkgArch="$(dpkg --print-architecture)" && \
case "${dpkgArch##*-}" in \ case "${dpkgArch##*-}" in \
@ -74,7 +74,7 @@ RUN cd /opt/mastodon && \
bundle install -j$(nproc) && \ bundle install -j$(nproc) && \
yarn install --pure-lockfile yarn install --pure-lockfile
FROM ubuntu:18.04 FROM ubuntu:20.04
# Copy over all the langs needed for runtime # Copy over all the langs needed for runtime
COPY --from=build-dep /opt/node /opt/node COPY --from=build-dep /opt/node /opt/node
@ -98,8 +98,8 @@ RUN apt update && \
# Install mastodon runtime deps # Install mastodon runtime deps
RUN apt -y --no-install-recommends install \ RUN apt -y --no-install-recommends install \
libssl1.1 libpq5 imagemagick ffmpeg \ libssl1.1 libpq5 imagemagick ffmpeg \
libicu60 libprotobuf10 libidn11 libyaml-0-2 \ libicu66 libprotobuf17 libidn11 libyaml-0-2 \
file ca-certificates tzdata libreadline7 && \ file ca-certificates tzdata libreadline8 && \
apt -y install gcc && \ apt -y install gcc && \
ln -s /opt/mastodon /mastodon && \ ln -s /opt/mastodon /mastodon && \
gem install bundler && \ gem install bundler && \

View File

@ -20,7 +20,7 @@ gem 'makara', '~> 0.4'
gem 'pghero', '~> 2.5' gem 'pghero', '~> 2.5'
gem 'dotenv-rails', '~> 2.7' gem 'dotenv-rails', '~> 2.7'
gem 'aws-sdk-s3', '~> 1.68', require: false gem 'aws-sdk-s3', '~> 1.69', require: false
gem 'fog-core', '<= 2.1.0' gem 'fog-core', '<= 2.1.0'
gem 'fog-openstack', '~> 0.3', require: false gem 'fog-openstack', '~> 0.3', require: false
gem 'paperclip', '~> 6.0' gem 'paperclip', '~> 6.0'
@ -120,12 +120,12 @@ group :production, :test do
end end
group :test do group :test do
gem 'capybara', '~> 3.32' gem 'capybara', '~> 3.33'
gem 'climate_control', '~> 0.2' gem 'climate_control', '~> 0.2'
gem 'faker', '~> 2.12' gem 'faker', '~> 2.12'
gem 'microformats', '~> 4.2' gem 'microformats', '~> 4.2'
gem 'rails-controller-testing', '~> 1.0' gem 'rails-controller-testing', '~> 1.0'
gem 'rspec-sidekiq', '~> 3.0' gem 'rspec-sidekiq', '~> 3.1'
gem 'simplecov', '~> 0.18', require: false gem 'simplecov', '~> 0.18', require: false
gem 'webmock', '~> 3.8' gem 'webmock', '~> 3.8'
gem 'parallel_tests', '~> 3.0' gem 'parallel_tests', '~> 3.0'

View File

@ -92,7 +92,7 @@ GEM
av (0.9.0) av (0.9.0)
cocaine (~> 0.5.3) cocaine (~> 0.5.3)
aws-eventstream (1.1.0) aws-eventstream (1.1.0)
aws-partitions (1.329.0) aws-partitions (1.332.0)
aws-sdk-core (3.100.0) aws-sdk-core (3.100.0)
aws-eventstream (~> 1, >= 1.0.2) aws-eventstream (~> 1, >= 1.0.2)
aws-partitions (~> 1, >= 1.239.0) aws-partitions (~> 1, >= 1.239.0)
@ -101,12 +101,12 @@ GEM
aws-sdk-kms (1.34.1) aws-sdk-kms (1.34.1)
aws-sdk-core (~> 3, >= 3.99.0) aws-sdk-core (~> 3, >= 3.99.0)
aws-sigv4 (~> 1.1) aws-sigv4 (~> 1.1)
aws-sdk-s3 (1.68.1) aws-sdk-s3 (1.69.0)
aws-sdk-core (~> 3, >= 3.99.0) aws-sdk-core (~> 3, >= 3.99.0)
aws-sdk-kms (~> 1) aws-sdk-kms (~> 1)
aws-sigv4 (~> 1.1) aws-sigv4 (~> 1.1)
aws-sigv4 (1.1.4) aws-sigv4 (1.2.0)
aws-eventstream (~> 1.0, >= 1.0.2) aws-eventstream (~> 1, >= 1.0.2)
bcrypt (3.1.13) bcrypt (3.1.13)
better_errors (2.7.1) better_errors (2.7.1)
coderay (>= 1.0.0) coderay (>= 1.0.0)
@ -143,7 +143,7 @@ GEM
sshkit (~> 1.3) sshkit (~> 1.3)
capistrano-yarn (2.0.2) capistrano-yarn (2.0.2)
capistrano (~> 3.0) capistrano (~> 3.0)
capybara (3.32.2) capybara (3.33.0)
addressable addressable
mini_mime (>= 0.1.3) mini_mime (>= 0.1.3)
nokogiri (~> 1.8) nokogiri (~> 1.8)
@ -202,13 +202,13 @@ GEM
railties (>= 3.2, < 6.1) railties (>= 3.2, < 6.1)
e2mmap (0.1.0) e2mmap (0.1.0)
ed25519 (1.2.4) ed25519 (1.2.4)
elasticsearch (7.7.0) elasticsearch (7.8.0)
elasticsearch-api (= 7.7.0) elasticsearch-api (= 7.8.0)
elasticsearch-transport (= 7.7.0) elasticsearch-transport (= 7.8.0)
elasticsearch-api (7.7.0) elasticsearch-api (7.8.0)
multi_json multi_json
elasticsearch-dsl (0.1.9) elasticsearch-dsl (0.1.9)
elasticsearch-transport (7.7.0) elasticsearch-transport (7.8.0)
faraday (~> 1) faraday (~> 1)
multi_json multi_json
encryptor (3.0.0) encryptor (3.0.0)
@ -216,7 +216,7 @@ GEM
erubi (1.9.0) erubi (1.9.0)
et-orbi (1.2.4) et-orbi (1.2.4)
tzinfo tzinfo
excon (0.74.0) excon (0.75.0)
fabrication (2.21.1) fabrication (2.21.1)
faker (2.12.0) faker (2.12.0)
i18n (>= 1.6, < 2) i18n (>= 1.6, < 2)
@ -341,7 +341,7 @@ GEM
activesupport (>= 4) activesupport (>= 4)
railties (>= 4) railties (>= 4)
request_store (~> 1.0) request_store (~> 1.0)
loofah (2.5.0) loofah (2.6.0)
crass (~> 1.0.2) crass (~> 1.0.2)
nokogiri (>= 1.5.9) nokogiri (>= 1.5.9)
mail (2.7.1) mail (2.7.1)
@ -407,8 +407,8 @@ GEM
parallel (1.19.2) parallel (1.19.2)
parallel_tests (3.0.0) parallel_tests (3.0.0)
parallel parallel
parser (2.7.1.3) parser (2.7.1.4)
ast (~> 2.4.0) ast (~> 2.4.1)
parslet (2.0.0) parslet (2.0.0)
pastel (0.7.4) pastel (0.7.4)
equatable (~> 0.6) equatable (~> 0.6)
@ -485,7 +485,7 @@ GEM
thor (>= 0.19.0, < 2.0) thor (>= 0.19.0, < 2.0)
rainbow (3.0.0) rainbow (3.0.0)
rake (13.0.1) rake (13.0.1)
rdf (3.1.2) rdf (3.1.3)
hamster (~> 3.0) hamster (~> 3.0)
link_header (~> 0.0, >= 0.0.8) link_header (~> 0.0, >= 0.0.8)
rdf-normalize (0.4.0) rdf-normalize (0.4.0)
@ -539,7 +539,7 @@ GEM
rspec-expectations (~> 3.9) rspec-expectations (~> 3.9)
rspec-mocks (~> 3.9) rspec-mocks (~> 3.9)
rspec-support (~> 3.9) rspec-support (~> 3.9)
rspec-sidekiq (3.0.3) rspec-sidekiq (3.1.0)
rspec-core (~> 3.0, >= 3.0.0) rspec-core (~> 3.0, >= 3.0.0)
sidekiq (>= 2.4.0) sidekiq (>= 2.4.0)
rspec-support (3.9.3) rspec-support (3.9.3)
@ -675,7 +675,7 @@ DEPENDENCIES
active_record_query_trace (~> 1.7) active_record_query_trace (~> 1.7)
addressable (~> 2.7) addressable (~> 2.7)
annotate (~> 3.1) annotate (~> 3.1)
aws-sdk-s3 (~> 1.68) aws-sdk-s3 (~> 1.69)
better_errors (~> 2.7) better_errors (~> 2.7)
binding_of_caller (~> 0.7) binding_of_caller (~> 0.7)
blurhash (~> 0.1) blurhash (~> 0.1)
@ -688,7 +688,7 @@ DEPENDENCIES
capistrano-rails (~> 1.5) capistrano-rails (~> 1.5)
capistrano-rbenv (~> 2.1) capistrano-rbenv (~> 2.1)
capistrano-yarn (~> 2.0) capistrano-yarn (~> 2.0)
capybara (~> 3.32) capybara (~> 3.33)
charlock_holmes (~> 0.7.7) charlock_holmes (~> 0.7.7)
chewy (~> 5.1) chewy (~> 5.1)
cld3 (~> 3.3.0) cld3 (~> 3.3.0)
@ -772,7 +772,7 @@ DEPENDENCIES
redis-rails (~> 5.0) redis-rails (~> 5.0)
rqrcode (~> 1.1) rqrcode (~> 1.1)
rspec-rails (~> 4.0) rspec-rails (~> 4.0)
rspec-sidekiq (~> 3.0) rspec-sidekiq (~> 3.1)
rspec_junit_formatter (~> 0.4) rspec_junit_formatter (~> 0.4)
rubocop (~> 0.85) rubocop (~> 0.85)
rubocop-rails (~> 2.6) rubocop-rails (~> 2.6)

View File

@ -77,6 +77,18 @@ module ApplicationHelper
content_tag(:i, nil, attributes.merge(class: class_names.join(' '))) content_tag(:i, nil, attributes.merge(class: class_names.join(' ')))
end end
def visibility_icon(status)
if status.public_visibility?
fa_icon('globe', title: I18n.t('statuses.visibilities.public'))
elsif status.unlisted_visibility?
fa_icon('unlock', title: I18n.t('statuses.visibilities.unlisted'))
elsif status.private_visibility? || status.limited_visibility?
fa_icon('lock', title: I18n.t('statuses.visibilities.private'))
elsif status.direct_visibility?
fa_icon('envelope', title: I18n.t('statuses.visibilities.direct'))
end
end
def custom_emoji_tag(custom_emoji, animate = true) def custom_emoji_tag(custom_emoji, animate = true)
if animate if animate
image_tag(custom_emoji.image.url, class: 'emojione', alt: ":#{custom_emoji.shortcode}:") image_tag(custom_emoji.image.url, class: 'emojione', alt: ":#{custom_emoji.shortcode}:")

View File

@ -15,11 +15,13 @@ module StatusesHelper
end end
def media_summary(status) def media_summary(status)
attachments = { image: 0, video: 0 } attachments = { image: 0, video: 0, audio: 0 }
status.media_attachments.each do |media| status.media_attachments.each do |media|
if media.video? if media.video?
attachments[:video] += 1 attachments[:video] += 1
elsif media.audio?
attachments[:audio] += 1
else else
attachments[:image] += 1 attachments[:image] += 1
end end

View File

@ -156,7 +156,9 @@ export default class Card extends React.PureComponent {
this.setState({ previewLoaded: true }); this.setState({ previewLoaded: true });
} }
handleReveal = () => { handleReveal = e => {
e.preventDefault();
e.stopPropagation();
this.setState({ revealed: true }); this.setState({ revealed: true });
} }
@ -244,7 +246,7 @@ export default class Card extends React.PureComponent {
} }
return ( return (
<div className={className} ref={this.setRef}> <div className={className} ref={this.setRef} onClick={revealed ? null : this.handleReveal} role={revealed ? 'button' : null}>
{embed} {embed}
{!compact && description} {!compact && description}
</div> </div>
@ -254,14 +256,12 @@ export default class Card extends React.PureComponent {
<div className='status-card__image'> <div className='status-card__image'>
{canvas} {canvas}
{thumbnail} {thumbnail}
{!revealed && spoilerButton}
</div> </div>
); );
} else { } else {
embed = ( embed = (
<div className='status-card__image'> <div className='status-card__image'>
<Icon id='file-text' /> <Icon id='file-text' />
{!revealed && spoilerButton}
</div> </div>
); );
} }
@ -270,6 +270,7 @@ export default class Card extends React.PureComponent {
<a href={card.get('url')} className={className} target='_blank' rel='noopener noreferrer' ref={this.setRef}> <a href={card.get('url')} className={className} target='_blank' rel='noopener noreferrer' ref={this.setRef}>
{embed} {embed}
{description} {description}
{!revealed && spoilerButton}
</a> </a>
); );
} }

View File

@ -185,15 +185,26 @@ class Video extends React.PureComponent {
handlePlay = () => { handlePlay = () => {
this.setState({ paused: false }); this.setState({ paused: false });
this._updateTime();
} }
handlePause = () => { handlePause = () => {
this.setState({ paused: true }); this.setState({ paused: true });
} }
_updateTime () {
requestAnimationFrame(() => {
this.handleTimeUpdate();
if (!this.state.paused) {
this._updateTime();
}
});
}
handleTimeUpdate = () => { handleTimeUpdate = () => {
this.setState({ this.setState({
currentTime: Math.floor(this.video.currentTime), currentTime: this.video.currentTime,
duration: Math.floor(this.video.duration), duration: Math.floor(this.video.duration),
}); });
} }
@ -231,7 +242,7 @@ class Video extends React.PureComponent {
this.video.volume = slideamt; this.video.volume = slideamt;
this.setState({ volume: slideamt }); this.setState({ volume: slideamt });
} }
}, 60); }, 15);
handleMouseDown = e => { handleMouseDown = e => {
document.addEventListener('mousemove', this.handleMouseMove, true); document.addEventListener('mousemove', this.handleMouseMove, true);
@ -259,13 +270,14 @@ class Video extends React.PureComponent {
handleMouseMove = throttle(e => { handleMouseMove = throttle(e => {
const { x } = getPointerPosition(this.seek, e); const { x } = getPointerPosition(this.seek, e);
const currentTime = Math.floor(this.video.duration * x); const currentTime = this.video.duration * x;
if (!isNaN(currentTime)) { if (!isNaN(currentTime)) {
this.setState({ currentTime }, () => {
this.video.currentTime = currentTime; this.video.currentTime = currentTime;
this.setState({ currentTime }); });
} }
}, 60); }, 15);
togglePlay = () => { togglePlay = () => {
if (this.state.paused) { if (this.state.paused) {
@ -374,8 +386,10 @@ class Video extends React.PureComponent {
} }
handleProgress = () => { handleProgress = () => {
if (this.video.buffered.length > 0) { const lastTimeRange = this.video.buffered.length - 1;
this.setState({ buffer: this.video.buffered.end(0) / this.video.duration * 100 });
if (lastTimeRange > -1) {
this.setState({ buffer: Math.ceil(this.video.buffered.end(lastTimeRange) / this.video.duration * 100) });
} }
} }
@ -477,7 +491,6 @@ class Video extends React.PureComponent {
onClick={this.togglePlay} onClick={this.togglePlay}
onPlay={this.handlePlay} onPlay={this.handlePlay}
onPause={this.handlePause} onPause={this.handlePause}
onTimeUpdate={this.handleTimeUpdate}
onLoadedData={this.handleLoadedData} onLoadedData={this.handleLoadedData}
onProgress={this.handleProgress} onProgress={this.handleProgress}
onVolumeChange={this.handleVolumeChange} onVolumeChange={this.handleVolumeChange}
@ -518,7 +531,7 @@ class Video extends React.PureComponent {
{(detailed || fullscreen) && ( {(detailed || fullscreen) && (
<span> <span>
<span className='video-player__time-current'>{formatTime(currentTime)}</span> <span className='video-player__time-current'>{formatTime(Math.floor(currentTime))}</span>
<span className='video-player__time-sep'>/</span> <span className='video-player__time-sep'>/</span>
<span className='video-player__time-total'>{formatTime(duration)}</span> <span className='video-player__time-total'>{formatTime(duration)}</span>
</span> </span>

View File

@ -171,9 +171,7 @@ $content-width: 840px;
} }
.content { .content {
padding: 20px 15px; padding: 55px 15px 20px 25px;
padding-top: 60px;
padding-left: 25px;
@media screen and (max-width: $no-columns-breakpoint) { @media screen and (max-width: $no-columns-breakpoint) {
max-width: none; max-width: none;
@ -184,7 +182,7 @@ $content-width: 840px;
&-heading { &-heading {
display: flex; display: flex;
padding-bottom: 40px; padding-bottom: 36px;
border-bottom: 1px solid lighten($ui-base-color, 8%); border-bottom: 1px solid lighten($ui-base-color, 8%);
margin: -15px -15px 40px 0; margin: -15px -15px 40px 0;
@ -215,7 +213,7 @@ $content-width: 840px;
h2 { h2 {
color: $secondary-text-color; color: $secondary-text-color;
font-size: 24px; font-size: 24px;
line-height: 28px; line-height: 36px;
font-weight: 400; font-weight: 400;
@media screen and (max-width: $no-columns-breakpoint) { @media screen and (max-width: $no-columns-breakpoint) {
@ -528,6 +526,16 @@ body,
max-width: 100%; max-width: 100%;
} }
.simple_form {
.actions {
margin-top: 15px;
}
.button {
font-size: 15px;
}
}
.batch-form-box { .batch-form-box {
display: flex; display: flex;
flex-wrap: wrap; flex-wrap: wrap;

View File

@ -66,6 +66,35 @@ body {
} }
} }
&.player {
padding: 0;
margin: 0;
position: absolute;
width: 100%;
height: 100%;
overflow: hidden;
& > div {
height: 100%;
}
.video-player video {
width: 100%;
height: 100%;
max-height: 100vh;
}
.media-gallery {
margin-top: 0;
height: 100% !important;
border-radius: 0;
}
.media-gallery__item {
border-radius: 0;
}
}
&.embed { &.embed {
background: lighten($ui-base-color, 4%); background: lighten($ui-base-color, 4%);
margin: 0; margin: 0;

View File

@ -776,6 +776,7 @@ a.status__display-name,
} }
.status-card { .status-card {
position: relative;
display: flex; display: flex;
font-size: 14px; font-size: 14px;
border: 1px solid lighten($ui-base-color, 8%); border: 1px solid lighten($ui-base-color, 8%);

View File

@ -136,6 +136,11 @@
.detailed-status { .detailed-status {
padding: 15px; padding: 15px;
.detailed-status__display-avatar .account__avatar {
width: 48px;
height: 48px;
}
} }
.status { .status {
@ -196,7 +201,8 @@
display: initial; display: initial;
} }
.status__relative-time { .status__relative-time,
.status__visibility-icon {
color: $dark-text-color; color: $dark-text-color;
float: right; float: right;
font-size: 14px; font-size: 14px;
@ -205,6 +211,11 @@
padding: initial; padding: initial;
} }
.status__visibility-icon {
margin-left: 4px;
margin-right: 4px;
}
.status__info .status__display-name { .status__info .status__display-name {
display: block; display: block;
max-width: 100%; max-width: 100%;
@ -238,7 +249,8 @@
padding-right: 0; padding-right: 0;
} }
.status__relative-time { .status__relative-time,
.status__visibility-icon {
float: left; float: left;
} }
} }

View File

@ -10,7 +10,7 @@ import StatusContent from './status_content';
import StatusActionBar from './status_action_bar'; import StatusActionBar from './status_action_bar';
import AttachmentList from './attachment_list'; import AttachmentList from './attachment_list';
import Card from '../features/status/components/card'; import Card from '../features/status/components/card';
import { injectIntl, FormattedMessage } from 'react-intl'; import { injectIntl, defineMessages, FormattedMessage } from 'react-intl';
import ImmutablePureComponent from 'react-immutable-pure-component'; import ImmutablePureComponent from 'react-immutable-pure-component';
import { MediaGallery, Video, Audio } from '../features/ui/util/async-components'; import { MediaGallery, Video, Audio } from '../features/ui/util/async-components';
import { HotKeys } from 'react-hotkeys'; import { HotKeys } from 'react-hotkeys';
@ -51,6 +51,13 @@ export const defaultMediaVisibility = (status) => {
return (displayMedia !== 'hide_all' && !status.get('sensitive') || displayMedia === 'show_all'); return (displayMedia !== 'hide_all' && !status.get('sensitive') || displayMedia === 'show_all');
}; };
const messages = defineMessages({
public_short: { id: 'privacy.public.short', defaultMessage: 'Public' },
unlisted_short: { id: 'privacy.unlisted.short', defaultMessage: 'Unlisted' },
private_short: { id: 'privacy.private.short', defaultMessage: 'Followers-only' },
direct_short: { id: 'privacy.direct.short', defaultMessage: 'Direct' },
});
export default @injectIntl export default @injectIntl
class Status extends ImmutablePureComponent { class Status extends ImmutablePureComponent {
@ -416,6 +423,15 @@ class Status extends ImmutablePureComponent {
statusAvatar = <AvatarOverlay account={status.get('account')} friend={account} />; statusAvatar = <AvatarOverlay account={status.get('account')} friend={account} />;
} }
const visibilityIconInfo = {
'public': { icon: 'globe', text: intl.formatMessage(messages.public_short) },
'unlisted': { icon: 'unlock', text: intl.formatMessage(messages.unlisted_short) },
'private': { icon: 'lock', text: intl.formatMessage(messages.private_short) },
'direct': { icon: 'envelope', text: intl.formatMessage(messages.direct_short) },
};
const visibilityIcon = visibilityIconInfo[status.get('visibility')];
return ( return (
<HotKeys handlers={handlers}> <HotKeys handlers={handlers}>
<div className={classNames('status__wrapper', `status__wrapper-${status.get('visibility')}`, { 'status__wrapper-reply': !!status.get('in_reply_to_id'), read: unread === false, focusable: !this.props.muted })} tabIndex={this.props.muted ? null : 0} data-featured={featured ? 'true' : null} aria-label={textForScreenReader(intl, status, rebloggedByText)} ref={this.handleRef}> <div className={classNames('status__wrapper', `status__wrapper-${status.get('visibility')}`, { 'status__wrapper-reply': !!status.get('in_reply_to_id'), read: unread === false, focusable: !this.props.muted })} tabIndex={this.props.muted ? null : 0} data-featured={featured ? 'true' : null} aria-label={textForScreenReader(intl, status, rebloggedByText)} ref={this.handleRef}>
@ -425,6 +441,7 @@ class Status extends ImmutablePureComponent {
<div className='status__expand' onClick={this.handleExpandClick} role='presentation' /> <div className='status__expand' onClick={this.handleExpandClick} role='presentation' />
<div className='status__info'> <div className='status__info'>
<a href={status.get('url')} className='status__relative-time' target='_blank' rel='noopener noreferrer'><RelativeTimestamp timestamp={status.get('created_at')} /></a> <a href={status.get('url')} className='status__relative-time' target='_blank' rel='noopener noreferrer'><RelativeTimestamp timestamp={status.get('created_at')} /></a>
<span className='status__visibility-icon'><Icon id={visibilityIcon.icon} title={visibilityIcon.text} /></span>
<a onClick={this.handleAccountClick} data-id={status.getIn(['account', 'id'])} href={status.getIn(['account', 'url'])} title={status.getIn(['account', 'acct'])} className='status__display-name' target='_blank' rel='noopener noreferrer'> <a onClick={this.handleAccountClick} data-id={status.getIn(['account', 'id'])} href={status.getIn(['account', 'url'])} title={status.getIn(['account', 'acct'])} className='status__display-name' target='_blank' rel='noopener noreferrer'>
<div className='status__avatar'> <div className='status__avatar'>

View File

@ -237,9 +237,6 @@ class StatusActionBar extends ImmutablePureComponent {
const account = status.get('account'); const account = status.get('account');
let menu = []; let menu = [];
let reblogIcon = 'retweet';
let replyIcon;
let replyTitle;
menu.push({ text: intl.formatMessage(messages.open), action: this.handleOpen }); menu.push({ text: intl.formatMessage(messages.open), action: this.handleOpen });
@ -259,10 +256,6 @@ class StatusActionBar extends ImmutablePureComponent {
if (status.getIn(['account', 'id']) === me) { if (status.getIn(['account', 'id']) === me) {
if (publicStatus) { if (publicStatus) {
menu.push({ text: intl.formatMessage(status.get('pinned') ? messages.unpin : messages.pin), action: this.handlePinClick }); menu.push({ text: intl.formatMessage(status.get('pinned') ? messages.unpin : messages.pin), action: this.handlePinClick });
} else {
if (status.get('visibility') === 'private') {
menu.push({ text: intl.formatMessage(status.get('reblogged') ? messages.cancel_reblog_private : messages.reblog_private), action: this.handleReblogClick });
}
} }
menu.push({ text: intl.formatMessage(messages.delete), action: this.handleDeleteClick }); menu.push({ text: intl.formatMessage(messages.delete), action: this.handleDeleteClick });
@ -305,12 +298,8 @@ class StatusActionBar extends ImmutablePureComponent {
} }
} }
if (status.get('visibility') === 'direct') { let replyIcon;
reblogIcon = 'envelope'; let replyTitle;
} else if (status.get('visibility') === 'private') {
reblogIcon = 'lock';
}
if (status.get('in_reply_to_id', null) === null) { if (status.get('in_reply_to_id', null) === null) {
replyIcon = 'reply'; replyIcon = 'reply';
replyTitle = intl.formatMessage(messages.reply); replyTitle = intl.formatMessage(messages.reply);
@ -319,6 +308,19 @@ class StatusActionBar extends ImmutablePureComponent {
replyTitle = intl.formatMessage(messages.replyAll); replyTitle = intl.formatMessage(messages.replyAll);
} }
const reblogPrivate = status.getIn(['account', 'id']) === me && status.get('visibility') === 'private';
let reblogTitle = '';
if (status.get('reblogged')) {
reblogTitle = intl.formatMessage(messages.cancel_reblog_private);
} else if (publicStatus) {
reblogTitle = intl.formatMessage(messages.reblog);
} else if (reblogPrivate) {
reblogTitle = intl.formatMessage(messages.reblog_private);
} else {
reblogTitle = intl.formatMessage(messages.cannot_reblog);
}
const shareButton = ('share' in navigator) && publicStatus && ( const shareButton = ('share' in navigator) && publicStatus && (
<IconButton className='status__action-bar-button' title={intl.formatMessage(messages.share)} icon='share-alt' onClick={this.handleShareClick} /> <IconButton className='status__action-bar-button' title={intl.formatMessage(messages.share)} icon='share-alt' onClick={this.handleShareClick} />
); );
@ -326,7 +328,7 @@ class StatusActionBar extends ImmutablePureComponent {
return ( return (
<div className='status__action-bar'> <div className='status__action-bar'>
<div className='status__action-bar__counter'><IconButton className='status__action-bar-button' title={replyTitle} icon={status.get('in_reply_to_account_id') === status.getIn(['account', 'id']) ? 'reply' : replyIcon} onClick={this.handleReplyClick} /><span className='status__action-bar__counter__label' >{obfuscatedCount(status.get('replies_count'))}</span></div> <div className='status__action-bar__counter'><IconButton className='status__action-bar-button' title={replyTitle} icon={status.get('in_reply_to_account_id') === status.getIn(['account', 'id']) ? 'reply' : replyIcon} onClick={this.handleReplyClick} /><span className='status__action-bar__counter__label' >{obfuscatedCount(status.get('replies_count'))}</span></div>
<IconButton className='status__action-bar-button' disabled={!publicStatus} active={status.get('reblogged')} pressed={status.get('reblogged')} title={!publicStatus ? intl.formatMessage(messages.cannot_reblog) : intl.formatMessage(messages.reblog)} icon={reblogIcon} onClick={this.handleReblogClick} /> <IconButton className='status__action-bar-button' disabled={!publicStatus && !reblogPrivate} active={status.get('reblogged')} pressed={status.get('reblogged')} title={reblogTitle} icon='retweet' onClick={this.handleReblogClick} />
<IconButton className='status__action-bar-button star-icon' animate active={status.get('favourited')} pressed={status.get('favourited')} title={intl.formatMessage(messages.favourite)} icon='star' onClick={this.handleFavouriteClick} /> <IconButton className='status__action-bar-button star-icon' animate active={status.get('favourited')} pressed={status.get('favourited')} title={intl.formatMessage(messages.favourite)} icon='star' onClick={this.handleFavouriteClick} />
{shareButton} {shareButton}

View File

@ -154,6 +154,7 @@ class Audio extends React.PureComponent {
width: PropTypes.number, width: PropTypes.number,
height: PropTypes.number, height: PropTypes.number,
editable: PropTypes.bool, editable: PropTypes.bool,
fullscreen: PropTypes.bool,
intl: PropTypes.object.isRequired, intl: PropTypes.object.isRequired,
cacheWidth: PropTypes.func, cacheWidth: PropTypes.func,
}; };
@ -180,7 +181,7 @@ class Audio extends React.PureComponent {
_setDimensions () { _setDimensions () {
const width = this.player.offsetWidth; const width = this.player.offsetWidth;
const height = width / (16/9); const height = this.props.fullscreen ? this.player.offsetHeight : (width / (16/9));
if (this.props.cacheWidth) { if (this.props.cacheWidth) {
this.props.cacheWidth(width); this.props.cacheWidth(width);
@ -291,8 +292,10 @@ class Audio extends React.PureComponent {
} }
handleProgress = () => { handleProgress = () => {
if (this.audio.buffered.length > 0) { const lastTimeRange = this.audio.buffered.length - 1;
this.setState({ buffer: this.audio.buffered.end(0) / this.audio.duration * 100 });
if (lastTimeRange > -1) {
this.setState({ buffer: Math.ceil(this.audio.buffered.end(lastTimeRange) / this.audio.duration * 100) });
} }
} }
@ -349,18 +352,18 @@ class Audio extends React.PureComponent {
handleMouseMove = throttle(e => { handleMouseMove = throttle(e => {
const { x } = getPointerPosition(this.seek, e); const { x } = getPointerPosition(this.seek, e);
const currentTime = Math.floor(this.audio.duration * x); const currentTime = this.audio.duration * x;
if (!isNaN(currentTime)) { if (!isNaN(currentTime)) {
this.setState({ currentTime }, () => { this.setState({ currentTime }, () => {
this.audio.currentTime = currentTime; this.audio.currentTime = currentTime;
}); });
} }
}, 60); }, 15);
handleTimeUpdate = () => { handleTimeUpdate = () => {
this.setState({ this.setState({
currentTime: Math.floor(this.audio.currentTime), currentTime: this.audio.currentTime,
duration: Math.floor(this.audio.duration), duration: Math.floor(this.audio.duration),
}); });
} }
@ -373,7 +376,7 @@ class Audio extends React.PureComponent {
this.audio.volume = x; this.audio.volume = x;
}); });
} }
}, 60); }, 15);
handleScroll = throttle(() => { handleScroll = throttle(() => {
if (!this.canvas || !this.audio) { if (!this.canvas || !this.audio) {
@ -451,6 +454,7 @@ class Audio extends React.PureComponent {
_renderCanvas () { _renderCanvas () {
requestAnimationFrame(() => { requestAnimationFrame(() => {
this.handleTimeUpdate();
this._clear(); this._clear();
this._draw(); this._draw();
@ -622,7 +626,7 @@ class Audio extends React.PureComponent {
const progress = (currentTime / duration) * 100; const progress = (currentTime / duration) * 100;
return ( return (
<div className={classNames('audio-player', { editable, 'with-light-background': darkText })} ref={this.setPlayerRef} style={{ width: '100%', height: this.state.height || this.props.height }} onMouseEnter={this.handleMouseEnter} onMouseLeave={this.handleMouseLeave}> <div className={classNames('audio-player', { editable, 'with-light-background': darkText })} ref={this.setPlayerRef} style={{ width: '100%', height: this.props.fullscreen ? '100%' : (this.state.height || this.props.height) }} onMouseEnter={this.handleMouseEnter} onMouseLeave={this.handleMouseLeave}>
<audio <audio
src={src} src={src}
ref={this.setAudioRef} ref={this.setAudioRef}
@ -630,7 +634,6 @@ class Audio extends React.PureComponent {
onPlay={this.handlePlay} onPlay={this.handlePlay}
onPause={this.handlePause} onPause={this.handlePause}
onProgress={this.handleProgress} onProgress={this.handleProgress}
onTimeUpdate={this.handleTimeUpdate}
crossOrigin='anonymous' crossOrigin='anonymous'
/> />
@ -691,7 +694,7 @@ class Audio extends React.PureComponent {
</div> </div>
<span className='video-player__time'> <span className='video-player__time'>
<span className='video-player__time-current'>{formatTime(currentTime)}</span> <span className='video-player__time-current'>{formatTime(Math.floor(currentTime))}</span>
<span className='video-player__time-sep'>/</span> <span className='video-player__time-sep'>/</span>
<span className='video-player__time-total'>{formatTime(this.state.duration || Math.floor(this.props.duration))}</span> <span className='video-player__time-total'>{formatTime(this.state.duration || Math.floor(this.props.duration))}</span>
</span> </span>

View File

@ -7,11 +7,9 @@ import ImmutablePureComponent from 'react-immutable-pure-component';
import ImmutablePropTypes from 'react-immutable-proptypes'; import ImmutablePropTypes from 'react-immutable-proptypes';
const messages = defineMessages({ const messages = defineMessages({
upload: { id: 'upload_button.label', defaultMessage: 'Add media ({formats})' }, upload: { id: 'upload_button.label', defaultMessage: 'Add images, a video or an audio file' },
}); });
const SUPPORTED_FORMATS = 'JPEG, PNG, GIF, WebM, MP4, MOV, OGG, WAV, MP3, FLAC';
const makeMapStateToProps = () => { const makeMapStateToProps = () => {
const mapStateToProps = state => ({ const mapStateToProps = state => ({
acceptContentTypes: state.getIn(['media_attachments', 'accept_content_types']), acceptContentTypes: state.getIn(['media_attachments', 'accept_content_types']),
@ -60,11 +58,13 @@ class UploadButton extends ImmutablePureComponent {
return null; return null;
} }
const message = intl.formatMessage(messages.upload);
return ( return (
<div className='compose-form__upload-button'> <div className='compose-form__upload-button'>
<IconButton icon='paperclip' title={intl.formatMessage(messages.upload, { formats: SUPPORTED_FORMATS })} disabled={disabled} onClick={this.handleClick} className='compose-form__upload-button-icon' size={18} inverted style={iconStyle} /> <IconButton icon='paperclip' title={message} disabled={disabled} onClick={this.handleClick} className='compose-form__upload-button-icon' size={18} inverted style={iconStyle} />
<label> <label>
<span style={{ display: 'none' }}>{intl.formatMessage(messages.upload, { formats: SUPPORTED_FORMATS })}</span> <span style={{ display: 'none' }}>{message}</span>
<input <input
key={resetFileKey} key={resetFileKey}
ref={this.setRef} ref={this.setRef}

View File

@ -201,10 +201,6 @@ class ActionBar extends React.PureComponent {
if (me === status.getIn(['account', 'id'])) { if (me === status.getIn(['account', 'id'])) {
if (publicStatus) { if (publicStatus) {
menu.push({ text: intl.formatMessage(status.get('pinned') ? messages.unpin : messages.pin), action: this.handlePinClick }); menu.push({ text: intl.formatMessage(status.get('pinned') ? messages.unpin : messages.pin), action: this.handlePinClick });
} else {
if (status.get('visibility') === 'private') {
menu.push({ text: intl.formatMessage(status.get('reblogged') ? messages.cancel_reblog_private : messages.reblog_private), action: this.handleReblogClick });
}
} }
menu.push(null); menu.push(null);
@ -261,14 +257,23 @@ class ActionBar extends React.PureComponent {
replyIcon = 'reply-all'; replyIcon = 'reply-all';
} }
let reblogIcon = 'retweet'; const reblogPrivate = status.getIn(['account', 'id']) === me && status.get('visibility') === 'private';
if (status.get('visibility') === 'direct') reblogIcon = 'envelope';
else if (status.get('visibility') === 'private') reblogIcon = 'lock'; let reblogTitle;
if (status.get('reblogged')) {
reblogTitle = intl.formatMessage(messages.cancel_reblog_private);
} else if (publicStatus) {
reblogTitle = intl.formatMessage(messages.reblog);
} else if (reblogPrivate) {
reblogTitle = intl.formatMessage(messages.reblog_private);
} else {
reblogTitle = intl.formatMessage(messages.cannot_reblog);
}
return ( return (
<div className='detailed-status__action-bar'> <div className='detailed-status__action-bar'>
<div className='detailed-status__button'><IconButton title={intl.formatMessage(messages.reply)} icon={status.get('in_reply_to_account_id') === status.getIn(['account', 'id']) ? 'reply' : replyIcon} onClick={this.handleReplyClick} /></div> <div className='detailed-status__button'><IconButton title={intl.formatMessage(messages.reply)} icon={status.get('in_reply_to_account_id') === status.getIn(['account', 'id']) ? 'reply' : replyIcon} onClick={this.handleReplyClick} /></div>
<div className='detailed-status__button'><IconButton disabled={!publicStatus} active={status.get('reblogged')} title={!publicStatus ? intl.formatMessage(messages.cannot_reblog) : intl.formatMessage(messages.reblog)} icon={reblogIcon} onClick={this.handleReblogClick} /></div> <div className='detailed-status__button'><IconButton disabled={!publicStatus && !reblogPrivate} active={status.get('reblogged')} title={reblogTitle} icon='retweet' onClick={this.handleReblogClick} /></div>
<div className='detailed-status__button'><IconButton className='star-icon' animate active={status.get('favourited')} title={intl.formatMessage(messages.favourite)} icon='star' onClick={this.handleFavouriteClick} /></div> <div className='detailed-status__button'><IconButton className='star-icon' animate active={status.get('favourited')} title={intl.formatMessage(messages.favourite)} icon='star' onClick={this.handleFavouriteClick} /></div>
{shareButton} {shareButton}
<div className='detailed-status__button'><IconButton className='bookmark-icon' active={status.get('bookmarked')} title={intl.formatMessage(messages.bookmark)} icon='bookmark' onClick={this.handleBookmarkClick} /></div> <div className='detailed-status__button'><IconButton className='bookmark-icon' active={status.get('bookmarked')} title={intl.formatMessage(messages.bookmark)} icon='bookmark' onClick={this.handleBookmarkClick} /></div>

View File

@ -191,7 +191,9 @@ export default class Card extends React.PureComponent {
this.setState({ previewLoaded: true }); this.setState({ previewLoaded: true });
} }
handleReveal = () => { handleReveal = e => {
e.preventDefault();
e.stopPropagation();
this.setState({ revealed: true }); this.setState({ revealed: true });
} }
@ -279,7 +281,7 @@ export default class Card extends React.PureComponent {
} }
return ( return (
<div className={className} ref={this.setRef}> <div className={className} ref={this.setRef} onClick={revealed ? null : this.handleReveal} role={revealed ? 'button' : null}>
{embed} {embed}
{!compact && description} {!compact && description}
</div> </div>
@ -289,14 +291,12 @@ export default class Card extends React.PureComponent {
<div className='status-card__image'> <div className='status-card__image'>
{canvas} {canvas}
{thumbnail} {thumbnail}
{!revealed && spoilerButton}
</div> </div>
); );
} else { } else {
embed = ( embed = (
<div className='status-card__image'> <div className='status-card__image'>
<Icon id='file-text' /> <Icon id='file-text' />
{!revealed && spoilerButton}
</div> </div>
); );
} }
@ -305,6 +305,7 @@ export default class Card extends React.PureComponent {
<a href={card.get('url')} className={className} target='_blank' rel='noopener noreferrer' ref={this.setRef}> <a href={card.get('url')} className={className} target='_blank' rel='noopener noreferrer' ref={this.setRef}>
{embed} {embed}
{description} {description}
{!revealed && spoilerButton}
</a> </a>
); );
} }

View File

@ -6,7 +6,7 @@ import DisplayName from '../../../components/display_name';
import StatusContent from '../../../components/status_content'; import StatusContent from '../../../components/status_content';
import MediaGallery from '../../../components/media_gallery'; import MediaGallery from '../../../components/media_gallery';
import { Link } from 'react-router-dom'; import { Link } from 'react-router-dom';
import { FormattedDate } from 'react-intl'; import { injectIntl, defineMessages, FormattedDate } from 'react-intl';
import Card from './card'; import Card from './card';
import ImmutablePureComponent from 'react-immutable-pure-component'; import ImmutablePureComponent from 'react-immutable-pure-component';
import Video from '../../video'; import Video from '../../video';
@ -16,7 +16,15 @@ import classNames from 'classnames';
import Icon from 'mastodon/components/icon'; import Icon from 'mastodon/components/icon';
import AnimatedNumber from 'mastodon/components/animated_number'; import AnimatedNumber from 'mastodon/components/animated_number';
export default class DetailedStatus extends ImmutablePureComponent { const messages = defineMessages({
public_short: { id: 'privacy.public.short', defaultMessage: 'Public' },
unlisted_short: { id: 'privacy.unlisted.short', defaultMessage: 'Unlisted' },
private_short: { id: 'privacy.private.short', defaultMessage: 'Followers-only' },
direct_short: { id: 'privacy.direct.short', defaultMessage: 'Direct' },
});
export default @injectIntl
class DetailedStatus extends ImmutablePureComponent {
static contextTypes = { static contextTypes = {
router: PropTypes.object, router: PropTypes.object,
@ -92,7 +100,7 @@ export default class DetailedStatus extends ImmutablePureComponent {
render () { render () {
const status = (this.props.status && this.props.status.get('reblog')) ? this.props.status.get('reblog') : this.props.status; const status = (this.props.status && this.props.status.get('reblog')) ? this.props.status.get('reblog') : this.props.status;
const outerStyle = { boxSizing: 'border-box' }; const outerStyle = { boxSizing: 'border-box' };
const { compact } = this.props; const { intl, compact } = this.props;
if (!status) { if (!status) {
return null; return null;
@ -157,34 +165,44 @@ export default class DetailedStatus extends ImmutablePureComponent {
} }
if (status.get('application')) { if (status.get('application')) {
applicationLink = <span> · <a className='detailed-status__application' href={status.getIn(['application', 'website'])} target='_blank' rel='noopener noreferrer'>{status.getIn(['application', 'name'])}</a></span>; applicationLink = <React.Fragment> · <a className='detailed-status__application' href={status.getIn(['application', 'website'])} target='_blank' rel='noopener noreferrer'>{status.getIn(['application', 'name'])}</a></React.Fragment>;
} }
if (status.get('visibility') === 'direct') { const visibilityIconInfo = {
reblogIcon = 'envelope'; 'public': { icon: 'globe', text: intl.formatMessage(messages.public_short) },
} else if (status.get('visibility') === 'private') { 'unlisted': { icon: 'unlock', text: intl.formatMessage(messages.unlisted_short) },
reblogIcon = 'lock'; 'private': { icon: 'lock', text: intl.formatMessage(messages.private_short) },
} 'direct': { icon: 'envelope', text: intl.formatMessage(messages.direct_short) },
};
const visibilityIcon = visibilityIconInfo[status.get('visibility')];
const visibilityLink = <React.Fragment> · <Icon id={visibilityIcon.icon} title={visibilityIcon.text} /></React.Fragment>;
if (['private', 'direct'].includes(status.get('visibility'))) { if (['private', 'direct'].includes(status.get('visibility'))) {
reblogLink = <Icon id={reblogIcon} />; reblogLink = '';
} else if (this.context.router) { } else if (this.context.router) {
reblogLink = ( reblogLink = (
<React.Fragment>
<React.Fragment> · </React.Fragment>
<Link to={`/statuses/${status.get('id')}/reblogs`} className='detailed-status__link'> <Link to={`/statuses/${status.get('id')}/reblogs`} className='detailed-status__link'>
<Icon id={reblogIcon} /> <Icon id={reblogIcon} />
<span className='detailed-status__reblogs'> <span className='detailed-status__reblogs'>
<AnimatedNumber value={status.get('reblogs_count')} /> <AnimatedNumber value={status.get('reblogs_count')} />
</span> </span>
</Link> </Link>
</React.Fragment>
); );
} else { } else {
reblogLink = ( reblogLink = (
<React.Fragment>
<React.Fragment> · </React.Fragment>
<a href={`/interact/${status.get('id')}?type=reblog`} className='detailed-status__link' onClick={this.handleModalLink}> <a href={`/interact/${status.get('id')}?type=reblog`} className='detailed-status__link' onClick={this.handleModalLink}>
<Icon id={reblogIcon} /> <Icon id={reblogIcon} />
<span className='detailed-status__reblogs'> <span className='detailed-status__reblogs'>
<AnimatedNumber value={status.get('reblogs_count')} /> <AnimatedNumber value={status.get('reblogs_count')} />
</span> </span>
</a> </a>
</React.Fragment>
); );
} }
@ -210,7 +228,7 @@ export default class DetailedStatus extends ImmutablePureComponent {
return ( return (
<div style={outerStyle}> <div style={outerStyle}>
<div ref={this.setRef} className={classNames('detailed-status', { compact })}> <div ref={this.setRef} className={classNames('detailed-status', `detailed-status-${status.get('visibility')}`, { compact })}>
<a href={status.getIn(['account', 'url'])} onClick={this.handleAccountClick} className='detailed-status__display-name'> <a href={status.getIn(['account', 'url'])} onClick={this.handleAccountClick} className='detailed-status__display-name'>
<div className='detailed-status__display-avatar'><Avatar account={status.get('account')} size={48} /></div> <div className='detailed-status__display-avatar'><Avatar account={status.get('account')} size={48} /></div>
<DisplayName account={status.get('account')} localDomain={this.props.domain} /> <DisplayName account={status.get('account')} localDomain={this.props.domain} />
@ -223,7 +241,7 @@ export default class DetailedStatus extends ImmutablePureComponent {
<div className='detailed-status__meta'> <div className='detailed-status__meta'>
<a className='detailed-status__datetime' href={status.get('url')} target='_blank' rel='noopener noreferrer'> <a className='detailed-status__datetime' href={status.get('url')} target='_blank' rel='noopener noreferrer'>
<FormattedDate value={new Date(status.get('created_at'))} hour12={false} year='numeric' month='short' day='2-digit' hour='2-digit' minute='2-digit' /> <FormattedDate value={new Date(status.get('created_at'))} hour12={false} year='numeric' month='short' day='2-digit' hour='2-digit' minute='2-digit' />
</a>{applicationLink} · {reblogLink} · {favouriteLink} </a>{visibilityLink}{applicationLink}{reblogLink} · {favouriteLink}
</div> </div>
</div> </div>
</div> </div>

View File

@ -177,15 +177,26 @@ class Video extends React.PureComponent {
handlePlay = () => { handlePlay = () => {
this.setState({ paused: false }); this.setState({ paused: false });
this._updateTime();
} }
handlePause = () => { handlePause = () => {
this.setState({ paused: true }); this.setState({ paused: true });
} }
_updateTime () {
requestAnimationFrame(() => {
this.handleTimeUpdate();
if (!this.state.paused) {
this._updateTime();
}
});
}
handleTimeUpdate = () => { handleTimeUpdate = () => {
this.setState({ this.setState({
currentTime: Math.floor(this.video.currentTime), currentTime: this.video.currentTime,
duration: Math.floor(this.video.duration), duration: Math.floor(this.video.duration),
}); });
} }
@ -217,7 +228,7 @@ class Video extends React.PureComponent {
this.video.volume = x; this.video.volume = x;
}); });
} }
}, 60); }, 15);
handleMouseDown = e => { handleMouseDown = e => {
document.addEventListener('mousemove', this.handleMouseMove, true); document.addEventListener('mousemove', this.handleMouseMove, true);
@ -245,13 +256,14 @@ class Video extends React.PureComponent {
handleMouseMove = throttle(e => { handleMouseMove = throttle(e => {
const { x } = getPointerPosition(this.seek, e); const { x } = getPointerPosition(this.seek, e);
const currentTime = Math.floor(this.video.duration * x); const currentTime = this.video.duration * x;
if (!isNaN(currentTime)) { if (!isNaN(currentTime)) {
this.setState({ currentTime }, () => {
this.video.currentTime = currentTime; this.video.currentTime = currentTime;
this.setState({ currentTime }); });
} }
}, 60); }, 15);
togglePlay = () => { togglePlay = () => {
if (this.state.paused) { if (this.state.paused) {
@ -387,8 +399,10 @@ class Video extends React.PureComponent {
} }
handleProgress = () => { handleProgress = () => {
if (this.video.buffered.length > 0) { const lastTimeRange = this.video.buffered.length - 1;
this.setState({ buffer: this.video.buffered.end(0) / this.video.duration * 100 });
if (lastTimeRange > -1) {
this.setState({ buffer: Math.ceil(this.video.buffered.end(lastTimeRange) / this.video.duration * 100) });
} }
} }
@ -484,7 +498,6 @@ class Video extends React.PureComponent {
onClick={this.togglePlay} onClick={this.togglePlay}
onPlay={this.handlePlay} onPlay={this.handlePlay}
onPause={this.handlePause} onPause={this.handlePause}
onTimeUpdate={this.handleTimeUpdate}
onLoadedData={this.handleLoadedData} onLoadedData={this.handleLoadedData}
onProgress={this.handleProgress} onProgress={this.handleProgress}
onVolumeChange={this.handleVolumeChange} onVolumeChange={this.handleVolumeChange}
@ -525,7 +538,7 @@ class Video extends React.PureComponent {
{(detailed || fullscreen) && ( {(detailed || fullscreen) && (
<span className='video-player__time'> <span className='video-player__time'>
<span className='video-player__time-current'>{formatTime(currentTime)}</span> <span className='video-player__time-current'>{formatTime(Math.floor(currentTime))}</span>
<span className='video-player__time-sep'>/</span> <span className='video-player__time-sep'>/</span>
<span className='video-player__time-total'>{formatTime(duration)}</span> <span className='video-player__time-total'>{formatTime(duration)}</span>
</span> </span>

View File

@ -422,7 +422,7 @@
"trends.trending_now": "Trending now", "trends.trending_now": "Trending now",
"ui.beforeunload": "El borrador va perdese si coles de Mastodon.", "ui.beforeunload": "El borrador va perdese si coles de Mastodon.",
"upload_area.title": "Arrastra y suelta pa xubir", "upload_area.title": "Arrastra y suelta pa xubir",
"upload_button.label": "Add media ({formats})", "upload_button.label": "Add images, a video or an audio file",
"upload_error.limit": "File upload limit exceeded.", "upload_error.limit": "File upload limit exceeded.",
"upload_error.poll": "La xuba de ficheros nun ta permitida con encuestes.", "upload_error.poll": "La xuba de ficheros nun ta permitida con encuestes.",
"upload_form.audio_description": "Descripción pa persones con perda auditiva", "upload_form.audio_description": "Descripción pa persones con perda auditiva",

View File

@ -1206,7 +1206,7 @@
{ {
"descriptors": [ "descriptors": [
{ {
"defaultMessage": "Add media ({formats})", "defaultMessage": "Add images, a video or an audio file",
"id": "upload_button.label" "id": "upload_button.label"
} }
], ],

View File

@ -427,7 +427,7 @@
"trends.trending_now": "Trending now", "trends.trending_now": "Trending now",
"ui.beforeunload": "Your draft will be lost if you leave Mastodon.", "ui.beforeunload": "Your draft will be lost if you leave Mastodon.",
"upload_area.title": "Drag & drop to upload", "upload_area.title": "Drag & drop to upload",
"upload_button.label": "Add media ({formats})", "upload_button.label": "Add images, a video or an audio file",
"upload_error.limit": "File upload limit exceeded.", "upload_error.limit": "File upload limit exceeded.",
"upload_error.poll": "File upload not allowed with polls.", "upload_error.poll": "File upload not allowed with polls.",
"upload_form.audio_description": "Describe for people with hearing loss", "upload_form.audio_description": "Describe for people with hearing loss",

View File

@ -422,7 +422,7 @@
"trends.trending_now": "Trending now", "trends.trending_now": "Trending now",
"ui.beforeunload": "Your draft will be lost if you leave Mastodon.", "ui.beforeunload": "Your draft will be lost if you leave Mastodon.",
"upload_area.title": "Drag & drop to upload", "upload_area.title": "Drag & drop to upload",
"upload_button.label": "Add media ({formats})", "upload_button.label": "Add images, a video or an audio file",
"upload_error.limit": "File upload limit exceeded.", "upload_error.limit": "File upload limit exceeded.",
"upload_error.poll": "File upload not allowed with polls.", "upload_error.poll": "File upload not allowed with polls.",
"upload_form.audio_description": "Describe for people with hearing loss", "upload_form.audio_description": "Describe for people with hearing loss",

View File

@ -422,7 +422,7 @@
"trends.trending_now": "Trending now", "trends.trending_now": "Trending now",
"ui.beforeunload": "Your draft will be lost if you leave Mastodon.", "ui.beforeunload": "Your draft will be lost if you leave Mastodon.",
"upload_area.title": "Drag & drop to upload", "upload_area.title": "Drag & drop to upload",
"upload_button.label": "Add media ({formats})", "upload_button.label": "Add images, a video or an audio file",
"upload_error.limit": "File upload limit exceeded.", "upload_error.limit": "File upload limit exceeded.",
"upload_error.poll": "File upload not allowed with polls.", "upload_error.poll": "File upload not allowed with polls.",
"upload_form.audio_description": "Describe for people with hearing loss", "upload_form.audio_description": "Describe for people with hearing loss",

View File

@ -422,7 +422,7 @@
"trends.trending_now": "Trending now", "trends.trending_now": "Trending now",
"ui.beforeunload": "Your draft will be lost if you leave Mastodon.", "ui.beforeunload": "Your draft will be lost if you leave Mastodon.",
"upload_area.title": "Drag & drop to upload", "upload_area.title": "Drag & drop to upload",
"upload_button.label": "Add media ({formats})", "upload_button.label": "Add images, a video or an audio file",
"upload_error.limit": "File upload limit exceeded.", "upload_error.limit": "File upload limit exceeded.",
"upload_error.poll": "File upload not allowed with polls.", "upload_error.poll": "File upload not allowed with polls.",
"upload_form.audio_description": "Describe for people with hearing loss", "upload_form.audio_description": "Describe for people with hearing loss",

View File

@ -422,7 +422,7 @@
"trends.trending_now": "Trending now", "trends.trending_now": "Trending now",
"ui.beforeunload": "Your draft will be lost if you leave Mastodon.", "ui.beforeunload": "Your draft will be lost if you leave Mastodon.",
"upload_area.title": "Drag & drop to upload", "upload_area.title": "Drag & drop to upload",
"upload_button.label": "Add media ({formats})", "upload_button.label": "Add images, a video or an audio file",
"upload_error.limit": "File upload limit exceeded.", "upload_error.limit": "File upload limit exceeded.",
"upload_error.poll": "File upload not allowed with polls.", "upload_error.poll": "File upload not allowed with polls.",
"upload_form.audio_description": "Describe for people with hearing loss", "upload_form.audio_description": "Describe for people with hearing loss",

View File

@ -422,7 +422,7 @@
"trends.trending_now": "Trending now", "trends.trending_now": "Trending now",
"ui.beforeunload": "Your draft will be lost if you leave Mastodon.", "ui.beforeunload": "Your draft will be lost if you leave Mastodon.",
"upload_area.title": "Drag & drop to upload", "upload_area.title": "Drag & drop to upload",
"upload_button.label": "Add media ({formats})", "upload_button.label": "Add images, a video or an audio file",
"upload_error.limit": "File upload limit exceeded.", "upload_error.limit": "File upload limit exceeded.",
"upload_error.poll": "File upload not allowed with polls.", "upload_error.poll": "File upload not allowed with polls.",
"upload_form.audio_description": "Describe for people with hearing loss", "upload_form.audio_description": "Describe for people with hearing loss",

View File

@ -422,7 +422,7 @@
"trends.trending_now": "Trending now", "trends.trending_now": "Trending now",
"ui.beforeunload": "Your draft will be lost if you leave Mastodon.", "ui.beforeunload": "Your draft will be lost if you leave Mastodon.",
"upload_area.title": "Drag & drop to upload", "upload_area.title": "Drag & drop to upload",
"upload_button.label": "Add media ({formats})", "upload_button.label": "Add images, a video or an audio file",
"upload_error.limit": "File upload limit exceeded.", "upload_error.limit": "File upload limit exceeded.",
"upload_error.poll": "File upload not allowed with polls.", "upload_error.poll": "File upload not allowed with polls.",
"upload_form.audio_description": "Describe for people with hearing loss", "upload_form.audio_description": "Describe for people with hearing loss",

View File

@ -422,7 +422,7 @@
"trends.trending_now": "Trending now", "trends.trending_now": "Trending now",
"ui.beforeunload": "Your draft will be lost if you leave Mastodon.", "ui.beforeunload": "Your draft will be lost if you leave Mastodon.",
"upload_area.title": "Drag & drop to upload", "upload_area.title": "Drag & drop to upload",
"upload_button.label": "Add media ({formats})", "upload_button.label": "Add images, a video or an audio file",
"upload_error.limit": "File upload limit exceeded.", "upload_error.limit": "File upload limit exceeded.",
"upload_error.poll": "File upload not allowed with polls.", "upload_error.poll": "File upload not allowed with polls.",
"upload_form.audio_description": "Describe for people with hearing loss", "upload_form.audio_description": "Describe for people with hearing loss",

View File

@ -422,7 +422,7 @@
"trends.trending_now": "Trending now", "trends.trending_now": "Trending now",
"ui.beforeunload": "Your draft will be lost if you leave Mastodon.", "ui.beforeunload": "Your draft will be lost if you leave Mastodon.",
"upload_area.title": "Drag & drop to upload", "upload_area.title": "Drag & drop to upload",
"upload_button.label": "Add media ({formats})", "upload_button.label": "Add images, a video or an audio file",
"upload_error.limit": "File upload limit exceeded.", "upload_error.limit": "File upload limit exceeded.",
"upload_error.poll": "File upload not allowed with polls.", "upload_error.poll": "File upload not allowed with polls.",
"upload_form.audio_description": "Describe for people with hearing loss", "upload_form.audio_description": "Describe for people with hearing loss",

View File

@ -422,7 +422,7 @@
"trends.trending_now": "Trending now", "trends.trending_now": "Trending now",
"ui.beforeunload": "Your draft will be lost if you leave Mastodon.", "ui.beforeunload": "Your draft will be lost if you leave Mastodon.",
"upload_area.title": "Drag & drop to upload", "upload_area.title": "Drag & drop to upload",
"upload_button.label": "Add media ({formats})", "upload_button.label": "Add images, a video or an audio file",
"upload_error.limit": "File upload limit exceeded.", "upload_error.limit": "File upload limit exceeded.",
"upload_error.poll": "File upload not allowed with polls.", "upload_error.poll": "File upload not allowed with polls.",
"upload_form.audio_description": "Describe for people with hearing loss", "upload_form.audio_description": "Describe for people with hearing loss",

View File

@ -422,7 +422,7 @@
"trends.trending_now": "Trending now", "trends.trending_now": "Trending now",
"ui.beforeunload": "Your draft will be lost if you leave Mastodon.", "ui.beforeunload": "Your draft will be lost if you leave Mastodon.",
"upload_area.title": "Drag & drop to upload", "upload_area.title": "Drag & drop to upload",
"upload_button.label": "Add media ({formats})", "upload_button.label": "Add images, a video or an audio file",
"upload_error.limit": "File upload limit exceeded.", "upload_error.limit": "File upload limit exceeded.",
"upload_error.poll": "File upload not allowed with polls.", "upload_error.poll": "File upload not allowed with polls.",
"upload_form.audio_description": "Describe for people with hearing loss", "upload_form.audio_description": "Describe for people with hearing loss",

View File

@ -171,9 +171,7 @@ $content-width: 840px;
} }
.content { .content {
padding: 20px 15px; padding: 55px 15px 20px 25px;
padding-top: 60px;
padding-left: 25px;
@media screen and (max-width: $no-columns-breakpoint) { @media screen and (max-width: $no-columns-breakpoint) {
max-width: none; max-width: none;
@ -184,7 +182,7 @@ $content-width: 840px;
&-heading { &-heading {
display: flex; display: flex;
padding-bottom: 40px; padding-bottom: 36px;
border-bottom: 1px solid lighten($ui-base-color, 8%); border-bottom: 1px solid lighten($ui-base-color, 8%);
margin: -15px -15px 40px 0; margin: -15px -15px 40px 0;
@ -215,7 +213,7 @@ $content-width: 840px;
h2 { h2 {
color: $secondary-text-color; color: $secondary-text-color;
font-size: 24px; font-size: 24px;
line-height: 28px; line-height: 36px;
font-weight: 400; font-weight: 400;
@media screen and (max-width: $no-columns-breakpoint) { @media screen and (max-width: $no-columns-breakpoint) {
@ -544,6 +542,16 @@ body,
max-width: 100%; max-width: 100%;
} }
.simple_form {
.actions {
margin-top: 15px;
}
.button {
font-size: 15px;
}
}
.batch-form-box { .batch-form-box {
display: flex; display: flex;
flex-wrap: wrap; flex-wrap: wrap;

View File

@ -68,7 +68,32 @@ body {
} }
&.player { &.player {
text-align: center; padding: 0;
margin: 0;
position: absolute;
width: 100%;
height: 100%;
overflow: hidden;
& > div {
height: 100%;
}
.video-player video {
width: 100%;
height: 100%;
max-height: 100vh;
}
.media-gallery {
margin-top: 0;
height: 100% !important;
border-radius: 0;
}
.media-gallery__item {
border-radius: 0;
}
} }
&.embed { &.embed {

View File

@ -1019,7 +1019,8 @@
} }
&.light { &.light {
.status__relative-time { .status__relative-time,
.status__visibility-icon {
color: $light-text-color; color: $light-text-color;
} }
@ -1065,12 +1066,18 @@
} }
.status__relative-time, .status__relative-time,
.status__visibility-icon,
.notification__relative_time { .notification__relative_time {
color: $dark-text-color; color: $dark-text-color;
float: right; float: right;
font-size: 14px; font-size: 14px;
} }
.status__visibility-icon {
margin-left: 4px;
margin-right: 4px;
}
.status__display-name { .status__display-name {
color: $dark-text-color; color: $dark-text-color;
} }
@ -3003,6 +3010,7 @@ a.account__display-name {
} }
.status-card { .status-card {
position: relative;
display: flex; display: flex;
font-size: 14px; font-size: 14px;
border: 1px solid lighten($ui-base-color, 8%); border: 1px solid lighten($ui-base-color, 8%);

View File

@ -158,6 +158,7 @@ body.rtl {
} }
.status__relative-time, .status__relative-time,
.status__visibility-icon,
.activity-stream .status.light .status__header .status__meta { .activity-stream .status.light .status__header .status__meta {
float: left; float: left;
} }

View File

@ -140,6 +140,11 @@
.detailed-status { .detailed-status {
padding: 15px; padding: 15px;
.detailed-status__display-avatar .account__avatar {
width: 48px;
height: 48px;
}
} }
.status { .status {

View File

@ -4,7 +4,7 @@ class LanguageDetector
include Singleton include Singleton
WORDS_THRESHOLD = 4 WORDS_THRESHOLD = 4
RELIABLE_CHARACTERS_RE = /[\p{Hebrew}\p{Arabic}\p{Syriac}\p{Thaana}\p{Nko}\p{Han}\p{Katakana}\p{Hiragana}\p{Hangul}]+/m RELIABLE_CHARACTERS_RE = /[\p{Hebrew}\p{Arabic}\p{Syriac}\p{Thaana}\p{Nko}\p{Han}\p{Katakana}\p{Hiragana}\p{Hangul}\p{Thai}]+/m
def initialize def initialize
@identifier = CLD3::NNetLanguageIdentifier.new(1, 2048) @identifier = CLD3::NNetLanguageIdentifier.new(1, 2048)

View File

@ -194,15 +194,17 @@ class MediaAttachment < ApplicationRecord
x, y = (point.is_a?(Enumerable) ? point : point.split(',')).map(&:to_f) x, y = (point.is_a?(Enumerable) ? point : point.split(',')).map(&:to_f)
meta = file.instance_read(:meta) || {} meta = (file.instance_read(:meta) || {}).with_indifferent_access.slice(:focus, :original, :small)
meta['focus'] = { 'x' => x, 'y' => y } meta['focus'] = { 'x' => x, 'y' => y }
file.instance_write(:meta, meta) file.instance_write(:meta, meta)
end end
def focus def focus
x = file.meta['focus']['x'] x = file.meta&.dig('focus', 'x')
y = file.meta['focus']['y'] y = file.meta&.dig('focus', 'y')
return if x.nil? || y.nil?
"#{x},#{y}" "#{x},#{y}"
end end
@ -219,12 +221,11 @@ class MediaAttachment < ApplicationRecord
before_create :prepare_description, unless: :local? before_create :prepare_description, unless: :local?
before_create :set_shortcode before_create :set_shortcode
before_create :set_processing before_create :set_processing
before_create :set_meta
before_post_process :set_type_and_extension before_post_process :set_type_and_extension
before_post_process :check_video_dimensions before_post_process :check_video_dimensions
before_save :set_meta
class << self class << self
def supported_mime_types def supported_mime_types
IMAGE_MIME_TYPES + VIDEO_MIME_TYPES + AUDIO_MIME_TYPES IMAGE_MIME_TYPES + VIDEO_MIME_TYPES + AUDIO_MIME_TYPES
@ -306,15 +307,11 @@ class MediaAttachment < ApplicationRecord
end end
def set_meta def set_meta
meta = populate_meta file.instance_write :meta, populate_meta
return if meta == {}
file.instance_write :meta, meta
end end
def populate_meta def populate_meta
meta = file.instance_read(:meta) || {} meta = (file.instance_read(:meta) || {}).with_indifferent_access.slice(:focus, :original, :small)
file.queued_for_write.each do |style, file| file.queued_for_write.each do |style, file|
meta[style] = style == :small || image? ? image_geometry(file) : video_metadata(file) meta[style] = style == :small || image? ? image_geometry(file) : video_metadata(file)

View File

@ -7,7 +7,7 @@
= opengraph 'og:title', yield(:page_title).strip = opengraph 'og:title', yield(:page_title).strip
= opengraph 'og:description', description = opengraph 'og:description', description
= opengraph 'og:image', full_asset_url(account.avatar.url(:original)) = opengraph 'og:image', full_asset_url(account.avatar.url(:original))
= opengraph 'og:image:width', '120' = opengraph 'og:image:width', '400'
= opengraph 'og:image:height', '120' = opengraph 'og:image:height', '400'
= opengraph 'twitter:card', 'summary' = opengraph 'twitter:card', 'summary'
= opengraph 'profile:username', acct(account)[1..-1] = opengraph 'profile:username', acct(account)[1..-1]

View File

@ -38,7 +38,7 @@
= text_field_tag key, params[key], class: 'string optional', placeholder: I18n.t("admin.accounts.#{key}") = text_field_tag key, params[key], class: 'string optional', placeholder: I18n.t("admin.accounts.#{key}")
.actions .actions
%button= t('admin.accounts.search') %button.button= t('admin.accounts.search')
= link_to t('admin.accounts.reset'), admin_accounts_path, class: 'button negative' = link_to t('admin.accounts.reset'), admin_accounts_path, class: 'button negative'
.table-wrapper .table-wrapper

View File

@ -31,7 +31,7 @@
= text_field_tag key, params[key], class: 'string optional', placeholder: I18n.t("admin.custom_emojis.#{key}") = text_field_tag key, params[key], class: 'string optional', placeholder: I18n.t("admin.custom_emojis.#{key}")
.actions .actions
%button= t('admin.accounts.search') %button.button= t('admin.accounts.search')
= link_to t('admin.accounts.reset'), admin_custom_emojis_path, class: 'button negative' = link_to t('admin.accounts.reset'), admin_custom_emojis_path, class: 'button negative'
= form_for(@form, url: batch_admin_custom_emojis_path) do |f| = form_for(@form, url: batch_admin_custom_emojis_path) do |f|

View File

@ -27,7 +27,7 @@
= text_field_tag key, params[key], class: 'string optional', placeholder: I18n.t("admin.instances.#{key}") = text_field_tag key, params[key], class: 'string optional', placeholder: I18n.t("admin.instances.#{key}")
.actions .actions
%button= t('admin.accounts.search') %button.button= t('admin.accounts.search')
= link_to t('admin.accounts.reset'), admin_instances_path, class: 'button negative' = link_to t('admin.accounts.reset'), admin_instances_path, class: 'button negative'
%hr.spacer/ %hr.spacer/

View File

@ -18,7 +18,7 @@
= text_field_tag key, params[key], class: 'string optional', placeholder: I18n.t("admin.reports.#{key}") = text_field_tag key, params[key], class: 'string optional', placeholder: I18n.t("admin.reports.#{key}")
.actions .actions
%button= t('admin.accounts.search') %button.button= t('admin.accounts.search')
= link_to t('admin.accounts.reset'), admin_reports_path, class: 'button negative' = link_to t('admin.accounts.reset'), admin_reports_path, class: 'button negative'
- @reports.group_by(&:target_account_id).each do |target_account_id, reports| - @reports.group_by(&:target_account_id).each do |target_account_id, reports|

View File

@ -33,7 +33,7 @@
= text_field_tag key, params[key], class: 'string optional', placeholder: I18n.t("admin.tags.#{key}") = text_field_tag key, params[key], class: 'string optional', placeholder: I18n.t("admin.tags.#{key}")
.actions .actions
%button= t('admin.accounts.search') %button.button= t('admin.accounts.search')
= link_to t('admin.accounts.reset'), admin_tags_path, class: 'button negative' = link_to t('admin.accounts.reset'), admin_tags_path, class: 'button negative'
%hr.spacer/ %hr.spacer/

View File

@ -1,2 +1,16 @@
%video{ poster: @media_attachment.file.url(:small), preload: 'auto', autoplay: 'autoplay', muted: 'muted', loop: 'loop', controls: 'controls', style: "width: #{@media_attachment.file.meta.dig('original', 'width')}px; height: #{@media_attachment.file.meta.dig('original', 'height')}px" } - content_for :header_tags do
%source{ src: @media_attachment.file.url(:original), type: @media_attachment.file_content_type } = render_initial_state
= javascript_pack_tag 'public', integrity: true, crossorigin: 'anonymous'
- if @media_attachment.video?
= react_component :video, src: @media_attachment.file.url(:original), preview: @media_attachment.file.url(:small), blurhash: @media_attachment.blurhash, width: 670, height: 380, editable: true, detailed: true, inline: true, alt: @media_attachment.description do
%video{ controls: 'controls' }
%source{ src: @media_attachment.file.url(:original) }
- elsif @media_attachment.gifv?
= react_component :media_gallery, height: 380, standalone: true, autoplay: true, media: [ActiveModelSerializers::SerializableResource.new(@media_attachment, serializer: REST::MediaAttachmentSerializer).as_json] do
%video{ autoplay: 'autoplay', muted: 'muted', loop: 'loop' }
%source{ src: @media_attachment.file.url(:original) }
- elsif @media_attachment.audio?
= react_component :audio, src: @media_attachment.file.url(:original), poster: full_asset_url(@media_attachment.account.avatar_static_url), width: 670, height: 380, fullscreen: true, alt: @media_attachment.description, duration: @media_attachment.file.meta.dig(:original, :duration) do
%audio{ controls: 'controls' }
%source{ src: @media_attachment.file.url(:original) }

View File

@ -1,4 +1,4 @@
.detailed-status.detailed-status--flex .detailed-status.detailed-status--flex{ class: "detailed-status-#{status.visibility}" }
.p-author.h-card .p-author.h-card
= link_to ActivityPub::TagManager.instance.url_for(status.account), class: 'detailed-status__display-name u-url', target: stream_link_target, rel: 'noopener' do = link_to ActivityPub::TagManager.instance.url_for(status.account), class: 'detailed-status__display-name u-url', target: stream_link_target, rel: 'noopener' do
.detailed-status__display-avatar .detailed-status__display-avatar
@ -33,7 +33,7 @@
= render partial: 'statuses/attachment_list', locals: { attachments: status.media_attachments } = render partial: 'statuses/attachment_list', locals: { attachments: status.media_attachments }
- elsif status.media_attachments.first.audio? - elsif status.media_attachments.first.audio?
- audio = status.media_attachments.first - audio = status.media_attachments.first
= react_component :audio, src: audio.file.url(:original), height: 130, alt: audio.description, preload: true, duration: audio.file.meta.dig(:original, :duration) do = react_component :audio, src: audio.file.url(:original), poster: full_asset_url(status.account.avatar_static_url), width: 670, height: 380, alt: audio.description, duration: audio.file.meta.dig(:original, :duration) do
= render partial: 'statuses/attachment_list', locals: { attachments: status.media_attachments } = render partial: 'statuses/attachment_list', locals: { attachments: status.media_attachments }
- else - else
= react_component :media_gallery, height: 380, sensitive: status.sensitive?, standalone: true, autoplay: autoplay, media: status.media_attachments.map { |a| ActiveModelSerializers::SerializableResource.new(a, serializer: REST::MediaAttachmentSerializer).as_json } do = react_component :media_gallery, height: 380, sensitive: status.sensitive?, standalone: true, autoplay: autoplay, media: status.media_attachments.map { |a| ActiveModelSerializers::SerializableResource.new(a, serializer: REST::MediaAttachmentSerializer).as_json } do
@ -47,6 +47,9 @@
= link_to ActivityPub::TagManager.instance.url_for(status), class: 'detailed-status__datetime u-url u-uid', target: stream_link_target, rel: 'noopener noreferrer' do = link_to ActivityPub::TagManager.instance.url_for(status), class: 'detailed-status__datetime u-url u-uid', target: stream_link_target, rel: 'noopener noreferrer' do
%time.formatted{ datetime: status.created_at.iso8601, title: l(status.created_at) }= l(status.created_at) %time.formatted{ datetime: status.created_at.iso8601, title: l(status.created_at) }= l(status.created_at)
· ·
%span.detailed-status__visibility-icon
= visibility_icon status
·
- if status.application && @account.user&.setting_show_application - if status.application && @account.user&.setting_show_application
- if status.application.website.blank? - if status.application.website.blank?
%strong.detailed-status__application= status.application.name %strong.detailed-status__application= status.application.name
@ -61,13 +64,7 @@
%span.detailed-status__reblogs>= number_to_human status.replies_count, strip_insignificant_zeros: true %span.detailed-status__reblogs>= number_to_human status.replies_count, strip_insignificant_zeros: true
= " " = " "
· ·
- if status.direct_visibility? - if status.public_visibility? || status.unlisted_visibility?
%span.detailed-status__link<
= fa_icon('envelope')
- elsif status.private_visibility? || status.limited_visibility?
%span.detailed-status__link<
= fa_icon('lock')
- else
= link_to remote_interaction_path(status, type: :reblog), class: 'modal-button detailed-status__link' do = link_to remote_interaction_path(status, type: :reblog), class: 'modal-button detailed-status__link' do
= fa_icon('retweet') = fa_icon('retweet')
%span.detailed-status__reblogs>= number_to_human status.reblogs_count, strip_insignificant_zeros: true %span.detailed-status__reblogs>= number_to_human status.reblogs_count, strip_insignificant_zeros: true

View File

@ -27,12 +27,25 @@
= opengraph 'og:video:height', media.file.meta.dig('original', 'height') = opengraph 'og:video:height', media.file.meta.dig('original', 'height')
= opengraph 'twitter:player:width', media.file.meta.dig('original', 'width') = opengraph 'twitter:player:width', media.file.meta.dig('original', 'width')
= opengraph 'twitter:player:height', media.file.meta.dig('original', 'height') = opengraph 'twitter:player:height', media.file.meta.dig('original', 'height')
- elsif media.audio?
- player_card = true
= opengraph 'og:image', full_asset_url(account.avatar.url(:original))
= opengraph 'og:image:width', '400'
= opengraph 'og:image:height','400'
= opengraph 'og:audio', full_asset_url(media.file.url(:original))
= opengraph 'og:audio:secure_url', full_asset_url(media.file.url(:original))
= opengraph 'og:audio:type', media.file_content_type
= opengraph 'twitter:player', medium_player_url(media)
= opengraph 'twitter:player:stream', full_asset_url(media.file.url(:original))
= opengraph 'twitter:player:stream:content_type', media.file_content_type
= opengraph 'twitter:player:width', '670'
= opengraph 'twitter:player:height', '380'
- if player_card - if player_card
= opengraph 'twitter:card', 'player' = opengraph 'twitter:card', 'player'
- else - else
= opengraph 'twitter:card', 'summary_large_image' = opengraph 'twitter:card', 'summary_large_image'
- else - else
= opengraph 'og:image', full_asset_url(account.avatar.url(:original)) = opengraph 'og:image', full_asset_url(account.avatar.url(:original))
= opengraph 'og:image:width', '120' = opengraph 'og:image:width', '400'
= opengraph 'og:image:height','120' = opengraph 'og:image:height','400'
= opengraph 'twitter:card', 'summary' = opengraph 'twitter:card', 'summary'

View File

@ -1,8 +1,10 @@
.status .status{ class: "status-#{status.visibility}" }
.status__info .status__info
= link_to ActivityPub::TagManager.instance.url_for(status), class: 'status__relative-time u-url u-uid', target: stream_link_target, rel: 'noopener noreferrer' do = link_to ActivityPub::TagManager.instance.url_for(status), class: 'status__relative-time u-url u-uid', target: stream_link_target, rel: 'noopener noreferrer' do
%time.time-ago{ datetime: status.created_at.iso8601, title: l(status.created_at) }= l(status.created_at) %time.time-ago{ datetime: status.created_at.iso8601, title: l(status.created_at) }= l(status.created_at)
%data.dt-published{ value: status.created_at.to_time.iso8601 } %data.dt-published{ value: status.created_at.to_time.iso8601 }
%span.status__visibility-icon
= visibility_icon status
.p-author.h-card .p-author.h-card
= link_to ActivityPub::TagManager.instance.url_for(status.account), class: 'status__display-name u-url', target: stream_link_target, rel: 'noopener noreferrer' do = link_to ActivityPub::TagManager.instance.url_for(status.account), class: 'status__display-name u-url', target: stream_link_target, rel: 'noopener noreferrer' do
@ -37,7 +39,7 @@
= render partial: 'statuses/attachment_list', locals: { attachments: status.media_attachments } = render partial: 'statuses/attachment_list', locals: { attachments: status.media_attachments }
- elsif status.media_attachments.first.audio? - elsif status.media_attachments.first.audio?
- audio = status.media_attachments.first - audio = status.media_attachments.first
= react_component :audio, src: audio.file.url(:original), height: 110, alt: audio.description, duration: audio.file.meta.dig(:original, :duration) do = react_component :audio, src: audio.file.url(:original), poster: full_asset_url(status.account.avatar_static_url), width: 610, height: 343, alt: audio.description, duration: audio.file.meta.dig(:original, :duration) do
= render partial: 'statuses/attachment_list', locals: { attachments: status.media_attachments } = render partial: 'statuses/attachment_list', locals: { attachments: status.media_attachments }
- else - else
= react_component :media_gallery, height: 343, sensitive: status.sensitive?, autoplay: autoplay, media: status.media_attachments.map { |a| ActiveModelSerializers::SerializableResource.new(a, serializer: REST::MediaAttachmentSerializer).as_json } do = react_component :media_gallery, height: 343, sensitive: status.sensitive?, autoplay: autoplay, media: status.media_attachments.map { |a| ActiveModelSerializers::SerializableResource.new(a, serializer: REST::MediaAttachmentSerializer).as_json } do

View File

@ -25,8 +25,14 @@ class PostProcessMediaWorker
media_attachment = MediaAttachment.find(media_attachment_id) media_attachment = MediaAttachment.find(media_attachment_id)
media_attachment.processing = :in_progress media_attachment.processing = :in_progress
media_attachment.save media_attachment.save
# Because paperclip-av-transcover overwrites this attribute
# we will save it here and restore it after reprocess is done
previous_meta = media_attachment.file_meta
media_attachment.file.reprocess!(:original) media_attachment.file.reprocess!(:original)
media_attachment.processing = :complete media_attachment.processing = :complete
media_attachment.file_meta = previous_meta
media_attachment.save media_attachment.save
rescue ActiveRecord::RecordNotFound rescue ActiveRecord::RecordNotFound
true true

View File

@ -1117,6 +1117,9 @@ en:
spam_detected: This is an automated report. Spam has been detected. spam_detected: This is an automated report. Spam has been detected.
statuses: statuses:
attached: attached:
audio:
one: "%{count} audio"
other: "%{count} audio"
description: 'Attached: %{attached}' description: 'Attached: %{attached}'
image: image:
one: "%{count} image" one: "%{count} image"

View File

@ -0,0 +1,12 @@
class RemoveDuplicatedIndexesPghero < ActiveRecord::Migration[5.2]
def change
remove_index :account_conversations, name: "index_account_conversations_on_account_id", column: :account_id
remove_index :account_identity_proofs, name: "index_account_identity_proofs_on_account_id", column: :account_id
remove_index :account_pins, name: "index_account_pins_on_account_id", column: :account_id
remove_index :announcement_mutes, name: "index_announcement_mutes_on_account_id", column: :account_id
remove_index :announcement_reactions, name: "index_announcement_reactions_on_account_id", column: :account_id
remove_index :bookmarks, name: "index_bookmarks_on_account_id", column: :account_id
remove_index :markers, name: "index_markers_on_user_id", column: :user_id
end
end

View File

@ -33,7 +33,6 @@ ActiveRecord::Schema.define(version: 2020_06_20_164023) do
t.integer "lock_version", default: 0, null: false t.integer "lock_version", default: 0, null: false
t.boolean "unread", default: false, null: false t.boolean "unread", default: false, null: false
t.index ["account_id", "conversation_id", "participant_account_ids"], name: "index_unique_conversations", unique: true t.index ["account_id", "conversation_id", "participant_account_ids"], name: "index_unique_conversations", unique: true
t.index ["account_id"], name: "index_account_conversations_on_account_id"
t.index ["conversation_id"], name: "index_account_conversations_on_conversation_id" t.index ["conversation_id"], name: "index_account_conversations_on_conversation_id"
end end
@ -55,7 +54,6 @@ ActiveRecord::Schema.define(version: 2020_06_20_164023) 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.index ["account_id", "provider", "provider_username"], name: "index_account_proofs_on_account_and_provider_and_username", unique: true t.index ["account_id", "provider", "provider_username"], name: "index_account_proofs_on_account_and_provider_and_username", unique: true
t.index ["account_id"], name: "index_account_identity_proofs_on_account_id"
end end
create_table "account_migrations", force: :cascade do |t| create_table "account_migrations", force: :cascade do |t|
@ -85,7 +83,6 @@ ActiveRecord::Schema.define(version: 2020_06_20_164023) 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.index ["account_id", "target_account_id"], name: "index_account_pins_on_account_id_and_target_account_id", unique: true t.index ["account_id", "target_account_id"], name: "index_account_pins_on_account_id_and_target_account_id", unique: true
t.index ["account_id"], name: "index_account_pins_on_account_id"
t.index ["target_account_id"], name: "index_account_pins_on_target_account_id" t.index ["target_account_id"], name: "index_account_pins_on_target_account_id"
end end
@ -207,7 +204,6 @@ ActiveRecord::Schema.define(version: 2020_06_20_164023) 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.index ["account_id", "announcement_id"], name: "index_announcement_mutes_on_account_id_and_announcement_id", unique: true t.index ["account_id", "announcement_id"], name: "index_announcement_mutes_on_account_id_and_announcement_id", unique: true
t.index ["account_id"], name: "index_announcement_mutes_on_account_id"
t.index ["announcement_id"], name: "index_announcement_mutes_on_announcement_id" t.index ["announcement_id"], name: "index_announcement_mutes_on_announcement_id"
end end
@ -219,7 +215,6 @@ ActiveRecord::Schema.define(version: 2020_06_20_164023) 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.index ["account_id", "announcement_id", "name"], name: "index_announcement_reactions_on_account_id_and_announcement_id", unique: true t.index ["account_id", "announcement_id", "name"], name: "index_announcement_reactions_on_account_id_and_announcement_id", unique: true
t.index ["account_id"], name: "index_announcement_reactions_on_account_id"
t.index ["announcement_id"], name: "index_announcement_reactions_on_announcement_id" t.index ["announcement_id"], name: "index_announcement_reactions_on_announcement_id"
t.index ["custom_emoji_id"], name: "index_announcement_reactions_on_custom_emoji_id" t.index ["custom_emoji_id"], name: "index_announcement_reactions_on_custom_emoji_id"
end end
@ -264,7 +259,6 @@ ActiveRecord::Schema.define(version: 2020_06_20_164023) 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.index ["account_id", "status_id"], name: "index_bookmarks_on_account_id_and_status_id", unique: true t.index ["account_id", "status_id"], name: "index_bookmarks_on_account_id_and_status_id", unique: true
t.index ["account_id"], name: "index_bookmarks_on_account_id"
t.index ["status_id"], name: "index_bookmarks_on_status_id" t.index ["status_id"], name: "index_bookmarks_on_status_id"
end end
@ -476,7 +470,6 @@ ActiveRecord::Schema.define(version: 2020_06_20_164023) 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.index ["user_id", "timeline"], name: "index_markers_on_user_id_and_timeline", unique: true t.index ["user_id", "timeline"], name: "index_markers_on_user_id_and_timeline", unique: true
t.index ["user_id"], name: "index_markers_on_user_id"
end end
create_table "media_attachments", force: :cascade do |t| create_table "media_attachments", force: :cascade do |t|

View File

@ -12,6 +12,7 @@ require_relative 'mastodon/domains_cli'
require_relative 'mastodon/preview_cards_cli' require_relative 'mastodon/preview_cards_cli'
require_relative 'mastodon/cache_cli' require_relative 'mastodon/cache_cli'
require_relative 'mastodon/upgrade_cli' require_relative 'mastodon/upgrade_cli'
require_relative 'mastodon/email_domain_blocks_cli'
require_relative 'mastodon/version' require_relative 'mastodon/version'
module Mastodon module Mastodon
@ -53,6 +54,9 @@ module Mastodon
desc 'upgrade SUBCOMMAND ...ARGS', 'Various version upgrade utilities' desc 'upgrade SUBCOMMAND ...ARGS', 'Various version upgrade utilities'
subcommand 'upgrade', Mastodon::UpgradeCLI subcommand 'upgrade', Mastodon::UpgradeCLI
desc 'email-domain-blocks SUBCOMMAND ...ARGS', 'Manage E-mail domain blocks'
subcommand 'email_domain_blocks', Mastodon::EmailDomainBlocksCLI
option :dry_run, type: :boolean option :dry_run, type: :boolean
desc 'self-destruct', 'Erase the server from the federation' desc 'self-destruct', 'Erase the server from the federation'
long_desc <<~LONG_DESC long_desc <<~LONG_DESC

View File

@ -0,0 +1,133 @@
# frozen_string_literal: true
require 'concurrent'
require_relative '../../config/boot'
require_relative '../../config/environment'
require_relative 'cli_helper'
module Mastodon
class EmailDomainBlocksCLI < Thor
include CLIHelper
def self.exit_on_failure?
true
end
desc 'list', 'list E-mail domain blocks'
long_desc <<-LONG_DESC
list up all E-mail domain blocks.
LONG_DESC
def list
EmailDomainBlock.where(parent_id: nil).order(id: 'DESC').find_each do |entry|
say(entry.domain.to_s, :white)
EmailDomainBlock.where(parent_id: entry.id).order(id: 'DESC').find_each do |child|
say(" #{child.domain}", :cyan)
end
end
end
option :with_dns_records, type: :boolean
desc 'add [DOMAIN...]', 'add E-mail domain blocks'
long_desc <<-LONG_DESC
add E-mail domain blocks from a given DOMAIN.
When the --with-dns-records option is given, An attempt to resolve the
given domain's DNS records will be made and the results will also be
blacklisted.
LONG_DESC
def add(*domains)
if domains.empty?
say('No domain(s) given', :red)
exit(1)
end
skipped = 0
processed = 0
domains.each do |domain|
if EmailDomainBlock.where(domain: domain).exists?
say("#{domain} is already blocked.", :yellow)
skipped += 1
next
end
email_domain_block = EmailDomainBlock.new(domain: domain, with_dns_records: options[:with_dns_records] || false)
email_domain_block.save!
processed += 1
next unless email_domain_block.with_dns_records?
hostnames = []
ips = []
Resolv::DNS.open do |dns|
dns.timeouts = 1
hostnames = dns.getresources(email_domain_block.domain, Resolv::DNS::Resource::IN::MX).to_a.map { |e| e.exchange.to_s }
([email_domain_block.domain] + hostnames).uniq.each do |hostname|
ips.concat(dns.getresources(hostname, Resolv::DNS::Resource::IN::A).to_a.map { |e| e.address.to_s })
ips.concat(dns.getresources(hostname, Resolv::DNS::Resource::IN::AAAA).to_a.map { |e| e.address.to_s })
end
end
(hostnames + ips).uniq.each do |hostname|
another_email_domain_block = EmailDomainBlock.new(domain: hostname, parent: email_domain_block)
if EmailDomainBlock.where(domain: hostname).exists?
say("#{hostname} is already blocked.", :yellow)
skipped += 1
next
end
another_email_domain_block.save!
processed += 1
end
end
say("Added #{processed}, skipped #{skipped}", color(processed, 0))
end
desc 'remove [DOMAIN...]', 'remove E-mail domain blocks'
def remove(*domains)
if domains.empty?
say('No domain(s) given', :red)
exit(1)
end
skipped = 0
processed = 0
failed = 0
domains.each do |domain|
entry = EmailDomainBlock.find_by(domain: domain)
if entry.nil?
say("#{domain} is not yet blocked.", :yellow)
skipped += 1
next
end
children_count = EmailDomainBlock.where(parent_id: entry.id).count
result = entry.destroy
if result
processed += 1 + children_count
else
say("#{domain} was not unblocked. 'destroy' returns false.", :red)
failed += 1
end
end
say("Removed #{processed}, skipped #{skipped}, failed #{failed}", color(processed, failed))
end
private
def color(processed, failed)
if !processed.zero? && failed.zero?
:green
elsif failed.zero?
:yellow
else
:red
end
end
end
end

View File

@ -2,7 +2,7 @@
"name": "@tootsuite/mastodon", "name": "@tootsuite/mastodon",
"license": "AGPL-3.0-or-later", "license": "AGPL-3.0-or-later",
"engines": { "engines": {
"node": ">=10.13 <13" "node": ">=10.13"
}, },
"scripts": { "scripts": {
"postversion": "git push --tags", "postversion": "git push --tags",
@ -60,9 +60,9 @@
}, },
"private": true, "private": true,
"dependencies": { "dependencies": {
"@babel/core": "^7.10.2", "@babel/core": "^7.10.3",
"@babel/plugin-proposal-class-properties": "^7.8.3", "@babel/plugin-proposal-class-properties": "^7.8.3",
"@babel/plugin-proposal-decorators": "^7.8.3", "@babel/plugin-proposal-decorators": "^7.10.3",
"@babel/plugin-transform-react-inline-elements": "^7.10.1", "@babel/plugin-transform-react-inline-elements": "^7.10.1",
"@babel/plugin-transform-runtime": "^7.10.1", "@babel/plugin-transform-runtime": "^7.10.1",
"@babel/preset-env": "^7.10.2", "@babel/preset-env": "^7.10.2",
@ -179,7 +179,7 @@
"enzyme-adapter-react-16": "^1.15.2", "enzyme-adapter-react-16": "^1.15.2",
"eslint": "^6.8.0", "eslint": "^6.8.0",
"eslint-plugin-import": "~2.21.2", "eslint-plugin-import": "~2.21.2",
"eslint-plugin-jsx-a11y": "~6.2.3", "eslint-plugin-jsx-a11y": "~6.3.1",
"eslint-plugin-promise": "~4.2.1", "eslint-plugin-promise": "~4.2.1",
"eslint-plugin-react": "~7.20.0", "eslint-plugin-react": "~7.20.0",
"jest": "^26.0.1", "jest": "^26.0.1",

View File

@ -118,7 +118,7 @@ const startWorker = (workerId) => {
host: process.env.REDIS_HOST || '127.0.0.1', host: process.env.REDIS_HOST || '127.0.0.1',
port: process.env.REDIS_PORT || 6379, port: process.env.REDIS_PORT || 6379,
db: process.env.REDIS_DB || 0, db: process.env.REDIS_DB || 0,
password: process.env.REDIS_PASSWORD, password: process.env.REDIS_PASSWORD || undefined,
}; };
if (redisNamespace) { if (redisNamespace) {

400
yarn.lock
View File

@ -2,12 +2,12 @@
# yarn lockfile v1 # yarn lockfile v1
"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.10.1": "@babel/code-frame@^7.0.0", "@babel/code-frame@^7.10.3":
version "7.10.1" version "7.10.3"
resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.10.1.tgz#d5481c5095daa1c57e16e54c6f9198443afb49ff" resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.10.3.tgz#324bcfd8d35cd3d47dae18cde63d752086435e9a"
integrity sha512-IGhtTmpjGbYzcEDOw7DcQtbQSXcG9ftmAXtWTu9V936vDye4xjjekktFAtgZsWpzTj/X01jocB46mTywm/4SZw== integrity sha512-fDx9eNW0qz0WkUeqL6tXEXzVlPh6Y5aCDEZesl0xBGA8ndRukX91Uk44ZqnkECp01NAZUdCAl+aiQNGi0k88Eg==
dependencies: dependencies:
"@babel/highlight" "^7.10.1" "@babel/highlight" "^7.10.3"
"@babel/compat-data@^7.10.1": "@babel/compat-data@^7.10.1":
version "7.10.1" version "7.10.1"
@ -18,19 +18,19 @@
invariant "^2.2.4" invariant "^2.2.4"
semver "^5.5.0" semver "^5.5.0"
"@babel/core@^7.1.0", "@babel/core@^7.10.2", "@babel/core@^7.7.2", "@babel/core@^7.7.5": "@babel/core@^7.1.0", "@babel/core@^7.10.3", "@babel/core@^7.7.2", "@babel/core@^7.7.5":
version "7.10.2" version "7.10.3"
resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.10.2.tgz#bd6786046668a925ac2bd2fd95b579b92a23b36a" resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.10.3.tgz#73b0e8ddeec1e3fdd7a2de587a60e17c440ec77e"
integrity sha512-KQmV9yguEjQsXqyOUGKjS4+3K8/DlOCE2pZcq4augdQmtTy5iv5EHtmMSJ7V4c1BIPjuwtZYqYLCq9Ga+hGBRQ== integrity sha512-5YqWxYE3pyhIi84L84YcwjeEgS+fa7ZjK6IBVGTjDVfm64njkR2lfDhVR5OudLk8x2GK59YoSyVv+L/03k1q9w==
dependencies: dependencies:
"@babel/code-frame" "^7.10.1" "@babel/code-frame" "^7.10.3"
"@babel/generator" "^7.10.2" "@babel/generator" "^7.10.3"
"@babel/helper-module-transforms" "^7.10.1" "@babel/helper-module-transforms" "^7.10.1"
"@babel/helpers" "^7.10.1" "@babel/helpers" "^7.10.1"
"@babel/parser" "^7.10.2" "@babel/parser" "^7.10.3"
"@babel/template" "^7.10.1" "@babel/template" "^7.10.3"
"@babel/traverse" "^7.10.1" "@babel/traverse" "^7.10.3"
"@babel/types" "^7.10.2" "@babel/types" "^7.10.3"
convert-source-map "^1.7.0" convert-source-map "^1.7.0"
debug "^4.1.0" debug "^4.1.0"
gensync "^1.0.0-beta.1" gensync "^1.0.0-beta.1"
@ -40,12 +40,12 @@
semver "^5.4.1" semver "^5.4.1"
source-map "^0.5.0" source-map "^0.5.0"
"@babel/generator@^7.10.1", "@babel/generator@^7.10.2": "@babel/generator@^7.10.3":
version "7.10.2" version "7.10.3"
resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.10.2.tgz#0fa5b5b2389db8bfdfcc3492b551ee20f5dd69a9" resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.10.3.tgz#32b9a0d963a71d7a54f5f6c15659c3dbc2a523a5"
integrity sha512-AxfBNHNu99DTMvlUPlt1h2+Hn7knPpH5ayJ8OqDWSeLld+Fi2AYBTC/IejWDM9Edcii4UzZRCsbUt0WlSDsDsA== integrity sha512-drt8MUHbEqRzNR0xnF8nMehbY11b1SDkRw03PSNH/3Rb2Z35oxkddVSi3rcaak0YJQ86PCuE7Qx1jSFhbLNBMA==
dependencies: dependencies:
"@babel/types" "^7.10.2" "@babel/types" "^7.10.3"
jsesc "^2.5.1" jsesc "^2.5.1"
lodash "^4.17.13" lodash "^4.17.13"
source-map "^0.5.0" source-map "^0.5.0"
@ -93,30 +93,18 @@
levenary "^1.1.1" levenary "^1.1.1"
semver "^5.5.0" semver "^5.5.0"
"@babel/helper-create-class-features-plugin@^7.10.1": "@babel/helper-create-class-features-plugin@^7.10.1", "@babel/helper-create-class-features-plugin@^7.10.3":
version "7.10.2" version "7.10.3"
resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.10.2.tgz#7474295770f217dbcf288bf7572eb213db46ee67" resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.10.3.tgz#2783daa6866822e3d5ed119163b50f0fc3ae4b35"
integrity sha512-5C/QhkGFh1vqcziq1vAL6SI9ymzUp8BCYjFpvYVhWP4DlATIb3u5q3iUd35mvlyGs8fO7hckkW7i0tmH+5+bvQ== integrity sha512-iRT9VwqtdFmv7UheJWthGc/h2s7MqoweBF9RUj77NFZsg9VfISvBTum3k6coAhJ8RWv2tj3yUjA03HxPd0vfpQ==
dependencies: dependencies:
"@babel/helper-function-name" "^7.10.1" "@babel/helper-function-name" "^7.10.3"
"@babel/helper-member-expression-to-functions" "^7.10.1" "@babel/helper-member-expression-to-functions" "^7.10.3"
"@babel/helper-optimise-call-expression" "^7.10.1" "@babel/helper-optimise-call-expression" "^7.10.3"
"@babel/helper-plugin-utils" "^7.10.1" "@babel/helper-plugin-utils" "^7.10.3"
"@babel/helper-replace-supers" "^7.10.1" "@babel/helper-replace-supers" "^7.10.1"
"@babel/helper-split-export-declaration" "^7.10.1" "@babel/helper-split-export-declaration" "^7.10.1"
"@babel/helper-create-class-features-plugin@^7.8.3":
version "7.8.3"
resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.8.3.tgz#5b94be88c255f140fd2c10dd151e7f98f4bff397"
integrity sha512-qmp4pD7zeTxsv0JNecSBsEmG1ei2MqwJq4YQcK3ZWm/0t07QstWfvuV/vm3Qt5xNMFETn2SZqpMx2MQzbtq+KA==
dependencies:
"@babel/helper-function-name" "^7.8.3"
"@babel/helper-member-expression-to-functions" "^7.8.3"
"@babel/helper-optimise-call-expression" "^7.8.3"
"@babel/helper-plugin-utils" "^7.8.3"
"@babel/helper-replace-supers" "^7.8.3"
"@babel/helper-split-export-declaration" "^7.8.3"
"@babel/helper-create-regexp-features-plugin@^7.10.1": "@babel/helper-create-regexp-features-plugin@^7.10.1":
version "7.10.1" version "7.10.1"
resolved "https://registry.yarnpkg.com/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.10.1.tgz#1b8feeab1594cbcfbf3ab5a3bbcabac0468efdbd" resolved "https://registry.yarnpkg.com/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.10.1.tgz#1b8feeab1594cbcfbf3ab5a3bbcabac0468efdbd"
@ -160,14 +148,14 @@
"@babel/template" "^7.10.1" "@babel/template" "^7.10.1"
"@babel/types" "^7.10.1" "@babel/types" "^7.10.1"
"@babel/helper-function-name@^7.8.3": "@babel/helper-function-name@^7.10.3":
version "7.8.3" version "7.10.3"
resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.8.3.tgz#eeeb665a01b1f11068e9fb86ad56a1cb1a824cca" resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.10.3.tgz#79316cd75a9fa25ba9787ff54544307ed444f197"
integrity sha512-BCxgX1BC2hD/oBlIFUgOCQDOPV8nSINxCwM3o93xP4P9Fq6aV5sgv2cOOITDMtCfQ+3PvHp3l689XZvAM9QyOA== integrity sha512-FvSj2aiOd8zbeqijjgqdMDSyxsGHaMt5Tr0XjQsGKHD3/1FP3wksjnLAWzxw7lvXiej8W1Jt47SKTZ6upQNiRw==
dependencies: dependencies:
"@babel/helper-get-function-arity" "^7.8.3" "@babel/helper-get-function-arity" "^7.10.3"
"@babel/template" "^7.8.3" "@babel/template" "^7.10.3"
"@babel/types" "^7.8.3" "@babel/types" "^7.10.3"
"@babel/helper-get-function-arity@^7.10.1": "@babel/helper-get-function-arity@^7.10.1":
version "7.10.1" version "7.10.1"
@ -176,12 +164,12 @@
dependencies: dependencies:
"@babel/types" "^7.10.1" "@babel/types" "^7.10.1"
"@babel/helper-get-function-arity@^7.8.3": "@babel/helper-get-function-arity@^7.10.3":
version "7.8.3" version "7.10.3"
resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.8.3.tgz#b894b947bd004381ce63ea1db9f08547e920abd5" resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.10.3.tgz#3a28f7b28ccc7719eacd9223b659fdf162e4c45e"
integrity sha512-FVDR+Gd9iLjUMY1fzE2SR0IuaJToR4RkCDARVfsBBPSP53GEqSFjD8gNyxg246VUyc/ALRxFaAK8rVG7UT7xRA== integrity sha512-iUD/gFsR+M6uiy69JA6fzM5seno8oE85IYZdbVVEuQaZlEzMO2MXblh+KSPJgsZAUx0EEbWXU0yJaW7C9CdAVg==
dependencies: dependencies:
"@babel/types" "^7.8.3" "@babel/types" "^7.10.3"
"@babel/helper-hoist-variables@^7.10.1": "@babel/helper-hoist-variables@^7.10.1":
version "7.10.1" version "7.10.1"
@ -197,12 +185,12 @@
dependencies: dependencies:
"@babel/types" "^7.10.1" "@babel/types" "^7.10.1"
"@babel/helper-member-expression-to-functions@^7.8.3": "@babel/helper-member-expression-to-functions@^7.10.3":
version "7.8.3" version "7.10.3"
resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.8.3.tgz#659b710498ea6c1d9907e0c73f206eee7dadc24c" resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.10.3.tgz#bc3663ac81ac57c39148fef4c69bf48a77ba8dd6"
integrity sha512-fO4Egq88utkQFjbPrSHGmGLFqmrshs11d46WI+WZDESt7Wu7wN2G2Iu+NMMZJFDOVRHAMIkB5SNh30NtwCA7RA== integrity sha512-q7+37c4EPLSjNb2NmWOjNwj0+BOyYlssuQ58kHEWk1Z78K5i8vTUsteq78HMieRPQSl/NtpQyJfdjt3qZ5V2vw==
dependencies: dependencies:
"@babel/types" "^7.8.3" "@babel/types" "^7.10.3"
"@babel/helper-module-imports@^7.0.0", "@babel/helper-module-imports@^7.0.0-beta.49", "@babel/helper-module-imports@^7.10.1": "@babel/helper-module-imports@^7.0.0", "@babel/helper-module-imports@^7.0.0-beta.49", "@babel/helper-module-imports@^7.10.1":
version "7.10.1" version "7.10.1"
@ -231,17 +219,17 @@
dependencies: dependencies:
"@babel/types" "^7.10.1" "@babel/types" "^7.10.1"
"@babel/helper-optimise-call-expression@^7.8.3": "@babel/helper-optimise-call-expression@^7.10.3":
version "7.8.3" version "7.10.3"
resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.8.3.tgz#7ed071813d09c75298ef4f208956006b6111ecb9" resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.10.3.tgz#f53c4b6783093195b0f69330439908841660c530"
integrity sha512-Kag20n86cbO2AvHca6EJsvqAd82gc6VMGule4HwebwMlwkpXuVqrNRj6CkCV2sKxgi9MyAUnZVnZ6lJ1/vKhHQ== integrity sha512-kT2R3VBH/cnSz+yChKpaKRJQJWxdGoc6SjioRId2wkeV3bK0wLLioFpJROrX0U4xr/NmxSSAWT/9Ih5snwIIzg==
dependencies: dependencies:
"@babel/types" "^7.8.3" "@babel/types" "^7.10.3"
"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.1", "@babel/helper-plugin-utils@^7.8.0", "@babel/helper-plugin-utils@^7.8.3": "@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.1", "@babel/helper-plugin-utils@^7.10.3", "@babel/helper-plugin-utils@^7.8.0":
version "7.10.1" version "7.10.3"
resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.1.tgz#ec5a5cf0eec925b66c60580328b122c01230a127" resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.3.tgz#aac45cccf8bc1873b99a85f34bceef3beb5d3244"
integrity sha512-fvoGeXt0bJc7VMWZGCAEBEMo/HAjW2mP8apF5eXK0wSqwLAVHAISCWRoLMBMUs2kqeaG77jltVqu4Hn8Egl3nA== integrity sha512-j/+j8NAWUTxOtx4LKHybpSClxHoq6I91DQ/mKgAXn5oNUPIUiGppjPIX3TDtJWPrdfP9Kfl7e4fgVMiQR9VE/g==
"@babel/helper-regex@^7.10.1": "@babel/helper-regex@^7.10.1":
version "7.10.1" version "7.10.1"
@ -278,16 +266,6 @@
"@babel/traverse" "^7.10.1" "@babel/traverse" "^7.10.1"
"@babel/types" "^7.10.1" "@babel/types" "^7.10.1"
"@babel/helper-replace-supers@^7.8.3":
version "7.8.3"
resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.8.3.tgz#91192d25f6abbcd41da8a989d4492574fb1530bc"
integrity sha512-xOUssL6ho41U81etpLoT2RTdvdus4VfHamCuAm4AHxGr+0it5fnwoVdwUJ7GFEqCsQYzJUhcbsN9wB9apcYKFA==
dependencies:
"@babel/helper-member-expression-to-functions" "^7.8.3"
"@babel/helper-optimise-call-expression" "^7.8.3"
"@babel/traverse" "^7.8.3"
"@babel/types" "^7.8.3"
"@babel/helper-simple-access@^7.10.1": "@babel/helper-simple-access@^7.10.1":
version "7.10.1" version "7.10.1"
resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.10.1.tgz#08fb7e22ace9eb8326f7e3920a1c2052f13d851e" resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.10.1.tgz#08fb7e22ace9eb8326f7e3920a1c2052f13d851e"
@ -303,17 +281,10 @@
dependencies: dependencies:
"@babel/types" "^7.10.1" "@babel/types" "^7.10.1"
"@babel/helper-split-export-declaration@^7.8.3": "@babel/helper-validator-identifier@^7.10.3":
version "7.8.3" version "7.10.3"
resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.8.3.tgz#31a9f30070f91368a7182cf05f831781065fc7a9" resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.10.3.tgz#60d9847f98c4cea1b279e005fdb7c28be5412d15"
integrity sha512-3x3yOeyBhW851hroze7ElzdkeRXQYQbFIb7gLK1WQYsw2GWDay5gAJNw1sWJ0VFP6z5J1whqeXH/WCdCjZv6dA== integrity sha512-bU8JvtlYpJSBPuj1VUmKpFGaDZuLxASky3LhaKj3bmpSTY6VWooSM8msk+Z0CZoErFye2tlABF6yDkT3FOPAXw==
dependencies:
"@babel/types" "^7.8.3"
"@babel/helper-validator-identifier@^7.10.1":
version "7.10.1"
resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.10.1.tgz#5770b0c1a826c4f53f5ede5e153163e0318e94b5"
integrity sha512-5vW/JXLALhczRCWP0PnFDMCJAchlBvM7f4uk/jXritBnIa6E1KmqmtrS3yn1LAnxFBypQ3eneLuXjsnfQsgILw==
"@babel/helper-wrap-function@^7.10.1": "@babel/helper-wrap-function@^7.10.1":
version "7.10.1" version "7.10.1"
@ -334,19 +305,19 @@
"@babel/traverse" "^7.10.1" "@babel/traverse" "^7.10.1"
"@babel/types" "^7.10.1" "@babel/types" "^7.10.1"
"@babel/highlight@^7.10.1": "@babel/highlight@^7.10.3":
version "7.10.1" version "7.10.3"
resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.10.1.tgz#841d098ba613ba1a427a2b383d79e35552c38ae0" resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.10.3.tgz#c633bb34adf07c5c13156692f5922c81ec53f28d"
integrity sha512-8rMof+gVP8mxYZApLF/JgNDAkdKa+aJt3ZYxF8z6+j/hpeXL7iMsKCPHa2jNMHu/qqBwzQF4OHNoYi8dMA/rYg== integrity sha512-Ih9B/u7AtgEnySE2L2F0Xm0GaM729XqqLfHkalTsbjXGyqmf/6M0Cu0WpvqueUlW+xk88BHw9Nkpj49naU+vWw==
dependencies: dependencies:
"@babel/helper-validator-identifier" "^7.10.1" "@babel/helper-validator-identifier" "^7.10.3"
chalk "^2.0.0" chalk "^2.0.0"
js-tokens "^4.0.0" js-tokens "^4.0.0"
"@babel/parser@^7.1.0", "@babel/parser@^7.10.1", "@babel/parser@^7.10.2", "@babel/parser@^7.7.0": "@babel/parser@^7.1.0", "@babel/parser@^7.10.3", "@babel/parser@^7.7.0":
version "7.10.2" version "7.10.3"
resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.10.2.tgz#871807f10442b92ff97e4783b9b54f6a0ca812d0" resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.10.3.tgz#7e71d892b0d6e7d04a1af4c3c79d72c1f10f5315"
integrity sha512-PApSXlNMJyB4JiGVhCOlzKIif+TKFTvu0aQAhnTvfP/z3vVSN6ZypH5bfUNwFXXjRQtUEBNFd2PtmCmG2Py3qQ== integrity sha512-oJtNJCMFdIMwXGmx+KxuaD7i3b8uS7TTFYW/FNG2BT8m+fmGHoiPYoH0Pe3gya07WuFmM5FCDIr1x0irkD/hyA==
"@babel/plugin-proposal-async-generator-functions@^7.10.1": "@babel/plugin-proposal-async-generator-functions@^7.10.1":
version "7.10.1" version "7.10.1"
@ -365,14 +336,14 @@
"@babel/helper-create-class-features-plugin" "^7.10.1" "@babel/helper-create-class-features-plugin" "^7.10.1"
"@babel/helper-plugin-utils" "^7.10.1" "@babel/helper-plugin-utils" "^7.10.1"
"@babel/plugin-proposal-decorators@^7.8.3": "@babel/plugin-proposal-decorators@^7.10.3":
version "7.8.3" version "7.10.3"
resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.8.3.tgz#2156860ab65c5abf068c3f67042184041066543e" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.10.3.tgz#2fc6b5696028adccfcd14bc826c184c578b857f8"
integrity sha512-e3RvdvS4qPJVTe288DlXjwKflpfy1hr0j5dz5WpIYYeP7vQZg2WfAEIp8k5/Lwis/m5REXEteIz6rrcDtXXG7w== integrity sha512-Rzwn5tcYFTdWWK3IrhMZkMDjzFQLIGYqHvv9XuzNnEB91Y6gHr/JjazYV1Yec9g0yMLhy1p/21eiW1P7f5UN4A==
dependencies: dependencies:
"@babel/helper-create-class-features-plugin" "^7.8.3" "@babel/helper-create-class-features-plugin" "^7.10.3"
"@babel/helper-plugin-utils" "^7.8.3" "@babel/helper-plugin-utils" "^7.10.3"
"@babel/plugin-syntax-decorators" "^7.8.3" "@babel/plugin-syntax-decorators" "^7.10.1"
"@babel/plugin-proposal-dynamic-import@^7.10.1": "@babel/plugin-proposal-dynamic-import@^7.10.1":
version "7.10.1" version "7.10.1"
@ -468,12 +439,12 @@
dependencies: dependencies:
"@babel/helper-plugin-utils" "^7.10.1" "@babel/helper-plugin-utils" "^7.10.1"
"@babel/plugin-syntax-decorators@^7.8.3": "@babel/plugin-syntax-decorators@^7.10.1":
version "7.8.3" version "7.10.1"
resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-decorators/-/plugin-syntax-decorators-7.8.3.tgz#8d2c15a9f1af624b0025f961682a9d53d3001bda" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-decorators/-/plugin-syntax-decorators-7.10.1.tgz#16b869c4beafc9a442565147bda7ce0967bd4f13"
integrity sha512-8Hg4dNNT9/LcA1zQlfwuKR8BUc/if7Q7NkTam9sGTcJphLwpf2g4S42uhspQrIrR+dpzE0dtTqBVFoHl8GtnnQ== integrity sha512-a9OAbQhKOwSle1Vr0NJu/ISg1sPfdEkfRKWpgPuzhnWWzForou2gIeUIIwjAMHRekhhpJ7eulZlYs0H14Cbi+g==
dependencies: dependencies:
"@babel/helper-plugin-utils" "^7.8.3" "@babel/helper-plugin-utils" "^7.10.1"
"@babel/plugin-syntax-dynamic-import@^7.8.0": "@babel/plugin-syntax-dynamic-import@^7.8.0":
version "7.8.3" version "7.8.3"
@ -958,6 +929,14 @@
"@babel/plugin-transform-react-jsx-source" "^7.10.1" "@babel/plugin-transform-react-jsx-source" "^7.10.1"
"@babel/plugin-transform-react-pure-annotations" "^7.10.1" "@babel/plugin-transform-react-pure-annotations" "^7.10.1"
"@babel/runtime-corejs3@^7.10.2":
version "7.10.3"
resolved "https://registry.yarnpkg.com/@babel/runtime-corejs3/-/runtime-corejs3-7.10.3.tgz#931ed6941d3954924a7aa967ee440e60c507b91a"
integrity sha512-HA7RPj5xvJxQl429r5Cxr2trJwOfPjKiqhCXcdQPSqO2G0RHPZpXu4fkYmBaTKCp2c/jRaMK9GB/lN+7zvvFPw==
dependencies:
core-js-pure "^3.0.0"
regenerator-runtime "^0.13.4"
"@babel/runtime-corejs3@^7.8.3": "@babel/runtime-corejs3@^7.8.3":
version "7.8.7" version "7.8.7"
resolved "https://registry.yarnpkg.com/@babel/runtime-corejs3/-/runtime-corejs3-7.8.7.tgz#8209d9dff2f33aa2616cb319c83fe159ffb07b8c" resolved "https://registry.yarnpkg.com/@babel/runtime-corejs3/-/runtime-corejs3-7.8.7.tgz#8209d9dff2f33aa2616cb319c83fe159ffb07b8c"
@ -973,43 +952,43 @@
dependencies: dependencies:
regenerator-runtime "^0.12.0" regenerator-runtime "^0.12.0"
"@babel/runtime@^7.1.2", "@babel/runtime@^7.2.0", "@babel/runtime@^7.4.4", "@babel/runtime@^7.4.5", "@babel/runtime@^7.5.5", "@babel/runtime@^7.6.3", "@babel/runtime@^7.7.2", "@babel/runtime@^7.8.4", "@babel/runtime@^7.9.2": "@babel/runtime@^7.1.2", "@babel/runtime@^7.10.2", "@babel/runtime@^7.2.0", "@babel/runtime@^7.4.4", "@babel/runtime@^7.5.5", "@babel/runtime@^7.6.3", "@babel/runtime@^7.7.2", "@babel/runtime@^7.8.4", "@babel/runtime@^7.9.2":
version "7.10.2" version "7.10.3"
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.10.2.tgz#d103f21f2602497d38348a32e008637d506db839" resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.10.3.tgz#670d002655a7c366540c67f6fd3342cd09500364"
integrity sha512-6sF3uQw2ivImfVIl62RZ7MXhO2tap69WeWK57vAaimT6AZbE4FbqjdEJIN1UqoD6wI6B+1n9UiagafH1sxjOtg== integrity sha512-RzGO0RLSdokm9Ipe/YD+7ww8X2Ro79qiXZF3HU9ljrM+qnJmH1Vqth+hbiQZy761LnMJTMitHDuKVYTk3k4dLw==
dependencies: dependencies:
regenerator-runtime "^0.13.4" regenerator-runtime "^0.13.4"
"@babel/template@^7.10.1", "@babel/template@^7.3.3", "@babel/template@^7.8.3": "@babel/template@^7.10.1", "@babel/template@^7.10.3", "@babel/template@^7.3.3":
version "7.10.1" version "7.10.3"
resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.10.1.tgz#e167154a94cb5f14b28dc58f5356d2162f539811" resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.10.3.tgz#4d13bc8e30bf95b0ce9d175d30306f42a2c9a7b8"
integrity sha512-OQDg6SqvFSsc9A0ej6SKINWrpJiNonRIniYondK2ViKhB06i3c0s+76XUft71iqBEe9S1OKsHwPAjfHnuvnCig== integrity sha512-5BjI4gdtD+9fHZUsaxPHPNpwa+xRkDO7c7JbhYn2afvrkDu5SfAAbi9AIMXw2xEhO/BR35TqiW97IqNvCo/GqA==
dependencies: dependencies:
"@babel/code-frame" "^7.10.1" "@babel/code-frame" "^7.10.3"
"@babel/parser" "^7.10.1" "@babel/parser" "^7.10.3"
"@babel/types" "^7.10.1" "@babel/types" "^7.10.3"
"@babel/traverse@^7.1.0", "@babel/traverse@^7.10.1", "@babel/traverse@^7.7.0", "@babel/traverse@^7.8.3": "@babel/traverse@^7.1.0", "@babel/traverse@^7.10.1", "@babel/traverse@^7.10.3", "@babel/traverse@^7.7.0":
version "7.10.1" version "7.10.3"
resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.10.1.tgz#bbcef3031e4152a6c0b50147f4958df54ca0dd27" resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.10.3.tgz#0b01731794aa7b77b214bcd96661f18281155d7e"
integrity sha512-C/cTuXeKt85K+p08jN6vMDz8vSV0vZcI0wmQ36o6mjbuo++kPMdpOYw23W2XH04dbRt9/nMEfA4W3eR21CD+TQ== integrity sha512-qO6623eBFhuPm0TmmrUFMT1FulCmsSeJuVGhiLodk2raUDFhhTECLd9E9jC4LBIWziqt4wgF6KuXE4d+Jz9yug==
dependencies: dependencies:
"@babel/code-frame" "^7.10.1" "@babel/code-frame" "^7.10.3"
"@babel/generator" "^7.10.1" "@babel/generator" "^7.10.3"
"@babel/helper-function-name" "^7.10.1" "@babel/helper-function-name" "^7.10.3"
"@babel/helper-split-export-declaration" "^7.10.1" "@babel/helper-split-export-declaration" "^7.10.1"
"@babel/parser" "^7.10.1" "@babel/parser" "^7.10.3"
"@babel/types" "^7.10.1" "@babel/types" "^7.10.3"
debug "^4.1.0" debug "^4.1.0"
globals "^11.1.0" globals "^11.1.0"
lodash "^4.17.13" lodash "^4.17.13"
"@babel/types@^7.0.0", "@babel/types@^7.0.0-beta.49", "@babel/types@^7.10.1", "@babel/types@^7.10.2", "@babel/types@^7.3.0", "@babel/types@^7.3.3", "@babel/types@^7.4.4", "@babel/types@^7.7.0", "@babel/types@^7.8.3": "@babel/types@^7.0.0", "@babel/types@^7.0.0-beta.49", "@babel/types@^7.10.1", "@babel/types@^7.10.2", "@babel/types@^7.10.3", "@babel/types@^7.3.0", "@babel/types@^7.3.3", "@babel/types@^7.4.4", "@babel/types@^7.7.0":
version "7.10.2" version "7.10.3"
resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.10.2.tgz#30283be31cad0dbf6fb00bd40641ca0ea675172d" resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.10.3.tgz#6535e3b79fea86a6b09e012ea8528f935099de8e"
integrity sha512-AD3AwWBSz0AWF0AkCN9VPiWrvldXq+/e3cHa4J89vo4ymjz1XwrBFFVZmkJTsQIPNk+ZVomPSXUJqq8yyjZsng== integrity sha512-nZxaJhBXBQ8HVoIcGsf9qWep3Oh3jCENK54V4mRF7qaJabVsAYdbTtmSD8WmAp1R6ytPiu5apMwSXyxB1WlaBA==
dependencies: dependencies:
"@babel/helper-validator-identifier" "^7.10.1" "@babel/helper-validator-identifier" "^7.10.3"
lodash "^4.17.13" lodash "^4.17.13"
to-fast-properties "^2.0.0" to-fast-properties "^2.0.0"
@ -1732,9 +1711,9 @@ acorn-jsx@^5.1.0:
integrity sha512-tMUqwBWfLFbJbizRmEcWSLw6HnFzfdJs2sOJEOwwtVPMoH/0Ay+E703oZz78VSXZiiDcZrQ5XKjPIUQixhmgVw== integrity sha512-tMUqwBWfLFbJbizRmEcWSLw6HnFzfdJs2sOJEOwwtVPMoH/0Ay+E703oZz78VSXZiiDcZrQ5XKjPIUQixhmgVw==
acorn-walk@^7.1.1: acorn-walk@^7.1.1:
version "7.1.1" version "7.2.0"
resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-7.1.1.tgz#345f0dffad5c735e7373d2fec9a1023e6a44b83e" resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-7.2.0.tgz#0de889a601203909b0fbe07b8938dc21d2e967bc"
integrity sha512-wdlPY2tm/9XBr7QkKlq0WQVgiuGTX6YWPyRyBviSoScBuLfTVQhvwg6wJ369GJ/1nPfTLMfnrFIfjqVg6d+jQQ== integrity sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==
acorn@^3.0.4: acorn@^3.0.4:
version "3.3.0" version "3.3.0"
@ -1916,13 +1895,13 @@ argparse@^1.0.7:
dependencies: dependencies:
sprintf-js "~1.0.2" sprintf-js "~1.0.2"
aria-query@^3.0.0: aria-query@^4.2.2:
version "3.0.0" version "4.2.2"
resolved "https://registry.yarnpkg.com/aria-query/-/aria-query-3.0.0.tgz#65b3fcc1ca1155a8c9ae64d6eee297f15d5133cc" resolved "https://registry.yarnpkg.com/aria-query/-/aria-query-4.2.2.tgz#0d2ca6c9aceb56b8977e9fed6aed7e15bbd2f83b"
integrity sha1-ZbP8wcoRVajJrmTW7uKX8V1RM8w= integrity sha512-o/HelwhuKpTj/frsOsbNLNgnNGVIFsVP/SW2BSF14gVl7kAfMOJ6/8wUAUvG1R1NHKrfG+2sHZTu0yauT1qBrA==
dependencies: dependencies:
ast-types-flow "0.0.7" "@babel/runtime" "^7.10.2"
commander "^2.11.0" "@babel/runtime-corejs3" "^7.10.2"
arr-diff@^4.0.0: arr-diff@^4.0.0:
version "4.0.0" version "4.0.0"
@ -1954,7 +1933,7 @@ array-flatten@^2.1.0:
resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-2.1.2.tgz#24ef80a28c1a893617e2149b0c6d0d788293b099" resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-2.1.2.tgz#24ef80a28c1a893617e2149b0c6d0d788293b099"
integrity sha512-hNfzcOV8W4NdualtqBFPyVO+54DSJuZGY9qT4pRroB6S9e3iiido2ISIC5h9R2sPJ8H3FHCIiEnsv1lPXO3KtQ== integrity sha512-hNfzcOV8W4NdualtqBFPyVO+54DSJuZGY9qT4pRroB6S9e3iiido2ISIC5h9R2sPJ8H3FHCIiEnsv1lPXO3KtQ==
array-includes@^3.0.3, array-includes@^3.1.1: array-includes@^3.1.1:
version "3.1.1" version "3.1.1"
resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.1.1.tgz#cdd67e6852bdf9c1215460786732255ed2459348" resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.1.1.tgz#cdd67e6852bdf9c1215460786732255ed2459348"
integrity sha512-c2VXaCHl7zPsvpkFsw4nxvFie4fh1ur9bpcgsVkIjqn0H/Xwdg+7fv3n2r/isyS8EBj5b06M9kHyZuIr4El6WQ== integrity sha512-c2VXaCHl7zPsvpkFsw4nxvFie4fh1ur9bpcgsVkIjqn0H/Xwdg+7fv3n2r/isyS8EBj5b06M9kHyZuIr4El6WQ==
@ -2040,7 +2019,7 @@ assign-symbols@^1.0.0:
resolved "https://registry.yarnpkg.com/assign-symbols/-/assign-symbols-1.0.0.tgz#59667f41fadd4f20ccbc2bb96b8d4f7f78ec0367" resolved "https://registry.yarnpkg.com/assign-symbols/-/assign-symbols-1.0.0.tgz#59667f41fadd4f20ccbc2bb96b8d4f7f78ec0367"
integrity sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c= integrity sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=
ast-types-flow@0.0.7, ast-types-flow@^0.0.7: ast-types-flow@^0.0.7:
version "0.0.7" version "0.0.7"
resolved "https://registry.yarnpkg.com/ast-types-flow/-/ast-types-flow-0.0.7.tgz#f70b735c6bca1a5c9c22d982c3e39e7feba3bdad" resolved "https://registry.yarnpkg.com/ast-types-flow/-/ast-types-flow-0.0.7.tgz#f70b735c6bca1a5c9c22d982c3e39e7feba3bdad"
integrity sha1-9wtzXGvKGlycItmCw+Oef+ujva0= integrity sha1-9wtzXGvKGlycItmCw+Oef+ujva0=
@ -2105,6 +2084,11 @@ aws4@^1.8.0:
resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.10.0.tgz#a17b3a8ea811060e74d47d306122400ad4497ae2" resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.10.0.tgz#a17b3a8ea811060e74d47d306122400ad4497ae2"
integrity sha512-3YDiu347mtVtjpyV3u5kVqQLP242c06zwDOgpeRnybmXlYYsLbtTrUBUm8i8srONt+FWobl5aibnU1030PeeuA== integrity sha512-3YDiu347mtVtjpyV3u5kVqQLP242c06zwDOgpeRnybmXlYYsLbtTrUBUm8i8srONt+FWobl5aibnU1030PeeuA==
axe-core@^3.5.4:
version "3.5.5"
resolved "https://registry.yarnpkg.com/axe-core/-/axe-core-3.5.5.tgz#84315073b53fa3c0c51676c588d59da09a192227"
integrity sha512-5P0QZ6J5xGikH780pghEdbEKijCTrruK9KxtPZCFWUpef0f6GipO+xEZ5GKCb020mmqgbiNO6TcA55CriL784Q==
axios@^0.19.2: axios@^0.19.2:
version "0.19.2" version "0.19.2"
resolved "https://registry.yarnpkg.com/axios/-/axios-0.19.2.tgz#3ea36c5d8818d0d5f8a8a97a6d36b86cdc00cb27" resolved "https://registry.yarnpkg.com/axios/-/axios-0.19.2.tgz#3ea36c5d8818d0d5f8a8a97a6d36b86cdc00cb27"
@ -2112,10 +2096,10 @@ axios@^0.19.2:
dependencies: dependencies:
follow-redirects "1.5.10" follow-redirects "1.5.10"
axobject-query@^2.0.2: axobject-query@^2.1.2:
version "2.1.2" version "2.2.0"
resolved "https://registry.yarnpkg.com/axobject-query/-/axobject-query-2.1.2.tgz#2bdffc0371e643e5f03ba99065d5179b9ca79799" resolved "https://registry.yarnpkg.com/axobject-query/-/axobject-query-2.2.0.tgz#943d47e10c0b704aa42275e20edf3722648989be"
integrity sha512-ICt34ZmrVt8UQnvPl6TVyDTkmhXmAyAT4Jh5ugfGUX4MOrZ+U/ZY6/sdylRw3qGNr9Ub5AJsaHeDMzNLehRdOQ== integrity sha512-Td525n+iPOOyUQIeBfcASuG6uJsDOITl7Mds5gFyerkWiX7qhUTdYUBlSgNMyVqtSJqwpt1kXGLdUt6SykLMRA==
babel-eslint@^10.1.0: babel-eslint@^10.1.0:
version "10.1.0" version "10.1.0"
@ -3020,7 +3004,7 @@ combined-stream@^1.0.6, combined-stream@~1.0.6:
dependencies: dependencies:
delayed-stream "~1.0.0" delayed-stream "~1.0.0"
commander@^2.11.0, commander@^2.18.0, commander@^2.19.0, commander@^2.20.0, commander@^2.8.1: commander@^2.18.0, commander@^2.19.0, commander@^2.20.0, commander@^2.8.1:
version "2.20.3" version "2.20.3"
resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33"
integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==
@ -3532,7 +3516,7 @@ d@1, d@^1.0.1:
es5-ext "^0.10.50" es5-ext "^0.10.50"
type "^1.0.1" type "^1.0.1"
damerau-levenshtein@^1.0.4: damerau-levenshtein@^1.0.6:
version "1.0.6" version "1.0.6"
resolved "https://registry.yarnpkg.com/damerau-levenshtein/-/damerau-levenshtein-1.0.6.tgz#143c1641cb3d85c60c32329e26899adea8701791" resolved "https://registry.yarnpkg.com/damerau-levenshtein/-/damerau-levenshtein-1.0.6.tgz#143c1641cb3d85c60c32329e26899adea8701791"
integrity sha512-JVrozIeElnj3QzfUIt8tB8YMluBJom4Vw9qTPpjGYQ9fYlB3D/rb6OordUxf3xeFB35LKWs0xqcO5U6ySvBtug== integrity sha512-JVrozIeElnj3QzfUIt8tB8YMluBJom4Vw9qTPpjGYQ9fYlB3D/rb6OordUxf3xeFB35LKWs0xqcO5U6ySvBtug==
@ -3921,9 +3905,9 @@ electron-to-chromium@^1.3.413:
integrity sha512-vcTeLpPm4+ccoYFXnepvkFt0KujdyrBU19KNEO40Pnkhta6mUi2K0Dn7NmpRcNz7BvysnSqeuIYScP003HWuYg== integrity sha512-vcTeLpPm4+ccoYFXnepvkFt0KujdyrBU19KNEO40Pnkhta6mUi2K0Dn7NmpRcNz7BvysnSqeuIYScP003HWuYg==
elliptic@^6.0.0, elliptic@^6.5.2: elliptic@^6.0.0, elliptic@^6.5.2:
version "6.5.2" version "6.5.3"
resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.5.2.tgz#05c5678d7173c049d8ca433552224a495d0e3762" resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.5.3.tgz#cb59eb2efdaf73a0bd78ccd7015a62ad6e0f93d6"
integrity sha512-f4x70okzZbIQl/NSRLkI/+tteV/9WqL98zx+SQ69KbXxmVrmjwsNUPn/gYJJ0sHvEak24cZgHIPegRePAtA/xw== integrity sha512-IMqzv5wNQf+E6aHeIqATs0tOLeOTwj1QKbRcS3jBbYkl5oLAserA8yJTT7/VyHUYG91PRmPyeQDObKLPpeS4dw==
dependencies: dependencies:
bn.js "^4.4.0" bn.js "^4.4.0"
brorand "^1.0.1" brorand "^1.0.1"
@ -3937,7 +3921,7 @@ emoji-mart@Gargron/emoji-mart#build:
version "2.6.3" version "2.6.3"
resolved "https://codeload.github.com/Gargron/emoji-mart/tar.gz/934f314fd8322276765066e8a2a6be5bac61b1cf" resolved "https://codeload.github.com/Gargron/emoji-mart/tar.gz/934f314fd8322276765066e8a2a6be5bac61b1cf"
emoji-regex@^7.0.1, emoji-regex@^7.0.2: emoji-regex@^7.0.1:
version "7.0.3" version "7.0.3"
resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-7.0.3.tgz#933a04052860c85e83c122479c4748a8e4c72156" resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-7.0.3.tgz#933a04052860c85e83c122479c4748a8e4c72156"
integrity sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA== integrity sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==
@ -3947,6 +3931,11 @@ emoji-regex@^8.0.0:
resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37"
integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==
emoji-regex@^9.0.0:
version "9.0.0"
resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-9.0.0.tgz#48a2309cc8a1d2e9d23bc6a67c39b63032e76ea4"
integrity sha512-6p1NII1Vm62wni/VR/cUMauVQoxmLVb9csqQlvLz+hO2gk8U2UYDfXHQSUYIBKmZwAKz867IDqG7B+u0mj+M6w==
emojis-list@^2.0.0: emojis-list@^2.0.0:
version "2.1.0" version "2.1.0"
resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-2.1.0.tgz#4daa4d9db00f9819880c79fa457ae5b09a1fd389" resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-2.1.0.tgz#4daa4d9db00f9819880c79fa457ae5b09a1fd389"
@ -4072,7 +4061,7 @@ error-stack-parser@^2.0.6:
dependencies: dependencies:
stackframe "^1.1.1" stackframe "^1.1.1"
es-abstract@^1.17.0, es-abstract@^1.17.5: es-abstract@^1.17.0, es-abstract@^1.17.0-next.0, es-abstract@^1.17.0-next.1, es-abstract@^1.17.2, es-abstract@^1.17.4, es-abstract@^1.17.5:
version "1.17.6" version "1.17.6"
resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.17.6.tgz#9142071707857b2cacc7b89ecb670316c3e2d52a" resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.17.6.tgz#9142071707857b2cacc7b89ecb670316c3e2d52a"
integrity sha512-Fr89bON3WFyUi5EvAeI48QTWX0AyekGgLA8H+c+7fbfCkJwRWRMLd8CQedNEyJuoYYhmtEqY92pgte1FAhBlhw== integrity sha512-Fr89bON3WFyUi5EvAeI48QTWX0AyekGgLA8H+c+7fbfCkJwRWRMLd8CQedNEyJuoYYhmtEqY92pgte1FAhBlhw==
@ -4089,23 +4078,6 @@ es-abstract@^1.17.0, es-abstract@^1.17.5:
string.prototype.trimend "^1.0.1" string.prototype.trimend "^1.0.1"
string.prototype.trimstart "^1.0.1" string.prototype.trimstart "^1.0.1"
es-abstract@^1.17.0-next.0, es-abstract@^1.17.0-next.1, es-abstract@^1.17.2, es-abstract@^1.17.4:
version "1.17.5"
resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.17.5.tgz#d8c9d1d66c8981fb9200e2251d799eee92774ae9"
integrity sha512-BR9auzDbySxOcfog0tLECW8l28eRGpDpU3Dm3Hp4q/N+VtLTmyj4EUN088XZWQDW/hzj6sYRDXeOFsaAODKvpg==
dependencies:
es-to-primitive "^1.2.1"
function-bind "^1.1.1"
has "^1.0.3"
has-symbols "^1.0.1"
is-callable "^1.1.5"
is-regex "^1.0.5"
object-inspect "^1.7.0"
object-keys "^1.1.1"
object.assign "^4.1.0"
string.prototype.trimleft "^2.1.1"
string.prototype.trimright "^2.1.1"
es-to-primitive@^1.2.1: es-to-primitive@^1.2.1:
version "1.2.1" version "1.2.1"
resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.2.1.tgz#e55cd4c9cdc188bcefb03b366c736323fc5c898a" resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.2.1.tgz#e55cd4c9cdc188bcefb03b366c736323fc5c898a"
@ -4254,20 +4226,22 @@ eslint-plugin-import@~2.21.2:
resolve "^1.17.0" resolve "^1.17.0"
tsconfig-paths "^3.9.0" tsconfig-paths "^3.9.0"
eslint-plugin-jsx-a11y@~6.2.3: eslint-plugin-jsx-a11y@~6.3.1:
version "6.2.3" version "6.3.1"
resolved "https://registry.yarnpkg.com/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.2.3.tgz#b872a09d5de51af70a97db1eea7dc933043708aa" resolved "https://registry.yarnpkg.com/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.3.1.tgz#99ef7e97f567cc6a5b8dd5ab95a94a67058a2660"
integrity sha512-CawzfGt9w83tyuVekn0GDPU9ytYtxyxyFZ3aSWROmnRRFQFT2BiPJd7jvRdzNDi6oLWaS2asMeYSNMjWTV4eNg== integrity sha512-i1S+P+c3HOlBJzMFORRbC58tHa65Kbo8b52/TwCwSKLohwvpfT5rm2GjGWzOHTEuq4xxf2aRlHHTtmExDQOP+g==
dependencies: dependencies:
"@babel/runtime" "^7.4.5" "@babel/runtime" "^7.10.2"
aria-query "^3.0.0" aria-query "^4.2.2"
array-includes "^3.0.3" array-includes "^3.1.1"
ast-types-flow "^0.0.7" ast-types-flow "^0.0.7"
axobject-query "^2.0.2" axe-core "^3.5.4"
damerau-levenshtein "^1.0.4" axobject-query "^2.1.2"
emoji-regex "^7.0.2" damerau-levenshtein "^1.0.6"
emoji-regex "^9.0.0"
has "^1.0.3" has "^1.0.3"
jsx-ast-utils "^2.2.1" jsx-ast-utils "^2.4.1"
language-tags "^1.0.5"
eslint-plugin-promise@~4.2.1: eslint-plugin-promise@~4.2.1:
version "4.2.1" version "4.2.1"
@ -4315,9 +4289,9 @@ eslint-utils@^1.4.3:
eslint-visitor-keys "^1.1.0" eslint-visitor-keys "^1.1.0"
eslint-visitor-keys@^1.0.0, eslint-visitor-keys@^1.1.0: eslint-visitor-keys@^1.0.0, eslint-visitor-keys@^1.1.0:
version "1.1.0" version "1.2.0"
resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.1.0.tgz#e2a82cea84ff246ad6fb57f9bde5b46621459ec2" resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.2.0.tgz#74415ac884874495f78ec2a97349525344c981fa"
integrity sha512-8y9YjtM1JBJU/A9Kc+SbaOV4y29sSWckBwMHa+FGtVj5gN/sbnKDf6xJUl+8g7FAij9LVaP8C24DUiH/f/2Z9A== integrity sha512-WFb4ihckKil6hu3Dp798xdzSfddwKKU3+nGniKF6HfeW6OLd2OUDEPP7TcHtB5+QXOKg2s6B2DaMPE1Nn/kxKQ==
eslint@^2.7.0: eslint@^2.7.0:
version "2.13.1" version "2.13.1"
@ -4667,9 +4641,9 @@ extsprintf@^1.2.0:
integrity sha1-4mifjzVvrWLMplo6kcXfX5VRaS8= integrity sha1-4mifjzVvrWLMplo6kcXfX5VRaS8=
fast-deep-equal@^3.1.1: fast-deep-equal@^3.1.1:
version "3.1.1" version "3.1.3"
resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.1.tgz#545145077c501491e33b15ec408c294376e94ae4" resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525"
integrity sha512-8UEa58QDLauDNfpbrX55Q9jrGHThw2ZMdOky5Gl1CDtVeJDPVrG4Jxx1N8jw2gkWaff5UUuX1KJd+9zGe2B+ZA== integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==
fast-glob@^3.1.1, fast-glob@^3.2.2: fast-glob@^3.1.1, fast-glob@^3.2.2:
version "3.2.4" version "3.2.4"
@ -6863,7 +6837,7 @@ jsprim@^1.2.2:
json-schema "0.2.3" json-schema "0.2.3"
verror "1.10.0" verror "1.10.0"
jsx-ast-utils@^2.2.1, jsx-ast-utils@^2.2.3: jsx-ast-utils@^2.2.3, jsx-ast-utils@^2.4.1:
version "2.4.1" version "2.4.1"
resolved "https://registry.yarnpkg.com/jsx-ast-utils/-/jsx-ast-utils-2.4.1.tgz#1114a4c1209481db06c690c2b4f488cc665f657e" resolved "https://registry.yarnpkg.com/jsx-ast-utils/-/jsx-ast-utils-2.4.1.tgz#1114a4c1209481db06c690c2b4f488cc665f657e"
integrity sha512-z1xSldJ6imESSzOjd3NNkieVJKRlKYSOtMG8SFyCj2FIrvSaSuli/WjpBkEzCBoR9bYYYFgqJw61Xhu7Lcgk+w== integrity sha512-z1xSldJ6imESSzOjd3NNkieVJKRlKYSOtMG8SFyCj2FIrvSaSuli/WjpBkEzCBoR9bYYYFgqJw61Xhu7Lcgk+w==
@ -6901,6 +6875,18 @@ known-css-properties@^0.3.0:
resolved "https://registry.yarnpkg.com/known-css-properties/-/known-css-properties-0.3.0.tgz#a3d135bbfc60ee8c6eacf2f7e7e6f2d4755e49a4" resolved "https://registry.yarnpkg.com/known-css-properties/-/known-css-properties-0.3.0.tgz#a3d135bbfc60ee8c6eacf2f7e7e6f2d4755e49a4"
integrity sha512-QMQcnKAiQccfQTqtBh/qwquGZ2XK/DXND1jrcN9M8gMMy99Gwla7GQjndVUsEqIaRyP6bsFRuhwRj5poafBGJQ== integrity sha512-QMQcnKAiQccfQTqtBh/qwquGZ2XK/DXND1jrcN9M8gMMy99Gwla7GQjndVUsEqIaRyP6bsFRuhwRj5poafBGJQ==
language-subtag-registry@~0.3.2:
version "0.3.20"
resolved "https://registry.yarnpkg.com/language-subtag-registry/-/language-subtag-registry-0.3.20.tgz#a00a37121894f224f763268e431c55556b0c0755"
integrity sha512-KPMwROklF4tEx283Xw0pNKtfTj1gZ4UByp4EsIFWLgBavJltF4TiYPc39k06zSTsLzxTVXXDSpbwaQXaFB4Qeg==
language-tags@^1.0.5:
version "1.0.5"
resolved "https://registry.yarnpkg.com/language-tags/-/language-tags-1.0.5.tgz#d321dbc4da30ba8bf3024e040fa5c14661f9193a"
integrity sha1-0yHbxNowuovzAk4ED6XBRmH5GTo=
dependencies:
language-subtag-registry "~0.3.2"
lcid@^2.0.0: lcid@^2.0.0:
version "2.0.0" version "2.0.0"
resolved "https://registry.yarnpkg.com/lcid/-/lcid-2.0.0.tgz#6ef5d2df60e52f82eb228a4c373e8d1f397253cf" resolved "https://registry.yarnpkg.com/lcid/-/lcid-2.0.0.tgz#6ef5d2df60e52f82eb228a4c373e8d1f397253cf"
@ -7692,9 +7678,9 @@ object-fit-images@^3.2.3:
integrity sha512-G+7LzpYfTfqUyrZlfrou/PLLLAPNC52FTy5y1CBywX+1/FkxIloOyQXBmZ3Zxa2AWO+lMF0JTuvqbr7G5e5CWg== integrity sha512-G+7LzpYfTfqUyrZlfrou/PLLLAPNC52FTy5y1CBywX+1/FkxIloOyQXBmZ3Zxa2AWO+lMF0JTuvqbr7G5e5CWg==
object-inspect@^1.7.0: object-inspect@^1.7.0:
version "1.7.0" version "1.8.0"
resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.7.0.tgz#f4f6bd181ad77f006b5ece60bd0b6f398ff74a67" resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.8.0.tgz#df807e5ecf53a609cc6bfe93eac3cc7be5b3a9d0"
integrity sha512-a7pEHdh1xKIAgTySUGgLMx/xwDZskN1Ud6egYYN3EdRW4ZMPNEDUTF+hwy2LUC+Bl+SyLXANnwz/jyh/qutKUw== integrity sha512-jLdtEOB112fORuypAyl/50VRVIBIdVQOSUUGQHzJ4xBSbit81zRarz7GThkEFZy1RceYrWYcPcBFPQwHyAc1gA==
object-is@^1.0.1, object-is@^1.0.2: object-is@^1.0.1, object-is@^1.0.2:
version "1.1.2" version "1.1.2"
@ -10284,9 +10270,9 @@ stack-utils@^2.0.2:
escape-string-regexp "^2.0.0" escape-string-regexp "^2.0.0"
stackframe@^1.1.1: stackframe@^1.1.1:
version "1.1.1" version "1.2.0"
resolved "https://registry.yarnpkg.com/stackframe/-/stackframe-1.1.1.tgz#ffef0a3318b1b60c3b58564989aca5660729ec71" resolved "https://registry.yarnpkg.com/stackframe/-/stackframe-1.2.0.tgz#52429492d63c62eb989804c11552e3d22e779303"
integrity sha512-0PlYhdKh6AfFxRyK/v+6/k+/mMfyiEBbTM5L94D0ZytQnJ166wuwoTYLHFWGbs2dpA8Rgq763KGWmN1EQEYHRQ== integrity sha512-GrdeshiRmS1YLMYgzF16olf2jJ/IzxXY9lhKOskuVziubpTYcYqyOwYeJKzQkwy7uN0fYSsbsC4RQaXf9LCrYA==
stacktrace-gps@^3.0.4: stacktrace-gps@^3.0.4:
version "3.0.4" version "3.0.4"
@ -10424,7 +10410,7 @@ string.prototype.trim@^1.2.1:
es-abstract "^1.17.0-next.1" es-abstract "^1.17.0-next.1"
function-bind "^1.1.1" function-bind "^1.1.1"
string.prototype.trimend@^1.0.0, string.prototype.trimend@^1.0.1: string.prototype.trimend@^1.0.1:
version "1.0.1" version "1.0.1"
resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.1.tgz#85812a6b847ac002270f5808146064c995fb6913" resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.1.tgz#85812a6b847ac002270f5808146064c995fb6913"
integrity sha512-LRPxFUaTtpqYsTeNKaFOw3R4bxIzWOnbQ837QfBylo8jIxtcbK/A/sMV7Q+OAV/vWo+7s25pOE10KYSjaSO06g== integrity sha512-LRPxFUaTtpqYsTeNKaFOw3R4bxIzWOnbQ837QfBylo8jIxtcbK/A/sMV7Q+OAV/vWo+7s25pOE10KYSjaSO06g==
@ -10432,25 +10418,7 @@ string.prototype.trimend@^1.0.0, string.prototype.trimend@^1.0.1:
define-properties "^1.1.3" define-properties "^1.1.3"
es-abstract "^1.17.5" es-abstract "^1.17.5"
string.prototype.trimleft@^2.1.1: string.prototype.trimstart@^1.0.1:
version "2.1.2"
resolved "https://registry.yarnpkg.com/string.prototype.trimleft/-/string.prototype.trimleft-2.1.2.tgz#4408aa2e5d6ddd0c9a80739b087fbc067c03b3cc"
integrity sha512-gCA0tza1JBvqr3bfAIFJGqfdRTyPae82+KTnm3coDXkZN9wnuW3HjGgN386D7hfv5CHQYCI022/rJPVlqXyHSw==
dependencies:
define-properties "^1.1.3"
es-abstract "^1.17.5"
string.prototype.trimstart "^1.0.0"
string.prototype.trimright@^2.1.1:
version "2.1.2"
resolved "https://registry.yarnpkg.com/string.prototype.trimright/-/string.prototype.trimright-2.1.2.tgz#c76f1cef30f21bbad8afeb8db1511496cfb0f2a3"
integrity sha512-ZNRQ7sY3KroTaYjRS6EbNiiHrOkjihL9aQE/8gfQ4DtAC/aEBRHFJa44OmoWxGGqXuJlfKkZW4WcXErGr+9ZFg==
dependencies:
define-properties "^1.1.3"
es-abstract "^1.17.5"
string.prototype.trimend "^1.0.0"
string.prototype.trimstart@^1.0.0, string.prototype.trimstart@^1.0.1:
version "1.0.1" version "1.0.1"
resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.1.tgz#14af6d9f34b053f7cfc89b72f8f2ee14b9039a54" resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.1.tgz#14af6d9f34b053f7cfc89b72f8f2ee14b9039a54"
integrity sha512-XxZn+QpvrBI1FOcg6dIpxUPgWCPuNXvMD72aaRaUQv1eD4e/Qy8i/hFTe0BUmD60p/QA6bh1avmuPTfNjqVWRw== integrity sha512-XxZn+QpvrBI1FOcg6dIpxUPgWCPuNXvMD72aaRaUQv1eD4e/Qy8i/hFTe0BUmD60p/QA6bh1avmuPTfNjqVWRw==