Merge commit '5241f7b2fd
' into kb_migration_development
This commit is contained in:
commit
cd452874a7
71 changed files with 875 additions and 287 deletions
72
.eslintrc.js
72
.eslintrc.js
|
@ -55,10 +55,7 @@ module.exports = {
|
||||||
'\\.(css|scss|json)$',
|
'\\.(css|scss|json)$',
|
||||||
],
|
],
|
||||||
'import/resolver': {
|
'import/resolver': {
|
||||||
node: {
|
typescript: {},
|
||||||
paths: ['app/javascript'],
|
|
||||||
extensions: ['.js', '.jsx', '.ts', '.tsx'],
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -167,11 +164,14 @@ module.exports = {
|
||||||
{
|
{
|
||||||
js: 'never',
|
js: 'never',
|
||||||
jsx: 'never',
|
jsx: 'never',
|
||||||
|
mjs: 'never',
|
||||||
ts: 'never',
|
ts: 'never',
|
||||||
tsx: 'never',
|
tsx: 'never',
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
'import/first': 'error',
|
||||||
'import/newline-after-import': 'error',
|
'import/newline-after-import': 'error',
|
||||||
|
'import/no-anonymous-default-export': 'error',
|
||||||
'import/no-extraneous-dependencies': [
|
'import/no-extraneous-dependencies': [
|
||||||
'error',
|
'error',
|
||||||
{
|
{
|
||||||
|
@ -186,6 +186,9 @@ module.exports = {
|
||||||
'import/no-amd': 'error',
|
'import/no-amd': 'error',
|
||||||
'import/no-commonjs': 'error',
|
'import/no-commonjs': 'error',
|
||||||
'import/no-import-module-exports': 'error',
|
'import/no-import-module-exports': 'error',
|
||||||
|
'import/no-relative-packages': 'error',
|
||||||
|
'import/no-self-import': 'error',
|
||||||
|
'import/no-useless-path-segments': 'error',
|
||||||
'import/no-webpack-loader-syntax': 'error',
|
'import/no-webpack-loader-syntax': 'error',
|
||||||
|
|
||||||
'promise/always-return': 'off',
|
'promise/always-return': 'off',
|
||||||
|
@ -257,6 +260,7 @@ module.exports = {
|
||||||
extends: [
|
extends: [
|
||||||
'eslint:recommended',
|
'eslint:recommended',
|
||||||
'plugin:@typescript-eslint/recommended',
|
'plugin:@typescript-eslint/recommended',
|
||||||
|
'plugin:@typescript-eslint/recommended-requiring-type-checking',
|
||||||
'plugin:react/recommended',
|
'plugin:react/recommended',
|
||||||
'plugin:react-hooks/recommended',
|
'plugin:react-hooks/recommended',
|
||||||
'plugin:jsx-a11y/recommended',
|
'plugin:jsx-a11y/recommended',
|
||||||
|
@ -267,8 +271,66 @@ module.exports = {
|
||||||
'plugin:prettier/recommended',
|
'plugin:prettier/recommended',
|
||||||
],
|
],
|
||||||
|
|
||||||
|
parserOptions: {
|
||||||
|
project: './tsconfig.json',
|
||||||
|
tsconfigRootDir: __dirname,
|
||||||
|
},
|
||||||
|
|
||||||
rules: {
|
rules: {
|
||||||
'@typescript-eslint/no-explicit-any': 'off',
|
'import/consistent-type-specifier-style': ['error', 'prefer-top-level'],
|
||||||
|
|
||||||
|
'import/order': [
|
||||||
|
'error',
|
||||||
|
{
|
||||||
|
alphabetize: { order: 'asc' },
|
||||||
|
'newlines-between': 'always',
|
||||||
|
groups: [
|
||||||
|
'builtin',
|
||||||
|
'external',
|
||||||
|
'internal',
|
||||||
|
'parent',
|
||||||
|
['index', 'sibling'],
|
||||||
|
'object',
|
||||||
|
],
|
||||||
|
pathGroups: [
|
||||||
|
// React core packages
|
||||||
|
{
|
||||||
|
pattern: '{react,react-dom,prop-types}',
|
||||||
|
group: 'builtin',
|
||||||
|
position: 'after',
|
||||||
|
},
|
||||||
|
// I18n
|
||||||
|
{
|
||||||
|
pattern: 'react-intl',
|
||||||
|
group: 'builtin',
|
||||||
|
position: 'after',
|
||||||
|
},
|
||||||
|
// Common React utilities
|
||||||
|
{
|
||||||
|
pattern: '{classnames,react-helmet}',
|
||||||
|
group: 'external',
|
||||||
|
position: 'before',
|
||||||
|
},
|
||||||
|
// Immutable / Redux / data store
|
||||||
|
{
|
||||||
|
pattern: '{immutable,react-redux,react-immutable-proptypes,react-immutable-pure-component,reselect}',
|
||||||
|
group: 'external',
|
||||||
|
position: 'before',
|
||||||
|
},
|
||||||
|
// Internal packages
|
||||||
|
{
|
||||||
|
pattern: '{mastodon/**}',
|
||||||
|
group: 'internal',
|
||||||
|
position: 'after',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
pathGroupsExcludedImportTypes: [],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
|
||||||
|
'@typescript-eslint/consistent-type-definitions': ['warn', 'interface'],
|
||||||
|
'@typescript-eslint/consistent-type-exports': 'error',
|
||||||
|
'@typescript-eslint/consistent-type-imports': 'error',
|
||||||
|
|
||||||
'jsdoc/require-jsdoc': 'off',
|
'jsdoc/require-jsdoc': 'off',
|
||||||
|
|
||||||
|
|
|
@ -648,14 +648,6 @@ RSpec/RepeatedExampleGroupDescription:
|
||||||
- 'spec/controllers/admin/reports/actions_controller_spec.rb'
|
- 'spec/controllers/admin/reports/actions_controller_spec.rb'
|
||||||
- 'spec/policies/report_note_policy_spec.rb'
|
- 'spec/policies/report_note_policy_spec.rb'
|
||||||
|
|
||||||
RSpec/ScatteredSetup:
|
|
||||||
Exclude:
|
|
||||||
- 'spec/controllers/activitypub/followers_synchronizations_controller_spec.rb'
|
|
||||||
- 'spec/controllers/activitypub/outboxes_controller_spec.rb'
|
|
||||||
- 'spec/controllers/admin/disputes/appeals_controller_spec.rb'
|
|
||||||
- 'spec/controllers/auth/registrations_controller_spec.rb'
|
|
||||||
- 'spec/services/activitypub/process_account_service_spec.rb'
|
|
||||||
|
|
||||||
# This cop supports safe autocorrection (--autocorrect).
|
# This cop supports safe autocorrection (--autocorrect).
|
||||||
RSpec/SharedContext:
|
RSpec/SharedContext:
|
||||||
Exclude:
|
Exclude:
|
||||||
|
|
|
@ -1,11 +1,12 @@
|
||||||
import { createAction } from '@reduxjs/toolkit';
|
import { createAction } from '@reduxjs/toolkit';
|
||||||
|
|
||||||
import type { LayoutType } from '../is_mobile';
|
import type { LayoutType } from '../is_mobile';
|
||||||
|
|
||||||
export const focusApp = createAction('APP_FOCUS');
|
export const focusApp = createAction('APP_FOCUS');
|
||||||
export const unfocusApp = createAction('APP_UNFOCUS');
|
export const unfocusApp = createAction('APP_UNFOCUS');
|
||||||
|
|
||||||
type ChangeLayoutPayload = {
|
interface ChangeLayoutPayload {
|
||||||
layout: LayoutType;
|
layout: LayoutType;
|
||||||
};
|
}
|
||||||
export const changeLayout =
|
export const changeLayout =
|
||||||
createAction<ChangeLayoutPayload>('APP_LAYOUT_CHANGE');
|
createAction<ChangeLayoutPayload>('APP_LAYOUT_CHANGE');
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
import api from '../api';
|
import api from '../api';
|
||||||
import { importFetchedStatuses } from './importer';
|
import { importFetchedStatuses } from './importer';
|
||||||
|
|
||||||
|
import { me } from '../initial_state';
|
||||||
|
|
||||||
export const PINNED_STATUSES_FETCH_REQUEST = 'PINNED_STATUSES_FETCH_REQUEST';
|
export const PINNED_STATUSES_FETCH_REQUEST = 'PINNED_STATUSES_FETCH_REQUEST';
|
||||||
export const PINNED_STATUSES_FETCH_SUCCESS = 'PINNED_STATUSES_FETCH_SUCCESS';
|
export const PINNED_STATUSES_FETCH_SUCCESS = 'PINNED_STATUSES_FETCH_SUCCESS';
|
||||||
export const PINNED_STATUSES_FETCH_FAIL = 'PINNED_STATUSES_FETCH_FAIL';
|
export const PINNED_STATUSES_FETCH_FAIL = 'PINNED_STATUSES_FETCH_FAIL';
|
||||||
|
|
||||||
import { me } from '../initial_state';
|
|
||||||
|
|
||||||
export function fetchPinnedStatuses() {
|
export function fetchPinnedStatuses() {
|
||||||
return (dispatch, getState) => {
|
return (dispatch, getState) => {
|
||||||
dispatch(fetchPinnedStatusesRequest());
|
dispatch(fetchPinnedStatusesRequest());
|
||||||
|
|
|
@ -8,12 +8,12 @@ import { defineMessages, injectIntl } from 'react-intl';
|
||||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||||
import { me } from '../initial_state';
|
import { me } from '../initial_state';
|
||||||
import { RelativeTimestamp } from './relative_timestamp';
|
import { RelativeTimestamp } from './relative_timestamp';
|
||||||
import Skeleton from 'mastodon/components/skeleton';
|
|
||||||
import { Link } from 'react-router-dom';
|
import { Link } from 'react-router-dom';
|
||||||
import { counterRenderer } from 'mastodon/components/common_counter';
|
import { counterRenderer } from 'mastodon/components/common_counter';
|
||||||
import ShortNumber from 'mastodon/components/short_number';
|
import ShortNumber from 'mastodon/components/short_number';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import { VerifiedBadge } from 'mastodon/components/verified_badge';
|
import { VerifiedBadge } from 'mastodon/components/verified_badge';
|
||||||
|
import { EmptyAccount } from 'mastodon/components/empty_account';
|
||||||
|
|
||||||
const messages = defineMessages({
|
const messages = defineMessages({
|
||||||
follow: { id: 'account.follow', defaultMessage: 'Follow' },
|
follow: { id: 'account.follow', defaultMessage: 'Follow' },
|
||||||
|
@ -78,20 +78,7 @@ class Account extends ImmutablePureComponent {
|
||||||
const { account, intl, hidden, onActionClick, actionIcon, actionTitle, defaultAction, size, minimal, children } = this.props;
|
const { account, intl, hidden, onActionClick, actionIcon, actionTitle, defaultAction, size, minimal, children } = this.props;
|
||||||
|
|
||||||
if (!account) {
|
if (!account) {
|
||||||
return (
|
return <EmptyAccount size={size} minimal={minimal} />;
|
||||||
<div className={classNames('account', { 'account--minimal': minimal })}>
|
|
||||||
<div className='account__wrapper'>
|
|
||||||
<div className='account__display-name'>
|
|
||||||
<div className='account__avatar-wrapper'><Skeleton width={size} height={size} /></div>
|
|
||||||
|
|
||||||
<div>
|
|
||||||
<DisplayName />
|
|
||||||
<Skeleton width='7ch' />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hidden) {
|
if (hidden) {
|
||||||
|
|
|
@ -1,8 +1,11 @@
|
||||||
import React, { useCallback, useState } from 'react';
|
import React, { useCallback, useState } from 'react';
|
||||||
import ShortNumber from './short_number';
|
|
||||||
import { TransitionMotion, spring } from 'react-motion';
|
import { TransitionMotion, spring } from 'react-motion';
|
||||||
|
|
||||||
import { reduceMotion } from '../initial_state';
|
import { reduceMotion } from '../initial_state';
|
||||||
|
|
||||||
|
import ShortNumber from './short_number';
|
||||||
|
|
||||||
const obfuscatedCount = (count: number) => {
|
const obfuscatedCount = (count: number) => {
|
||||||
if (count < 0) {
|
if (count < 0) {
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -13,10 +16,10 @@ const obfuscatedCount = (count: number) => {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
type Props = {
|
interface Props {
|
||||||
value: number;
|
value: number;
|
||||||
obfuscate?: boolean;
|
obfuscate?: boolean;
|
||||||
};
|
}
|
||||||
export const AnimatedNumber: React.FC<Props> = ({ value, obfuscate }) => {
|
export const AnimatedNumber: React.FC<Props> = ({ value, obfuscate }) => {
|
||||||
const [previousValue, setPreviousValue] = useState(value);
|
const [previousValue, setPreviousValue] = useState(value);
|
||||||
const [direction, setDirection] = useState<1 | -1>(1);
|
const [direction, setDirection] = useState<1 | -1>(1);
|
||||||
|
@ -64,7 +67,11 @@ export const AnimatedNumber: React.FC<Props> = ({ value, obfuscate }) => {
|
||||||
transform: `translateY(${style.y * 100}%)`,
|
transform: `translateY(${style.y * 100}%)`,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{obfuscate ? obfuscatedCount(data) : <ShortNumber value={data} />}
|
{obfuscate ? (
|
||||||
|
obfuscatedCount(data as number)
|
||||||
|
) : (
|
||||||
|
<ShortNumber value={data as number} />
|
||||||
|
)}
|
||||||
</span>
|
</span>
|
||||||
))}
|
))}
|
||||||
</span>
|
</span>
|
||||||
|
|
|
@ -1,16 +1,18 @@
|
||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
|
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import { autoPlayGif } from '../initial_state';
|
|
||||||
import { useHovering } from '../../hooks/useHovering';
|
import { useHovering } from '../../hooks/useHovering';
|
||||||
import type { Account } from '../../types/resources';
|
import type { Account } from '../../types/resources';
|
||||||
|
import { autoPlayGif } from '../initial_state';
|
||||||
|
|
||||||
type Props = {
|
interface Props {
|
||||||
account: Account;
|
account: Account;
|
||||||
size: number;
|
size: number;
|
||||||
style?: React.CSSProperties;
|
style?: React.CSSProperties;
|
||||||
inline?: boolean;
|
inline?: boolean;
|
||||||
animate?: boolean;
|
animate?: boolean;
|
||||||
};
|
}
|
||||||
|
|
||||||
export const Avatar: React.FC<Props> = ({
|
export const Avatar: React.FC<Props> = ({
|
||||||
account,
|
account,
|
||||||
|
|
|
@ -1,15 +1,16 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import type { Account } from '../../types/resources';
|
|
||||||
import { useHovering } from '../../hooks/useHovering';
|
import { useHovering } from '../../hooks/useHovering';
|
||||||
|
import type { Account } from '../../types/resources';
|
||||||
import { autoPlayGif } from '../initial_state';
|
import { autoPlayGif } from '../initial_state';
|
||||||
|
|
||||||
type Props = {
|
interface Props {
|
||||||
account: Account;
|
account: Account;
|
||||||
friend: Account;
|
friend: Account;
|
||||||
size?: number;
|
size?: number;
|
||||||
baseSize?: number;
|
baseSize?: number;
|
||||||
overlaySize?: number;
|
overlaySize?: number;
|
||||||
};
|
}
|
||||||
|
|
||||||
export const AvatarOverlay: React.FC<Props> = ({
|
export const AvatarOverlay: React.FC<Props> = ({
|
||||||
account,
|
account,
|
||||||
|
|
|
@ -1,14 +1,14 @@
|
||||||
import { decode } from 'blurhash';
|
|
||||||
import React, { useRef, useEffect } from 'react';
|
import React, { useRef, useEffect } from 'react';
|
||||||
|
|
||||||
type Props = {
|
import { decode } from 'blurhash';
|
||||||
|
|
||||||
|
interface Props extends React.HTMLAttributes<HTMLCanvasElement> {
|
||||||
hash: string;
|
hash: string;
|
||||||
width?: number;
|
width?: number;
|
||||||
height?: number;
|
height?: number;
|
||||||
dummy?: boolean; // Whether dummy mode is enabled. If enabled, nothing is rendered and canvas left untouched
|
dummy?: boolean; // Whether dummy mode is enabled. If enabled, nothing is rendered and canvas left untouched
|
||||||
children?: never;
|
children?: never;
|
||||||
[key: string]: any;
|
}
|
||||||
};
|
|
||||||
const Blurhash: React.FC<Props> = ({
|
const Blurhash: React.FC<Props> = ({
|
||||||
hash,
|
hash,
|
||||||
width = 32,
|
width = 32,
|
||||||
|
@ -21,6 +21,7 @@ const Blurhash: React.FC<Props> = ({
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||||
const canvas = canvasRef.current!;
|
const canvas = canvasRef.current!;
|
||||||
|
|
||||||
// eslint-disable-next-line no-self-assign
|
// eslint-disable-next-line no-self-assign
|
||||||
canvas.width = canvas.width; // resets canvas
|
canvas.width = canvas.width; // resets canvas
|
||||||
|
|
||||||
|
|
|
@ -1,14 +1,18 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { autoPlayGif } from '..//initial_state';
|
|
||||||
import Skeleton from './skeleton';
|
|
||||||
import { Account } from '../../types/resources';
|
|
||||||
import { List } from 'immutable';
|
|
||||||
|
|
||||||
type Props = {
|
import type { List } from 'immutable';
|
||||||
account: Account;
|
|
||||||
others: List<Account>;
|
import type { Account } from '../../types/resources';
|
||||||
localDomain: string;
|
import { autoPlayGif } from '../initial_state';
|
||||||
};
|
|
||||||
|
import Skeleton from './skeleton';
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
account?: Account;
|
||||||
|
others?: List<Account>;
|
||||||
|
localDomain?: string;
|
||||||
|
}
|
||||||
|
|
||||||
export class DisplayName extends React.PureComponent<Props> {
|
export class DisplayName extends React.PureComponent<Props> {
|
||||||
handleMouseEnter: React.ReactEventHandler<HTMLSpanElement> = ({
|
handleMouseEnter: React.ReactEventHandler<HTMLSpanElement> = ({
|
||||||
currentTarget,
|
currentTarget,
|
||||||
|
@ -45,7 +49,15 @@ export class DisplayName extends React.PureComponent<Props> {
|
||||||
render() {
|
render() {
|
||||||
const { others, localDomain } = this.props;
|
const { others, localDomain } = this.props;
|
||||||
|
|
||||||
let displayName: React.ReactNode, suffix: React.ReactNode, account: Account;
|
let displayName: React.ReactNode,
|
||||||
|
suffix: React.ReactNode,
|
||||||
|
account: Account | undefined;
|
||||||
|
|
||||||
|
if (others && others.size > 0) {
|
||||||
|
account = others.first();
|
||||||
|
} else if (this.props.account) {
|
||||||
|
account = this.props.account;
|
||||||
|
}
|
||||||
|
|
||||||
if (others && others.size > 1) {
|
if (others && others.size > 1) {
|
||||||
displayName = others
|
displayName = others
|
||||||
|
@ -63,13 +75,7 @@ export class DisplayName extends React.PureComponent<Props> {
|
||||||
if (others.size - 2 > 0) {
|
if (others.size - 2 > 0) {
|
||||||
suffix = `+${others.size - 2}`;
|
suffix = `+${others.size - 2}`;
|
||||||
}
|
}
|
||||||
} else if ((others && others.size > 0) || this.props.account) {
|
} else if (account) {
|
||||||
if (others && others.size > 0) {
|
|
||||||
account = others.first();
|
|
||||||
} else {
|
|
||||||
account = this.props.account;
|
|
||||||
}
|
|
||||||
|
|
||||||
let acct = account.get('acct');
|
let acct = account.get('acct');
|
||||||
|
|
||||||
if (acct.indexOf('@') === -1 && localDomain) {
|
if (acct.indexOf('@') === -1 && localDomain) {
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
import React, { useCallback } from 'react';
|
import React, { useCallback } from 'react';
|
||||||
|
|
||||||
|
import type { InjectedIntl } from 'react-intl';
|
||||||
|
import { defineMessages, injectIntl } from 'react-intl';
|
||||||
|
|
||||||
import { IconButton } from './icon_button';
|
import { IconButton } from './icon_button';
|
||||||
import { InjectedIntl, defineMessages, injectIntl } from 'react-intl';
|
|
||||||
|
|
||||||
const messages = defineMessages({
|
const messages = defineMessages({
|
||||||
unblockDomain: {
|
unblockDomain: {
|
||||||
|
@ -9,11 +12,11 @@ const messages = defineMessages({
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
type Props = {
|
interface Props {
|
||||||
domain: string;
|
domain: string;
|
||||||
onUnblockDomain: (domain: string) => void;
|
onUnblockDomain: (domain: string) => void;
|
||||||
intl: InjectedIntl;
|
intl: InjectedIntl;
|
||||||
};
|
}
|
||||||
const _Domain: React.FC<Props> = ({ domain, onUnblockDomain, intl }) => {
|
const _Domain: React.FC<Props> = ({ domain, onUnblockDomain, intl }) => {
|
||||||
const handleDomainUnblock = useCallback(() => {
|
const handleDomainUnblock = useCallback(() => {
|
||||||
onUnblockDomain(domain);
|
onUnblockDomain(domain);
|
||||||
|
|
33
app/javascript/mastodon/components/empty_account.tsx
Normal file
33
app/javascript/mastodon/components/empty_account.tsx
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
import classNames from 'classnames';
|
||||||
|
|
||||||
|
import { DisplayName } from 'mastodon/components/display_name';
|
||||||
|
import Skeleton from 'mastodon/components/skeleton';
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
size?: number;
|
||||||
|
minimal?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const EmptyAccount: React.FC<Props> = ({
|
||||||
|
size = 46,
|
||||||
|
minimal = false,
|
||||||
|
}) => {
|
||||||
|
return (
|
||||||
|
<div className={classNames('account', { 'account--minimal': minimal })}>
|
||||||
|
<div className='account__wrapper'>
|
||||||
|
<div className='account__display-name'>
|
||||||
|
<div className='account__avatar-wrapper'>
|
||||||
|
<Skeleton width={size} height={size} />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<DisplayName />
|
||||||
|
<Skeleton width='7ch' />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
|
@ -1,6 +1,6 @@
|
||||||
import React, { useCallback, useState } from 'react';
|
import React, { useCallback, useState } from 'react';
|
||||||
|
|
||||||
type Props = {
|
interface Props {
|
||||||
src: string;
|
src: string;
|
||||||
key: string;
|
key: string;
|
||||||
alt?: string;
|
alt?: string;
|
||||||
|
@ -8,7 +8,7 @@ type Props = {
|
||||||
width: number;
|
width: number;
|
||||||
height: number;
|
height: number;
|
||||||
onClick?: () => void;
|
onClick?: () => void;
|
||||||
};
|
}
|
||||||
|
|
||||||
export const GIFV: React.FC<Props> = ({
|
export const GIFV: React.FC<Props> = ({
|
||||||
src,
|
src,
|
||||||
|
|
|
@ -1,13 +1,14 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
|
|
||||||
type Props = {
|
interface Props extends React.HTMLAttributes<HTMLImageElement> {
|
||||||
id: string;
|
id: string;
|
||||||
className?: string;
|
className?: string;
|
||||||
fixedWidth?: boolean;
|
fixedWidth?: boolean;
|
||||||
children?: never;
|
children?: never;
|
||||||
[key: string]: any;
|
}
|
||||||
};
|
|
||||||
export const Icon: React.FC<Props> = ({
|
export const Icon: React.FC<Props> = ({
|
||||||
id,
|
id,
|
||||||
className,
|
className,
|
||||||
|
|
|
@ -1,9 +1,11 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import classNames from 'classnames';
|
|
||||||
import { Icon } from './icon';
|
|
||||||
import { AnimatedNumber } from './animated_number';
|
|
||||||
|
|
||||||
type Props = {
|
import classNames from 'classnames';
|
||||||
|
|
||||||
|
import { AnimatedNumber } from './animated_number';
|
||||||
|
import { Icon } from './icon';
|
||||||
|
|
||||||
|
interface Props {
|
||||||
className?: string;
|
className?: string;
|
||||||
title: string;
|
title: string;
|
||||||
icon: string;
|
icon: string;
|
||||||
|
@ -25,11 +27,11 @@ type Props = {
|
||||||
obfuscateCount?: boolean;
|
obfuscateCount?: boolean;
|
||||||
href?: string;
|
href?: string;
|
||||||
ariaHidden: boolean;
|
ariaHidden: boolean;
|
||||||
};
|
}
|
||||||
type States = {
|
interface States {
|
||||||
activate: boolean;
|
activate: boolean;
|
||||||
deactivate: boolean;
|
deactivate: boolean;
|
||||||
};
|
}
|
||||||
export class IconButton extends React.PureComponent<Props, States> {
|
export class IconButton extends React.PureComponent<Props, States> {
|
||||||
static defaultProps = {
|
static defaultProps = {
|
||||||
size: 18,
|
size: 18,
|
||||||
|
|
|
@ -1,14 +1,15 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
import { Icon } from './icon';
|
import { Icon } from './icon';
|
||||||
|
|
||||||
const formatNumber = (num: number): number | string => (num > 40 ? '40+' : num);
|
const formatNumber = (num: number): number | string => (num > 40 ? '40+' : num);
|
||||||
|
|
||||||
type Props = {
|
interface Props {
|
||||||
id: string;
|
id: string;
|
||||||
count: number;
|
count: number;
|
||||||
issueBadge: boolean;
|
issueBadge: boolean;
|
||||||
className: string;
|
className: string;
|
||||||
};
|
}
|
||||||
export const IconWithBadge: React.FC<Props> = ({
|
export const IconWithBadge: React.FC<Props> = ({
|
||||||
id,
|
id,
|
||||||
count,
|
count,
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
import logo from 'mastodon/../images/logo.svg';
|
import logo from 'mastodon/../images/logo.svg';
|
||||||
|
|
||||||
export const WordmarkLogo: React.FC = () => (
|
export const WordmarkLogo: React.FC = () => (
|
||||||
|
|
|
@ -266,7 +266,7 @@ class MediaGallery extends React.PureComponent {
|
||||||
};
|
};
|
||||||
|
|
||||||
handleClick = (index) => {
|
handleClick = (index) => {
|
||||||
this.props.onOpenMedia(this.props.media, index);
|
this.props.onOpenMedia(this.props.media, index, this.props.lang);
|
||||||
};
|
};
|
||||||
|
|
||||||
handleRef = c => {
|
handleRef = c => {
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
import { FormattedMessage } from 'react-intl';
|
import { FormattedMessage } from 'react-intl';
|
||||||
|
|
||||||
export const NotSignedInIndicator: React.FC = () => (
|
export const NotSignedInIndicator: React.FC = () => (
|
||||||
|
@ -6,7 +7,7 @@ export const NotSignedInIndicator: React.FC = () => (
|
||||||
<div className='empty-column-indicator'>
|
<div className='empty-column-indicator'>
|
||||||
<FormattedMessage
|
<FormattedMessage
|
||||||
id='not_signed_in_indicator.not_signed_in'
|
id='not_signed_in_indicator.not_signed_in'
|
||||||
defaultMessage='You need to sign in to access this resource.'
|
defaultMessage='You need to login to access this resource.'
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,13 +1,14 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
|
|
||||||
type Props = {
|
interface Props {
|
||||||
value: string;
|
value: string;
|
||||||
checked: boolean;
|
checked: boolean;
|
||||||
name: string;
|
name: string;
|
||||||
onChange: (event: React.ChangeEvent<HTMLInputElement>) => void;
|
onChange: (event: React.ChangeEvent<HTMLInputElement>) => void;
|
||||||
label: React.ReactNode;
|
label: React.ReactNode;
|
||||||
};
|
}
|
||||||
|
|
||||||
export const RadioButton: React.FC<Props> = ({
|
export const RadioButton: React.FC<Props> = ({
|
||||||
name,
|
name,
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { injectIntl, defineMessages, InjectedIntl } from 'react-intl';
|
|
||||||
|
import type { InjectedIntl } from 'react-intl';
|
||||||
|
import { injectIntl, defineMessages } from 'react-intl';
|
||||||
|
|
||||||
const messages = defineMessages({
|
const messages = defineMessages({
|
||||||
today: { id: 'relative_time.today', defaultMessage: 'today' },
|
today: { id: 'relative_time.today', defaultMessage: 'today' },
|
||||||
|
@ -187,16 +189,16 @@ const timeRemainingString = (
|
||||||
return relativeTime;
|
return relativeTime;
|
||||||
};
|
};
|
||||||
|
|
||||||
type Props = {
|
interface Props {
|
||||||
intl: InjectedIntl;
|
intl: InjectedIntl;
|
||||||
timestamp: string;
|
timestamp: string;
|
||||||
year: number;
|
year: number;
|
||||||
futureDate?: boolean;
|
futureDate?: boolean;
|
||||||
short?: boolean;
|
short?: boolean;
|
||||||
};
|
}
|
||||||
type States = {
|
interface States {
|
||||||
now: number;
|
now: number;
|
||||||
};
|
}
|
||||||
class RelativeTimestamp extends React.Component<Props, States> {
|
class RelativeTimestamp extends React.Component<Props, States> {
|
||||||
state = {
|
state = {
|
||||||
now: this.props.intl.now(),
|
now: this.props.intl.now(),
|
||||||
|
|
|
@ -1,13 +1,15 @@
|
||||||
import React, { useCallback, useState } from 'react';
|
import React, { useCallback, useState } from 'react';
|
||||||
import { Blurhash } from './blurhash';
|
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
|
|
||||||
type Props = {
|
import { Blurhash } from './blurhash';
|
||||||
|
|
||||||
|
interface Props {
|
||||||
src: string;
|
src: string;
|
||||||
srcSet?: string;
|
srcSet?: string;
|
||||||
blurhash?: string;
|
blurhash?: string;
|
||||||
className?: string;
|
className?: string;
|
||||||
};
|
}
|
||||||
|
|
||||||
export const ServerHeroImage: React.FC<Props> = ({
|
export const ServerHeroImage: React.FC<Props> = ({
|
||||||
src,
|
src,
|
||||||
|
|
|
@ -199,11 +199,12 @@ class Status extends ImmutablePureComponent {
|
||||||
|
|
||||||
handleOpenVideo = (options) => {
|
handleOpenVideo = (options) => {
|
||||||
const status = this._properStatus();
|
const status = this._properStatus();
|
||||||
this.props.onOpenVideo(status.get('id'), status.getIn(['media_attachments', 0]), options);
|
this.props.onOpenVideo(status.get('id'), status.getIn(['media_attachments', 0]), status.get('language'), options);
|
||||||
};
|
};
|
||||||
|
|
||||||
handleOpenMedia = (media, index) => {
|
handleOpenMedia = (media, index) => {
|
||||||
this.props.onOpenMedia(this._properStatus().get('id'), media, index);
|
const status = this._properStatus();
|
||||||
|
this.props.onOpenMedia(status.get('id'), media, index, status.get('language'));
|
||||||
};
|
};
|
||||||
|
|
||||||
handleHotkeyOpenMedia = e => {
|
handleHotkeyOpenMedia = e => {
|
||||||
|
@ -213,10 +214,11 @@ class Status extends ImmutablePureComponent {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|
||||||
if (status.get('media_attachments').size > 0) {
|
if (status.get('media_attachments').size > 0) {
|
||||||
|
const lang = status.get('language');
|
||||||
if (status.getIn(['media_attachments', 0, 'type']) === 'video') {
|
if (status.getIn(['media_attachments', 0, 'type']) === 'video') {
|
||||||
onOpenVideo(status.get('id'), status.getIn(['media_attachments', 0]), { startTime: 0 });
|
onOpenVideo(status.get('id'), status.getIn(['media_attachments', 0]), lang, { startTime: 0 });
|
||||||
} else {
|
} else {
|
||||||
onOpenMedia(status.get('id'), status.get('media_attachments'), 0);
|
onOpenMedia(status.get('id'), status.get('media_attachments'), 0, lang);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
import { Icon } from './icon';
|
import { Icon } from './icon';
|
||||||
|
|
||||||
type Props = {
|
interface Props {
|
||||||
link: string;
|
link: string;
|
||||||
};
|
}
|
||||||
export const VerifiedBadge: React.FC<Props> = ({ link }) => (
|
export const VerifiedBadge: React.FC<Props> = ({ link }) => (
|
||||||
<span className='verified-badge'>
|
<span className='verified-badge'>
|
||||||
<Icon id='check' className='verified-badge__mark' />
|
<Icon id='check' className='verified-badge__mark' />
|
||||||
|
|
|
@ -29,19 +29,20 @@ export default class MediaContainer extends PureComponent {
|
||||||
state = {
|
state = {
|
||||||
media: null,
|
media: null,
|
||||||
index: null,
|
index: null,
|
||||||
|
lang: null,
|
||||||
time: null,
|
time: null,
|
||||||
backgroundColor: null,
|
backgroundColor: null,
|
||||||
options: null,
|
options: null,
|
||||||
};
|
};
|
||||||
|
|
||||||
handleOpenMedia = (media, index) => {
|
handleOpenMedia = (media, index, lang) => {
|
||||||
document.body.classList.add('with-modals--active');
|
document.body.classList.add('with-modals--active');
|
||||||
document.documentElement.style.marginRight = `${getScrollbarWidth()}px`;
|
document.documentElement.style.marginRight = `${getScrollbarWidth()}px`;
|
||||||
|
|
||||||
this.setState({ media, index });
|
this.setState({ media, index, lang });
|
||||||
};
|
};
|
||||||
|
|
||||||
handleOpenVideo = (options) => {
|
handleOpenVideo = (lang, options) => {
|
||||||
const { components } = this.props;
|
const { components } = this.props;
|
||||||
const { media } = JSON.parse(components[options.componentIndex].getAttribute('data-props'));
|
const { media } = JSON.parse(components[options.componentIndex].getAttribute('data-props'));
|
||||||
const mediaList = fromJS(media);
|
const mediaList = fromJS(media);
|
||||||
|
@ -49,7 +50,7 @@ export default class MediaContainer extends PureComponent {
|
||||||
document.body.classList.add('with-modals--active');
|
document.body.classList.add('with-modals--active');
|
||||||
document.documentElement.style.marginRight = `${getScrollbarWidth()}px`;
|
document.documentElement.style.marginRight = `${getScrollbarWidth()}px`;
|
||||||
|
|
||||||
this.setState({ media: mediaList, options });
|
this.setState({ media: mediaList, lang, options });
|
||||||
};
|
};
|
||||||
|
|
||||||
handleCloseMedia = () => {
|
handleCloseMedia = () => {
|
||||||
|
@ -105,6 +106,7 @@ export default class MediaContainer extends PureComponent {
|
||||||
<MediaModal
|
<MediaModal
|
||||||
media={this.state.media}
|
media={this.state.media}
|
||||||
index={this.state.index || 0}
|
index={this.state.index || 0}
|
||||||
|
lang={this.state.lang}
|
||||||
currentTime={this.state.options?.startTime}
|
currentTime={this.state.options?.startTime}
|
||||||
autoPlay={this.state.options?.autoPlay}
|
autoPlay={this.state.options?.autoPlay}
|
||||||
volume={this.state.options?.defaultVolume}
|
volume={this.state.options?.defaultVolume}
|
||||||
|
|
|
@ -192,12 +192,12 @@ const mapDispatchToProps = (dispatch, { intl, contextType }) => ({
|
||||||
dispatch(mentionCompose(account, router));
|
dispatch(mentionCompose(account, router));
|
||||||
},
|
},
|
||||||
|
|
||||||
onOpenMedia (statusId, media, index) {
|
onOpenMedia (statusId, media, index, lang) {
|
||||||
dispatch(openModal('MEDIA', { statusId, media, index }));
|
dispatch(openModal('MEDIA', { statusId, media, index, lang }));
|
||||||
},
|
},
|
||||||
|
|
||||||
onOpenVideo (statusId, media, options) {
|
onOpenVideo (statusId, media, lang, options) {
|
||||||
dispatch(openModal('VIDEO', { statusId, media, options }));
|
dispatch(openModal('VIDEO', { statusId, media, lang, options }));
|
||||||
},
|
},
|
||||||
|
|
||||||
onBlock (status) {
|
onBlock (status) {
|
||||||
|
|
|
@ -136,16 +136,17 @@ class AccountGallery extends ImmutablePureComponent {
|
||||||
handleOpenMedia = attachment => {
|
handleOpenMedia = attachment => {
|
||||||
const { dispatch } = this.props;
|
const { dispatch } = this.props;
|
||||||
const statusId = attachment.getIn(['status', 'id']);
|
const statusId = attachment.getIn(['status', 'id']);
|
||||||
|
const lang = attachment.getIn(['status', 'language']);
|
||||||
|
|
||||||
if (attachment.get('type') === 'video') {
|
if (attachment.get('type') === 'video') {
|
||||||
dispatch(openModal('VIDEO', { media: attachment, statusId, options: { autoPlay: true } }));
|
dispatch(openModal('VIDEO', { media: attachment, statusId, lang, options: { autoPlay: true } }));
|
||||||
} else if (attachment.get('type') === 'audio') {
|
} else if (attachment.get('type') === 'audio') {
|
||||||
dispatch(openModal('AUDIO', { media: attachment, statusId, options: { autoPlay: true } }));
|
dispatch(openModal('AUDIO', { media: attachment, statusId, lang, options: { autoPlay: true } }));
|
||||||
} else {
|
} else {
|
||||||
const media = attachment.getIn(['status', 'media_attachments']);
|
const media = attachment.getIn(['status', 'media_attachments']);
|
||||||
const index = media.findIndex(x => x.get('id') === attachment.get('id'));
|
const index = media.findIndex(x => x.get('id') === attachment.get('id'));
|
||||||
|
|
||||||
dispatch(openModal('MEDIA', { media, index, statusId }));
|
dispatch(openModal('MEDIA', { media, index, statusId, lang }));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,7 @@ import { connect } from 'react-redux';
|
||||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { lookupAccount, fetchAccount } from '../../actions/accounts';
|
import { lookupAccount, fetchAccount } from '../../actions/accounts';
|
||||||
import { expandAccountFeaturedTimeline, expandAccountTimeline } from '../../actions/timelines';
|
import { expandAccountFeaturedTimeline, expandAccountTimeline, connectTimeline, disconnectTimeline } from '../../actions/timelines';
|
||||||
import StatusList from '../../components/status_list';
|
import StatusList from '../../components/status_list';
|
||||||
import LoadingIndicator from '../../components/loading_indicator';
|
import LoadingIndicator from '../../components/loading_indicator';
|
||||||
import Column from '../ui/components/column';
|
import Column from '../ui/components/column';
|
||||||
|
@ -14,7 +14,6 @@ import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||||
import { FormattedMessage } from 'react-intl';
|
import { FormattedMessage } from 'react-intl';
|
||||||
import TimelineHint from 'mastodon/components/timeline_hint';
|
import TimelineHint from 'mastodon/components/timeline_hint';
|
||||||
import { me } from 'mastodon/initial_state';
|
import { me } from 'mastodon/initial_state';
|
||||||
import { connectTimeline, disconnectTimeline } from 'mastodon/actions/timelines';
|
|
||||||
import LimitedAccountHint from './components/limited_account_hint';
|
import LimitedAccountHint from './components/limited_account_hint';
|
||||||
import { getAccountHidden } from 'mastodon/selectors';
|
import { getAccountHidden } from 'mastodon/selectors';
|
||||||
import { fetchFeaturedTags } from '../../actions/featured_tags';
|
import { fetchFeaturedTags } from '../../actions/featured_tags';
|
||||||
|
|
|
@ -148,7 +148,7 @@ class InteractionModal extends React.PureComponent {
|
||||||
<div className='interaction-modal__choices'>
|
<div className='interaction-modal__choices'>
|
||||||
<div className='interaction-modal__choices__choice'>
|
<div className='interaction-modal__choices__choice'>
|
||||||
<h3><FormattedMessage id='interaction_modal.on_this_server' defaultMessage='On this server' /></h3>
|
<h3><FormattedMessage id='interaction_modal.on_this_server' defaultMessage='On this server' /></h3>
|
||||||
<a href='/auth/sign_in' className='button button--block'><FormattedMessage id='sign_in_banner.sign_in' defaultMessage='Sign in' /></a>
|
<a href='/auth/sign_in' className='button button--block'><FormattedMessage id='sign_in_banner.sign_in' defaultMessage='Login' /></a>
|
||||||
{signupButton}
|
{signupButton}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,7 @@ import { fetchSuggestions } from 'mastodon/actions/suggestions';
|
||||||
import { markAsPartial } from 'mastodon/actions/timelines';
|
import { markAsPartial } from 'mastodon/actions/timelines';
|
||||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||||
import Account from 'mastodon/containers/account_container';
|
import Account from 'mastodon/containers/account_container';
|
||||||
import EmptyAccount from 'mastodon/components/account';
|
import { EmptyAccount } from 'mastodon/components/empty_account';
|
||||||
import { FormattedMessage, FormattedHTMLMessage } from 'react-intl';
|
import { FormattedMessage, FormattedHTMLMessage } from 'react-intl';
|
||||||
import { makeGetAccount } from 'mastodon/selectors';
|
import { makeGetAccount } from 'mastodon/selectors';
|
||||||
import { me } from 'mastodon/initial_state';
|
import { me } from 'mastodon/initial_state';
|
||||||
|
@ -31,6 +31,7 @@ class Follows extends React.PureComponent {
|
||||||
suggestions: ImmutablePropTypes.list,
|
suggestions: ImmutablePropTypes.list,
|
||||||
account: ImmutablePropTypes.map,
|
account: ImmutablePropTypes.map,
|
||||||
isLoading: PropTypes.bool,
|
isLoading: PropTypes.bool,
|
||||||
|
multiColumn: PropTypes.bool,
|
||||||
};
|
};
|
||||||
|
|
||||||
componentDidMount () {
|
componentDidMount () {
|
||||||
|
@ -44,7 +45,7 @@ class Follows extends React.PureComponent {
|
||||||
}
|
}
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
const { onBack, isLoading, suggestions, account } = this.props;
|
const { onBack, isLoading, suggestions, account, multiColumn } = this.props;
|
||||||
|
|
||||||
let loadedContent;
|
let loadedContent;
|
||||||
|
|
||||||
|
@ -58,7 +59,7 @@ class Follows extends React.PureComponent {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Column>
|
<Column>
|
||||||
<ColumnBackButton onClick={onBack} />
|
<ColumnBackButton multiColumn={multiColumn} onClick={onBack} />
|
||||||
|
|
||||||
<div className='scrollable privacy-policy'>
|
<div className='scrollable privacy-policy'>
|
||||||
<div className='column-title'>
|
<div className='column-title'>
|
||||||
|
|
|
@ -40,6 +40,7 @@ class Onboarding extends ImmutablePureComponent {
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
dispatch: PropTypes.func.isRequired,
|
dispatch: PropTypes.func.isRequired,
|
||||||
account: ImmutablePropTypes.map,
|
account: ImmutablePropTypes.map,
|
||||||
|
multiColumn: PropTypes.bool,
|
||||||
};
|
};
|
||||||
|
|
||||||
state = {
|
state = {
|
||||||
|
@ -93,14 +94,14 @@ class Onboarding extends ImmutablePureComponent {
|
||||||
}
|
}
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
const { account } = this.props;
|
const { account, multiColumn } = this.props;
|
||||||
const { step, shareClicked } = this.state;
|
const { step, shareClicked } = this.state;
|
||||||
|
|
||||||
switch(step) {
|
switch(step) {
|
||||||
case 'follows':
|
case 'follows':
|
||||||
return <Follows onBack={this.handleBackClick} />;
|
return <Follows onBack={this.handleBackClick} multiColumn={multiColumn} />;
|
||||||
case 'share':
|
case 'share':
|
||||||
return <Share onBack={this.handleBackClick} />;
|
return <Share onBack={this.handleBackClick} multiColumn={multiColumn} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
|
@ -140,17 +140,18 @@ class Share extends React.PureComponent {
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
onBack: PropTypes.func,
|
onBack: PropTypes.func,
|
||||||
account: ImmutablePropTypes.map,
|
account: ImmutablePropTypes.map,
|
||||||
|
multiColumn: PropTypes.bool,
|
||||||
intl: PropTypes.object,
|
intl: PropTypes.object,
|
||||||
};
|
};
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
const { onBack, account, intl } = this.props;
|
const { onBack, account, multiColumn, intl } = this.props;
|
||||||
|
|
||||||
const url = (new URL(`/@${account.get('username')}`, document.baseURI)).href;
|
const url = (new URL(`/@${account.get('username')}`, document.baseURI)).href;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Column>
|
<Column>
|
||||||
<ColumnBackButton onClick={onBack} />
|
<ColumnBackButton multiColumn={multiColumn} onClick={onBack} />
|
||||||
|
|
||||||
<div className='scrollable privacy-policy'>
|
<div className='scrollable privacy-policy'>
|
||||||
<div className='column-title'>
|
<div className='column-title'>
|
||||||
|
|
|
@ -138,12 +138,12 @@ const mapDispatchToProps = (dispatch, { intl }) => ({
|
||||||
dispatch(mentionCompose(account, router));
|
dispatch(mentionCompose(account, router));
|
||||||
},
|
},
|
||||||
|
|
||||||
onOpenMedia (media, index) {
|
onOpenMedia (media, index, lang) {
|
||||||
dispatch(openModal('MEDIA', { media, index }));
|
dispatch(openModal('MEDIA', { media, index, lang }));
|
||||||
},
|
},
|
||||||
|
|
||||||
onOpenVideo (media, options) {
|
onOpenVideo (media, lang, options) {
|
||||||
dispatch(openModal('VIDEO', { media, options }));
|
dispatch(openModal('VIDEO', { media, lang, options }));
|
||||||
},
|
},
|
||||||
|
|
||||||
onBlock (status) {
|
onBlock (status) {
|
||||||
|
|
|
@ -367,12 +367,12 @@ class Status extends ImmutablePureComponent {
|
||||||
this.props.dispatch(mentionCompose(account, router));
|
this.props.dispatch(mentionCompose(account, router));
|
||||||
};
|
};
|
||||||
|
|
||||||
handleOpenMedia = (media, index) => {
|
handleOpenMedia = (media, index, lang) => {
|
||||||
this.props.dispatch(openModal('MEDIA', { statusId: this.props.status.get('id'), media, index }));
|
this.props.dispatch(openModal('MEDIA', { statusId: this.props.status.get('id'), media, index, lang }));
|
||||||
};
|
};
|
||||||
|
|
||||||
handleOpenVideo = (media, options) => {
|
handleOpenVideo = (media, lang, options) => {
|
||||||
this.props.dispatch(openModal('VIDEO', { statusId: this.props.status.get('id'), media, options }));
|
this.props.dispatch(openModal('VIDEO', { statusId: this.props.status.get('id'), media, lang, options }));
|
||||||
};
|
};
|
||||||
|
|
||||||
handleHotkeyOpenMedia = e => {
|
handleHotkeyOpenMedia = e => {
|
||||||
|
|
|
@ -19,7 +19,7 @@ import {
|
||||||
BookmarkedStatuses,
|
BookmarkedStatuses,
|
||||||
ListTimeline,
|
ListTimeline,
|
||||||
Directory,
|
Directory,
|
||||||
} from '../../ui/util/async-components';
|
} from '../util/async-components';
|
||||||
import ComposePanel from './compose_panel';
|
import ComposePanel from './compose_panel';
|
||||||
import NavigationPanel from './navigation_panel';
|
import NavigationPanel from './navigation_panel';
|
||||||
import { supportsPassiveEvents } from 'detect-passive-events';
|
import { supportsPassiveEvents } from 'detect-passive-events';
|
||||||
|
|
|
@ -5,11 +5,10 @@ import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import { changeUploadCompose, uploadThumbnail, onChangeMediaDescription, onChangeMediaFocus } from '../../../actions/compose';
|
import { changeUploadCompose, uploadThumbnail, onChangeMediaDescription, onChangeMediaFocus } from '../../../actions/compose';
|
||||||
import { getPointerPosition } from '../../video';
|
import Video, { getPointerPosition } from '../../video';
|
||||||
import { FormattedMessage, defineMessages, injectIntl } from 'react-intl';
|
import { FormattedMessage, defineMessages, injectIntl } from 'react-intl';
|
||||||
import { IconButton } from 'mastodon/components/icon_button';
|
import { IconButton } from 'mastodon/components/icon_button';
|
||||||
import Button from 'mastodon/components/button';
|
import Button from 'mastodon/components/button';
|
||||||
import Video from 'mastodon/features/video';
|
|
||||||
import Audio from 'mastodon/features/audio';
|
import Audio from 'mastodon/features/audio';
|
||||||
import Textarea from 'react-textarea-autosize';
|
import Textarea from 'react-textarea-autosize';
|
||||||
import UploadProgress from 'mastodon/features/compose/components/upload_progress';
|
import UploadProgress from 'mastodon/features/compose/components/upload_progress';
|
||||||
|
|
|
@ -51,13 +51,13 @@ class Header extends React.PureComponent {
|
||||||
|
|
||||||
if (registrationsOpen) {
|
if (registrationsOpen) {
|
||||||
signupButton = (
|
signupButton = (
|
||||||
<a href='/auth/sign_up' className='button button-tertiary'>
|
<a href='/auth/sign_up' className='button'>
|
||||||
<FormattedMessage id='sign_in_banner.create_account' defaultMessage='Create account' />
|
<FormattedMessage id='sign_in_banner.create_account' defaultMessage='Create account' />
|
||||||
</a>
|
</a>
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
signupButton = (
|
signupButton = (
|
||||||
<button className='button button-tertiary' onClick={openClosedRegistrationsModal}>
|
<button className='button' onClick={openClosedRegistrationsModal}>
|
||||||
<FormattedMessage id='sign_in_banner.create_account' defaultMessage='Create account' />
|
<FormattedMessage id='sign_in_banner.create_account' defaultMessage='Create account' />
|
||||||
</button>
|
</button>
|
||||||
);
|
);
|
||||||
|
@ -65,8 +65,8 @@ class Header extends React.PureComponent {
|
||||||
|
|
||||||
content = (
|
content = (
|
||||||
<>
|
<>
|
||||||
<a href='/auth/sign_in' className='button'><FormattedMessage id='sign_in_banner.sign_in' defaultMessage='Sign in' /></a>
|
|
||||||
{signupButton}
|
{signupButton}
|
||||||
|
<a href='/auth/sign_in' className='button button-tertiary'><FormattedMessage id='sign_in_banner.sign_in' defaultMessage='Login' /></a>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,6 @@ import ReactSwipeableViews from 'react-swipeable-views';
|
||||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import Video from 'mastodon/features/video';
|
import Video from 'mastodon/features/video';
|
||||||
import { connect } from 'react-redux';
|
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import { defineMessages, injectIntl } from 'react-intl';
|
import { defineMessages, injectIntl } from 'react-intl';
|
||||||
import { IconButton } from 'mastodon/components/icon_button';
|
import { IconButton } from 'mastodon/components/icon_button';
|
||||||
|
@ -21,15 +20,12 @@ const messages = defineMessages({
|
||||||
next: { id: 'lightbox.next', defaultMessage: 'Next' },
|
next: { id: 'lightbox.next', defaultMessage: 'Next' },
|
||||||
});
|
});
|
||||||
|
|
||||||
const mapStateToProps = (state, { statusId }) => ({
|
|
||||||
language: state.getIn(['statuses', statusId, 'language']),
|
|
||||||
});
|
|
||||||
|
|
||||||
class MediaModal extends ImmutablePureComponent {
|
class MediaModal extends ImmutablePureComponent {
|
||||||
|
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
media: ImmutablePropTypes.list.isRequired,
|
media: ImmutablePropTypes.list.isRequired,
|
||||||
statusId: PropTypes.string,
|
statusId: PropTypes.string,
|
||||||
|
lang: PropTypes.string,
|
||||||
index: PropTypes.number.isRequired,
|
index: PropTypes.number.isRequired,
|
||||||
onClose: PropTypes.func.isRequired,
|
onClose: PropTypes.func.isRequired,
|
||||||
intl: PropTypes.object.isRequired,
|
intl: PropTypes.object.isRequired,
|
||||||
|
@ -133,7 +129,7 @@ class MediaModal extends ImmutablePureComponent {
|
||||||
};
|
};
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
const { media, language, statusId, intl, onClose } = this.props;
|
const { media, statusId, lang, intl, onClose } = this.props;
|
||||||
const { navigationHidden } = this.state;
|
const { navigationHidden } = this.state;
|
||||||
|
|
||||||
const index = this.getIndex();
|
const index = this.getIndex();
|
||||||
|
@ -153,7 +149,7 @@ class MediaModal extends ImmutablePureComponent {
|
||||||
width={width}
|
width={width}
|
||||||
height={height}
|
height={height}
|
||||||
alt={image.get('description')}
|
alt={image.get('description')}
|
||||||
lang={language}
|
lang={lang}
|
||||||
key={image.get('url')}
|
key={image.get('url')}
|
||||||
onClick={this.toggleNavigation}
|
onClick={this.toggleNavigation}
|
||||||
zoomButtonHidden={this.state.zoomButtonHidden}
|
zoomButtonHidden={this.state.zoomButtonHidden}
|
||||||
|
@ -176,7 +172,7 @@ class MediaModal extends ImmutablePureComponent {
|
||||||
onCloseVideo={onClose}
|
onCloseVideo={onClose}
|
||||||
detailed
|
detailed
|
||||||
alt={image.get('description')}
|
alt={image.get('description')}
|
||||||
lang={language}
|
lang={lang}
|
||||||
key={image.get('url')}
|
key={image.get('url')}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
@ -188,7 +184,7 @@ class MediaModal extends ImmutablePureComponent {
|
||||||
height={height}
|
height={height}
|
||||||
key={image.get('url')}
|
key={image.get('url')}
|
||||||
alt={image.get('description')}
|
alt={image.get('description')}
|
||||||
lang={language}
|
lang={lang}
|
||||||
onClick={this.toggleNavigation}
|
onClick={this.toggleNavigation}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
@ -256,4 +252,4 @@ class MediaModal extends ImmutablePureComponent {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default connect(mapStateToProps, null, null, { forwardRef: true })(injectIntl(MediaModal));
|
export default injectIntl(MediaModal);
|
||||||
|
|
|
@ -16,13 +16,13 @@ const SignInBanner = () => {
|
||||||
|
|
||||||
if (registrationsOpen) {
|
if (registrationsOpen) {
|
||||||
signupButton = (
|
signupButton = (
|
||||||
<a href='/auth/sign_up' className='button button--block button-tertiary'>
|
<a href='/auth/sign_up' className='button button--block'>
|
||||||
<FormattedMessage id='sign_in_banner.create_account' defaultMessage='Create account' />
|
<FormattedMessage id='sign_in_banner.create_account' defaultMessage='Create account' />
|
||||||
</a>
|
</a>
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
signupButton = (
|
signupButton = (
|
||||||
<button className='button button--block button-tertiary' onClick={openClosedRegistrationsModal}>
|
<button className='button button--block' onClick={openClosedRegistrationsModal}>
|
||||||
<FormattedMessage id='sign_in_banner.create_account' defaultMessage='Create account' />
|
<FormattedMessage id='sign_in_banner.create_account' defaultMessage='Create account' />
|
||||||
</button>
|
</button>
|
||||||
);
|
);
|
||||||
|
@ -30,9 +30,9 @@ const SignInBanner = () => {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='sign-in-banner'>
|
<div className='sign-in-banner'>
|
||||||
<p><FormattedMessage id='sign_in_banner.text' defaultMessage='Sign in to follow profiles or hashtags, favourite, share and reply to posts. You can also interact from your account on a different server.' /></p>
|
<p><FormattedMessage id='sign_in_banner.text' defaultMessage='Login to follow profiles or hashtags, favourite, share and reply to posts. You can also interact from your account on a different server.' /></p>
|
||||||
<a href='/auth/sign_in' className='button button--block'><FormattedMessage id='sign_in_banner.sign_in' defaultMessage='Sign in' /></a>
|
|
||||||
{signupButton}
|
{signupButton}
|
||||||
|
<a href='/auth/sign_in' className='button button--block button-tertiary'><FormattedMessage id='sign_in_banner.sign_in' defaultMessage='Login' /></a>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import Motion from '../../ui/util/optional_motion';
|
import Motion from '../util/optional_motion';
|
||||||
import spring from 'react-motion/lib/spring';
|
import spring from 'react-motion/lib/spring';
|
||||||
import { FormattedMessage } from 'react-intl';
|
import { FormattedMessage } from 'react-intl';
|
||||||
|
|
||||||
|
|
|
@ -469,7 +469,7 @@ class Video extends React.PureComponent {
|
||||||
handleOpenVideo = () => {
|
handleOpenVideo = () => {
|
||||||
this.video.pause();
|
this.video.pause();
|
||||||
|
|
||||||
this.props.onOpenVideo({
|
this.props.onOpenVideo(this.props.lang, {
|
||||||
startTime: this.video.currentTime,
|
startTime: this.video.currentTime,
|
||||||
autoPlay: !this.state.paused,
|
autoPlay: !this.state.paused,
|
||||||
defaultVolume: this.state.volume,
|
defaultVolume: this.state.volume,
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import { supportsPassiveEvents } from 'detect-passive-events';
|
import { supportsPassiveEvents } from 'detect-passive-events';
|
||||||
|
|
||||||
import { forceSingleColumn } from './initial_state';
|
import { forceSingleColumn } from './initial_state';
|
||||||
|
|
||||||
const LAYOUT_BREAKPOINT = 630;
|
const LAYOUT_BREAKPOINT = 630;
|
||||||
|
|
|
@ -356,7 +356,7 @@
|
||||||
{
|
{
|
||||||
"descriptors": [
|
"descriptors": [
|
||||||
{
|
{
|
||||||
"defaultMessage": "You need to sign in to access this resource.",
|
"defaultMessage": "You need to login to access this resource.",
|
||||||
"id": "not_signed_in_indicator.not_signed_in"
|
"id": "not_signed_in_indicator.not_signed_in"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
@ -2623,7 +2623,7 @@
|
||||||
"id": "interaction_modal.on_this_server"
|
"id": "interaction_modal.on_this_server"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"defaultMessage": "Sign in",
|
"defaultMessage": "Login",
|
||||||
"id": "sign_in_banner.sign_in"
|
"id": "sign_in_banner.sign_in"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -4175,7 +4175,7 @@
|
||||||
"id": "sign_in_banner.create_account"
|
"id": "sign_in_banner.create_account"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"defaultMessage": "Sign in",
|
"defaultMessage": "Login",
|
||||||
"id": "sign_in_banner.sign_in"
|
"id": "sign_in_banner.sign_in"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
@ -4374,11 +4374,11 @@
|
||||||
"id": "sign_in_banner.create_account"
|
"id": "sign_in_banner.create_account"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"defaultMessage": "Sign in to follow profiles or hashtags, favourite, share and reply to posts. You can also interact from your account on a different server.",
|
"defaultMessage": "Login to follow profiles or hashtags, favourite, share and reply to posts. You can also interact from your account on a different server.",
|
||||||
"id": "sign_in_banner.text"
|
"id": "sign_in_banner.text"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"defaultMessage": "Sign in",
|
"defaultMessage": "Login",
|
||||||
"id": "sign_in_banner.sign_in"
|
"id": "sign_in_banner.sign_in"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
|
|
@ -394,7 +394,7 @@
|
||||||
"navigation_bar.public_timeline": "Federated timeline",
|
"navigation_bar.public_timeline": "Federated timeline",
|
||||||
"navigation_bar.search": "Search",
|
"navigation_bar.search": "Search",
|
||||||
"navigation_bar.security": "Security",
|
"navigation_bar.security": "Security",
|
||||||
"not_signed_in_indicator.not_signed_in": "You need to sign in to access this resource.",
|
"not_signed_in_indicator.not_signed_in": "You need to login to access this resource.",
|
||||||
"notification.admin.report": "{name} reported {target}",
|
"notification.admin.report": "{name} reported {target}",
|
||||||
"notification.admin.sign_up": "{name} signed up",
|
"notification.admin.sign_up": "{name} signed up",
|
||||||
"notification.emoji_reaction": "{name} reacted your post with emoji",
|
"notification.emoji_reaction": "{name} reacted your post with emoji",
|
||||||
|
@ -588,8 +588,8 @@
|
||||||
"server_banner.learn_more": "Learn more",
|
"server_banner.learn_more": "Learn more",
|
||||||
"server_banner.server_stats": "Server stats:",
|
"server_banner.server_stats": "Server stats:",
|
||||||
"sign_in_banner.create_account": "Create account",
|
"sign_in_banner.create_account": "Create account",
|
||||||
"sign_in_banner.sign_in": "Sign in",
|
"sign_in_banner.sign_in": "Login",
|
||||||
"sign_in_banner.text": "Sign in to follow profiles or hashtags, favourite, share and reply to posts. You can also interact from your account on a different server.",
|
"sign_in_banner.text": "Login to follow profiles or hashtags, favourite, share and reply to posts. You can also interact from your account on a different server.",
|
||||||
"status.admin_account": "Open moderation interface for @{name}",
|
"status.admin_account": "Open moderation interface for @{name}",
|
||||||
"status.admin_domain": "Open moderation interface for {domain}",
|
"status.admin_domain": "Open moderation interface for {domain}",
|
||||||
"status.admin_status": "Open this post in the moderation interface",
|
"status.admin_status": "Open this post in the moderation interface",
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
/*eslint no-nested-ternary: "off"*/
|
/*eslint no-nested-ternary: "off"*/
|
||||||
/*eslint quotes: "off"*/
|
/*eslint quotes: "off"*/
|
||||||
|
|
||||||
export default [{
|
const rules = [{
|
||||||
locale: "co",
|
locale: "co",
|
||||||
pluralRuleFunction: function (e, a) {
|
pluralRuleFunction: function (e, a) {
|
||||||
return a ? 1 == e ? "one" : "other" : e >= 0 && e < 2 ? "one" : "other";
|
return a ? 1 == e ? "one" : "other" : e >= 0 && e < 2 ? "one" : "other";
|
||||||
|
@ -106,3 +106,5 @@ export default [{
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}];
|
}];
|
||||||
|
|
||||||
|
export default rules;
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
/*eslint no-nested-ternary: "off"*/
|
/*eslint no-nested-ternary: "off"*/
|
||||||
/*eslint quotes: "off"*/
|
/*eslint quotes: "off"*/
|
||||||
|
|
||||||
export default [{
|
const rules = [{
|
||||||
locale: "oc",
|
locale: "oc",
|
||||||
pluralRuleFunction: function (e, a) {
|
pluralRuleFunction: function (e, a) {
|
||||||
return a ? 1 == e ? "one" : "other" : e >= 0 && e < 2 ? "one" : "other";
|
return a ? 1 == e ? "one" : "other" : e >= 0 && e < 2 ? "one" : "other";
|
||||||
|
@ -106,3 +106,5 @@ export default [{
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}];
|
}];
|
||||||
|
|
||||||
|
export default rules;
|
||||||
|
|
|
@ -2,9 +2,8 @@
|
||||||
/*eslint no-nested-ternary: "off"*/
|
/*eslint no-nested-ternary: "off"*/
|
||||||
/*eslint quotes: "off"*/
|
/*eslint quotes: "off"*/
|
||||||
/*eslint comma-dangle: "off"*/
|
/*eslint comma-dangle: "off"*/
|
||||||
/*eslint semi: "off"*/
|
|
||||||
|
|
||||||
export default [
|
const rules = [
|
||||||
{
|
{
|
||||||
locale: "sa",
|
locale: "sa",
|
||||||
fields: {
|
fields: {
|
||||||
|
@ -94,4 +93,6 @@ export default [
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
];
|
||||||
|
|
||||||
|
export default rules;
|
||||||
|
|
|
@ -10,8 +10,13 @@ if (!HTMLCanvasElement.prototype.toBlob) {
|
||||||
const BASE64_MARKER = ';base64,';
|
const BASE64_MARKER = ';base64,';
|
||||||
|
|
||||||
Object.defineProperty(HTMLCanvasElement.prototype, 'toBlob', {
|
Object.defineProperty(HTMLCanvasElement.prototype, 'toBlob', {
|
||||||
value(callback: BlobCallback, type = 'image/png', quality: any) {
|
value: function (
|
||||||
const dataURL = this.toDataURL(type, quality);
|
this: HTMLCanvasElement,
|
||||||
|
callback: BlobCallback,
|
||||||
|
type = 'image/png',
|
||||||
|
quality: unknown
|
||||||
|
) {
|
||||||
|
const dataURL: string = this.toDataURL(type, quality);
|
||||||
let data;
|
let data;
|
||||||
|
|
||||||
if (dataURL.indexOf(BASE64_MARKER) >= 0) {
|
if (dataURL.indexOf(BASE64_MARKER) >= 0) {
|
||||||
|
|
|
@ -1,49 +1,50 @@
|
||||||
import { combineReducers } from 'redux-immutable';
|
|
||||||
import dropdown_menu from './dropdown_menu';
|
|
||||||
import timelines from './timelines';
|
|
||||||
import meta from './meta';
|
|
||||||
import alerts from './alerts';
|
|
||||||
import { loadingBarReducer } from 'react-redux-loading-bar';
|
import { loadingBarReducer } from 'react-redux-loading-bar';
|
||||||
import modal from './modal';
|
import { combineReducers } from 'redux-immutable';
|
||||||
import user_lists from './user_lists';
|
|
||||||
import domain_lists from './domain_lists';
|
|
||||||
import accounts from './accounts';
|
import accounts from './accounts';
|
||||||
import accounts_counters from './accounts_counters';
|
import accounts_counters from './accounts_counters';
|
||||||
import statuses from './statuses';
|
import accounts_map from './accounts_map';
|
||||||
import relationships from './relationships';
|
import alerts from './alerts';
|
||||||
import settings from './settings';
|
import announcements from './announcements';
|
||||||
import push_notifications from './push_notifications';
|
import antennaAdder from './antenna_adder';
|
||||||
import status_lists from './status_lists';
|
import antennaEditor from './antenna_editor';
|
||||||
import mutes from './mutes';
|
import antennas from './antennas';
|
||||||
import blocks from './blocks';
|
import blocks from './blocks';
|
||||||
import boosts from './boosts';
|
import boosts from './boosts';
|
||||||
import server from './server';
|
|
||||||
import contexts from './contexts';
|
|
||||||
import compose from './compose';
|
import compose from './compose';
|
||||||
import search from './search';
|
import contexts from './contexts';
|
||||||
import media_attachments from './media_attachments';
|
|
||||||
import notifications from './notifications';
|
|
||||||
import height_cache from './height_cache';
|
|
||||||
import custom_emojis from './custom_emojis';
|
|
||||||
import lists from './lists';
|
|
||||||
import listEditor from './list_editor';
|
|
||||||
import listAdder from './list_adder';
|
|
||||||
import antennas from './antennas';
|
|
||||||
import antennaEditor from './antenna_editor';
|
|
||||||
import antennaAdder from './antenna_adder';
|
|
||||||
import filters from './filters';
|
|
||||||
import conversations from './conversations';
|
import conversations from './conversations';
|
||||||
import suggestions from './suggestions';
|
import custom_emojis from './custom_emojis';
|
||||||
import polls from './polls';
|
import domain_lists from './domain_lists';
|
||||||
import trends from './trends';
|
import dropdown_menu from './dropdown_menu';
|
||||||
import { missedUpdatesReducer } from './missed_updates';
|
import filters from './filters';
|
||||||
import announcements from './announcements';
|
|
||||||
import markers from './markers';
|
|
||||||
import picture_in_picture from './picture_in_picture';
|
|
||||||
import accounts_map from './accounts_map';
|
|
||||||
import history from './history';
|
|
||||||
import tags from './tags';
|
|
||||||
import followed_tags from './followed_tags';
|
import followed_tags from './followed_tags';
|
||||||
|
import height_cache from './height_cache';
|
||||||
|
import history from './history';
|
||||||
|
import listAdder from './list_adder';
|
||||||
|
import listEditor from './list_editor';
|
||||||
|
import lists from './lists';
|
||||||
|
import markers from './markers';
|
||||||
|
import media_attachments from './media_attachments';
|
||||||
|
import meta from './meta';
|
||||||
|
import { missedUpdatesReducer } from './missed_updates';
|
||||||
|
import modal from './modal';
|
||||||
|
import mutes from './mutes';
|
||||||
|
import notifications from './notifications';
|
||||||
|
import picture_in_picture from './picture_in_picture';
|
||||||
|
import polls from './polls';
|
||||||
|
import push_notifications from './push_notifications';
|
||||||
|
import relationships from './relationships';
|
||||||
|
import search from './search';
|
||||||
|
import server from './server';
|
||||||
|
import settings from './settings';
|
||||||
|
import status_lists from './status_lists';
|
||||||
|
import statuses from './statuses';
|
||||||
|
import suggestions from './suggestions';
|
||||||
|
import tags from './tags';
|
||||||
|
import timelines from './timelines';
|
||||||
|
import trends from './trends';
|
||||||
|
import user_lists from './user_lists';
|
||||||
|
|
||||||
const reducers = {
|
const reducers = {
|
||||||
announcements,
|
announcements,
|
||||||
|
|
|
@ -2,13 +2,13 @@ import {
|
||||||
MARKERS_SUBMIT_SUCCESS,
|
MARKERS_SUBMIT_SUCCESS,
|
||||||
} from '../actions/markers';
|
} from '../actions/markers';
|
||||||
|
|
||||||
|
import { Map as ImmutableMap } from 'immutable';
|
||||||
|
|
||||||
const initialState = ImmutableMap({
|
const initialState = ImmutableMap({
|
||||||
home: '0',
|
home: '0',
|
||||||
notifications: '0',
|
notifications: '0',
|
||||||
});
|
});
|
||||||
|
|
||||||
import { Map as ImmutableMap } from 'immutable';
|
|
||||||
|
|
||||||
export default function markers(state = initialState, action) {
|
export default function markers(state = initialState, action) {
|
||||||
switch(action.type) {
|
switch(action.type) {
|
||||||
case MARKERS_SUBMIT_SUCCESS:
|
case MARKERS_SUBMIT_SUCCESS:
|
||||||
|
|
|
@ -1,12 +1,14 @@
|
||||||
import { Record } from 'immutable';
|
import { Record } from 'immutable';
|
||||||
import type { Action } from 'redux';
|
|
||||||
import { NOTIFICATIONS_UPDATE } from '../actions/notifications';
|
|
||||||
import { focusApp, unfocusApp } from '../actions/app';
|
|
||||||
|
|
||||||
type MissedUpdatesState = {
|
import type { Action } from 'redux';
|
||||||
|
|
||||||
|
import { focusApp, unfocusApp } from '../actions/app';
|
||||||
|
import { NOTIFICATIONS_UPDATE } from '../actions/notifications';
|
||||||
|
|
||||||
|
interface MissedUpdatesState {
|
||||||
focused: boolean;
|
focused: boolean;
|
||||||
unread: number;
|
unread: number;
|
||||||
};
|
}
|
||||||
const initialState = Record<MissedUpdatesState>({
|
const initialState = Record<MissedUpdatesState>({
|
||||||
focused: true,
|
focused: true,
|
||||||
unread: 0,
|
unread: 0,
|
||||||
|
|
|
@ -1,9 +1,13 @@
|
||||||
|
import type { TypedUseSelectorHook } from 'react-redux';
|
||||||
|
import { useDispatch, useSelector } from 'react-redux';
|
||||||
|
|
||||||
import { configureStore } from '@reduxjs/toolkit';
|
import { configureStore } from '@reduxjs/toolkit';
|
||||||
|
|
||||||
import { rootReducer } from '../reducers';
|
import { rootReducer } from '../reducers';
|
||||||
import { loadingBarMiddleware } from './middlewares/loading_bar';
|
|
||||||
import { errorsMiddleware } from './middlewares/errors';
|
import { errorsMiddleware } from './middlewares/errors';
|
||||||
|
import { loadingBarMiddleware } from './middlewares/loading_bar';
|
||||||
import { soundsMiddleware } from './middlewares/sounds';
|
import { soundsMiddleware } from './middlewares/sounds';
|
||||||
import { TypedUseSelectorHook, useDispatch, useSelector } from 'react-redux';
|
|
||||||
|
|
||||||
export const store = configureStore({
|
export const store = configureStore({
|
||||||
reducer: rootReducer,
|
reducer: rootReducer,
|
||||||
|
|
|
@ -1,17 +1,18 @@
|
||||||
import { Middleware } from 'redux';
|
import type { AnyAction, Middleware } from 'redux';
|
||||||
|
|
||||||
|
import type { RootState } from '..';
|
||||||
import { showAlertForError } from '../../actions/alerts';
|
import { showAlertForError } from '../../actions/alerts';
|
||||||
import { RootState } from '..';
|
|
||||||
|
|
||||||
const defaultFailSuffix = 'FAIL';
|
const defaultFailSuffix = 'FAIL';
|
||||||
|
|
||||||
export const errorsMiddleware: Middleware<Record<string, never>, RootState> =
|
export const errorsMiddleware: Middleware<Record<string, never>, RootState> =
|
||||||
({ dispatch }) =>
|
({ dispatch }) =>
|
||||||
(next) =>
|
(next) =>
|
||||||
(action) => {
|
(action: AnyAction & { skipAlert?: boolean; skipNotFound?: boolean }) => {
|
||||||
if (action.type && !action.skipAlert) {
|
if (action.type && !action.skipAlert) {
|
||||||
const isFail = new RegExp(`${defaultFailSuffix}$`, 'g');
|
const isFail = new RegExp(`${defaultFailSuffix}$`, 'g');
|
||||||
|
|
||||||
if (action.type.match(isFail)) {
|
if (typeof action.type === 'string' && action.type.match(isFail)) {
|
||||||
dispatch(showAlertForError(action.error, action.skipNotFound));
|
dispatch(showAlertForError(action.error, action.skipNotFound));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import { showLoading, hideLoading } from 'react-redux-loading-bar';
|
import { showLoading, hideLoading } from 'react-redux-loading-bar';
|
||||||
import { Middleware } from 'redux';
|
import type { AnyAction, Middleware } from 'redux';
|
||||||
import { RootState } from '..';
|
|
||||||
|
import type { RootState } from '..';
|
||||||
|
|
||||||
interface Config {
|
interface Config {
|
||||||
promiseTypeSuffixes?: string[];
|
promiseTypeSuffixes?: string[];
|
||||||
|
@ -19,7 +20,7 @@ export const loadingBarMiddleware = (
|
||||||
|
|
||||||
return ({ dispatch }) =>
|
return ({ dispatch }) =>
|
||||||
(next) =>
|
(next) =>
|
||||||
(action) => {
|
(action: AnyAction) => {
|
||||||
if (action.type && !action.skipLoading) {
|
if (action.type && !action.skipLoading) {
|
||||||
const [PENDING, FULFILLED, REJECTED] = promiseTypeSuffixes;
|
const [PENDING, FULFILLED, REJECTED] = promiseTypeSuffixes;
|
||||||
|
|
||||||
|
@ -27,6 +28,7 @@ export const loadingBarMiddleware = (
|
||||||
const isFulfilled = new RegExp(`${FULFILLED}$`, 'g');
|
const isFulfilled = new RegExp(`${FULFILLED}$`, 'g');
|
||||||
const isRejected = new RegExp(`${REJECTED}$`, 'g');
|
const isRejected = new RegExp(`${REJECTED}$`, 'g');
|
||||||
|
|
||||||
|
if (typeof action.type === 'string') {
|
||||||
if (action.type.match(isPending)) {
|
if (action.type.match(isPending)) {
|
||||||
dispatch(showLoading());
|
dispatch(showLoading());
|
||||||
} else if (
|
} else if (
|
||||||
|
@ -36,6 +38,7 @@ export const loadingBarMiddleware = (
|
||||||
dispatch(hideLoading());
|
dispatch(hideLoading());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return next(action);
|
return next(action);
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import { Middleware, AnyAction } from 'redux';
|
import type { Middleware, AnyAction } from 'redux';
|
||||||
import { RootState } from '..';
|
|
||||||
|
import type { RootState } from '..';
|
||||||
|
|
||||||
interface AudioSource {
|
interface AudioSource {
|
||||||
src: string;
|
src: string;
|
||||||
|
@ -27,7 +28,7 @@ const play = (audio: HTMLAudioElement) => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
audio.play();
|
void audio.play();
|
||||||
};
|
};
|
||||||
|
|
||||||
export const soundsMiddleware = (): Middleware<
|
export const soundsMiddleware = (): Middleware<
|
||||||
|
@ -47,7 +48,9 @@ export const soundsMiddleware = (): Middleware<
|
||||||
]),
|
]),
|
||||||
};
|
};
|
||||||
|
|
||||||
return () => (next) => (action: AnyAction) => {
|
return () =>
|
||||||
|
(next) =>
|
||||||
|
(action: AnyAction & { meta?: { sound?: string } }) => {
|
||||||
const sound = action?.meta?.sound;
|
const sound = action?.meta?.sound;
|
||||||
|
|
||||||
if (sound && soundCache[sound]) {
|
if (sound && soundCache[sound]) {
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
export function uuid(a?: string): string {
|
export function uuid(a?: string): string {
|
||||||
return a
|
return a
|
||||||
? (
|
? (
|
||||||
(a as any as number) ^
|
(a as unknown as number) ^
|
||||||
((Math.random() * 16) >> ((a as any as number) / 4))
|
((Math.random() * 16) >> ((a as unknown as number) / 4))
|
||||||
).toString(16)
|
).toString(16)
|
||||||
: ('' + 1e7 + -1e3 + -4e3 + -8e3 + -1e11).replace(/[018]/g, uuid);
|
: // eslint-disable-next-line @typescript-eslint/restrict-plus-operands
|
||||||
|
('' + 1e7 + -1e3 + -4e3 + -8e3 + -1e11).replace(/[018]/g, uuid);
|
||||||
}
|
}
|
||||||
|
|
|
@ -6526,13 +6526,6 @@ a.status-card.compact:hover {
|
||||||
&--wide {
|
&--wide {
|
||||||
grid-column: span 2;
|
grid-column: span 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.standalone {
|
|
||||||
.media-gallery__item-gifv-thumbnail {
|
|
||||||
transform: none;
|
|
||||||
top: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.media-gallery__item-thumbnail {
|
.media-gallery__item-thumbnail {
|
||||||
|
@ -6580,11 +6573,7 @@ a.status-card.compact:hover {
|
||||||
cursor: zoom-in;
|
cursor: zoom-in;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
object-fit: cover;
|
object-fit: cover;
|
||||||
position: relative;
|
|
||||||
top: 50%;
|
|
||||||
transform: translateY(-50%);
|
|
||||||
width: 100%;
|
width: 100%;
|
||||||
z-index: 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.media-gallery__item-thumbnail-label {
|
.media-gallery__item-thumbnail-label {
|
||||||
|
@ -6683,6 +6672,8 @@ a.status-card.compact:hover {
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
color: $white;
|
color: $white;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
&.editable {
|
&.editable {
|
||||||
border-radius: 0;
|
border-radius: 0;
|
||||||
|
@ -6717,9 +6708,6 @@ a.status-card.compact:hover {
|
||||||
&.inline {
|
&.inline {
|
||||||
video {
|
video {
|
||||||
object-fit: contain;
|
object-fit: contain;
|
||||||
position: relative;
|
|
||||||
top: 50%;
|
|
||||||
transform: translateY(-50%);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -12,7 +12,7 @@ type AccountField = Record<{
|
||||||
verified_at: string | null;
|
verified_at: string | null;
|
||||||
}>;
|
}>;
|
||||||
|
|
||||||
type AccountApiResponseValues = {
|
interface AccountApiResponseValues {
|
||||||
acct: string;
|
acct: string;
|
||||||
avatar: string;
|
avatar: string;
|
||||||
avatar_static: string;
|
avatar_static: string;
|
||||||
|
@ -34,7 +34,7 @@ type AccountApiResponseValues = {
|
||||||
statuses_count: number;
|
statuses_count: number;
|
||||||
url: string;
|
url: string;
|
||||||
username: string;
|
username: string;
|
||||||
};
|
}
|
||||||
|
|
||||||
type NormalizedAccountField = Record<{
|
type NormalizedAccountField = Record<{
|
||||||
name_emojified: string;
|
name_emojified: string;
|
||||||
|
@ -42,12 +42,12 @@ type NormalizedAccountField = Record<{
|
||||||
value_plain: string;
|
value_plain: string;
|
||||||
}>;
|
}>;
|
||||||
|
|
||||||
type NormalizedAccountValues = {
|
interface NormalizedAccountValues {
|
||||||
display_name_html: string;
|
display_name_html: string;
|
||||||
fields: NormalizedAccountField[];
|
fields: NormalizedAccountField[];
|
||||||
note_emojified: string;
|
note_emojified: string;
|
||||||
note_plain: string;
|
note_plain: string;
|
||||||
};
|
}
|
||||||
|
|
||||||
export type Account = Record<
|
export type Account = Record<
|
||||||
AccountApiResponseValues & NormalizedAccountValues
|
AccountApiResponseValues & NormalizedAccountValues
|
||||||
|
|
|
@ -9,10 +9,12 @@ class Vacuum::AccessTokensVacuum
|
||||||
private
|
private
|
||||||
|
|
||||||
def vacuum_revoked_access_tokens!
|
def vacuum_revoked_access_tokens!
|
||||||
Doorkeeper::AccessToken.where.not(revoked_at: nil).where('revoked_at < NOW()').delete_all
|
Doorkeeper::AccessToken.where.not(expires_in: nil).where('created_at + make_interval(secs => expires_in) < NOW()').in_batches.delete_all
|
||||||
|
Doorkeeper::AccessToken.where.not(revoked_at: nil).where('revoked_at < NOW()').in_batches.delete_all
|
||||||
end
|
end
|
||||||
|
|
||||||
def vacuum_revoked_access_grants!
|
def vacuum_revoked_access_grants!
|
||||||
Doorkeeper::AccessGrant.where.not(revoked_at: nil).where('revoked_at < NOW()').delete_all
|
Doorkeeper::AccessGrant.where.not(expires_in: nil).where('created_at + make_interval(secs => expires_in) < NOW()').in_batches.delete_all
|
||||||
|
Doorkeeper::AccessGrant.where.not(revoked_at: nil).where('revoked_at < NOW()').in_batches.delete_all
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
- if status.ordered_media_attachments.first.video?
|
- if status.ordered_media_attachments.first.video?
|
||||||
- video = status.ordered_media_attachments.first
|
- video = status.ordered_media_attachments.first
|
||||||
= react_component :video, src: video.file.url(:original), preview: video.file.url(:small), frameRate: video.file.meta.dig('original', 'frame_rate'), blurhash: video.blurhash, sensitive: status.sensitive?, visible: false, width: 610, height: 343, inline: true, alt: video.description, media: [ActiveModelSerializers::SerializableResource.new(video, serializer: REST::MediaAttachmentSerializer)].as_json
|
= react_component :video, src: video.file.url(:original), preview: video.file.url(:small), frameRate: video.file.meta.dig('original', 'frame_rate'), blurhash: video.blurhash, sensitive: status.sensitive?, visible: false, width: 610, height: 343, inline: true, alt: video.description, lang: status.language, media: [ActiveModelSerializers::SerializableResource.new(video, serializer: REST::MediaAttachmentSerializer)].as_json
|
||||||
- elsif status.ordered_media_attachments.first.audio?
|
- elsif status.ordered_media_attachments.first.audio?
|
||||||
- audio = status.ordered_media_attachments.first
|
- audio = status.ordered_media_attachments.first
|
||||||
= react_component :audio, src: audio.file.url(:original), height: 110, alt: audio.description, duration: audio.file.meta.dig(:original, :duration)
|
= react_component :audio, src: audio.file.url(:original), height: 110, alt: audio.description, lang: status.language, duration: audio.file.meta.dig(:original, :duration)
|
||||||
- else
|
- else
|
||||||
= react_component :media_gallery, height: 343, sensitive: status.sensitive?, visible: false, media: status.ordered_media_attachments.map { |a| ActiveModelSerializers::SerializableResource.new(a, serializer: REST::MediaAttachmentSerializer).as_json }
|
= react_component :media_gallery, height: 343, sensitive: status.sensitive?, visible: false, lang: status.language, media: status.ordered_media_attachments.map { |a| ActiveModelSerializers::SerializableResource.new(a, serializer: REST::MediaAttachmentSerializer).as_json }
|
||||||
|
|
|
@ -13,8 +13,8 @@ en:
|
||||||
locked: Your account is locked.
|
locked: Your account is locked.
|
||||||
not_found_in_database: Invalid %{authentication_keys} or password.
|
not_found_in_database: Invalid %{authentication_keys} or password.
|
||||||
pending: Your account is still under review.
|
pending: Your account is still under review.
|
||||||
timeout: Your session expired. Please sign in again to continue.
|
timeout: Your session expired. Please login again to continue.
|
||||||
unauthenticated: You need to sign in or sign up before continuing.
|
unauthenticated: You need to login or sign up before continuing.
|
||||||
unconfirmed: You have to confirm your email address before continuing.
|
unconfirmed: You have to confirm your email address before continuing.
|
||||||
mailer:
|
mailer:
|
||||||
confirmation_instructions:
|
confirmation_instructions:
|
||||||
|
@ -102,7 +102,7 @@ en:
|
||||||
unlocks:
|
unlocks:
|
||||||
send_instructions: You will receive an email with instructions for how to unlock your account in a few minutes. Please check your spam folder if you didn't receive this email.
|
send_instructions: You will receive an email with instructions for how to unlock your account in a few minutes. Please check your spam folder if you didn't receive this email.
|
||||||
send_paranoid_instructions: If your account exists, you will receive an email with instructions for how to unlock it in a few minutes. Please check your spam folder if you didn't receive this email.
|
send_paranoid_instructions: If your account exists, you will receive an email with instructions for how to unlock it in a few minutes. Please check your spam folder if you didn't receive this email.
|
||||||
unlocked: Your account has been unlocked successfully. Please sign in to continue.
|
unlocked: Your account has been unlocked successfully. Please login to continue.
|
||||||
errors:
|
errors:
|
||||||
messages:
|
messages:
|
||||||
already_confirmed: was already confirmed, please try signing in
|
already_confirmed: was already confirmed, please try signing in
|
||||||
|
|
|
@ -1115,8 +1115,8 @@ en:
|
||||||
new_confirmation_instructions_sent: You will receive a new e-mail with the confirmation link in a few minutes!
|
new_confirmation_instructions_sent: You will receive a new e-mail with the confirmation link in a few minutes!
|
||||||
title: Check your inbox
|
title: Check your inbox
|
||||||
sign_in:
|
sign_in:
|
||||||
preamble_html: Sign in with your <strong>%{domain}</strong> credentials. If your account is hosted on a different server, you will not be able to log in here.
|
preamble_html: Login with your <strong>%{domain}</strong> credentials. If your account is hosted on a different server, you will not be able to log in here.
|
||||||
title: Sign in to %{domain}
|
title: Login to %{domain}
|
||||||
sign_up:
|
sign_up:
|
||||||
manual_review: Sign-ups on %{domain} go through manual review by our moderators. To help us process your registration, write a bit about yourself and why you want an account on %{domain}.
|
manual_review: Sign-ups on %{domain} go through manual review by our moderators. To help us process your registration, write a bit about yourself and why you want an account on %{domain}.
|
||||||
preamble: With an account on this Mastodon server, you'll be able to follow any other person on the network, regardless of where their account is hosted.
|
preamble: With an account on this Mastodon server, you'll be able to follow any other person on the network, regardless of where their account is hosted.
|
||||||
|
@ -1698,7 +1698,7 @@ en:
|
||||||
show_newer: Show newer
|
show_newer: Show newer
|
||||||
show_older: Show older
|
show_older: Show older
|
||||||
show_thread: Show thread
|
show_thread: Show thread
|
||||||
sign_in_to_participate: Sign in to participate in the conversation
|
sign_in_to_participate: Login to participate in the conversation
|
||||||
title: '%{name}: "%{quote}"'
|
title: '%{name}: "%{quote}"'
|
||||||
visibilities:
|
visibilities:
|
||||||
direct: Direct
|
direct: Direct
|
||||||
|
|
|
@ -181,6 +181,7 @@
|
||||||
"babel-jest": "^29.5.0",
|
"babel-jest": "^29.5.0",
|
||||||
"eslint": "^8.39.0",
|
"eslint": "^8.39.0",
|
||||||
"eslint-config-prettier": "^8.8.0",
|
"eslint-config-prettier": "^8.8.0",
|
||||||
|
"eslint-import-resolver-typescript": "^3.5.5",
|
||||||
"eslint-plugin-formatjs": "^4.10.1",
|
"eslint-plugin-formatjs": "^4.10.1",
|
||||||
"eslint-plugin-import": "~2.27.5",
|
"eslint-plugin-import": "~2.27.5",
|
||||||
"eslint-plugin-jsdoc": "^43.1.1",
|
"eslint-plugin-jsdoc": "^43.1.1",
|
||||||
|
|
|
@ -14,9 +14,7 @@ RSpec.describe ActivityPub::FollowersSynchronizationsController do
|
||||||
follower_2.follow!(account)
|
follower_2.follow!(account)
|
||||||
follower_3.follow!(account)
|
follower_3.follow!(account)
|
||||||
follower_4.follow!(account)
|
follower_4.follow!(account)
|
||||||
end
|
|
||||||
|
|
||||||
before do
|
|
||||||
allow(controller).to receive(:signed_request_actor).and_return(remote_account)
|
allow(controller).to receive(:signed_request_actor).and_return(remote_account)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -27,9 +27,7 @@ RSpec.describe ActivityPub::OutboxesController do
|
||||||
Fabricate(:status, account: account, visibility: :private)
|
Fabricate(:status, account: account, visibility: :private)
|
||||||
Fabricate(:status, account: account, visibility: :direct)
|
Fabricate(:status, account: account, visibility: :direct)
|
||||||
Fabricate(:status, account: account, visibility: :limited)
|
Fabricate(:status, account: account, visibility: :limited)
|
||||||
end
|
|
||||||
|
|
||||||
before do
|
|
||||||
allow(controller).to receive(:signed_request_actor).and_return(remote_account)
|
allow(controller).to receive(:signed_request_actor).and_return(remote_account)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -5,16 +5,16 @@ require 'rails_helper'
|
||||||
RSpec.describe Admin::Disputes::AppealsController do
|
RSpec.describe Admin::Disputes::AppealsController do
|
||||||
render_views
|
render_views
|
||||||
|
|
||||||
before { sign_in current_user, scope: :user }
|
before do
|
||||||
|
sign_in current_user, scope: :user
|
||||||
|
|
||||||
|
target_account.suspend!
|
||||||
|
end
|
||||||
|
|
||||||
let(:target_account) { Fabricate(:account) }
|
let(:target_account) { Fabricate(:account) }
|
||||||
let(:strike) { Fabricate(:account_warning, target_account: target_account, action: :suspend) }
|
let(:strike) { Fabricate(:account_warning, target_account: target_account, action: :suspend) }
|
||||||
let(:appeal) { Fabricate(:appeal, strike: strike, account: target_account) }
|
let(:appeal) { Fabricate(:appeal, strike: strike, account: target_account) }
|
||||||
|
|
||||||
before do
|
|
||||||
target_account.suspend!
|
|
||||||
end
|
|
||||||
|
|
||||||
describe 'POST #approve' do
|
describe 'POST #approve' do
|
||||||
let(:current_user) { Fabricate(:user, role: UserRole.find_by(name: 'Admin')) }
|
let(:current_user) { Fabricate(:user, role: UserRole.find_by(name: 'Admin')) }
|
||||||
|
|
||||||
|
|
|
@ -101,6 +101,8 @@ RSpec.describe Auth::RegistrationsController do
|
||||||
|
|
||||||
before do
|
before do
|
||||||
session[:registration_form_time] = 5.seconds.ago
|
session[:registration_form_time] = 5.seconds.ago
|
||||||
|
|
||||||
|
request.env['devise.mapping'] = Devise.mappings[:user]
|
||||||
end
|
end
|
||||||
|
|
||||||
around do |example|
|
around do |example|
|
||||||
|
@ -109,8 +111,6 @@ RSpec.describe Auth::RegistrationsController do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
before { request.env['devise.mapping'] = Devise.mappings[:user] }
|
|
||||||
|
|
||||||
context do
|
context do
|
||||||
subject do
|
subject do
|
||||||
Setting.registrations_mode = 'open'
|
Setting.registrations_mode = 'open'
|
||||||
|
|
292
spec/lib/mastodon/ip_blocks_cli_spec.rb
Normal file
292
spec/lib/mastodon/ip_blocks_cli_spec.rb
Normal file
|
@ -0,0 +1,292 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require 'rails_helper'
|
||||||
|
require 'mastodon/ip_blocks_cli'
|
||||||
|
|
||||||
|
RSpec.describe Mastodon::IpBlocksCLI do
|
||||||
|
let(:cli) { described_class.new }
|
||||||
|
|
||||||
|
describe '#add' do
|
||||||
|
let(:ip_list) do
|
||||||
|
[
|
||||||
|
'192.0.2.1',
|
||||||
|
'172.16.0.1',
|
||||||
|
'192.0.2.0/24',
|
||||||
|
'172.16.0.0/16',
|
||||||
|
'10.0.0.0/8',
|
||||||
|
'2001:0db8:85a3:0000:0000:8a2e:0370:7334',
|
||||||
|
'fe80::1',
|
||||||
|
'::1',
|
||||||
|
'2001:0db8::/32',
|
||||||
|
'fe80::/10',
|
||||||
|
'::/128',
|
||||||
|
]
|
||||||
|
end
|
||||||
|
let(:options) { { severity: 'no_access' } }
|
||||||
|
|
||||||
|
shared_examples 'ip address blocking' do
|
||||||
|
it 'blocks all specified IP addresses' do
|
||||||
|
cli.invoke(:add, ip_list, options)
|
||||||
|
|
||||||
|
blocked_ip_addresses = IpBlock.where(ip: ip_list).pluck(:ip)
|
||||||
|
expected_ip_addresses = ip_list.map { |ip| IPAddr.new(ip) }
|
||||||
|
|
||||||
|
expect(blocked_ip_addresses).to match_array(expected_ip_addresses)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'sets the severity for all blocked IP addresses' do
|
||||||
|
cli.invoke(:add, ip_list, options)
|
||||||
|
|
||||||
|
blocked_ips_severity = IpBlock.where(ip: ip_list).pluck(:severity).all?(options[:severity])
|
||||||
|
|
||||||
|
expect(blocked_ips_severity).to be(true)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'displays a success message with a summary' do
|
||||||
|
expect { cli.invoke(:add, ip_list, options) }.to output(
|
||||||
|
a_string_including("Added #{ip_list.size}, skipped 0, failed 0")
|
||||||
|
).to_stdout
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'with valid IP addresses' do
|
||||||
|
include_examples 'ip address blocking'
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when a specified IP address is already blocked' do
|
||||||
|
let!(:blocked_ip) { IpBlock.create(ip: ip_list.last, severity: options[:severity]) }
|
||||||
|
|
||||||
|
it 'skips the already blocked IP address' do
|
||||||
|
allow(IpBlock).to receive(:new).and_call_original
|
||||||
|
|
||||||
|
cli.invoke(:add, ip_list, options)
|
||||||
|
|
||||||
|
expect(IpBlock).to_not have_received(:new).with(ip: ip_list.last)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'displays the correct summary' do
|
||||||
|
expect { cli.invoke(:add, ip_list, options) }.to output(
|
||||||
|
a_string_including("#{ip_list.last} is already blocked\nAdded #{ip_list.size - 1}, skipped 1, failed 0")
|
||||||
|
).to_stdout
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'with --force option' do
|
||||||
|
let!(:blocked_ip) { IpBlock.create(ip: ip_list.last, severity: 'no_access') }
|
||||||
|
let(:options) { { severity: 'sign_up_requires_approval', force: true } }
|
||||||
|
|
||||||
|
it 'overwrites the existing IP block record' do
|
||||||
|
expect { cli.invoke(:add, ip_list, options) }
|
||||||
|
.to change { blocked_ip.reload.severity }
|
||||||
|
.from('no_access')
|
||||||
|
.to('sign_up_requires_approval')
|
||||||
|
end
|
||||||
|
|
||||||
|
include_examples 'ip address blocking'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when a specified IP address is invalid' do
|
||||||
|
let(:ip_list) { ['320.15.175.0', '9.5.105.255', '0.0.0.0'] }
|
||||||
|
|
||||||
|
it 'displays the correct summary' do
|
||||||
|
expect { cli.invoke(:add, ip_list, options) }.to output(
|
||||||
|
a_string_including("#{ip_list.first} is invalid\nAdded #{ip_list.size - 1}, skipped 0, failed 1")
|
||||||
|
).to_stdout
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'with --comment option' do
|
||||||
|
let(:options) { { severity: 'no_access', comment: 'Spam' } }
|
||||||
|
|
||||||
|
include_examples 'ip address blocking'
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'with --duration option' do
|
||||||
|
let(:options) { { severity: 'no_access', duration: 10.days } }
|
||||||
|
|
||||||
|
include_examples 'ip address blocking'
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'with "sign_up_requires_approval" severity' do
|
||||||
|
let(:options) { { severity: 'sign_up_requires_approval' } }
|
||||||
|
|
||||||
|
include_examples 'ip address blocking'
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'with "sign_up_block" severity' do
|
||||||
|
let(:options) { { severity: 'sign_up_block' } }
|
||||||
|
|
||||||
|
include_examples 'ip address blocking'
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when a specified IP address fails to be blocked' do
|
||||||
|
let(:ip_address) { '127.0.0.1' }
|
||||||
|
let(:ip_block) { instance_double(IpBlock, ip: ip_address, save: false) }
|
||||||
|
|
||||||
|
before do
|
||||||
|
allow(IpBlock).to receive(:new).and_return(ip_block)
|
||||||
|
allow(ip_block).to receive(:severity=)
|
||||||
|
allow(ip_block).to receive(:expires_in=)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'displays an error message' do
|
||||||
|
expect { cli.invoke(:add, [ip_address], options) }
|
||||||
|
.to output(
|
||||||
|
a_string_including("#{ip_address} could not be saved")
|
||||||
|
).to_stdout
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when no IP address is provided' do
|
||||||
|
it 'exits with an error message' do
|
||||||
|
expect { cli.add }.to output(
|
||||||
|
a_string_including('No IP(s) given')
|
||||||
|
).to_stdout
|
||||||
|
.and raise_error(SystemExit)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe '#remove' do
|
||||||
|
context 'when removing exact matches' do
|
||||||
|
let(:ip_list) do
|
||||||
|
[
|
||||||
|
'192.0.2.1',
|
||||||
|
'172.16.0.1',
|
||||||
|
'192.0.2.0/24',
|
||||||
|
'172.16.0.0/16',
|
||||||
|
'10.0.0.0/8',
|
||||||
|
'2001:0db8:85a3:0000:0000:8a2e:0370:7334',
|
||||||
|
'fe80::1',
|
||||||
|
'::1',
|
||||||
|
'2001:0db8::/32',
|
||||||
|
'fe80::/10',
|
||||||
|
'::/128',
|
||||||
|
]
|
||||||
|
end
|
||||||
|
|
||||||
|
before do
|
||||||
|
ip_list.each { |ip| IpBlock.create(ip: ip, severity: :no_access) }
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'removes exact IP blocks' do
|
||||||
|
cli.invoke(:remove, ip_list)
|
||||||
|
|
||||||
|
expect(IpBlock.where(ip: ip_list)).to_not exist
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'displays success message with a summary' do
|
||||||
|
expect { cli.invoke(:remove, ip_list) }.to output(
|
||||||
|
a_string_including("Removed #{ip_list.size}, skipped 0")
|
||||||
|
).to_stdout
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'with --force option' do
|
||||||
|
let!(:block1) { IpBlock.create(ip: '192.168.0.0/24', severity: :no_access) }
|
||||||
|
let!(:block2) { IpBlock.create(ip: '10.0.0.0/16', severity: :no_access) }
|
||||||
|
let!(:block3) { IpBlock.create(ip: '172.16.0.0/20', severity: :no_access) }
|
||||||
|
let(:arguments) { ['192.168.0.5', '10.0.1.50'] }
|
||||||
|
let(:options) { { force: true } }
|
||||||
|
|
||||||
|
it 'removes blocks for IP ranges that cover given IP(s)' do
|
||||||
|
cli.invoke(:remove, arguments, options)
|
||||||
|
|
||||||
|
expect(IpBlock.where(id: [block1.id, block2.id])).to_not exist
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'does not remove other IP ranges' do
|
||||||
|
cli.invoke(:remove, arguments, options)
|
||||||
|
|
||||||
|
expect(IpBlock.where(id: block3.id)).to exist
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when a specified IP address is not blocked' do
|
||||||
|
let(:unblocked_ip) { '192.0.2.1' }
|
||||||
|
|
||||||
|
it 'skips the IP address' do
|
||||||
|
expect { cli.invoke(:remove, [unblocked_ip]) }.to output(
|
||||||
|
a_string_including("#{unblocked_ip} is not yet blocked")
|
||||||
|
).to_stdout
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'displays the summary correctly' do
|
||||||
|
expect { cli.invoke(:remove, [unblocked_ip]) }.to output(
|
||||||
|
a_string_including('Removed 0, skipped 1')
|
||||||
|
).to_stdout
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when a specified IP address is invalid' do
|
||||||
|
let(:invalid_ip) { '320.15.175.0' }
|
||||||
|
|
||||||
|
it 'skips the invalid IP address' do
|
||||||
|
expect { cli.invoke(:remove, [invalid_ip]) }.to output(
|
||||||
|
a_string_including("#{invalid_ip} is invalid")
|
||||||
|
).to_stdout
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'displays the summary correctly' do
|
||||||
|
expect { cli.invoke(:remove, [invalid_ip]) }.to output(
|
||||||
|
a_string_including('Removed 0, skipped 1')
|
||||||
|
).to_stdout
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when no IP address is provided' do
|
||||||
|
it 'exits with an error message' do
|
||||||
|
expect { cli.remove }.to output(
|
||||||
|
a_string_including('No IP(s) given')
|
||||||
|
).to_stdout
|
||||||
|
.and raise_error(SystemExit)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe '#export' do
|
||||||
|
let(:block1) { IpBlock.create(ip: '192.168.0.0/24', severity: :no_access) }
|
||||||
|
let(:block2) { IpBlock.create(ip: '10.0.0.0/16', severity: :no_access) }
|
||||||
|
let(:block3) { IpBlock.create(ip: '127.0.0.1', severity: :sign_up_block) }
|
||||||
|
|
||||||
|
context 'when --format option is set to "plain"' do
|
||||||
|
let(:options) { { format: 'plain' } }
|
||||||
|
|
||||||
|
it 'exports blocked IPs with "no_access" severity in plain format' do
|
||||||
|
expect { cli.invoke(:export, nil, options) }.to output(
|
||||||
|
a_string_including("#{block1.ip}/#{block1.ip.prefix}\n#{block2.ip}/#{block2.ip.prefix}")
|
||||||
|
).to_stdout
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'does not export bloked IPs with different severities' do
|
||||||
|
expect { cli.invoke(:export, nil, options) }.to_not output(
|
||||||
|
a_string_including("#{block3.ip}/#{block1.ip.prefix}")
|
||||||
|
).to_stdout
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when --format option is set to "nginx"' do
|
||||||
|
let(:options) { { format: 'nginx' } }
|
||||||
|
|
||||||
|
it 'exports blocked IPs with "no_access" severity in plain format' do
|
||||||
|
expect { cli.invoke(:export, nil, options) }.to output(
|
||||||
|
a_string_including("deny #{block1.ip}/#{block1.ip.prefix};\ndeny #{block2.ip}/#{block2.ip.prefix};")
|
||||||
|
).to_stdout
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'does not export bloked IPs with different severities' do
|
||||||
|
expect { cli.invoke(:export, nil, options) }.to_not output(
|
||||||
|
a_string_including("deny #{block3.ip}/#{block1.ip.prefix};")
|
||||||
|
).to_stdout
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when --format option is not provided' do
|
||||||
|
it 'exports blocked IPs in plain format by default' do
|
||||||
|
expect { cli.export }.to output(
|
||||||
|
a_string_including("#{block1.ip}/#{block1.ip.prefix}\n#{block2.ip}/#{block2.ip.prefix}")
|
||||||
|
).to_stdout
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -7,9 +7,11 @@ RSpec.describe Vacuum::AccessTokensVacuum do
|
||||||
|
|
||||||
describe '#perform' do
|
describe '#perform' do
|
||||||
let!(:revoked_access_token) { Fabricate(:access_token, revoked_at: 1.minute.ago) }
|
let!(:revoked_access_token) { Fabricate(:access_token, revoked_at: 1.minute.ago) }
|
||||||
|
let!(:expired_access_token) { Fabricate(:access_token, expires_in: 59.minutes.to_i, created_at: 1.hour.ago) }
|
||||||
let!(:active_access_token) { Fabricate(:access_token) }
|
let!(:active_access_token) { Fabricate(:access_token) }
|
||||||
|
|
||||||
let!(:revoked_access_grant) { Fabricate(:access_grant, revoked_at: 1.minute.ago) }
|
let!(:revoked_access_grant) { Fabricate(:access_grant, revoked_at: 1.minute.ago) }
|
||||||
|
let!(:expired_access_grant) { Fabricate(:access_grant, expires_in: 59.minutes.to_i, created_at: 1.hour.ago) }
|
||||||
let!(:active_access_grant) { Fabricate(:access_grant) }
|
let!(:active_access_grant) { Fabricate(:access_grant) }
|
||||||
|
|
||||||
before do
|
before do
|
||||||
|
@ -20,10 +22,18 @@ RSpec.describe Vacuum::AccessTokensVacuum do
|
||||||
expect { revoked_access_token.reload }.to raise_error ActiveRecord::RecordNotFound
|
expect { revoked_access_token.reload }.to raise_error ActiveRecord::RecordNotFound
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it 'deletes expired access tokens' do
|
||||||
|
expect { expired_access_token.reload }.to raise_error ActiveRecord::RecordNotFound
|
||||||
|
end
|
||||||
|
|
||||||
it 'deletes revoked access grants' do
|
it 'deletes revoked access grants' do
|
||||||
expect { revoked_access_grant.reload }.to raise_error ActiveRecord::RecordNotFound
|
expect { revoked_access_grant.reload }.to raise_error ActiveRecord::RecordNotFound
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it 'deletes expired access grants' do
|
||||||
|
expect { expired_access_grant.reload }.to raise_error ActiveRecord::RecordNotFound
|
||||||
|
end
|
||||||
|
|
||||||
it 'does not delete active access tokens' do
|
it 'does not delete active access tokens' do
|
||||||
expect { active_access_token.reload }.to_not raise_error
|
expect { active_access_token.reload }.to_not raise_error
|
||||||
end
|
end
|
||||||
|
|
|
@ -139,10 +139,6 @@ RSpec.describe ActivityPub::ProcessAccountService, type: :service do
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when Accounts referencing other accounts' do
|
context 'when Accounts referencing other accounts' do
|
||||||
before do
|
|
||||||
stub_const 'ActivityPub::ProcessAccountService::DISCOVERIES_PER_REQUEST', 5
|
|
||||||
end
|
|
||||||
|
|
||||||
let(:payload) do
|
let(:payload) do
|
||||||
{
|
{
|
||||||
'@context': ['https://www.w3.org/ns/activitystreams'],
|
'@context': ['https://www.w3.org/ns/activitystreams'],
|
||||||
|
@ -155,6 +151,8 @@ RSpec.describe ActivityPub::ProcessAccountService, type: :service do
|
||||||
end
|
end
|
||||||
|
|
||||||
before do
|
before do
|
||||||
|
stub_const 'ActivityPub::ProcessAccountService::DISCOVERIES_PER_REQUEST', 5
|
||||||
|
|
||||||
8.times do |i|
|
8.times do |i|
|
||||||
actor_json = {
|
actor_json = {
|
||||||
'@context': ['https://www.w3.org/ns/activitystreams'],
|
'@context': ['https://www.w3.org/ns/activitystreams'],
|
||||||
|
|
172
yarn.lock
172
yarn.lock
|
@ -1678,6 +1678,18 @@
|
||||||
resolved "https://registry.yarnpkg.com/@pkgjs/parseargs/-/parseargs-0.11.0.tgz#a77ea742fab25775145434eb1d2328cf5013ac33"
|
resolved "https://registry.yarnpkg.com/@pkgjs/parseargs/-/parseargs-0.11.0.tgz#a77ea742fab25775145434eb1d2328cf5013ac33"
|
||||||
integrity sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==
|
integrity sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==
|
||||||
|
|
||||||
|
"@pkgr/utils@^2.3.1":
|
||||||
|
version "2.4.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/@pkgr/utils/-/utils-2.4.0.tgz#b6373d2504aedaf2fc7cdf2d13ab1f48fa5f12d5"
|
||||||
|
integrity sha512-2OCURAmRtdlL8iUDTypMrrxfwe8frXTeXaxGsVOaYtc/wrUyk8Z/0OBetM7cdlsy7ZFWlMX72VogKeh+A4Xcjw==
|
||||||
|
dependencies:
|
||||||
|
cross-spawn "^7.0.3"
|
||||||
|
fast-glob "^3.2.12"
|
||||||
|
is-glob "^4.0.3"
|
||||||
|
open "^9.1.0"
|
||||||
|
picocolors "^1.0.0"
|
||||||
|
tslib "^2.5.0"
|
||||||
|
|
||||||
"@polka/url@^1.0.0-next.9":
|
"@polka/url@^1.0.0-next.9":
|
||||||
version "1.0.0-next.11"
|
version "1.0.0-next.11"
|
||||||
resolved "https://registry.yarnpkg.com/@polka/url/-/url-1.0.0-next.11.tgz#aeb16f50649a91af79dbe36574b66d0f9e4d9f71"
|
resolved "https://registry.yarnpkg.com/@polka/url/-/url-1.0.0-next.11.tgz#aeb16f50649a91af79dbe36574b66d0f9e4d9f71"
|
||||||
|
@ -3374,6 +3386,11 @@ batch@0.6.1:
|
||||||
resolved "https://registry.yarnpkg.com/batch/-/batch-0.6.1.tgz#dc34314f4e679318093fc760272525f94bf25c16"
|
resolved "https://registry.yarnpkg.com/batch/-/batch-0.6.1.tgz#dc34314f4e679318093fc760272525f94bf25c16"
|
||||||
integrity sha1-3DQxT05nkxgJP8dgJyUl+UvyXBY=
|
integrity sha1-3DQxT05nkxgJP8dgJyUl+UvyXBY=
|
||||||
|
|
||||||
|
big-integer@^1.6.44:
|
||||||
|
version "1.6.51"
|
||||||
|
resolved "https://registry.yarnpkg.com/big-integer/-/big-integer-1.6.51.tgz#0df92a5d9880560d3ff2d5fd20245c889d130686"
|
||||||
|
integrity sha512-GPEid2Y9QU1Exl1rpO9B2IPJGHPSupF5GnVIP0blYvNOMer2bTvSWs1jGOUg04hTmu67nmLsQ9TBo1puaotBHg==
|
||||||
|
|
||||||
big.js@^5.2.2:
|
big.js@^5.2.2:
|
||||||
version "5.2.2"
|
version "5.2.2"
|
||||||
resolved "https://registry.yarnpkg.com/big.js/-/big.js-5.2.2.tgz#65f0af382f578bcdc742bd9c281e9cb2d7768328"
|
resolved "https://registry.yarnpkg.com/big.js/-/big.js-5.2.2.tgz#65f0af382f578bcdc742bd9c281e9cb2d7768328"
|
||||||
|
@ -3456,6 +3473,13 @@ boolbase@^1.0.0:
|
||||||
resolved "https://registry.yarnpkg.com/boolbase/-/boolbase-1.0.0.tgz#68dff5fbe60c51eb37725ea9e3ed310dcc1e776e"
|
resolved "https://registry.yarnpkg.com/boolbase/-/boolbase-1.0.0.tgz#68dff5fbe60c51eb37725ea9e3ed310dcc1e776e"
|
||||||
integrity sha1-aN/1++YMUes3cl6p4+0xDcwed24=
|
integrity sha1-aN/1++YMUes3cl6p4+0xDcwed24=
|
||||||
|
|
||||||
|
bplist-parser@^0.2.0:
|
||||||
|
version "0.2.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/bplist-parser/-/bplist-parser-0.2.0.tgz#43a9d183e5bf9d545200ceac3e712f79ebbe8d0e"
|
||||||
|
integrity sha512-z0M+byMThzQmD9NILRniCUXYsYpjwnlO8N5uCFaCqIOpqRsJCrQL9NK3JsD67CN5a08nF5oIL2bD6loTdHOuKw==
|
||||||
|
dependencies:
|
||||||
|
big-integer "^1.6.44"
|
||||||
|
|
||||||
brace-expansion@^1.1.7:
|
brace-expansion@^1.1.7:
|
||||||
version "1.1.11"
|
version "1.1.11"
|
||||||
resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd"
|
resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd"
|
||||||
|
@ -3631,6 +3655,13 @@ builtin-status-codes@^3.0.0:
|
||||||
resolved "https://registry.yarnpkg.com/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz#85982878e21b98e1c66425e03d0174788f569ee8"
|
resolved "https://registry.yarnpkg.com/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz#85982878e21b98e1c66425e03d0174788f569ee8"
|
||||||
integrity sha1-hZgoeOIbmOHGZCXgPQF0eI9Wnug=
|
integrity sha1-hZgoeOIbmOHGZCXgPQF0eI9Wnug=
|
||||||
|
|
||||||
|
bundle-name@^3.0.0:
|
||||||
|
version "3.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/bundle-name/-/bundle-name-3.0.0.tgz#ba59bcc9ac785fb67ccdbf104a2bf60c099f0e1a"
|
||||||
|
integrity sha512-PKA4BeSvBpQKQ8iPOGCSiell+N8P+Tf1DlwqmYhpe2gAhKPHn8EYOxVT+ShuGmhg8lN8XiSlS80yiExKXrURlw==
|
||||||
|
dependencies:
|
||||||
|
run-applescript "^5.0.0"
|
||||||
|
|
||||||
bytes@3.0.0:
|
bytes@3.0.0:
|
||||||
version "3.0.0"
|
version "3.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.0.0.tgz#d32815404d689699f85a4ea4fa8755dd13a96048"
|
resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.0.0.tgz#d32815404d689699f85a4ea4fa8755dd13a96048"
|
||||||
|
@ -4531,6 +4562,24 @@ deepmerge@^4.0, deepmerge@^4.2.2:
|
||||||
resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.2.2.tgz#44d2ea3679b8f4d4ffba33f03d865fc1e7bf4955"
|
resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.2.2.tgz#44d2ea3679b8f4d4ffba33f03d865fc1e7bf4955"
|
||||||
integrity sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==
|
integrity sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==
|
||||||
|
|
||||||
|
default-browser-id@^3.0.0:
|
||||||
|
version "3.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/default-browser-id/-/default-browser-id-3.0.0.tgz#bee7bbbef1f4e75d31f98f4d3f1556a14cea790c"
|
||||||
|
integrity sha512-OZ1y3y0SqSICtE8DE4S8YOE9UZOJ8wO16fKWVP5J1Qz42kV9jcnMVFrEE/noXb/ss3Q4pZIH79kxofzyNNtUNA==
|
||||||
|
dependencies:
|
||||||
|
bplist-parser "^0.2.0"
|
||||||
|
untildify "^4.0.0"
|
||||||
|
|
||||||
|
default-browser@^4.0.0:
|
||||||
|
version "4.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/default-browser/-/default-browser-4.0.0.tgz#53c9894f8810bf86696de117a6ce9085a3cbc7da"
|
||||||
|
integrity sha512-wX5pXO1+BrhMkSbROFsyxUm0i/cJEScyNhA4PPxc41ICuv05ZZB/MX28s8aZx6xjmatvebIapF6hLEKEcpneUA==
|
||||||
|
dependencies:
|
||||||
|
bundle-name "^3.0.0"
|
||||||
|
default-browser-id "^3.0.0"
|
||||||
|
execa "^7.1.1"
|
||||||
|
titleize "^3.0.0"
|
||||||
|
|
||||||
default-gateway@^4.2.0:
|
default-gateway@^4.2.0:
|
||||||
version "4.2.0"
|
version "4.2.0"
|
||||||
resolved "https://registry.yarnpkg.com/default-gateway/-/default-gateway-4.2.0.tgz#167104c7500c2115f6dd69b0a536bb8ed720552b"
|
resolved "https://registry.yarnpkg.com/default-gateway/-/default-gateway-4.2.0.tgz#167104c7500c2115f6dd69b0a536bb8ed720552b"
|
||||||
|
@ -4539,6 +4588,11 @@ default-gateway@^4.2.0:
|
||||||
execa "^1.0.0"
|
execa "^1.0.0"
|
||||||
ip-regex "^2.1.0"
|
ip-regex "^2.1.0"
|
||||||
|
|
||||||
|
define-lazy-prop@^3.0.0:
|
||||||
|
version "3.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/define-lazy-prop/-/define-lazy-prop-3.0.0.tgz#dbb19adfb746d7fc6d734a06b72f4a00d021255f"
|
||||||
|
integrity sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==
|
||||||
|
|
||||||
define-properties@^1.1.3, define-properties@^1.1.4:
|
define-properties@^1.1.3, define-properties@^1.1.4:
|
||||||
version "1.1.4"
|
version "1.1.4"
|
||||||
resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.4.tgz#0b14d7bd7fbeb2f3572c3a7eda80ea5d57fb05b1"
|
resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.4.tgz#0b14d7bd7fbeb2f3572c3a7eda80ea5d57fb05b1"
|
||||||
|
@ -4877,6 +4931,14 @@ enhanced-resolve@^4.1.1, enhanced-resolve@^4.5.0:
|
||||||
memory-fs "^0.5.0"
|
memory-fs "^0.5.0"
|
||||||
tapable "^1.0.0"
|
tapable "^1.0.0"
|
||||||
|
|
||||||
|
enhanced-resolve@^5.12.0:
|
||||||
|
version "5.13.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.13.0.tgz#26d1ecc448c02de997133217b5c1053f34a0a275"
|
||||||
|
integrity sha512-eyV8f0y1+bzyfh8xAwW/WTSZpLbjhqc4ne9eGSH4Zo2ejdyiNG9pU6mf9DG8a7+Auk6MFTlNOT4Y2y/9k8GKVg==
|
||||||
|
dependencies:
|
||||||
|
graceful-fs "^4.2.4"
|
||||||
|
tapable "^2.2.0"
|
||||||
|
|
||||||
entities@^4.2.0, entities@^4.4.0:
|
entities@^4.2.0, entities@^4.4.0:
|
||||||
version "4.4.0"
|
version "4.4.0"
|
||||||
resolved "https://registry.yarnpkg.com/entities/-/entities-4.4.0.tgz#97bdaba170339446495e653cfd2db78962900174"
|
resolved "https://registry.yarnpkg.com/entities/-/entities-4.4.0.tgz#97bdaba170339446495e653cfd2db78962900174"
|
||||||
|
@ -5015,6 +5077,20 @@ eslint-import-resolver-node@^0.3.7:
|
||||||
is-core-module "^2.11.0"
|
is-core-module "^2.11.0"
|
||||||
resolve "^1.22.1"
|
resolve "^1.22.1"
|
||||||
|
|
||||||
|
eslint-import-resolver-typescript@^3.5.5:
|
||||||
|
version "3.5.5"
|
||||||
|
resolved "https://registry.yarnpkg.com/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-3.5.5.tgz#0a9034ae7ed94b254a360fbea89187b60ea7456d"
|
||||||
|
integrity sha512-TdJqPHs2lW5J9Zpe17DZNQuDnox4xo2o+0tE7Pggain9Rbc19ik8kFtXdxZ250FVx2kF4vlt2RSf4qlUpG7bhw==
|
||||||
|
dependencies:
|
||||||
|
debug "^4.3.4"
|
||||||
|
enhanced-resolve "^5.12.0"
|
||||||
|
eslint-module-utils "^2.7.4"
|
||||||
|
get-tsconfig "^4.5.0"
|
||||||
|
globby "^13.1.3"
|
||||||
|
is-core-module "^2.11.0"
|
||||||
|
is-glob "^4.0.3"
|
||||||
|
synckit "^0.8.5"
|
||||||
|
|
||||||
eslint-module-utils@^2.7.4:
|
eslint-module-utils@^2.7.4:
|
||||||
version "2.7.4"
|
version "2.7.4"
|
||||||
resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.7.4.tgz#4f3e41116aaf13a20792261e61d3a2e7e0583974"
|
resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.7.4.tgz#4f3e41116aaf13a20792261e61d3a2e7e0583974"
|
||||||
|
@ -5320,7 +5396,7 @@ execa@^5.0.0:
|
||||||
signal-exit "^3.0.3"
|
signal-exit "^3.0.3"
|
||||||
strip-final-newline "^2.0.0"
|
strip-final-newline "^2.0.0"
|
||||||
|
|
||||||
execa@^7.0.0:
|
execa@^7.0.0, execa@^7.1.1:
|
||||||
version "7.1.1"
|
version "7.1.1"
|
||||||
resolved "https://registry.yarnpkg.com/execa/-/execa-7.1.1.tgz#3eb3c83d239488e7b409d48e8813b76bb55c9c43"
|
resolved "https://registry.yarnpkg.com/execa/-/execa-7.1.1.tgz#3eb3c83d239488e7b409d48e8813b76bb55c9c43"
|
||||||
integrity sha512-wH0eMf/UXckdUYnO21+HDztteVv05rq2GXksxT4fCGeHkBhw1DROXh40wcjMcRqDOWE7iPJ4n3M7e2+YFP+76Q==
|
integrity sha512-wH0eMf/UXckdUYnO21+HDztteVv05rq2GXksxT4fCGeHkBhw1DROXh40wcjMcRqDOWE7iPJ4n3M7e2+YFP+76Q==
|
||||||
|
@ -5447,7 +5523,7 @@ fast-diff@^1.1.2:
|
||||||
resolved "https://registry.yarnpkg.com/fast-diff/-/fast-diff-1.2.0.tgz#73ee11982d86caaf7959828d519cfe927fac5f03"
|
resolved "https://registry.yarnpkg.com/fast-diff/-/fast-diff-1.2.0.tgz#73ee11982d86caaf7959828d519cfe927fac5f03"
|
||||||
integrity sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==
|
integrity sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==
|
||||||
|
|
||||||
fast-glob@^3.2.12, fast-glob@^3.2.9:
|
fast-glob@^3.2.11, fast-glob@^3.2.12, fast-glob@^3.2.9:
|
||||||
version "3.2.12"
|
version "3.2.12"
|
||||||
resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.12.tgz#7f39ec99c2e6ab030337142da9e0c18f37afae80"
|
resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.12.tgz#7f39ec99c2e6ab030337142da9e0c18f37afae80"
|
||||||
integrity sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==
|
integrity sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==
|
||||||
|
@ -5814,6 +5890,11 @@ get-symbol-description@^1.0.0:
|
||||||
call-bind "^1.0.2"
|
call-bind "^1.0.2"
|
||||||
get-intrinsic "^1.1.1"
|
get-intrinsic "^1.1.1"
|
||||||
|
|
||||||
|
get-tsconfig@^4.5.0:
|
||||||
|
version "4.5.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/get-tsconfig/-/get-tsconfig-4.5.0.tgz#6d52d1c7b299bd3ee9cd7638561653399ac77b0f"
|
||||||
|
integrity sha512-MjhiaIWCJ1sAU4pIQ5i5OfOuHHxVo1oYeNsWTON7jxYkod8pHocXeh+SSbmu5OZZZK73B6cbJ2XADzXehLyovQ==
|
||||||
|
|
||||||
get-value@^2.0.3, get-value@^2.0.6:
|
get-value@^2.0.3, get-value@^2.0.6:
|
||||||
version "2.0.6"
|
version "2.0.6"
|
||||||
resolved "https://registry.yarnpkg.com/get-value/-/get-value-2.0.6.tgz#dc15ca1c672387ca76bd37ac0a395ba2042a2c28"
|
resolved "https://registry.yarnpkg.com/get-value/-/get-value-2.0.6.tgz#dc15ca1c672387ca76bd37ac0a395ba2042a2c28"
|
||||||
|
@ -5924,6 +6005,17 @@ globby@^11.1.0:
|
||||||
merge2 "^1.4.1"
|
merge2 "^1.4.1"
|
||||||
slash "^3.0.0"
|
slash "^3.0.0"
|
||||||
|
|
||||||
|
globby@^13.1.3:
|
||||||
|
version "13.1.4"
|
||||||
|
resolved "https://registry.yarnpkg.com/globby/-/globby-13.1.4.tgz#2f91c116066bcec152465ba36e5caa4a13c01317"
|
||||||
|
integrity sha512-iui/IiiW+QrJ1X1hKH5qwlMQyv34wJAYwH1vrf8b9kBA4sNiif3gKsMHa+BrdnOpEudWjpotfa7LrTzB1ERS/g==
|
||||||
|
dependencies:
|
||||||
|
dir-glob "^3.0.1"
|
||||||
|
fast-glob "^3.2.11"
|
||||||
|
ignore "^5.2.0"
|
||||||
|
merge2 "^1.4.1"
|
||||||
|
slash "^4.0.0"
|
||||||
|
|
||||||
globby@^6.1.0:
|
globby@^6.1.0:
|
||||||
version "6.1.0"
|
version "6.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/globby/-/globby-6.1.0.tgz#f5a6d70e8395e21c858fb0489d64df02424d506c"
|
resolved "https://registry.yarnpkg.com/globby/-/globby-6.1.0.tgz#f5a6d70e8395e21c858fb0489d64df02424d506c"
|
||||||
|
@ -5952,6 +6044,11 @@ graceful-fs@^4.1.11, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0,
|
||||||
resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.9.tgz#041b05df45755e587a24942279b9d113146e1c96"
|
resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.9.tgz#041b05df45755e587a24942279b9d113146e1c96"
|
||||||
integrity sha512-NtNxqUcXgpW2iMrfqSfR73Glt39K+BLwWsPs94yR63v45T0Wbej7eRmL5cWfwEgqXnmjQp3zaJTshdRW/qC2ZQ==
|
integrity sha512-NtNxqUcXgpW2iMrfqSfR73Glt39K+BLwWsPs94yR63v45T0Wbej7eRmL5cWfwEgqXnmjQp3zaJTshdRW/qC2ZQ==
|
||||||
|
|
||||||
|
graceful-fs@^4.2.4:
|
||||||
|
version "4.2.11"
|
||||||
|
resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3"
|
||||||
|
integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==
|
||||||
|
|
||||||
grapheme-splitter@^1.0.4:
|
grapheme-splitter@^1.0.4:
|
||||||
version "1.0.4"
|
version "1.0.4"
|
||||||
resolved "https://registry.yarnpkg.com/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz#9cf3a665c6247479896834af35cf1dbb4400767e"
|
resolved "https://registry.yarnpkg.com/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz#9cf3a665c6247479896834af35cf1dbb4400767e"
|
||||||
|
@ -6607,6 +6704,16 @@ is-descriptor@^1.0.0, is-descriptor@^1.0.2:
|
||||||
is-data-descriptor "^1.0.0"
|
is-data-descriptor "^1.0.0"
|
||||||
kind-of "^6.0.2"
|
kind-of "^6.0.2"
|
||||||
|
|
||||||
|
is-docker@^2.0.0:
|
||||||
|
version "2.2.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/is-docker/-/is-docker-2.2.1.tgz#33eeabe23cfe86f14bde4408a02c0cfb853acdaa"
|
||||||
|
integrity sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==
|
||||||
|
|
||||||
|
is-docker@^3.0.0:
|
||||||
|
version "3.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/is-docker/-/is-docker-3.0.0.tgz#90093aa3106277d8a77a5910dbae71747e15a200"
|
||||||
|
integrity sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==
|
||||||
|
|
||||||
is-electron@^2.2.0:
|
is-electron@^2.2.0:
|
||||||
version "2.2.0"
|
version "2.2.0"
|
||||||
resolved "https://registry.yarnpkg.com/is-electron/-/is-electron-2.2.0.tgz#8943084f09e8b731b3a7a0298a7b5d56f6b7eef0"
|
resolved "https://registry.yarnpkg.com/is-electron/-/is-electron-2.2.0.tgz#8943084f09e8b731b3a7a0298a7b5d56f6b7eef0"
|
||||||
|
@ -6663,6 +6770,13 @@ is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3, is-glob@~4.0.1:
|
||||||
dependencies:
|
dependencies:
|
||||||
is-extglob "^2.1.1"
|
is-extglob "^2.1.1"
|
||||||
|
|
||||||
|
is-inside-container@^1.0.0:
|
||||||
|
version "1.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/is-inside-container/-/is-inside-container-1.0.0.tgz#e81fba699662eb31dbdaf26766a61d4814717ea4"
|
||||||
|
integrity sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==
|
||||||
|
dependencies:
|
||||||
|
is-docker "^3.0.0"
|
||||||
|
|
||||||
is-map@^2.0.1, is-map@^2.0.2:
|
is-map@^2.0.1, is-map@^2.0.2:
|
||||||
version "2.0.2"
|
version "2.0.2"
|
||||||
resolved "https://registry.yarnpkg.com/is-map/-/is-map-2.0.2.tgz#00922db8c9bf73e81b7a335827bc2a43f2b91127"
|
resolved "https://registry.yarnpkg.com/is-map/-/is-map-2.0.2.tgz#00922db8c9bf73e81b7a335827bc2a43f2b91127"
|
||||||
|
@ -6846,6 +6960,13 @@ is-wsl@^1.1.0:
|
||||||
resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-1.1.0.tgz#1f16e4aa22b04d1336b66188a66af3c600c3a66d"
|
resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-1.1.0.tgz#1f16e4aa22b04d1336b66188a66af3c600c3a66d"
|
||||||
integrity sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0=
|
integrity sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0=
|
||||||
|
|
||||||
|
is-wsl@^2.2.0:
|
||||||
|
version "2.2.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-2.2.0.tgz#74a4c76e77ca9fd3f932f290c17ea326cd157271"
|
||||||
|
integrity sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==
|
||||||
|
dependencies:
|
||||||
|
is-docker "^2.0.0"
|
||||||
|
|
||||||
isarray@0.0.1:
|
isarray@0.0.1:
|
||||||
version "0.0.1"
|
version "0.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf"
|
resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf"
|
||||||
|
@ -8493,6 +8614,16 @@ onetime@^6.0.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
mimic-fn "^4.0.0"
|
mimic-fn "^4.0.0"
|
||||||
|
|
||||||
|
open@^9.1.0:
|
||||||
|
version "9.1.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/open/-/open-9.1.0.tgz#684934359c90ad25742f5a26151970ff8c6c80b6"
|
||||||
|
integrity sha512-OS+QTnw1/4vrf+9hh1jc1jnYjzSG4ttTBB8UxOwAnInG3Uo4ssetzC1ihqaIHjLJnA5GGlRl6QlZXOTQhRBUvg==
|
||||||
|
dependencies:
|
||||||
|
default-browser "^4.0.0"
|
||||||
|
define-lazy-prop "^3.0.0"
|
||||||
|
is-inside-container "^1.0.0"
|
||||||
|
is-wsl "^2.2.0"
|
||||||
|
|
||||||
opencollective-postinstall@^2.0.2:
|
opencollective-postinstall@^2.0.2:
|
||||||
version "2.0.3"
|
version "2.0.3"
|
||||||
resolved "https://registry.yarnpkg.com/opencollective-postinstall/-/opencollective-postinstall-2.0.3.tgz#7a0fff978f6dbfa4d006238fbac98ed4198c3259"
|
resolved "https://registry.yarnpkg.com/opencollective-postinstall/-/opencollective-postinstall-2.0.3.tgz#7a0fff978f6dbfa4d006238fbac98ed4198c3259"
|
||||||
|
@ -10099,6 +10230,13 @@ rrweb-cssom@^0.6.0:
|
||||||
resolved "https://registry.yarnpkg.com/rrweb-cssom/-/rrweb-cssom-0.6.0.tgz#ed298055b97cbddcdeb278f904857629dec5e0e1"
|
resolved "https://registry.yarnpkg.com/rrweb-cssom/-/rrweb-cssom-0.6.0.tgz#ed298055b97cbddcdeb278f904857629dec5e0e1"
|
||||||
integrity sha512-APM0Gt1KoXBz0iIkkdB/kfvGOwC4UuJFeG/c+yV7wSc7q96cG/kJ0HiYCnzivD9SB53cLV1MlHFNfOuPaadYSw==
|
integrity sha512-APM0Gt1KoXBz0iIkkdB/kfvGOwC4UuJFeG/c+yV7wSc7q96cG/kJ0HiYCnzivD9SB53cLV1MlHFNfOuPaadYSw==
|
||||||
|
|
||||||
|
run-applescript@^5.0.0:
|
||||||
|
version "5.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/run-applescript/-/run-applescript-5.0.0.tgz#e11e1c932e055d5c6b40d98374e0268d9b11899c"
|
||||||
|
integrity sha512-XcT5rBksx1QdIhlFOCtgZkB99ZEouFZ1E2Kc2LHqNW13U3/74YGdkQRmThTwxy4QIyookibDKYZOPqX//6BlAg==
|
||||||
|
dependencies:
|
||||||
|
execa "^5.0.0"
|
||||||
|
|
||||||
run-parallel@^1.1.9:
|
run-parallel@^1.1.9:
|
||||||
version "1.2.0"
|
version "1.2.0"
|
||||||
resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee"
|
resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee"
|
||||||
|
@ -10411,6 +10549,11 @@ slash@^3.0.0:
|
||||||
resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634"
|
resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634"
|
||||||
integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==
|
integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==
|
||||||
|
|
||||||
|
slash@^4.0.0:
|
||||||
|
version "4.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/slash/-/slash-4.0.0.tgz#2422372176c4c6c5addb5e2ada885af984b396a7"
|
||||||
|
integrity sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==
|
||||||
|
|
||||||
slice-ansi@^3.0.0:
|
slice-ansi@^3.0.0:
|
||||||
version "3.0.0"
|
version "3.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-3.0.0.tgz#31ddc10930a1b7e0b67b08c96c2f49b77a789787"
|
resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-3.0.0.tgz#31ddc10930a1b7e0b67b08c96c2f49b77a789787"
|
||||||
|
@ -11055,6 +11198,14 @@ symbol-tree@^3.2.4:
|
||||||
resolved "https://registry.yarnpkg.com/symbol-tree/-/symbol-tree-3.2.4.tgz#430637d248ba77e078883951fb9aa0eed7c63fa2"
|
resolved "https://registry.yarnpkg.com/symbol-tree/-/symbol-tree-3.2.4.tgz#430637d248ba77e078883951fb9aa0eed7c63fa2"
|
||||||
integrity sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==
|
integrity sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==
|
||||||
|
|
||||||
|
synckit@^0.8.5:
|
||||||
|
version "0.8.5"
|
||||||
|
resolved "https://registry.yarnpkg.com/synckit/-/synckit-0.8.5.tgz#b7f4358f9bb559437f9f167eb6bc46b3c9818fa3"
|
||||||
|
integrity sha512-L1dapNV6vu2s/4Sputv8xGsCdAVlb5nRDMFU/E27D44l5U6cw1g0dGd45uLc+OXjNMmF4ntiMdCimzcjFKQI8Q==
|
||||||
|
dependencies:
|
||||||
|
"@pkgr/utils" "^2.3.1"
|
||||||
|
tslib "^2.5.0"
|
||||||
|
|
||||||
table@^6.8.1:
|
table@^6.8.1:
|
||||||
version "6.8.1"
|
version "6.8.1"
|
||||||
resolved "https://registry.yarnpkg.com/table/-/table-6.8.1.tgz#ea2b71359fe03b017a5fbc296204471158080bdf"
|
resolved "https://registry.yarnpkg.com/table/-/table-6.8.1.tgz#ea2b71359fe03b017a5fbc296204471158080bdf"
|
||||||
|
@ -11071,6 +11222,11 @@ tapable@^1.0, tapable@^1.0.0, tapable@^1.1.3:
|
||||||
resolved "https://registry.yarnpkg.com/tapable/-/tapable-1.1.3.tgz#a1fccc06b58db61fd7a45da2da44f5f3a3e67ba2"
|
resolved "https://registry.yarnpkg.com/tapable/-/tapable-1.1.3.tgz#a1fccc06b58db61fd7a45da2da44f5f3a3e67ba2"
|
||||||
integrity sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA==
|
integrity sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA==
|
||||||
|
|
||||||
|
tapable@^2.2.0:
|
||||||
|
version "2.2.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/tapable/-/tapable-2.2.1.tgz#1967a73ef4060a82f12ab96af86d52fdb76eeca0"
|
||||||
|
integrity sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==
|
||||||
|
|
||||||
tar@^6.0.2:
|
tar@^6.0.2:
|
||||||
version "6.1.11"
|
version "6.1.11"
|
||||||
resolved "https://registry.yarnpkg.com/tar/-/tar-6.1.11.tgz#6760a38f003afa1b2ffd0ffe9e9abbd0eab3d621"
|
resolved "https://registry.yarnpkg.com/tar/-/tar-6.1.11.tgz#6760a38f003afa1b2ffd0ffe9e9abbd0eab3d621"
|
||||||
|
@ -11193,6 +11349,11 @@ tiny-warning@^1.0.0:
|
||||||
resolved "https://registry.yarnpkg.com/tiny-warning/-/tiny-warning-1.0.3.tgz#94a30db453df4c643d0fd566060d60a875d84754"
|
resolved "https://registry.yarnpkg.com/tiny-warning/-/tiny-warning-1.0.3.tgz#94a30db453df4c643d0fd566060d60a875d84754"
|
||||||
integrity sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==
|
integrity sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==
|
||||||
|
|
||||||
|
titleize@^3.0.0:
|
||||||
|
version "3.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/titleize/-/titleize-3.0.0.tgz#71c12eb7fdd2558aa8a44b0be83b8a76694acd53"
|
||||||
|
integrity sha512-KxVu8EYHDPBdUYdKZdKtU2aj2XfEx9AfjXxE/Aj0vT06w2icA09Vus1rh6eSu1y01akYg6BjIK/hxyLJINoMLQ==
|
||||||
|
|
||||||
tmpl@1.0.5:
|
tmpl@1.0.5:
|
||||||
version "1.0.5"
|
version "1.0.5"
|
||||||
resolved "https://registry.yarnpkg.com/tmpl/-/tmpl-1.0.5.tgz#8683e0b902bb9c20c4f726e3c0b69f36518c07cc"
|
resolved "https://registry.yarnpkg.com/tmpl/-/tmpl-1.0.5.tgz#8683e0b902bb9c20c4f726e3c0b69f36518c07cc"
|
||||||
|
@ -11301,7 +11462,7 @@ tsconfig-paths@^3.14.1:
|
||||||
minimist "^1.2.6"
|
minimist "^1.2.6"
|
||||||
strip-bom "^3.0.0"
|
strip-bom "^3.0.0"
|
||||||
|
|
||||||
tslib@2.5.0, tslib@^2.1.0, tslib@^2.4.0:
|
tslib@2.5.0, tslib@^2.1.0, tslib@^2.4.0, tslib@^2.5.0:
|
||||||
version "2.5.0"
|
version "2.5.0"
|
||||||
resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.5.0.tgz#42bfed86f5787aeb41d031866c8f402429e0fddf"
|
resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.5.0.tgz#42bfed86f5787aeb41d031866c8f402429e0fddf"
|
||||||
integrity sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==
|
integrity sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==
|
||||||
|
@ -11519,6 +11680,11 @@ unset-value@^1.0.0:
|
||||||
has-value "^0.3.1"
|
has-value "^0.3.1"
|
||||||
isobject "^3.0.0"
|
isobject "^3.0.0"
|
||||||
|
|
||||||
|
untildify@^4.0.0:
|
||||||
|
version "4.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/untildify/-/untildify-4.0.0.tgz#2bc947b953652487e4600949fb091e3ae8cd919b"
|
||||||
|
integrity sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw==
|
||||||
|
|
||||||
upath@^1.1.1, upath@^1.2.0:
|
upath@^1.1.1, upath@^1.2.0:
|
||||||
version "1.2.0"
|
version "1.2.0"
|
||||||
resolved "https://registry.yarnpkg.com/upath/-/upath-1.2.0.tgz#8f66dbcd55a883acdae4408af8b035a5044c1894"
|
resolved "https://registry.yarnpkg.com/upath/-/upath-1.2.0.tgz#8f66dbcd55a883acdae4408af8b035a5044c1894"
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue