~cytrogen/masto-fe

1a4a23b5c8a8e0beacded9bc44354e3f8778ae26 — Claire 2 years ago 9af2483 + 05159d2
Merge pull request #2439 from ClearlyClaire/glitch-soc/merge-upstream

Merge upstream changes up to 4c2aca777f6ae6942d0cf11aee56a925694ccdef
39 files changed, 251 insertions(+), 189 deletions(-)

M .eslintrc.js
M app/javascript/flavours/glitch/actions/importer/normalizer.js
M app/javascript/flavours/glitch/components/column.jsx
M app/javascript/flavours/glitch/components/poll.jsx
M app/javascript/flavours/glitch/features/compose/components/search.jsx
M app/javascript/flavours/glitch/features/explore/results.jsx
M app/javascript/flavours/glitch/features/firehose/index.jsx
M app/javascript/flavours/glitch/features/interaction_modal/index.jsx
M app/javascript/flavours/glitch/features/report/comment.jsx
M app/javascript/flavours/glitch/features/status/index.jsx
M app/javascript/flavours/glitch/features/ui/components/header.jsx
M app/javascript/flavours/glitch/features/ui/components/modal_root.jsx
M app/javascript/flavours/glitch/features/ui/components/sign_in_banner.jsx
M app/javascript/mastodon/actions/alerts.js
M app/javascript/mastodon/actions/importer/normalizer.js
M app/javascript/mastodon/components/column.jsx
M app/javascript/mastodon/components/poll.jsx
M app/javascript/mastodon/components/status.jsx
M app/javascript/mastodon/features/compose/components/navigation_bar.jsx
M app/javascript/mastodon/features/compose/components/search.jsx
M app/javascript/mastodon/features/explore/results.jsx
M app/javascript/mastodon/features/firehose/index.jsx
M app/javascript/mastodon/features/interaction_modal/index.jsx
M app/javascript/mastodon/features/reblogs/index.jsx
M app/javascript/mastodon/features/report/comment.jsx
M app/javascript/mastodon/features/status/components/detailed_status.jsx
M app/javascript/mastodon/features/status/index.jsx
M app/javascript/mastodon/features/ui/components/header.jsx
M app/javascript/mastodon/features/ui/components/modal_root.jsx
M app/javascript/mastodon/features/ui/components/sign_in_banner.jsx
M app/javascript/mastodon/locales/my.json
M app/javascript/mastodon/locales/si.json
M app/javascript/packs/application.js
M config/locales/devise.si.yml
M config/locales/si.yml
M config/locales/simple_form.my.yml
M config/locales/simple_form.si.yml
M streaming/index.js
M yarn.lock
M .eslintrc.js => .eslintrc.js +2 -1
@@ 9,7 9,6 @@ module.exports = {
    'plugin:import/recommended',
    'plugin:promise/recommended',
    'plugin:jsdoc/recommended',
    'plugin:prettier/recommended',
  ],

  env: {


@@ 63,7 62,9 @@ module.exports = {
    'consistent-return': 'error',
    'dot-notation': 'error',
    eqeqeq: ['error', 'always', { 'null': 'ignore' }],
    'indent': ['error', 2],
    'jsx-quotes': ['error', 'prefer-single'],
    'semi': ['error', 'always'],
    'no-case-declarations': 'off',
    'no-catch-shadow': 'error',
    'no-console': [

M app/javascript/flavours/glitch/actions/importer/normalizer.js => app/javascript/flavours/glitch/actions/importer/normalizer.js +3 -3
@@ 96,7 96,7 @@ export function normalizeStatus(status, normalOldStatus, settings) {
      normalStatus.media_attachments.forEach(item => {
        const oldItem = list.find(i => i.get('id') === item.id);
        if (oldItem && oldItem.get('description') === item.description) {
          item.translation = oldItem.get('translation')
          item.translation = oldItem.get('translation');
        }
      });
    }


@@ 129,13 129,13 @@ export function normalizePoll(poll, normalOldPoll) {
      ...option,
      voted: poll.own_votes && poll.own_votes.includes(index),
      titleHtml: emojify(escapeTextContentForBrowser(option.title), emojiMap),
    }
    };

    if (normalOldPoll && normalOldPoll.getIn(['options', index, 'title']) === option.title) {
      normalOption.translation = normalOldPoll.getIn(['options', index, 'translation']);
    }

    return normalOption
    return normalOption;
  });

  return normalPoll;

M app/javascript/flavours/glitch/components/column.jsx => app/javascript/flavours/glitch/components/column.jsx +1 -1
@@ 30,7 30,7 @@ export default class Column extends PureComponent {
      if (scrollable.classList.contains('scrollable--flex')) {
        scrollable = scrollable?.querySelector('.scrollable') || scrollable;
      }
   }
    }

    if (!scrollable) {
      return;

M app/javascript/flavours/glitch/components/poll.jsx => app/javascript/flavours/glitch/components/poll.jsx +1 -1
@@ 133,7 133,7 @@ class Poll extends ImmutablePureComponent {

  handleReveal = () => {
    this.setState({ revealed: true });
  }
  };

  renderOption (option, optionIndex, showResults) {
    const { poll, lang, disabled, intl } = this.props;

M app/javascript/flavours/glitch/features/compose/components/search.jsx => app/javascript/flavours/glitch/features/compose/components/search.jsx +9 -9
@@ 59,14 59,14 @@ class Search extends PureComponent {
  };

  defaultOptions = [
    { label: <><mark>has:</mark> <FormattedList type='disjunction' value={['media', 'poll', 'embed']} /></>, action: e => { e.preventDefault(); this._insertText('has:') } },
    { label: <><mark>is:</mark> <FormattedList type='disjunction' value={['reply', 'sensitive']} /></>, action: e => { e.preventDefault(); this._insertText('is:') } },
    { label: <><mark>language:</mark> <FormattedMessage id='search_popout.language_code' defaultMessage='ISO language code' /></>, action: e => { e.preventDefault(); this._insertText('language:') } },
    { label: <><mark>from:</mark> <FormattedMessage id='search_popout.user' defaultMessage='user' /></>, action: e => { e.preventDefault(); this._insertText('from:') } },
    { label: <><mark>before:</mark> <FormattedMessage id='search_popout.specific_date' defaultMessage='specific date' /></>, action: e => { e.preventDefault(); this._insertText('before:') } },
    { label: <><mark>during:</mark> <FormattedMessage id='search_popout.specific_date' defaultMessage='specific date' /></>, action: e => { e.preventDefault(); this._insertText('during:') } },
    { label: <><mark>after:</mark> <FormattedMessage id='search_popout.specific_date' defaultMessage='specific date' /></>, action: e => { e.preventDefault(); this._insertText('after:') } },
    { label: <><mark>in:</mark> <FormattedList type='disjunction' value={['all', 'library']} /></>, action: e => { e.preventDefault(); this._insertText('in:') } }
    { label: <><mark>has:</mark> <FormattedList type='disjunction' value={['media', 'poll', 'embed']} /></>, action: e => { e.preventDefault(); this._insertText('has:'); } },
    { label: <><mark>is:</mark> <FormattedList type='disjunction' value={['reply', 'sensitive']} /></>, action: e => { e.preventDefault(); this._insertText('is:'); } },
    { label: <><mark>language:</mark> <FormattedMessage id='search_popout.language_code' defaultMessage='ISO language code' /></>, action: e => { e.preventDefault(); this._insertText('language:'); } },
    { label: <><mark>from:</mark> <FormattedMessage id='search_popout.user' defaultMessage='user' /></>, action: e => { e.preventDefault(); this._insertText('from:'); } },
    { label: <><mark>before:</mark> <FormattedMessage id='search_popout.specific_date' defaultMessage='specific date' /></>, action: e => { e.preventDefault(); this._insertText('before:'); } },
    { label: <><mark>during:</mark> <FormattedMessage id='search_popout.specific_date' defaultMessage='specific date' /></>, action: e => { e.preventDefault(); this._insertText('during:'); } },
    { label: <><mark>after:</mark> <FormattedMessage id='search_popout.specific_date' defaultMessage='specific date' /></>, action: e => { e.preventDefault(); this._insertText('after:'); } },
    { label: <><mark>in:</mark> <FormattedList type='disjunction' value={['all', 'library']} /></>, action: e => { e.preventDefault(); this._insertText('in:'); } }
  ];

  setRef = c => {


@@ 92,7 92,7 @@ class Search extends PureComponent {

    if (value.length > 0 || submitted) {
      onClear();
      this.setState({ options: [], selectedOption: -1 })
      this.setState({ options: [], selectedOption: -1 });
    }
  };


M app/javascript/flavours/glitch/features/explore/results.jsx => app/javascript/flavours/glitch/features/explore/results.jsx +3 -3
@@ 80,7 80,7 @@ class Results extends PureComponent {
    }

    return null;
  };
  }

  handleSelectAll = () => {
    const { submittedType, dispatch } = this.props;


@@ 116,7 116,7 @@ class Results extends PureComponent {
    }

    this.setState({ type: 'hashtags' });
  }
  };

  handleSelectStatuses = () => {
    const { submittedType, dispatch } = this.props;


@@ 128,7 128,7 @@ class Results extends PureComponent {
    }

    this.setState({ type: 'statuses' });
  }
  };

  handleLoadMoreAccounts = () => this._loadMore('accounts');
  handleLoadMoreStatuses = () => this._loadMore('statuses');

M app/javascript/flavours/glitch/features/firehose/index.jsx => app/javascript/flavours/glitch/features/firehose/index.jsx +1 -1
@@ 221,7 221,7 @@ const Firehose = ({ feedType, multiColumn }) => {
      </Helmet>
    </Column>
  );
}
};

Firehose.propTypes = {
  multiColumn: PropTypes.bool,

M app/javascript/flavours/glitch/features/interaction_modal/index.jsx => app/javascript/flavours/glitch/features/interaction_modal/index.jsx +4 -4
@@ 27,9 27,9 @@ const mapStateToProps = (state, { accountId }) => ({
const mapDispatchToProps = (dispatch) => ({
  onSignupClick() {
    dispatch(closeModal({
        modalType: undefined,
        ignoreFocus: false,
      }));
      modalType: undefined,
      ignoreFocus: false,
    }));
    dispatch(openModal({ modalType: 'CLOSED_REGISTRATIONS' }));
  },
});


@@ 187,7 187,7 @@ class LoginForm extends React.PureComponent {

  setIFrameRef = (iframe) => {
    this.iframeRef = iframe;
  }
  };

  handleFocus = () => {
    this.setState({ expanded: true });

M app/javascript/flavours/glitch/features/report/comment.jsx => app/javascript/flavours/glitch/features/report/comment.jsx +1 -1
@@ 104,7 104,7 @@ const Comment = ({ comment, domain, statusIds, isRemote, isSubmitting, selectedD
      </div>
    </>
  );
}
};

Comment.propTypes = {
  comment: PropTypes.string.isRequired,

M app/javascript/flavours/glitch/features/status/index.jsx => app/javascript/flavours/glitch/features/status/index.jsx +29 -4
@@ 217,6 217,7 @@ class Status extends ImmutablePureComponent {
  componentDidMount () {
    attachFullscreenListener(this.onFullScreenChange);
    this.props.dispatch(fetchStatus(this.props.params.statusId));
    this._scrollStatusIntoView();
  }

  static getDerivedStateFromProps(props, state) {


@@ 614,10 615,10 @@ class Status extends ImmutablePureComponent {
    this.column = c;
  };

  componentDidUpdate (prevProps) {
    const { status, ancestorsIds, multiColumn } = this.props;
  _scrollStatusIntoView () {
    const { status, multiColumn } = this.props;

    if (status && (ancestorsIds.size > prevProps.ancestorsIds.size || prevProps.status?.get('id') !== status.get('id'))) {
    if (status) {
      window.requestAnimationFrame(() => {
        this.node?.querySelector('.detailed-status__wrapper')?.scrollIntoView(true);



@@ 634,6 635,14 @@ class Status extends ImmutablePureComponent {
    }
  }

  componentDidUpdate (prevProps) {
    const { status, ancestorsIds } = this.props;

    if (status && (ancestorsIds.size > prevProps.ancestorsIds.size || prevProps.status?.get('id') !== status.get('id'))) {
      this._scrollStatusIntoView();
    }
  }

  componentWillUnmount () {
    detachFullscreenListener(this.onFullScreenChange);
  }


@@ 642,6 651,22 @@ class Status extends ImmutablePureComponent {
    this.setState({ fullscreen: isFullscreen() });
  };

  shouldUpdateScroll = (prevRouterProps, { location }) => {
    // Do not change scroll when opening a modal
    if (location.state?.mastodonModalKey && location.state?.mastodonModalKey !== prevRouterProps?.location?.state?.mastodonModalKey) {
      return false;
    }

    // Scroll to focused post if it is loaded
    const child = this.node?.querySelector('.detailed-status__wrapper');
    if (child) {
      return [0, child.offsetTop];
    }

    // Do not scroll otherwise, `componentDidUpdate` will take care of that
    return false;
  };

  render () {
    let ancestors, descendants;
    const { isLoading, status, settings, ancestorsIds, descendantsIds, intl, domain, multiColumn, pictureInPicture } = this.props;


@@ 701,7 726,7 @@ class Status extends ImmutablePureComponent {
          )}
        />

        <ScrollContainer scrollKey='thread'>
        <ScrollContainer scrollKey='thread' shouldUpdateScroll={this.shouldUpdateScroll}>
          <div className={classNames('scrollable', { fullscreen })} ref={this.setRef}>
            {ancestors}


M app/javascript/flavours/glitch/features/ui/components/header.jsx => app/javascript/flavours/glitch/features/ui/components/header.jsx +2 -2
@@ 77,8 77,8 @@ class Header extends PureComponent {

      if (sso_redirect) {
        content = (
            <a href={sso_redirect} data-method='post' className='button button--block button-tertiary'><FormattedMessage id='sign_in_banner.sso_redirect' defaultMessage='Login or Register' /></a>
        )
          <a href={sso_redirect} data-method='post' className='button button--block button-tertiary'><FormattedMessage id='sign_in_banner.sso_redirect' defaultMessage='Login or Register' /></a>
        );
      } else {
        let signupButton;


M app/javascript/flavours/glitch/features/ui/components/modal_root.jsx => app/javascript/flavours/glitch/features/ui/components/modal_root.jsx +1 -1
@@ 128,7 128,7 @@ export default class ModalRoot extends PureComponent {
            <BundleContainer fetchComponent={MODAL_COMPONENTS[type]} loading={this.renderLoading(type)} error={this.renderError} renderDelay={200}>
              {(SpecificComponent) => {
                const ref = typeof SpecificComponent !== 'function' ? this.setModalRef : undefined;
                return <SpecificComponent {...props} onChangeBackgroundColor={this.setBackgroundColor} onClose={this.handleClose} ref={ref} />
                return <SpecificComponent {...props} onChangeBackgroundColor={this.setBackgroundColor} onClose={this.handleClose} ref={ref} />;
              }}
            </BundleContainer>


M app/javascript/flavours/glitch/features/ui/components/sign_in_banner.jsx => app/javascript/flavours/glitch/features/ui/components/sign_in_banner.jsx +1 -1
@@ 24,7 24,7 @@ const SignInBanner = () => {
        <p><FormattedMessage id='sign_in_banner.text' defaultMessage='Login to follow profiles or hashtags, favorite, share and reply to posts. You can also interact from your account on a different server.' /></p>
        <a href={sso_redirect} data-method='post' className='button button--block button-tertiary'><FormattedMessage id='sign_in_banner.sso_redirect' defaultMessage='Login or Register' /></a>
      </div>
    )
    );
  }

  if (registrationsOpen) {

M app/javascript/mastodon/actions/alerts.js => app/javascript/mastodon/actions/alerts.js +1 -1
@@ 56,4 56,4 @@ export const showAlertForError = (error, skipNotFound = false) => {
    title: messages.unexpectedTitle,
    message: messages.unexpectedMessage,
  });
}
};

M app/javascript/mastodon/actions/importer/normalizer.js => app/javascript/mastodon/actions/importer/normalizer.js +3 -3
@@ 104,7 104,7 @@ export function normalizeStatus(status, normalOldStatus) {
      normalStatus.media_attachments.forEach(item => {
        const oldItem = list.find(i => i.get('id') === item.id);
        if (oldItem && oldItem.get('description') === item.description) {
          item.translation = oldItem.get('translation')
          item.translation = oldItem.get('translation');
        }
      });
    }


@@ 137,13 137,13 @@ export function normalizePoll(poll, normalOldPoll) {
      ...option,
      voted: poll.own_votes && poll.own_votes.includes(index),
      titleHtml: emojify(escapeTextContentForBrowser(option.title), emojiMap),
    }
    };

    if (normalOldPoll && normalOldPoll.getIn(['options', index, 'title']) === option.title) {
      normalOption.translation = normalOldPoll.getIn(['options', index, 'translation']);
    }

    return normalOption
    return normalOption;
  });

  return normalPoll;

M app/javascript/mastodon/components/column.jsx => app/javascript/mastodon/components/column.jsx +1 -1
@@ 22,7 22,7 @@ export default class Column extends PureComponent {
      scrollable = document.scrollingElement;
    } else {
      scrollable = this.node.querySelector('.scrollable');
   }
    }

    if (!scrollable) {
      return;

M app/javascript/mastodon/components/poll.jsx => app/javascript/mastodon/components/poll.jsx +1 -1
@@ 132,7 132,7 @@ class Poll extends ImmutablePureComponent {

  handleReveal = () => {
    this.setState({ revealed: true });
  }
  };

  renderOption (option, optionIndex, showResults) {
    const { poll, lang, disabled, intl } = this.props;

M app/javascript/mastodon/components/status.jsx => app/javascript/mastodon/components/status.jsx +1 -1
@@ 199,7 199,7 @@ class Status extends ImmutablePureComponent {
    } else if (attachments.getIn([0, 'type']) === 'audio') {
      return '16 / 9';
    } else {
      return (attachments.size === 1 && attachments.getIn([0, 'meta', 'small', 'aspect'])) ? attachments.getIn([0, 'meta', 'small', 'aspect']) : '3 / 2'
      return (attachments.size === 1 && attachments.getIn([0, 'meta', 'small', 'aspect'])) ? attachments.getIn([0, 'meta', 'small', 'aspect']) : '3 / 2';
    }
  }


M app/javascript/mastodon/features/compose/components/navigation_bar.jsx => app/javascript/mastodon/features/compose/components/navigation_bar.jsx +1 -1
@@ 20,7 20,7 @@ export default class NavigationBar extends ImmutablePureComponent {
  };

  render () {
    const username = this.props.account.get('acct')
    const username = this.props.account.get('acct');
    return (
      <div className='navigation-bar'>
        <Link to={`/@${username}`}>

M app/javascript/mastodon/features/compose/components/search.jsx => app/javascript/mastodon/features/compose/components/search.jsx +8 -8
@@ 57,14 57,14 @@ class Search extends PureComponent {
  };

  defaultOptions = [
    { label: <><mark>has:</mark> <FormattedList type='disjunction' value={['media', 'poll', 'embed']} /></>, action: e => { e.preventDefault(); this._insertText('has:') } },
    { label: <><mark>is:</mark> <FormattedList type='disjunction' value={['reply', 'sensitive']} /></>, action: e => { e.preventDefault(); this._insertText('is:') } },
    { label: <><mark>language:</mark> <FormattedMessage id='search_popout.language_code' defaultMessage='ISO language code' /></>, action: e => { e.preventDefault(); this._insertText('language:') } },
    { label: <><mark>from:</mark> <FormattedMessage id='search_popout.user' defaultMessage='user' /></>, action: e => { e.preventDefault(); this._insertText('from:') } },
    { label: <><mark>before:</mark> <FormattedMessage id='search_popout.specific_date' defaultMessage='specific date' /></>, action: e => { e.preventDefault(); this._insertText('before:') } },
    { label: <><mark>during:</mark> <FormattedMessage id='search_popout.specific_date' defaultMessage='specific date' /></>, action: e => { e.preventDefault(); this._insertText('during:') } },
    { label: <><mark>after:</mark> <FormattedMessage id='search_popout.specific_date' defaultMessage='specific date' /></>, action: e => { e.preventDefault(); this._insertText('after:') } },
    { label: <><mark>in:</mark> <FormattedList type='disjunction' value={['all', 'library']} /></>, action: e => { e.preventDefault(); this._insertText('in:') } }
    { label: <><mark>has:</mark> <FormattedList type='disjunction' value={['media', 'poll', 'embed']} /></>, action: e => { e.preventDefault(); this._insertText('has:'); } },
    { label: <><mark>is:</mark> <FormattedList type='disjunction' value={['reply', 'sensitive']} /></>, action: e => { e.preventDefault(); this._insertText('is:'); } },
    { label: <><mark>language:</mark> <FormattedMessage id='search_popout.language_code' defaultMessage='ISO language code' /></>, action: e => { e.preventDefault(); this._insertText('language:'); } },
    { label: <><mark>from:</mark> <FormattedMessage id='search_popout.user' defaultMessage='user' /></>, action: e => { e.preventDefault(); this._insertText('from:'); } },
    { label: <><mark>before:</mark> <FormattedMessage id='search_popout.specific_date' defaultMessage='specific date' /></>, action: e => { e.preventDefault(); this._insertText('before:'); } },
    { label: <><mark>during:</mark> <FormattedMessage id='search_popout.specific_date' defaultMessage='specific date' /></>, action: e => { e.preventDefault(); this._insertText('during:'); } },
    { label: <><mark>after:</mark> <FormattedMessage id='search_popout.specific_date' defaultMessage='specific date' /></>, action: e => { e.preventDefault(); this._insertText('after:'); } },
    { label: <><mark>in:</mark> <FormattedList type='disjunction' value={['all', 'library']} /></>, action: e => { e.preventDefault(); this._insertText('in:'); } }
  ];

  setRef = c => {

M app/javascript/mastodon/features/explore/results.jsx => app/javascript/mastodon/features/explore/results.jsx +3 -3
@@ 80,7 80,7 @@ class Results extends PureComponent {
    }

    return null;
  };
  }

  handleSelectAll = () => {
    const { submittedType, dispatch } = this.props;


@@ 116,7 116,7 @@ class Results extends PureComponent {
    }

    this.setState({ type: 'hashtags' });
  }
  };

  handleSelectStatuses = () => {
    const { submittedType, dispatch } = this.props;


@@ 128,7 128,7 @@ class Results extends PureComponent {
    }

    this.setState({ type: 'statuses' });
  }
  };

  handleLoadMoreAccounts = () => this._loadMore('accounts');
  handleLoadMoreStatuses = () => this._loadMore('statuses');

M app/javascript/mastodon/features/firehose/index.jsx => app/javascript/mastodon/features/firehose/index.jsx +1 -1
@@ 199,7 199,7 @@ const Firehose = ({ feedType, multiColumn }) => {
      </Helmet>
    </Column>
  );
}
};

Firehose.propTypes = {
  multiColumn: PropTypes.bool,

M app/javascript/mastodon/features/interaction_modal/index.jsx => app/javascript/mastodon/features/interaction_modal/index.jsx +4 -4
@@ 27,9 27,9 @@ const mapStateToProps = (state, { accountId }) => ({
const mapDispatchToProps = (dispatch) => ({
  onSignupClick() {
    dispatch(closeModal({
        modalType: undefined,
        ignoreFocus: false,
      }));
      modalType: undefined,
      ignoreFocus: false,
    }));
    dispatch(openModal({ modalType: 'CLOSED_REGISTRATIONS' }));
  },
});


@@ 187,7 187,7 @@ class LoginForm extends React.PureComponent {

  setIFrameRef = (iframe) => {
    this.iframeRef = iframe;
  }
  };

  handleFocus = () => {
    this.setState({ expanded: true });

M app/javascript/mastodon/features/reblogs/index.jsx => app/javascript/mastodon/features/reblogs/index.jsx +1 -1
@@ 45,7 45,7 @@ class Reblogs extends ImmutablePureComponent {
    if (!this.props.accountIds) {
      this.props.dispatch(fetchReblogs(this.props.params.statusId));
    }
  };
  }

  handleRefresh = () => {
    this.props.dispatch(fetchReblogs(this.props.params.statusId));

M app/javascript/mastodon/features/report/comment.jsx => app/javascript/mastodon/features/report/comment.jsx +1 -1
@@ 104,7 104,7 @@ const Comment = ({ comment, domain, statusIds, isRemote, isSubmitting, selectedD
      </div>
    </>
  );
}
};

Comment.propTypes = {
  comment: PropTypes.string.isRequired,

M app/javascript/mastodon/features/status/components/detailed_status.jsx => app/javascript/mastodon/features/status/components/detailed_status.jsx +1 -1
@@ 132,7 132,7 @@ class DetailedStatus extends ImmutablePureComponent {
    } else if (attachments.getIn([0, 'type']) === 'audio') {
      return '16 / 9';
    } else {
      return (attachments.size === 1 && attachments.getIn([0, 'meta', 'small', 'aspect'])) ? attachments.getIn([0, 'meta', 'small', 'aspect']) : '3 / 2'
      return (attachments.size === 1 && attachments.getIn([0, 'meta', 'small', 'aspect'])) ? attachments.getIn([0, 'meta', 'small', 'aspect']) : '3 / 2';
    }
  }


M app/javascript/mastodon/features/status/index.jsx => app/javascript/mastodon/features/status/index.jsx +30 -4
@@ 220,6 220,8 @@ class Status extends ImmutablePureComponent {

  componentDidMount () {
    attachFullscreenListener(this.onFullScreenChange);

    this._scrollStatusIntoView();
  }

  UNSAFE_componentWillReceiveProps (nextProps) {


@@ 579,10 581,10 @@ class Status extends ImmutablePureComponent {
    this.node = c;
  };

  componentDidUpdate (prevProps) {
    const { status, ancestorsIds, multiColumn } = this.props;
  _scrollStatusIntoView () {
    const { status, multiColumn } = this.props;

    if (status && (ancestorsIds.size > prevProps.ancestorsIds.size || prevProps.status?.get('id') !== status.get('id'))) {
    if (status) {
      window.requestAnimationFrame(() => {
        this.node?.querySelector('.detailed-status__wrapper')?.scrollIntoView(true);



@@ 599,6 601,14 @@ class Status extends ImmutablePureComponent {
    }
  }

  componentDidUpdate (prevProps) {
    const { status, ancestorsIds } = this.props;

    if (status && (ancestorsIds.size > prevProps.ancestorsIds.size || prevProps.status?.get('id') !== status.get('id'))) {
      this._scrollStatusIntoView();
    }
  }

  componentWillUnmount () {
    detachFullscreenListener(this.onFullScreenChange);
  }


@@ 607,6 617,22 @@ class Status extends ImmutablePureComponent {
    this.setState({ fullscreen: isFullscreen() });
  };

  shouldUpdateScroll = (prevRouterProps, { location }) => {
    // Do not change scroll when opening a modal
    if (location.state?.mastodonModalKey && location.state?.mastodonModalKey !== prevRouterProps?.location?.state?.mastodonModalKey) {
      return false;
    }

    // Scroll to focused post if it is loaded
    const child = this.node?.querySelector('.detailed-status__wrapper');
    if (child) {
      return [0, child.offsetTop];
    }

    // Do not scroll otherwise, `componentDidUpdate` will take care of that
    return false;
  };

  render () {
    let ancestors, descendants;
    const { isLoading, status, ancestorsIds, descendantsIds, intl, domain, multiColumn, pictureInPicture } = this.props;


@@ 660,7 686,7 @@ class Status extends ImmutablePureComponent {
          )}
        />

        <ScrollContainer scrollKey='thread'>
        <ScrollContainer scrollKey='thread' shouldUpdateScroll={this.shouldUpdateScroll}>
          <div className={classNames('scrollable', { fullscreen })} ref={this.setRef}>
            {ancestors}


M app/javascript/mastodon/features/ui/components/header.jsx => app/javascript/mastodon/features/ui/components/header.jsx +2 -2
@@ 76,8 76,8 @@ class Header extends PureComponent {

      if (sso_redirect) {
        content = (
            <a href={sso_redirect} data-method='post' className='button button--block button-tertiary'><FormattedMessage id='sign_in_banner.sso_redirect' defaultMessage='Login or Register' /></a>
        )
          <a href={sso_redirect} data-method='post' className='button button--block button-tertiary'><FormattedMessage id='sign_in_banner.sso_redirect' defaultMessage='Login or Register' /></a>
        );
      } else {
        let signupButton;


M app/javascript/mastodon/features/ui/components/modal_root.jsx => app/javascript/mastodon/features/ui/components/modal_root.jsx +1 -1
@@ 117,7 117,7 @@ export default class ModalRoot extends PureComponent {
            <BundleContainer fetchComponent={MODAL_COMPONENTS[type]} loading={this.renderLoading(type)} error={this.renderError} renderDelay={200}>
              {(SpecificComponent) => {
                const ref = typeof SpecificComponent !== 'function' ? this.setModalRef : undefined;
                return <SpecificComponent {...props} onChangeBackgroundColor={this.setBackgroundColor} onClose={this.handleClose} ref={ref} />
                return <SpecificComponent {...props} onChangeBackgroundColor={this.setBackgroundColor} onClose={this.handleClose} ref={ref} />;
              }}
            </BundleContainer>


M app/javascript/mastodon/features/ui/components/sign_in_banner.jsx => app/javascript/mastodon/features/ui/components/sign_in_banner.jsx +1 -1
@@ 25,7 25,7 @@ const SignInBanner = () => {
        <p><FormattedMessage id='sign_in_banner.text' defaultMessage='Login to follow profiles or hashtags, favorite, share and reply to posts. You can also interact from your account on a different server.' /></p>
        <a href={sso_redirect} data-method='post' className='button button--block button-tertiary'><FormattedMessage id='sign_in_banner.sso_redirect' defaultMessage='Login or Register' /></a>
      </div>
    )
    );
  }

  if (registrationsOpen) {

M app/javascript/mastodon/locales/my.json => app/javascript/mastodon/locales/my.json +2 -0
@@ 312,6 312,7 @@
  "home.hide_announcements": "ကြေညာချက်များကို ဖျောက်ပါ",
  "home.pending_critical_update.body": "သင့် Mastodon ဆာဗာ အမြန်ဆုံး အပ်ဒိတ်လုပ်ပါ။",
  "home.pending_critical_update.link": "အပ်ဒိတ်များကြည့်ရန်",
  "home.pending_critical_update.title": "အရေးကြီးသည့် လုံခြုံရေးအပ်ဒိတ် ရနိုင်ပါမည်။",
  "home.show_announcements": "ကြေညာချက်များကို ပြပါ",
  "interaction_modal.description.favourite": "Mastodon အကောင့်ဖြင့် ဤပို့စ်ကို သင် favorite ပြုလုပ်ကြောင်း စာရေးသူအား အသိပေးပြီး နောက်ပိုင်းတွင် သိမ်းဆည်းနိုင်သည်။",
  "interaction_modal.description.follow": "Mastodon အကောင့်ဖြင့် သင်၏ ပင်မစာမျက်နှာတွင် ၎င်းတို့၏ ပို့စ်များကို ရရှိရန်အတွက် {name} ကို စောင့်ကြည့်နိုင်ပါသည်။",


@@ 594,6 595,7 @@
  "search_popout.options": "ရွေးချယ်ထားသည်များ ရှာဖွေရန်",
  "search_popout.quick_actions": "အမြန်လုပ်ဆောင်မှုများ",
  "search_popout.recent": "လတ်တလော ရှာဖွေမှုများ",
  "search_popout.specific_date": "သီးခြားရက်စွဲ",
  "search_popout.user": "အသုံးပြုသူ",
  "search_results.accounts": "စာမျက်နှာ",
  "search_results.all": "အားလုံး",

M app/javascript/mastodon/locales/si.json => app/javascript/mastodon/locales/si.json +15 -6
@@ 6,6 6,7 @@
  "about.rules": "සේවාදායකයේ නීති",
  "account.account_note_header": "සටහන",
  "account.add_or_remove_from_list": "ලැයිස්තු වලින් එකතු හෝ ඉවත් කරන්න",
  "account.badges.bot": "ස්වයංක්‍රියයි",
  "account.badges.group": "සමූහය",
  "account.block": "@{name} අවහිර කරන්න",
  "account.block_domain": "{domain} වසම අවහිර කරන්න",


@@ 21,14 22,15 @@
  "account.follow": "අනුගමනය",
  "account.followers": "අනුගාමිකයින්",
  "account.followers.empty": "කිසිවෙක් අනුගමනය කර නැත.",
  "account.following": "අනුගමනය",
  "account.following_counter": "{count, plural, one {අනුගාමිකයින් {counter}} other {අනුගාමිකයින් {counter}}}",
  "account.followers_counter": "{count, plural, one {අනුගාමිකයින් {counter}} other {අනුගාමිකයින් {counter}}}",
  "account.following": "අනුගමන",
  "account.following_counter": "{count, plural, one {අනුගමන {counter}} other {අනුගමන {counter}}}",
  "account.follows.empty": "තවමත් කිසිවෙක් අනුගමනය නොකරයි.",
  "account.follows_you": "ඔබව අනුගමනය කරයි",
  "account.go_to_profile": "පැතිකඩට යන්න",
  "account.joined_short": "එක් වූ දිනය",
  "account.link_verified_on": "මෙම සබැඳියේ අයිතිය {date} දී පරීක්‍ෂා කෙරිණි",
  "account.media": "මාධ්‍යය",
  "account.media": "මාධ්‍ය",
  "account.mention": "@{name} සඳහන් කරන්ක",
  "account.mute": "@{name} නිහඬ කරන්න",
  "account.mute_short": "නිහඬ",


@@ 37,6 39,7 @@
  "account.posts_with_replies": "ලිපි සහ පිළිතුරු",
  "account.report": "@{name} වාර්තා කරන්න",
  "account.share": "@{name} ගේ පැතිකඩ බෙදාගන්න",
  "account.statuses_counter": "{count, plural, one {ලිපි {counter}} other {ලිපි {counter}}}",
  "account.unblock": "@{name} අනවහිර කරන්න",
  "account.unblock_domain": "{domain} වසම අනවහිර කරන්න",
  "account.unblock_short": "අනවහිර",


@@ 53,11 56,17 @@
  "audio.hide": "හඬපටය සඟවන්න",
  "autosuggest_hashtag.per_week": "සතියකට {count}",
  "boost_modal.combo": "ඊළඟ වතාවේ මෙය මඟ හැරීමට {combo} එබීමට හැකිය",
  "bundle_column_error.copy_stacktrace": "දෝෂ වාර්තාවේ පිටපතක්",
  "bundle_column_error.error.title": "අපොයි!",
  "bundle_column_error.network.title": "ජාලයේ දෝෂයකි",
  "bundle_column_error.retry": "නැවත උත්සාහ කරන්න",
  "bundle_column_error.return": "ආපසු මුලට යන්න",
  "bundle_column_error.routing.title": "404",
  "bundle_modal_error.close": "වසන්න",
  "bundle_modal_error.message": "මෙම සංරචකය පූරණයේ දී යම් දෙයක් වැරදී ඇත.",
  "bundle_modal_error.retry": "නැවත උත්සාහ කරන්න",
  "closed_registrations_modal.find_another_server": "වෙනත් සේවාදායක",
  "closed_registrations_modal.title": "මාස්ටඩන් හි ලියාපදිංචි වන්න",
  "column.about": "පිලිබඳව",
  "column.blocks": "අවහිර කළ අය",
  "column.bookmarks": "පොත්යොමු",


@@ 159,7 168,7 @@
  "empty_column.domain_blocks": "අවහිර කරන ලද වසම් නැත.",
  "empty_column.explore_statuses": "දැන් කිසිවක් නැඹුරු නොවේ. පසුව නැවත පරීක්ෂා කරන්න!",
  "empty_column.follow_requests": "ඔබට තවමත් අනුගමන ඉල්ලීම් ලැබී නැත. ඉල්ලීමක් ලැබුණු විට, එය මෙහි පෙන්වනු ඇත.",
  "empty_column.home": "ඔබගේ මුල් පිටුව හිස් ය! මෙය පිරවීමට බොහෝ පුද්ගලයින් අනුගමනය කරන්න.",
  "empty_column.home": "මුල් පිටුව හිස් ය! මෙය පිරවීමට බොහෝ පුද්ගලයින් අනුගමනය කරන්න.",
  "empty_column.lists": "ඔබට තවමත් ලැයිස්තු කිසිවක් නැත. ඔබ එකක් සාදන විට, එය මෙහි පෙන්වනු ඇත.",
  "empty_column.mutes": "ඔබ තවමත් කිසිදු පරිශීලකයෙකු නිහඬ කර නැත.",
  "empty_column.notifications": "ඔබට දැනුම්දීම් ලැබී නැත. අන් අය සහ ඔබ අතර අන්‍යෝන්‍ය බලපවත්වන දෑ මෙහි දිස්වනු ඇත.",


@@ 264,7 273,7 @@
  "navigation_bar.favourites": "ප්‍රියතමයන්",
  "navigation_bar.filters": "නිහඬ කළ වචන",
  "navigation_bar.follow_requests": "අනුගමන ඉල්ලීම්",
  "navigation_bar.follows_and_followers": "අනුගමනය හා අනුගාමිකයින්",
  "navigation_bar.follows_and_followers": "අනුගමන හා අනුගාමික",
  "navigation_bar.lists": "ලැයිස්තු",
  "navigation_bar.logout": "නික්මෙන්න",
  "navigation_bar.mutes": "නිහඬ කළ අය",


@@ 445,7 454,7 @@
  "time_remaining.seconds": "{number, plural, one {තත්පර #} other {තත්පර #}} ක් ඉතිරිය",
  "timeline_hint.remote_resource_not_displayed": "වෙනත් සේවාදායකයන්ගෙන් {resource} දර්ශනය නොවේ.",
  "timeline_hint.resources.followers": "අනුගාමිකයින්",
  "timeline_hint.resources.follows": "අනුගමනය",
  "timeline_hint.resources.follows": "අනුගමන",
  "timeline_hint.resources.statuses": "පරණ ලිපි",
  "trends.trending_now": "දැන් නැගී එන",
  "ui.beforeunload": "ඔබ මාස්ටඩන් හැර ගියහොත් කටුපිටපත අහිමි වේ.",

M app/javascript/packs/application.js => app/javascript/packs/application.js +1 -1
@@ 1,5 1,5 @@
import './public-path';
import main from "mastodon/main"
import main from "mastodon/main";

import { start } from '../mastodon/common';
import { loadLocale } from '../mastodon/locales';

M config/locales/devise.si.yml => config/locales/devise.si.yml +1 -1
@@ 86,7 86,7 @@ si:
      signed_up_but_locked: ඔබ සාර්ථකව ලියාපදිංචි වී ඇත. කෙසේ වෙතත්, ඔබගේ ගිණුම අගුලු දමා ඇති නිසා අපට ඔබව පුරනය කිරීමට නොහැකි විය.
      signed_up_but_pending: තහවුරු කිරීමේ සබැඳියක් සහිත පණිවිඩයක් ඔබගේ විද්‍යුත් තැපැල් ලිපිනයට යවා ඇත. ඔබ සබැඳිය ක්ලික් කළ පසු, අපි ඔබගේ අයදුම්පත සමාලෝචනය කරන්නෙමු. එය අනුමත වුවහොත් ඔබට දැනුම් දෙනු ලැබේ.
      signed_up_but_unconfirmed: තහවුරු කිරීමේ සබැඳියක් සහිත පණිවිඩයක් ඔබගේ විද්‍යුත් තැපැල් ලිපිනයට යවා ඇත. ඔබගේ ගිණුම සක්‍රිය කිරීමට කරුණාකර සබැඳිය අනුගමනය කරන්න. ඔබට මෙම විද්‍යුත් තැපෑල නොලැබුනේ නම් කරුණාකර ඔබගේ අයාචිත තැපැල් ෆෝල්ඩරය පරීක්ෂා කරන්න.
      update_needs_confirmation: ඔබගේ ගිණුම සාර්ථකව යාවත්කාලීන වුවද අපට නව වි-තැපැල් ලිපිනය තහවුරු කර ගැනීමට වුවමනා කෙරේ. කරුණාකර ඔබගේ වි-තැපෑල පරීක්‍ෂා කර ඊට අදාළ සබැඳිය අනුගමනය කර ඔබගේ නව වි-තැපැල් ලිපිනය තහවුරු කරන්න. ඔබට මෙම වි-තැපෑල නොලැබුණේ නම් කරුණාකර අයාචිත තැපැල් බහාලුම බලන්න.
      update_needs_confirmation: ඔබගේ ගිණුම සාර්ථකව යාවත්කාලීන වුවද අපට නව වි-තැපැල් ලිපිනය සත්‍යාපනය කර ගැනීමට වුවමනා කෙරේ. කරුණාකර ඔබගේ වි-තැපෑල පරීක්‍ෂා කර ඊට අදාළ සබැඳිය අනුගමනය කර ඔබගේ නව වි-තැපැල් ලිපිනය තහවුරු කරන්න. ඔබට මෙම වි-තැපෑල නොලැබුණේ නම් කරුණාකර අයාචිත තැපැල් බහාලුම බලන්න.
      updated: ඔබගේ ගිණුම සාර්ථකව යාවත්කාලීන කර ඇත.
    sessions:
      already_signed_out: සාර්ථකව නික්මිණි.

M config/locales/si.yml => config/locales/si.yml +15 -14
@@ 11,7 11,7 @@ si:
    followers:
      one: අනුගාමිකයා
      other: අනුගාමිකයින්
    following: අනුගමනය
    following: අනුගමන
    instance_actor_flash: මෙම ගිණුම සේවාදායකයම නියෝජනය කිරීමට භාවිතා කරන අතථ්‍ය නළුවෙකු වන අතර කිසිදු තනි පරිශීලකයෙකු නොවේ. එය ෆෙඩරේෂන් අරමුණු සඳහා භාවිතා කරන අතර අත්හිටුවිය යුතු නොවේ.
    last_active: අවසාන ක්රියාකාරී
    link_verified_on: මෙම සබැඳියේ හිමිකාරිත්වය %{date}හි පරීක්ෂා කරන ලදී


@@ 383,7 383,7 @@ si:
      status: තත්‍වය
      suppress: අනුගමනය නිර්දේශය යටපත් කරන්න
      suppressed: යටපත් කළා
      title: නිර්දේශ අනුගමනය කරන්න
      title: අනුගමනයට නිර්දේශ
      unsuppress: නිර්දේශ පිළිපැදීම ප්‍රතිසාධනය කරන්න
    instances:
      availability:


@@ 622,7 622,7 @@ si:
      history: අනුවාද ඉතිහාසය
      language: භාෂාව
      media:
        title: මාධ්‍යය
        title: මාධ්‍ය
      metadata: පාරදත්ත
      no_status_selected: කිසිවක් නොතේරූ බැවින් ලිපි කිසිවක් වෙනස් කර නැත
      open: ලිපිය අරින්න


@@ 788,7 788,7 @@ si:
    localization:
      body: මාස්ටඩන් ස්වේච්ඡාවෙන් පරිවර්තනය කර ඇත.
      guide_link: https://crowdin.com/project/mastodon
      guide_link_text: සෑම කෙනෙකුටම දායක විය හැකිය.
      guide_link_text: පරිවර්තකයින්ට දායක වීමට හැකිය.
    sensitive_content: සංවේදී අන්තර්ගත
  application_mailer:
    notification_preferences: ඊමේල් මනාප වෙනස් කරන්න


@@ 1192,7 1192,7 @@ si:
  relationships:
    activity: ගිණුමේ ක්‍රියාකාරකම්
    dormant: නිදිමතයි
    follow_selected_followers: තෝරාගත් අනුගාමිකයින් අනුගමනය කරන්න
    follow_selected_followers: තේරූ අනුගාමිකයින් අනුගමනය කරන්න
    followers: අනුගාමිකයින්
    following: අනුගමනය
    invited: ආරාධනා කළා


@@ 1202,9 1202,9 @@ si:
    mutual: අන්යෝන්ය
    primary: ප්‍රාථමික
    relationship: සම්බන්ධතාවය
    remove_selected_domains: තෝරාගත් වසම් වලින් සියලුම අනුගාමිකයින් ඉවත් කරන්න
    remove_selected_followers: තෝරාගත් අනුගාමිකයින් ඉවත් කරන්න
    remove_selected_follows: තෝරාගත් පරිශීලකයින් අනුගමනය නොකරන්න
    remove_selected_domains: තේරූ වසම් වල සියලුම අනුගාමිකයින් ඉවත් කරන්න
    remove_selected_followers: තේරූ අනුගාමිකයින් ඉවත් කරන්න
    remove_selected_follows: තේරූ අය අනුගමනය නොකරන්න
    status: ගිණුමේ තත්‍වය
  remote_follow:
    missing_resource: ඔබගේ ගිණුම සඳහා අවශ්‍ය යළි-යොමුවීම් URL එක සොයා ගැනීමට නොහැකි විය


@@ 1280,7 1280,7 @@ si:
    notifications: දැනුම්දීම්
    preferences: අභිප්‍රේත
    profile: ප්‍රසිද්ධ පැතිකඩ
    relationships: අනුගාමිකයින් සහ අනුගාමිකයින්
    relationships: අනුගමන හා අනුගාමික
    statuses_cleanup: ස්වයංක්‍රීය ලිපි මැකීම
    two_factor_authentication: ද්වි සාධක Aut
    webauthn_authentication: ආරක්‍ෂණ යතුරු


@@ 1325,7 1325,7 @@ si:
    title: '%{name}: "%{quote}"'
    visibilities:
      direct: සෘජු
      private: අනුගාමිකයින්-පමණි
      private: අනුගාමිකයින් පමණි
      private_long: අනුගාමිකයින්ට පමණක් පෙන්වන්න
      public: ප්‍රසිද්ධ
      public_long: හැමෝටම පේනවා


@@ 1337,12 1337,13 @@ si:
    ignore_favs: ප්‍රියතමයන් නොසලකන්න
    interaction_exceptions: අන්තර්ක්‍රියා මත පදනම් වූ ව්‍යතිරේක
    keep_direct: සෘජු පණිවිඩ තබාගන්න
    keep_direct_hint: ඔබගේ සෘජු පණිවිඩ කිසිවක් මැකෙන්නේ නැත
    keep_direct_hint: ඔබගේ සෘජු පණිවිඩ කිසිවක් නොමැකෙයි
    keep_media: මාධ්‍ය ඇමුණුම් සහිත ලිපි තබාගන්න
    keep_media_hint: මාධ්‍ය ඇමුණුම් සහිත ඔබගේ ලිපි කිසිවක් මැකෙන්නේ නැත
    keep_media_hint: මාධ්‍ය ඇමුණුම් සහිත ඔබගේ ලිපි කිසිවක් නොමැකෙයි
    keep_pinned: ඇමිණූ ලිපි තබාගන්න
    keep_pinned_hint: ඔබ ඇමිණූ ලිපි කිසිවක් නොමැකෙයි
    keep_polls_hint: ඔබගේ මත විමසුම් මැකෙන්නේ නැත
    keep_polls: මත විමසුම් තබාගන්න
    keep_polls_hint: ඔබගේ මත විමසුම් නොමැකෙයි
    keep_self_bookmark: ඔබ පොත්යොමු තැබූ ලිපි තබාගන්න
    keep_self_bookmark_hint: ඔබගේම ලිපි වලට පොත්යොමු තබා ඇත්නම් ඒවා මකා නොදැමෙයි
    keep_self_fav: ඔබ ප්‍රිය කළ ලිපි තබාගන්න


@@ 1356,7 1357,7 @@ si:
      '604800': සති 1
      '63113904': අවුරුදු 2
      '7889238': මාස 3
    min_age_label: වයස් සීමාව
    min_age_label: කාල සීමාව
    min_favs: අවම වශයෙන් ප්‍රිය කළ ලිපි තබාගන්න
  stream_entries:
    sensitive_content: සංවේදී අන්තර්ගතයකි

M config/locales/simple_form.my.yml => config/locales/simple_form.my.yml +1 -0
@@ 323,6 323,7 @@ my:
        url: URL ဆုံးမှတ်
    'no': မလုပ်ပါ
    not_recommended: ထောက်ခံထားမှုမရှိ
    overridden: ပယ်ဖျက်
    recommended: ထောက်ခံထားပြီး
    required:
      mark: "*"

M config/locales/simple_form.si.yml => config/locales/simple_form.si.yml +5 -2
@@ 90,6 90,8 @@ si:
        fields:
          name: නම්පත
          value: අන්තර්ගතය
        show_collections: අනුගමන හා අනුගාමිකයින් පැතිකඩෙහි පෙන්වන්න
        unlocked: නව අනුගාමිකයින් ස්වයංක්‍රීයව පිළිගන්න
      account_alias:
        acct: පැරණි ගිණුමේ හැසිරවීම
      account_migration:


@@ 118,8 120,9 @@ si:
      appeal:
        text: මෙම තීරණය ආපසු හැරවිය යුත්තේ මන්දැයි පැහැදිලි කරන්න
      defaults:
        autofollow: ඔබගේ ගිණුම අනුගමනය කිරීමට ආරාධනා කරන්න
        autofollow: ඔබගේ ගිණුම අනුගමනයයට ආරාධනා කරන්න
        avatar: පැතිකඩ ඡායාරූපය
        bot: මෙම ගිණුම ස්වයංක්‍රියයි
        chosen_languages: භාෂා පෙරන්න
        confirm_new_password: නව මුරපදය තහවුරු කරන්න
        confirm_password: මුරපදය තහවුරු කරන්න


@@ 140,7 143,7 @@ si:
        otp_attempt: ද්වි සාධක කේතය
        password: මුරපදය
        phrase: මූල පදය හෝ වාක්‍ය ඛණ්ඩය
        setting_advanced_layout: උසස් වෙබ් අතුරු මුහුණත සබල කරන්න
        setting_advanced_layout: සංකීර්ණ අතුරු මුහුණත සබල කරන්න
        setting_always_send_emails: සෑම විටම විද්‍යුත් තැපැල් දැනුම්දීම් යවන්න
        setting_auto_play_gif: සජීවිකරණ GIF ස්වයංක්‍රීයව ධාවනය කරන්න
        setting_default_language: ලිපිවල භාෂාව

M streaming/index.js => streaming/index.js +5 -5
@@ 256,7 256,7 @@ const startServer = async () => {
  CHANNEL_NAMES.forEach(( channel ) => {
    connectedChannels.set({ type: 'websocket', channel }, 0);
    connectedChannels.set({ type: 'eventsource', channel }, 0);
  })
  });

  // Prime the counters so that we don't loose metrics between restarts.
  // Unfortunately counters don't support the set() API, so instead I'm using


@@ 1317,7 1317,7 @@ const startServer = async () => {
      log.verbose(request.requestId, 'Subscription error:', err.toString());
      socket.send(JSON.stringify({ error: err.toString() }));
    });
  }
  };


  const removeSubscription = (subscriptions, channelIds, request) => {


@@ 1337,7 1337,7 @@ const startServer = async () => {
    subscription.stopHeartbeat();

    delete subscriptions[channelIds.join(';')];
  }
  };

  /**
   * @param {WebSocketSession} session


@@ 1357,7 1357,7 @@ const startServer = async () => {
        socket.send(JSON.stringify({ error: "Error unsubscribing from channel" }));
      }
    });
  }
  };

  /**
   * @param {WebSocketSession} session


@@ 1435,7 1435,7 @@ const startServer = async () => {
      const subscriptions = Object.keys(session.subscriptions);

      subscriptions.forEach(channelIds => {
        removeSubscription(session.subscriptions, channelIds.split(';'), req)
        removeSubscription(session.subscriptions, channelIds.split(';'), req);
      });

      // Decrement the metrics for connected clients:

M yarn.lock => yarn.lock +87 -93
@@ 1305,15 1305,10 @@
  dependencies:
    eslint-visitor-keys "^3.3.0"

"@eslint-community/regexpp@^4.5.1":
  version "4.9.0"
  resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.9.0.tgz#7ccb5f58703fa61ffdcbf39e2c604a109e781162"
  integrity sha512-zJmuCWj2VLBt4c25CfBIbMZLGLyhkvs7LznyVX5HfpzeocThgIj5XQK4L+g3U36mMcx8bPMhGyPpwCATamC4jQ==

"@eslint-community/regexpp@^4.6.1":
  version "4.8.1"
  resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.8.1.tgz#8c4bb756cc2aa7eaf13cfa5e69c83afb3260c20c"
  integrity sha512-PWiOzLIUAjN/w5K17PoF4n6sKBw0gqLHPhywmYHP4t1VFQQVYeb1yWsJwnMVEMl3tUHME7X/SJPZLmtG7XBDxQ==
"@eslint-community/regexpp@^4.5.1", "@eslint-community/regexpp@^4.6.1":
  version "4.9.1"
  resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.9.1.tgz#449dfa81a57a1d755b09aa58d826c1262e4283b4"
  integrity sha512-Y27x+MBLjXa+0JWDhykM3+JE+il3kHKAEqabfEWq3SDhZjLYb6/BHL/JKFnH3fe207JaXkyDo685Oc2Glt6ifA==

"@eslint/eslintrc@^2.1.2":
  version "2.1.2"


@@ 1330,10 1325,10 @@
    minimatch "^3.1.2"
    strip-json-comments "^3.1.1"

"@eslint/js@8.50.0":
  version "8.50.0"
  resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.50.0.tgz#9e93b850f0f3fa35f5fa59adfd03adae8488e484"
  integrity sha512-NCC3zz2+nvYd+Ckfh87rA47zfu2QsQpvc6k1yzTk+b9KzRj0wkGa8LSoGOXN6Zv4lRf/EIoZ80biDh9HOI+RNQ==
"@eslint/js@8.51.0":
  version "8.51.0"
  resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.51.0.tgz#6d419c240cfb2b66da37df230f7e7eef801c32fa"
  integrity sha512-HxjQ8Qn+4SI3/AFv6sOrDB+g6PpUTDwSJiQqOrnneEk8L71161srI9gjzzZvYVbzHiVg/BvcH95+cK/zfIt4pg==

"@floating-ui/core@^1.3.1":
  version "1.3.1"


@@ 2386,9 2381,9 @@
  integrity sha512-xrO9OoVPqFuYyR/loIHjnbvvyRZREYKLjxV4+dY6v3FQR3stQ9ZxIGkaclF7YhI9hfjpuTbu14hZEy94qKLtOA==

"@types/react-dom@^18.0.0", "@types/react-dom@^18.2.4":
  version "18.2.8"
  resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-18.2.8.tgz#338f1b0a646c9f10e0a97208c1d26b9f473dffd6"
  integrity sha512-bAIvO5lN/U8sPGvs1Xm61rlRHHaq5rp5N3kp9C+NJ/Q41P8iqjkXSu0+/qu8POsjH9pNWb0OYabFez7taP7omw==
  version "18.2.11"
  resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-18.2.11.tgz#4332c315544698a0875dfdb6e320dda59e1b3d58"
  integrity sha512-zq6Dy0EiCuF9pWFW6I6k6W2LdpUixLE4P6XjXU1QHLfak3GPACQfLwEuHzY5pOYa4hzj1d0GxX/P141aFjZsyg==
  dependencies:
    "@types/react" "*"



@@ 2488,9 2483,9 @@
    "@types/react" "*"

"@types/react@*", "@types/react@16 || 17 || 18", "@types/react@>=16.9.11", "@types/react@^18.0.26", "@types/react@^18.2.7":
  version "18.2.24"
  resolved "https://registry.yarnpkg.com/@types/react/-/react-18.2.24.tgz#3c7d68c02e0205a472f04abe4a0c1df35d995c05"
  integrity sha512-Ee0Jt4sbJxMu1iDcetZEIKQr99J1Zfb6D4F3qfUWoR1JpInkY1Wdg4WwCyBjL257D0+jGqSl1twBjV8iCaC0Aw==
  version "18.2.25"
  resolved "https://registry.yarnpkg.com/@types/react/-/react-18.2.25.tgz#99fa44154132979e870ff409dc5b6e67f06f0199"
  integrity sha512-24xqse6+VByVLIr+xWaQ9muX1B4bXJKXBbjszbld/UEDslGLY53+ZucF44HCmLbMPejTzGG9XgR+3m2/Wqu1kw==
  dependencies:
    "@types/prop-types" "*"
    "@types/scheduler" "*"


@@ 2581,14 2576,14 @@
  integrity sha512-EwmlvuaxPNej9+T4v5AuBPJa2x2UOJVdjCtDHgcDqitUeOtjnJKJ+apYjVcAoBEMjKW1VVFGZLUb5+qqa09XFA==

"@types/uuid@^9.0.0":
  version "9.0.4"
  resolved "https://registry.yarnpkg.com/@types/uuid/-/uuid-9.0.4.tgz#e884a59338da907bda8d2ed03e01c5c49d036f1c"
  integrity sha512-zAuJWQflfx6dYJM62vna+Sn5aeSWhh3OB+wfUEACNcqUSc0AGc5JKl+ycL1vrH7frGTXhJchYjE1Hak8L819dA==
  version "9.0.5"
  resolved "https://registry.yarnpkg.com/@types/uuid/-/uuid-9.0.5.tgz#25a71eb73eba95ac0e559ff3dd018fc08294acf6"
  integrity sha512-xfHdwa1FMJ082prjSJpoEI57GZITiQz10r3vEJCHa2khEFQjKy91aWKz6+zybzssCvXUwE1LQWgWVwZ4nYUvHQ==

"@types/warning@^3.0.0":
  version "3.0.0"
  resolved "https://registry.yarnpkg.com/@types/warning/-/warning-3.0.0.tgz#0d2501268ad8f9962b740d387c4654f5f8e23e52"
  integrity sha512-t/Tvs5qR47OLOr+4E9ckN8AmP2Tf16gWq+/qA4iUGS/OOyHVO8wv2vjJuX8SNOUTJyWb+2t7wJm6cXILFnOROA==
  version "3.0.1"
  resolved "https://registry.yarnpkg.com/@types/warning/-/warning-3.0.1.tgz#a62d1d2b7f34376da84ee0afe0145152e62b9699"
  integrity sha512-ywJmriP+nvjBKNBEMaNZgj2irZHoxcKeYcyMLbqhYKbDVn8yCIULy2Ol/tvIb37O3IBeZj3RU4tXqQTtGwoAMg==

"@types/webpack-sources@*":
  version "3.2.1"


@@ 2617,22 2612,22 @@
  integrity sha512-axdPBuLuEJt0c4yI5OZssC19K2Mq1uKdrfZBzuxLvaztgqUtFYZUNw7lETExPYJR9jdEoIg4mb7RQKRQzOkeGQ==

"@types/yargs@^17.0.24", "@types/yargs@^17.0.8":
  version "17.0.26"
  resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-17.0.26.tgz#388e5002a8b284ad7b4599ba89920a6d74d8d79a"
  integrity sha512-Y3vDy2X6zw/ZCumcwLpdhM5L7jmyGpmBCTYMHDLqT2IKVMYRRLdv6ZakA+wxhra6Z/3bwhNbNl9bDGXaFU+6rw==
  version "17.0.28"
  resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-17.0.28.tgz#d106e4301fbacde3d1796ab27374dd16588ec851"
  integrity sha512-N3e3fkS86hNhtk6BEnc0rj3zcehaxx8QWhCROJkqpl5Zaoi7nAic3jH8q94jVD3zu5LGk+PUB6KAiDmimYOEQw==
  dependencies:
    "@types/yargs-parser" "*"

"@typescript-eslint/eslint-plugin@^6.0.0":
  version "6.7.3"
  resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.7.3.tgz#d98046e9f7102d49a93d944d413c6055c47fafd7"
  integrity sha512-vntq452UHNltxsaaN+L9WyuMch8bMd9CqJ3zhzTPXXidwbf5mqqKCVXEuvRZUqLJSTLeWE65lQwyXsRGnXkCTA==
  version "6.7.4"
  resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.7.4.tgz#057338df21b6062c2f2fc5999fbea8af9973ac6d"
  integrity sha512-DAbgDXwtX+pDkAHwiGhqP3zWUGpW49B7eqmgpPtg+BKJXwdct79ut9+ifqOFPJGClGKSHXn2PTBatCnldJRUoA==
  dependencies:
    "@eslint-community/regexpp" "^4.5.1"
    "@typescript-eslint/scope-manager" "6.7.3"
    "@typescript-eslint/type-utils" "6.7.3"
    "@typescript-eslint/utils" "6.7.3"
    "@typescript-eslint/visitor-keys" "6.7.3"
    "@typescript-eslint/scope-manager" "6.7.4"
    "@typescript-eslint/type-utils" "6.7.4"
    "@typescript-eslint/utils" "6.7.4"
    "@typescript-eslint/visitor-keys" "6.7.4"
    debug "^4.3.4"
    graphemer "^1.4.0"
    ignore "^5.2.4"


@@ 2641,31 2636,31 @@
    ts-api-utils "^1.0.1"

"@typescript-eslint/parser@^6.0.0":
  version "6.7.3"
  resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-6.7.3.tgz#aaf40092a32877439e5957e18f2d6a91c82cc2fd"
  integrity sha512-TlutE+iep2o7R8Lf+yoer3zU6/0EAUc8QIBB3GYBc1KGz4c4TRm83xwXUZVPlZ6YCLss4r77jbu6j3sendJoiQ==
  dependencies:
    "@typescript-eslint/scope-manager" "6.7.3"
    "@typescript-eslint/types" "6.7.3"
    "@typescript-eslint/typescript-estree" "6.7.3"
    "@typescript-eslint/visitor-keys" "6.7.3"
  version "6.7.4"
  resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-6.7.4.tgz#23d1dd4fe5d295c7fa2ab651f5406cd9ad0bd435"
  integrity sha512-I5zVZFY+cw4IMZUeNCU7Sh2PO5O57F7Lr0uyhgCJmhN/BuTlnc55KxPonR4+EM3GBdfiCyGZye6DgMjtubQkmA==
  dependencies:
    "@typescript-eslint/scope-manager" "6.7.4"
    "@typescript-eslint/types" "6.7.4"
    "@typescript-eslint/typescript-estree" "6.7.4"
    "@typescript-eslint/visitor-keys" "6.7.4"
    debug "^4.3.4"

"@typescript-eslint/scope-manager@6.7.3":
  version "6.7.3"
  resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-6.7.3.tgz#07e5709c9bdae3eaf216947433ef97b3b8b7d755"
  integrity sha512-wOlo0QnEou9cHO2TdkJmzF7DFGvAKEnB82PuPNHpT8ZKKaZu6Bm63ugOTn9fXNJtvuDPanBc78lGUGGytJoVzQ==
"@typescript-eslint/scope-manager@6.7.4":
  version "6.7.4"
  resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-6.7.4.tgz#a484a17aa219e96044db40813429eb7214d7b386"
  integrity sha512-SdGqSLUPTXAXi7c3Ob7peAGVnmMoGzZ361VswK2Mqf8UOYcODiYvs8rs5ILqEdfvX1lE7wEZbLyELCW+Yrql1A==
  dependencies:
    "@typescript-eslint/types" "6.7.3"
    "@typescript-eslint/visitor-keys" "6.7.3"
    "@typescript-eslint/types" "6.7.4"
    "@typescript-eslint/visitor-keys" "6.7.4"

"@typescript-eslint/type-utils@6.7.3":
  version "6.7.3"
  resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-6.7.3.tgz#c2c165c135dda68a5e70074ade183f5ad68f3400"
  integrity sha512-Fc68K0aTDrKIBvLnKTZ5Pf3MXK495YErrbHb1R6aTpfK5OdSFj0rVN7ib6Tx6ePrZ2gsjLqr0s98NG7l96KSQw==
"@typescript-eslint/type-utils@6.7.4":
  version "6.7.4"
  resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-6.7.4.tgz#847cd3b59baf948984499be3e0a12ff07373e321"
  integrity sha512-n+g3zi1QzpcAdHFP9KQF+rEFxMb2KxtnJGID3teA/nxKHOVi3ylKovaqEzGBbVY2pBttU6z85gp0D00ufLzViQ==
  dependencies:
    "@typescript-eslint/typescript-estree" "6.7.3"
    "@typescript-eslint/utils" "6.7.3"
    "@typescript-eslint/typescript-estree" "6.7.4"
    "@typescript-eslint/utils" "6.7.4"
    debug "^4.3.4"
    ts-api-utils "^1.0.1"



@@ 2674,10 2669,10 @@
  resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.62.0.tgz#258607e60effa309f067608931c3df6fed41fd2f"
  integrity sha512-87NVngcbVXUahrRTqIK27gD2t5Cu1yuCXxbLcFtCzZGlfyVWWh8mLHkoxzjsB6DDNnvdL+fW8MiwPEJyGJQDgQ==

"@typescript-eslint/types@6.7.3":
  version "6.7.3"
  resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-6.7.3.tgz#0402b5628a63f24f2dc9d4a678e9a92cc50ea3e9"
  integrity sha512-4g+de6roB2NFcfkZb439tigpAMnvEIg3rIjWQ+EM7IBaYt/CdJt6em9BJ4h4UpdgaBWdmx2iWsafHTrqmgIPNw==
"@typescript-eslint/types@6.7.4":
  version "6.7.4"
  resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-6.7.4.tgz#5d358484d2be986980c039de68e9f1eb62ea7897"
  integrity sha512-o9XWK2FLW6eSS/0r/tgjAGsYasLAnOWg7hvZ/dGYSSNjCh+49k5ocPN8OmG5aZcSJ8pclSOyVKP2x03Sj+RrCA==

"@typescript-eslint/typescript-estree@5.62.0":
  version "5.62.0"


@@ 2692,30 2687,30 @@
    semver "^7.3.7"
    tsutils "^3.21.0"

"@typescript-eslint/typescript-estree@6.7.3":
  version "6.7.3"
  resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-6.7.3.tgz#ec5bb7ab4d3566818abaf0e4a8fa1958561b7279"
  integrity sha512-YLQ3tJoS4VxLFYHTw21oe1/vIZPRqAO91z6Uv0Ss2BKm/Ag7/RVQBcXTGcXhgJMdA4U+HrKuY5gWlJlvoaKZ5g==
"@typescript-eslint/typescript-estree@6.7.4":
  version "6.7.4"
  resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-6.7.4.tgz#f2baece09f7bb1df9296e32638b2e1130014ef1a"
  integrity sha512-ty8b5qHKatlNYd9vmpHooQz3Vki3gG+3PchmtsA4TgrZBKWHNjWfkQid7K7xQogBqqc7/BhGazxMD5vr6Ha+iQ==
  dependencies:
    "@typescript-eslint/types" "6.7.3"
    "@typescript-eslint/visitor-keys" "6.7.3"
    "@typescript-eslint/types" "6.7.4"
    "@typescript-eslint/visitor-keys" "6.7.4"
    debug "^4.3.4"
    globby "^11.1.0"
    is-glob "^4.0.3"
    semver "^7.5.4"
    ts-api-utils "^1.0.1"

"@typescript-eslint/utils@6.7.3":
  version "6.7.3"
  resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-6.7.3.tgz#96c655816c373135b07282d67407cb577f62e143"
  integrity sha512-vzLkVder21GpWRrmSR9JxGZ5+ibIUSudXlW52qeKpzUEQhRSmyZiVDDj3crAth7+5tmN1ulvgKaCU2f/bPRCzg==
"@typescript-eslint/utils@6.7.4":
  version "6.7.4"
  resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-6.7.4.tgz#2236f72b10e38277ee05ef06142522e1de470ff2"
  integrity sha512-PRQAs+HUn85Qdk+khAxsVV+oULy3VkbH3hQ8hxLRJXWBEd7iI+GbQxH5SEUSH7kbEoTp6oT1bOwyga24ELALTA==
  dependencies:
    "@eslint-community/eslint-utils" "^4.4.0"
    "@types/json-schema" "^7.0.12"
    "@types/semver" "^7.5.0"
    "@typescript-eslint/scope-manager" "6.7.3"
    "@typescript-eslint/types" "6.7.3"
    "@typescript-eslint/typescript-estree" "6.7.3"
    "@typescript-eslint/scope-manager" "6.7.4"
    "@typescript-eslint/types" "6.7.4"
    "@typescript-eslint/typescript-estree" "6.7.4"
    semver "^7.5.4"

"@typescript-eslint/visitor-keys@5.62.0":


@@ 2726,12 2721,12 @@
    "@typescript-eslint/types" "5.62.0"
    eslint-visitor-keys "^3.3.0"

"@typescript-eslint/visitor-keys@6.7.3":
  version "6.7.3"
  resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-6.7.3.tgz#83809631ca12909bd2083558d2f93f5747deebb2"
  integrity sha512-HEVXkU9IB+nk9o63CeICMHxFWbHWr3E1mpilIQBe9+7L/lH97rleFLVtYsfnWB+JVMaiFnEaxvknvmIzX+CqVg==
"@typescript-eslint/visitor-keys@6.7.4":
  version "6.7.4"
  resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-6.7.4.tgz#80dfecf820fc67574012375859085f91a4dff043"
  integrity sha512-pOW37DUhlTZbvph50x5zZCkFn3xzwkGtNoJHzIM3svpiSkJzwOYr/kVBaXmf+RAQiUDs1AHEZVNPg6UJCJpwRA==
  dependencies:
    "@typescript-eslint/types" "6.7.3"
    "@typescript-eslint/types" "6.7.4"
    eslint-visitor-keys "^3.4.1"

"@webassemblyjs/ast@1.9.0":


@@ 5533,14 5528,14 @@ eslint-visitor-keys@^3.3.0, eslint-visitor-keys@^3.4.1, eslint-visitor-keys@^3.4
  integrity sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==

eslint@^8.41.0:
  version "8.50.0"
  resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.50.0.tgz#2ae6015fee0240fcd3f83e1e25df0287f487d6b2"
  integrity sha512-FOnOGSuFuFLv/Sa+FDVRZl4GGVAAFFi8LecRsI5a1tMO5HIE8nCm4ivAlzt4dT3ol/PaaGC0rJEEXQmHJBGoOg==
  version "8.51.0"
  resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.51.0.tgz#4a82dae60d209ac89a5cff1604fea978ba4950f3"
  integrity sha512-2WuxRZBrlwnXi+/vFSJyjMqrNjtJqiasMzehF0shoLaW7DzS3/9Yvrmq5JiT66+pNjiX4UBnLDiKHcWAr/OInA==
  dependencies:
    "@eslint-community/eslint-utils" "^4.2.0"
    "@eslint-community/regexpp" "^4.6.1"
    "@eslint/eslintrc" "^2.1.2"
    "@eslint/js" "8.50.0"
    "@eslint/js" "8.51.0"
    "@humanwhocodes/config-array" "^0.11.11"
    "@humanwhocodes/module-importer" "^1.0.1"
    "@nodelib/fs.walk" "^1.2.8"


@@ 6016,15 6011,15 @@ findup-sync@^3.0.0:
    resolve-dir "^1.0.1"

flat-cache@^3.0.4:
  version "3.1.0"
  resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-3.1.0.tgz#0e54ab4a1a60fe87e2946b6b00657f1c99e1af3f"
  integrity sha512-OHx4Qwrrt0E4jEIcI5/Xb+f+QmJYNj2rrK8wiIdQOIrB9WrrJL8cjZvXdXuBTkkEwEqLycb5BeZDV1o2i9bTew==
  version "3.1.1"
  resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-3.1.1.tgz#a02a15fdec25a8f844ff7cc658f03dd99eb4609b"
  integrity sha512-/qM2b3LUIaIgviBQovTLvijfyOQXPtSRnRK26ksj2J7rzPIecePUIpJsZ4T02Qg+xiAEKIs5K8dsHEd+VaKa/Q==
  dependencies:
    flatted "^3.2.7"
    flatted "^3.2.9"
    keyv "^4.5.3"
    rimraf "^3.0.2"

flatted@^3.2.7:
flatted@^3.2.9:
  version "3.2.9"
  resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.2.9.tgz#7eb4c67ca1ba34232ca9d2d93e9886e611ad7daf"
  integrity sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ==


@@ 6323,9 6318,9 @@ globals@^11.1.0:
  integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==

globals@^13.19.0:
  version "13.22.0"
  resolved "https://registry.yarnpkg.com/globals/-/globals-13.22.0.tgz#0c9fcb9c48a2494fbb5edbfee644285543eba9d8"
  integrity sha512-H1Ddc/PbZHTDVJSnj8kWptIRSD6AM3pK+mKytuIVF4uoBV7rshFlhhvA58ceJ5wp3Er58w6zj7bykMpYXt3ETw==
  version "13.23.0"
  resolved "https://registry.yarnpkg.com/globals/-/globals-13.23.0.tgz#ef31673c926a0976e1f61dab4dca57e0c0a8af02"
  integrity sha512-XAmF0RjlrjY23MA51q3HltdlGxUpXPvg0GioKiD9X6HD28iMjo2dKC8Vqwm7lne4GNr78+RHTfliktR6ZH09wA==
  dependencies:
    type-fest "^0.20.2"



@@ 8034,9 8029,9 @@ keycode@^2.1.7:
  integrity sha512-Rdgz9Hl9Iv4QKi8b0OlCRQEzp4AgVxyCtz5S/+VIHezDmrDhkp2N2TqBWOLz0/gbeREXOOiI9/4b8BY9uw2vFg==

keyv@^4.5.3:
  version "4.5.3"
  resolved "https://registry.yarnpkg.com/keyv/-/keyv-4.5.3.tgz#00873d2b046df737963157bd04f294ca818c9c25"
  integrity sha512-QCiSav9WaX1PgETJ+SpNnx2PRRapJ/oRSXM4VO5OGYGSjrxbKPVFVhB3l2OCbLCk329N8qyAtsJjSjvVBWzEug==
  version "4.5.4"
  resolved "https://registry.yarnpkg.com/keyv/-/keyv-4.5.4.tgz#a879a99e29452f942439f2a405e3af8b31d4de93"
  integrity sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==
  dependencies:
    json-buffer "3.0.1"



@@ 11493,7 11488,6 @@ stringz@^2.1.0:
    char-regex "^1.0.2"

"strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@^6.0.0, strip-ansi@^6.0.1:
  name strip-ansi-cjs
  version "6.0.1"
  resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
  integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==