diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 7fb8999e2..90c856e40 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -57,7 +57,7 @@ lint-sass: jest: stage: test - script: yarn test:coverage + script: yarn test:coverage --runInBand only: changes: - "**/*.js" diff --git a/app/soapbox/actions/__tests__/account-notes.test.ts b/app/soapbox/actions/__tests__/account-notes.test.ts index 134b0abc7..61e0c20b0 100644 --- a/app/soapbox/actions/__tests__/account-notes.test.ts +++ b/app/soapbox/actions/__tests__/account-notes.test.ts @@ -1,18 +1,20 @@ import { Map as ImmutableMap } from 'immutable'; import { __stub } from 'soapbox/api'; -import { mockStore } from 'soapbox/jest/test-helpers'; -import rootReducer from 'soapbox/reducers'; +import { mockStore, rootState } from 'soapbox/jest/test-helpers'; +import { ReducerRecord, EditRecord } from 'soapbox/reducers/account_notes'; -import { normalizeAccount } from '../../normalizers'; +import { normalizeAccount, normalizeRelationship } from '../../normalizers'; import { changeAccountNoteComment, initAccountNoteModal, submitAccountNote } from '../account-notes'; +import type { Account } from 'soapbox/types/entities'; + describe('submitAccountNote()', () => { - let store; + let store: ReturnType; beforeEach(() => { - const state = rootReducer(undefined, {}) - .set('account_notes', { edit: { account: 1, comment: 'hello' } }); + const state = rootState + .set('account_notes', ReducerRecord({ edit: EditRecord({ account: '1', comment: 'hello' }) })); store = mockStore(state); }); @@ -60,11 +62,11 @@ describe('submitAccountNote()', () => { }); describe('initAccountNoteModal()', () => { - let store; + let store: ReturnType; beforeEach(() => { - const state = rootReducer(undefined, {}) - .set('relationships', ImmutableMap({ 1: { note: 'hello' } })); + const state = rootState + .set('relationships', ImmutableMap({ '1': normalizeRelationship({ note: 'hello' }) })); store = mockStore(state); }); @@ -75,7 +77,7 @@ describe('initAccountNoteModal()', () => { display_name: 'Justin L', avatar: 'test.jpg', verified: true, - }); + }) as Account; const expectedActions = [ { type: 'ACCOUNT_NOTE_INIT_MODAL', account, comment: 'hello' }, { type: 'MODAL_OPEN', modalType: 'ACCOUNT_NOTE' }, @@ -88,10 +90,10 @@ describe('initAccountNoteModal()', () => { }); describe('changeAccountNoteComment()', () => { - let store; + let store: ReturnType; beforeEach(() => { - const state = rootReducer(undefined, {}); + const state = rootState; store = mockStore(state); }); diff --git a/app/soapbox/actions/__tests__/accounts.test.ts b/app/soapbox/actions/__tests__/accounts.test.ts index dcfeabcf1..0793e36f7 100644 --- a/app/soapbox/actions/__tests__/accounts.test.ts +++ b/app/soapbox/actions/__tests__/accounts.test.ts @@ -1,10 +1,10 @@ import { Map as ImmutableMap } from 'immutable'; import { __stub } from 'soapbox/api'; -import { mockStore } from 'soapbox/jest/test-helpers'; -import rootReducer from 'soapbox/reducers'; +import { mockStore, rootState } from 'soapbox/jest/test-helpers'; +import { ListRecord, ReducerRecord } from 'soapbox/reducers/user_lists'; -import { normalizeAccount } from '../../normalizers'; +import { normalizeAccount, normalizeInstance, normalizeRelationship } from '../../normalizers'; import { authorizeFollowRequest, blockAccount, @@ -28,7 +28,7 @@ import { unsubscribeAccount, } from '../accounts'; -let store; +let store: ReturnType; describe('createAccount()', () => { const params = { @@ -37,7 +37,7 @@ describe('createAccount()', () => { describe('with a successful API request', () => { beforeEach(() => { - const state = rootReducer(undefined, {}); + const state = rootState; store = mockStore(state); __stub((mock) => { @@ -74,10 +74,10 @@ describe('fetchAccount()', () => { avatar: 'test.jpg', }); - const state = rootReducer(undefined, {}) + const state = rootState .set('accounts', ImmutableMap({ [id]: account, - })); + }) as any); store = mockStore(state); @@ -98,7 +98,7 @@ describe('fetchAccount()', () => { const account = require('soapbox/__fixtures__/pleroma-account.json'); beforeEach(() => { - const state = rootReducer(undefined, {}); + const state = rootState; store = mockStore(state); __stub((mock) => { @@ -125,7 +125,7 @@ describe('fetchAccount()', () => { describe('with an unsuccessful API request', () => { beforeEach(() => { - const state = rootReducer(undefined, {}); + const state = rootState; store = mockStore(state); __stub((mock) => { @@ -155,7 +155,7 @@ describe('fetchAccount()', () => { describe('fetchAccountByUsername()', () => { const id = '123'; const username = 'tiger'; - let state, account; + let state, account: any; beforeEach(() => { account = normalizeAccount({ @@ -166,7 +166,7 @@ describe('fetchAccountByUsername()', () => { birthday: undefined, }); - state = rootReducer(undefined, {}) + state = rootState .set('accounts', ImmutableMap({ [id]: account, })); @@ -180,15 +180,15 @@ describe('fetchAccountByUsername()', () => { describe('when "accountByUsername" feature is enabled', () => { beforeEach(() => { - const state = rootReducer(undefined, {}) - .set('instance', { + const state = rootState + .set('instance', normalizeInstance({ version: '2.7.2 (compatible; Pleroma 2.4.52-1337-g4779199e.gleasonator+soapbox)', pleroma: ImmutableMap({ metadata: ImmutableMap({ features: [], }), }), - }) + })) .set('me', '123'); store = mockStore(state); }); @@ -243,15 +243,15 @@ describe('fetchAccountByUsername()', () => { describe('when "accountLookup" feature is enabled', () => { beforeEach(() => { - const state = rootReducer(undefined, {}) - .set('instance', { + const state = rootState + .set('instance', normalizeInstance({ version: '3.4.1 (compatible; TruthSocial 1.0.0)', pleroma: ImmutableMap({ metadata: ImmutableMap({ features: [], }), }), - }) + })) .set('me', '123'); store = mockStore(state); }); @@ -308,7 +308,7 @@ describe('fetchAccountByUsername()', () => { describe('when using the accountSearch function', () => { beforeEach(() => { - const state = rootReducer(undefined, {}).set('me', '123'); + const state = rootState.set('me', '123'); store = mockStore(state); }); @@ -373,12 +373,12 @@ describe('fetchAccountByUsername()', () => { describe('followAccount()', () => { describe('when logged out', () => { beforeEach(() => { - const state = rootReducer(undefined, {}).set('me', null); + const state = rootState.set('me', null); store = mockStore(state); }); it('should do nothing', async() => { - await store.dispatch(followAccount(1)); + await store.dispatch(followAccount('1')); const actions = store.getActions(); expect(actions).toEqual([]); @@ -386,10 +386,10 @@ describe('followAccount()', () => { }); describe('when logged in', () => { - const id = 1; + const id = '1'; beforeEach(() => { - const state = rootReducer(undefined, {}).set('me', '123'); + const state = rootState.set('me', '123'); store = mockStore(state); }); @@ -460,12 +460,12 @@ describe('followAccount()', () => { describe('unfollowAccount()', () => { describe('when logged out', () => { beforeEach(() => { - const state = rootReducer(undefined, {}).set('me', null); + const state = rootState.set('me', null); store = mockStore(state); }); it('should do nothing', async() => { - await store.dispatch(unfollowAccount(1)); + await store.dispatch(unfollowAccount('1')); const actions = store.getActions(); expect(actions).toEqual([]); @@ -473,10 +473,10 @@ describe('unfollowAccount()', () => { }); describe('when logged in', () => { - const id = 1; + const id = '1'; beforeEach(() => { - const state = rootReducer(undefined, {}).set('me', '123'); + const state = rootState.set('me', '123'); store = mockStore(state); }); @@ -489,7 +489,7 @@ describe('unfollowAccount()', () => { it('should dispatch the correct actions', async() => { const expectedActions = [ - { type: 'ACCOUNT_UNFOLLOW_REQUEST', id: 1, skipLoading: true }, + { type: 'ACCOUNT_UNFOLLOW_REQUEST', id: '1', skipLoading: true }, { type: 'ACCOUNT_UNFOLLOW_SUCCESS', relationship: { success: true }, @@ -534,11 +534,11 @@ describe('unfollowAccount()', () => { }); describe('blockAccount()', () => { - const id = 1; + const id = '1'; describe('when logged out', () => { beforeEach(() => { - const state = rootReducer(undefined, {}).set('me', null); + const state = rootState.set('me', null); store = mockStore(state); }); @@ -552,7 +552,7 @@ describe('blockAccount()', () => { describe('when logged in', () => { beforeEach(() => { - const state = rootReducer(undefined, {}).set('me', '123'); + const state = rootState.set('me', '123'); store = mockStore(state); }); @@ -601,11 +601,11 @@ describe('blockAccount()', () => { }); describe('unblockAccount()', () => { - const id = 1; + const id = '1'; describe('when logged out', () => { beforeEach(() => { - const state = rootReducer(undefined, {}).set('me', null); + const state = rootState.set('me', null); store = mockStore(state); }); @@ -619,7 +619,7 @@ describe('unblockAccount()', () => { describe('when logged in', () => { beforeEach(() => { - const state = rootReducer(undefined, {}).set('me', '123'); + const state = rootState.set('me', '123'); store = mockStore(state); }); @@ -667,11 +667,11 @@ describe('unblockAccount()', () => { }); describe('muteAccount()', () => { - const id = 1; + const id = '1'; describe('when logged out', () => { beforeEach(() => { - const state = rootReducer(undefined, {}).set('me', null); + const state = rootState.set('me', null); store = mockStore(state); }); @@ -685,7 +685,7 @@ describe('muteAccount()', () => { describe('when logged in', () => { beforeEach(() => { - const state = rootReducer(undefined, {}).set('me', '123'); + const state = rootState.set('me', '123'); store = mockStore(state); }); @@ -734,11 +734,11 @@ describe('muteAccount()', () => { }); describe('unmuteAccount()', () => { - const id = 1; + const id = '1'; describe('when logged out', () => { beforeEach(() => { - const state = rootReducer(undefined, {}).set('me', null); + const state = rootState.set('me', null); store = mockStore(state); }); @@ -752,7 +752,7 @@ describe('unmuteAccount()', () => { describe('when logged in', () => { beforeEach(() => { - const state = rootReducer(undefined, {}).set('me', '123'); + const state = rootState.set('me', '123'); store = mockStore(state); }); @@ -800,11 +800,11 @@ describe('unmuteAccount()', () => { }); describe('subscribeAccount()', () => { - const id = 1; + const id = '1'; describe('when logged out', () => { beforeEach(() => { - const state = rootReducer(undefined, {}).set('me', null); + const state = rootState.set('me', null); store = mockStore(state); }); @@ -818,7 +818,7 @@ describe('subscribeAccount()', () => { describe('when logged in', () => { beforeEach(() => { - const state = rootReducer(undefined, {}).set('me', '123'); + const state = rootState.set('me', '123'); store = mockStore(state); }); @@ -866,11 +866,11 @@ describe('subscribeAccount()', () => { }); describe('unsubscribeAccount()', () => { - const id = 1; + const id = '1'; describe('when logged out', () => { beforeEach(() => { - const state = rootReducer(undefined, {}).set('me', null); + const state = rootState.set('me', null); store = mockStore(state); }); @@ -884,7 +884,7 @@ describe('unsubscribeAccount()', () => { describe('when logged in', () => { beforeEach(() => { - const state = rootReducer(undefined, {}).set('me', '123'); + const state = rootState.set('me', '123'); store = mockStore(state); }); @@ -936,7 +936,7 @@ describe('removeFromFollowers()', () => { describe('when logged out', () => { beforeEach(() => { - const state = rootReducer(undefined, {}).set('me', null); + const state = rootState.set('me', null); store = mockStore(state); }); @@ -950,7 +950,7 @@ describe('removeFromFollowers()', () => { describe('when logged in', () => { beforeEach(() => { - const state = rootReducer(undefined, {}).set('me', '123'); + const state = rootState.set('me', '123'); store = mockStore(state); }); @@ -1002,7 +1002,7 @@ describe('fetchFollowers()', () => { describe('when logged in', () => { beforeEach(() => { - const state = rootReducer(undefined, {}).set('me', '123'); + const state = rootState.set('me', '123'); store = mockStore(state); }); @@ -1059,7 +1059,7 @@ describe('expandFollowers()', () => { describe('when logged out', () => { beforeEach(() => { - const state = rootReducer(undefined, {}).set('me', null); + const state = rootState.set('me', null); store = mockStore(state); }); @@ -1073,28 +1073,28 @@ describe('expandFollowers()', () => { describe('when logged in', () => { beforeEach(() => { - const state = rootReducer(undefined, {}) - .set('user_lists', { + const state = rootState + .set('user_lists', ReducerRecord({ followers: ImmutableMap({ - [id]: { + [id]: ListRecord({ next: 'next_url', - }, + }), }), - }) + })) .set('me', '123'); store = mockStore(state); }); describe('when the url is null', () => { beforeEach(() => { - const state = rootReducer(undefined, {}) - .set('user_lists', { + const state = rootState + .set('user_lists', ReducerRecord({ followers: ImmutableMap({ - [id]: { + [id]: ListRecord({ next: null, - }, + }), }), - }) + })) .set('me', '123'); store = mockStore(state); }); @@ -1160,7 +1160,7 @@ describe('fetchFollowing()', () => { describe('when logged in', () => { beforeEach(() => { - const state = rootReducer(undefined, {}).set('me', '123'); + const state = rootState.set('me', '123'); store = mockStore(state); }); @@ -1217,7 +1217,7 @@ describe('expandFollowing()', () => { describe('when logged out', () => { beforeEach(() => { - const state = rootReducer(undefined, {}).set('me', null); + const state = rootState.set('me', null); store = mockStore(state); }); @@ -1231,28 +1231,28 @@ describe('expandFollowing()', () => { describe('when logged in', () => { beforeEach(() => { - const state = rootReducer(undefined, {}) - .set('user_lists', { + const state = rootState + .set('user_lists', ReducerRecord({ following: ImmutableMap({ - [id]: { + [id]: ListRecord({ next: 'next_url', - }, + }), }), - }) + })) .set('me', '123'); store = mockStore(state); }); describe('when the url is null', () => { beforeEach(() => { - const state = rootReducer(undefined, {}) - .set('user_lists', { + const state = rootState + .set('user_lists', ReducerRecord({ following: ImmutableMap({ - [id]: { + [id]: ListRecord({ next: null, - }, + }), }), - }) + })) .set('me', '123'); store = mockStore(state); }); @@ -1318,7 +1318,7 @@ describe('fetchRelationships()', () => { describe('when logged out', () => { beforeEach(() => { - const state = rootReducer(undefined, {}).set('me', null); + const state = rootState.set('me', null); store = mockStore(state); }); @@ -1332,15 +1332,15 @@ describe('fetchRelationships()', () => { describe('when logged in', () => { beforeEach(() => { - const state = rootReducer(undefined, {}) + const state = rootState .set('me', '123'); store = mockStore(state); }); describe('without newAccountIds', () => { beforeEach(() => { - const state = rootReducer(undefined, {}) - .set('relationships', ImmutableMap({ [id]: {} })) + const state = rootState + .set('relationships', ImmutableMap({ [id]: normalizeRelationship({}) })) .set('me', '123'); store = mockStore(state); }); @@ -1355,7 +1355,7 @@ describe('fetchRelationships()', () => { describe('with a successful API request', () => { beforeEach(() => { - const state = rootReducer(undefined, {}) + const state = rootState .set('relationships', ImmutableMap({})) .set('me', '123'); store = mockStore(state); @@ -1409,7 +1409,7 @@ describe('fetchRelationships()', () => { describe('fetchFollowRequests()', () => { describe('when logged out', () => { beforeEach(() => { - const state = rootReducer(undefined, {}).set('me', null); + const state = rootState.set('me', null); store = mockStore(state); }); @@ -1423,14 +1423,14 @@ describe('fetchFollowRequests()', () => { describe('when logged in', () => { beforeEach(() => { - const state = rootReducer(undefined, {}) + const state = rootState .set('me', '123'); store = mockStore(state); }); describe('with a successful API request', () => { beforeEach(() => { - const state = rootReducer(undefined, {}) + const state = rootState .set('relationships', ImmutableMap({})) .set('me', '123'); store = mockStore(state); @@ -1483,7 +1483,7 @@ describe('fetchFollowRequests()', () => { describe('expandFollowRequests()', () => { describe('when logged out', () => { beforeEach(() => { - const state = rootReducer(undefined, {}).set('me', null); + const state = rootState.set('me', null); store = mockStore(state); }); @@ -1497,24 +1497,24 @@ describe('expandFollowRequests()', () => { describe('when logged in', () => { beforeEach(() => { - const state = rootReducer(undefined, {}) - .set('user_lists', { - follow_requests: { + const state = rootState + .set('user_lists', ReducerRecord({ + follow_requests: ListRecord({ next: 'next_url', - }, - }) + }), + })) .set('me', '123'); store = mockStore(state); }); describe('when the url is null', () => { beforeEach(() => { - const state = rootReducer(undefined, {}) - .set('user_lists', { - follow_requests: { + const state = rootState + .set('user_lists', ReducerRecord({ + follow_requests: ListRecord({ next: null, - }, - }) + }), + })) .set('me', '123'); store = mockStore(state); }); @@ -1579,7 +1579,7 @@ describe('authorizeFollowRequest()', () => { describe('when logged out', () => { beforeEach(() => { - const state = rootReducer(undefined, {}).set('me', null); + const state = rootState.set('me', null); store = mockStore(state); }); @@ -1593,7 +1593,7 @@ describe('authorizeFollowRequest()', () => { describe('when logged in', () => { beforeEach(() => { - const state = rootReducer(undefined, {}).set('me', '123'); + const state = rootState.set('me', '123'); store = mockStore(state); }); diff --git a/app/soapbox/actions/__tests__/alerts.test.ts b/app/soapbox/actions/__tests__/alerts.test.ts index f2419893a..5f1f9f4d6 100644 --- a/app/soapbox/actions/__tests__/alerts.test.ts +++ b/app/soapbox/actions/__tests__/alerts.test.ts @@ -1,11 +1,10 @@ import { AxiosError } from 'axios'; -import { mockStore } from 'soapbox/jest/test-helpers'; -import rootReducer from 'soapbox/reducers'; +import { mockStore, rootState } from 'soapbox/jest/test-helpers'; import { dismissAlert, showAlert, showAlertForError } from '../alerts'; -const buildError = (message: string, status: number) => new AxiosError(message, String(status), null, null, { +const buildError = (message: string, status: number) => new AxiosError(message, String(status), undefined, null, { data: { error: message, }, @@ -15,10 +14,10 @@ const buildError = (message: string, status: number) => new AxiosError(mess config: {}, }); -let store; +let store: ReturnType; beforeEach(() => { - const state = rootReducer(undefined, {}); + const state = rootState; store = mockStore(state); }); @@ -28,7 +27,7 @@ describe('dismissAlert()', () => { const expectedActions = [ { type: 'ALERT_DISMISS', alert }, ]; - await store.dispatch(dismissAlert(alert)); + await store.dispatch(dismissAlert(alert as any)); const actions = store.getActions(); expect(actions).toEqual(expectedActions); @@ -70,11 +69,10 @@ describe('showAlert()', () => { it('dispatches the proper actions', async() => { const error = buildError('', 404); - const expectedActions = []; await store.dispatch(showAlertForError(error)); const actions = store.getActions(); - expect(actions).toEqual(expectedActions); + expect(actions).toEqual([]); }); }); @@ -82,11 +80,10 @@ describe('showAlert()', () => { it('dispatches the proper actions', async() => { const error = buildError('', 410); - const expectedActions = []; await store.dispatch(showAlertForError(error)); const actions = store.getActions(); - expect(actions).toEqual(expectedActions); + expect(actions).toEqual([]); }); }); diff --git a/app/soapbox/actions/__tests__/blocks.test.ts b/app/soapbox/actions/__tests__/blocks.test.ts index 2d4832007..8b4c040b3 100644 --- a/app/soapbox/actions/__tests__/blocks.test.ts +++ b/app/soapbox/actions/__tests__/blocks.test.ts @@ -1,8 +1,6 @@ -import { Record as ImmutableRecord } from 'immutable'; - import { __stub } from 'soapbox/api'; -import { mockStore } from 'soapbox/jest/test-helpers'; -import rootReducer from 'soapbox/reducers'; +import { mockStore, rootState } from 'soapbox/jest/test-helpers'; +import { ListRecord, ReducerRecord as UserListsRecord } from 'soapbox/reducers/user_lists'; import { expandBlocks, fetchBlocks } from '../blocks'; @@ -14,11 +12,11 @@ const account = { }; describe('fetchBlocks()', () => { - let store; + let store: ReturnType; describe('if logged out', () => { beforeEach(() => { - const state = rootReducer(undefined, {}).set('me', null); + const state = rootState.set('me', null); store = mockStore(state); }); @@ -32,7 +30,7 @@ describe('fetchBlocks()', () => { describe('if logged in', () => { beforeEach(() => { - const state = rootReducer(undefined, {}).set('me', '1234'); + const state = rootState.set('me', '1234'); store = mockStore(state); }); @@ -87,11 +85,11 @@ describe('fetchBlocks()', () => { }); describe('expandBlocks()', () => { - let store; + let store: ReturnType; describe('if logged out', () => { beforeEach(() => { - const state = rootReducer(undefined, {}).set('me', null); + const state = rootState.set('me', null); store = mockStore(state); }); @@ -105,15 +103,15 @@ describe('expandBlocks()', () => { describe('if logged in', () => { beforeEach(() => { - const state = rootReducer(undefined, {}).set('me', '1234'); + const state = rootState.set('me', '1234'); store = mockStore(state); }); describe('without a url', () => { beforeEach(() => { - const state = rootReducer(undefined, {}) + const state = rootState .set('me', '1234') - .set('user_lists', ImmutableRecord({ blocks: { next: null } })()); + .set('user_lists', UserListsRecord({ blocks: ListRecord({ next: null }) })); store = mockStore(state); }); @@ -127,9 +125,9 @@ describe('expandBlocks()', () => { describe('with a url', () => { beforeEach(() => { - const state = rootReducer(undefined, {}) + const state = rootState .set('me', '1234') - .set('user_lists', ImmutableRecord({ blocks: { next: 'example' } })()); + .set('user_lists', UserListsRecord({ blocks: ListRecord({ next: 'example' }) })); store = mockStore(state); }); diff --git a/app/soapbox/actions/__tests__/carousels.test.ts b/app/soapbox/actions/__tests__/carousels.test.ts index 0953b8276..44e4ff0c0 100644 --- a/app/soapbox/actions/__tests__/carousels.test.ts +++ b/app/soapbox/actions/__tests__/carousels.test.ts @@ -4,14 +4,14 @@ import { mockStore, rootState } from 'soapbox/jest/test-helpers'; import { fetchCarouselAvatars } from '../carousels'; describe('fetchCarouselAvatars()', () => { - let store; + let store: ReturnType; beforeEach(() => { store = mockStore(rootState); }); describe('with a successful API request', () => { - let avatars; + let avatars: Record[]; beforeEach(() => { avatars = [ diff --git a/app/soapbox/actions/__tests__/compose.test.ts b/app/soapbox/actions/__tests__/compose.test.ts index 0dd6fc309..6a9ac6e43 100644 --- a/app/soapbox/actions/__tests__/compose.test.ts +++ b/app/soapbox/actions/__tests__/compose.test.ts @@ -1,28 +1,29 @@ -import { fromJS } from 'immutable'; +import { Map as ImmutableMap } from 'immutable'; -import { mockStore } from 'soapbox/jest/test-helpers'; +import { mockStore, rootState } from 'soapbox/jest/test-helpers'; import { InstanceRecord } from 'soapbox/normalizers'; -import rootReducer from 'soapbox/reducers'; import { uploadCompose } from '../compose'; +import type { IntlShape } from 'react-intl'; + describe('uploadCompose()', () => { describe('with images', () => { - let files, store; + let files: FileList, store: ReturnType; beforeEach(() => { const instance = InstanceRecord({ - configuration: fromJS({ - statuses: { + configuration: ImmutableMap({ + statuses: ImmutableMap({ max_media_attachments: 4, - }, - media_attachments: { + }), + media_attachments: ImmutableMap({ image_size_limit: 10, - }, + }), }), }); - const state = rootReducer(undefined, {}) + const state = rootState .set('me', '1234') .set('instance', instance); @@ -32,13 +33,13 @@ describe('uploadCompose()', () => { name: 'Image', size: 15, type: 'image/png', - }]; + }] as unknown as FileList; }); it('creates an alert if exceeds max size', async() => { const mockIntl = { formatMessage: jest.fn().mockReturnValue('Image exceeds the current file size limit (10 Bytes)'), - }; + } as unknown as IntlShape; const expectedActions = [ { type: 'COMPOSE_UPLOAD_REQUEST', skipLoading: true }, @@ -60,21 +61,21 @@ describe('uploadCompose()', () => { }); describe('with videos', () => { - let files, store; + let files: FileList, store: ReturnType; beforeEach(() => { const instance = InstanceRecord({ - configuration: fromJS({ - statuses: { + configuration: ImmutableMap({ + statuses: ImmutableMap({ max_media_attachments: 4, - }, - media_attachments: { + }), + media_attachments: ImmutableMap({ video_size_limit: 10, - }, + }), }), }); - const state = rootReducer(undefined, {}) + const state = rootState .set('me', '1234') .set('instance', instance); @@ -84,13 +85,13 @@ describe('uploadCompose()', () => { name: 'Video', size: 15, type: 'video/mp4', - }]; + }] as unknown as FileList; }); it('creates an alert if exceeds max size', async() => { const mockIntl = { formatMessage: jest.fn().mockReturnValue('Video exceeds the current file size limit (10 Bytes)'), - }; + } as unknown as IntlShape; const expectedActions = [ { type: 'COMPOSE_UPLOAD_REQUEST', skipLoading: true }, diff --git a/app/soapbox/actions/__tests__/onboarding.test.ts b/app/soapbox/actions/__tests__/onboarding.test.ts index cdd268ed5..f786c7f90 100644 --- a/app/soapbox/actions/__tests__/onboarding.test.ts +++ b/app/soapbox/actions/__tests__/onboarding.test.ts @@ -1,5 +1,4 @@ -import { mockStore, mockWindowProperty } from 'soapbox/jest/test-helpers'; -import rootReducer from 'soapbox/reducers'; +import { mockStore, mockWindowProperty, rootState } from 'soapbox/jest/test-helpers'; import { checkOnboardingStatus, startOnboarding, endOnboarding } from '../onboarding'; @@ -17,7 +16,7 @@ describe('checkOnboarding()', () => { it('does nothing if localStorage item is not set', async() => { mockGetItem = jest.fn().mockReturnValue(null); - const state = rootReducer(undefined, { onboarding: { needsOnboarding: false } }); + const state = rootState.setIn(['onboarding', 'needsOnboarding'], false); const store = mockStore(state); await store.dispatch(checkOnboardingStatus()); @@ -30,7 +29,7 @@ describe('checkOnboarding()', () => { it('does nothing if localStorage item is invalid', async() => { mockGetItem = jest.fn().mockReturnValue('invalid'); - const state = rootReducer(undefined, { onboarding: { needsOnboarding: false } }); + const state = rootState.setIn(['onboarding', 'needsOnboarding'], false); const store = mockStore(state); await store.dispatch(checkOnboardingStatus()); @@ -43,7 +42,7 @@ describe('checkOnboarding()', () => { it('dispatches the correct action', async() => { mockGetItem = jest.fn().mockReturnValue('1'); - const state = rootReducer(undefined, { onboarding: { needsOnboarding: false } }); + const state = rootState.setIn(['onboarding', 'needsOnboarding'], false); const store = mockStore(state); await store.dispatch(checkOnboardingStatus()); @@ -66,7 +65,7 @@ describe('startOnboarding()', () => { }); it('dispatches the correct action', async() => { - const state = rootReducer(undefined, { onboarding: { needsOnboarding: false } }); + const state = rootState.setIn(['onboarding', 'needsOnboarding'], false); const store = mockStore(state); await store.dispatch(startOnboarding()); @@ -89,7 +88,7 @@ describe('endOnboarding()', () => { }); it('dispatches the correct action', async() => { - const state = rootReducer(undefined, { onboarding: { needsOnboarding: false } }); + const state = rootState.setIn(['onboarding', 'needsOnboarding'], false); const store = mockStore(state); await store.dispatch(endOnboarding()); diff --git a/app/soapbox/actions/__tests__/statuses.test.ts b/app/soapbox/actions/__tests__/statuses.test.ts index b206f17b9..18cbc173b 100644 --- a/app/soapbox/actions/__tests__/statuses.test.ts +++ b/app/soapbox/actions/__tests__/statuses.test.ts @@ -4,7 +4,6 @@ import { STATUSES_IMPORT } from 'soapbox/actions/importer'; import { __stub } from 'soapbox/api'; import { mockStore, rootState } from 'soapbox/jest/test-helpers'; import { normalizeStatus } from 'soapbox/normalizers/status'; -import rootReducer from 'soapbox/reducers'; import { deleteStatus, fetchContext } from '../statuses'; @@ -19,7 +18,7 @@ describe('fetchContext()', () => { const store = mockStore(rootState); - store.dispatch(fetchContext('017ed505-5926-392f-256a-f86d5075df70')).then(context => { + store.dispatch(fetchContext('017ed505-5926-392f-256a-f86d5075df70')).then(() => { const actions = store.getActions(); expect(actions[3].type).toEqual(STATUSES_IMPORT); @@ -31,11 +30,11 @@ describe('fetchContext()', () => { }); describe('deleteStatus()', () => { - let store; + let store: ReturnType; describe('if logged out', () => { beforeEach(() => { - const state = rootReducer(undefined, {}).set('me', null); + const state = rootState.set('me', null); store = mockStore(state); }); @@ -54,16 +53,16 @@ describe('deleteStatus()', () => { }); beforeEach(() => { - const state = rootReducer(undefined, {}) + const state = rootState .set('me', '1234') .set('statuses', fromJS({ [statusId]: cachedStatus, - })); + }) as any); store = mockStore(state); }); describe('with a successful API request', () => { - let status; + let status: any; beforeEach(() => { status = require('soapbox/__fixtures__/pleroma-status-deleted.json'); diff --git a/app/soapbox/actions/__tests__/suggestions.test.ts b/app/soapbox/actions/__tests__/suggestions.test.ts new file mode 100644 index 000000000..3c8d0c95a --- /dev/null +++ b/app/soapbox/actions/__tests__/suggestions.test.ts @@ -0,0 +1,108 @@ +import { Map as ImmutableMap } from 'immutable'; + +import { __stub } from 'soapbox/api'; +import { mockStore, rootState } from 'soapbox/jest/test-helpers'; +import { normalizeInstance } from 'soapbox/normalizers'; + +import { + fetchSuggestions, +} from '../suggestions'; + +let store: ReturnType; +let state; + +describe('fetchSuggestions()', () => { + describe('with Truth Social software', () => { + beforeEach(() => { + state = rootState + .set('instance', normalizeInstance({ + version: '3.4.1 (compatible; TruthSocial 1.0.0)', + pleroma: ImmutableMap({ + metadata: ImmutableMap({ + features: [], + }), + }), + })) + .set('me', '123'); + store = mockStore(state); + }); + + describe('with a successful API request', () => { + const response = [ + { + account_id: '1', + acct: 'jl', + account_avatar: 'https://example.com/some.jpg', + display_name: 'justin', + note: '

note

', + verified: true, + }, + ]; + + beforeEach(() => { + __stub((mock) => { + mock.onGet('/api/v1/truth/carousels/suggestions').reply(200, response, { + link: '; rel=\'prev\'', + }); + }); + }); + + it('dispatches the correct actions', async() => { + const expectedActions = [ + { type: 'SUGGESTIONS_V2_FETCH_REQUEST', skipLoading: true }, + { + type: 'ACCOUNTS_IMPORT', accounts: [{ + acct: response[0].acct, + avatar: response[0].account_avatar, + avatar_static: response[0].account_avatar, + id: response[0].account_id, + note: response[0].note, + verified: response[0].verified, + display_name: response[0].display_name, + }], + }, + { + type: 'SUGGESTIONS_TRUTH_FETCH_SUCCESS', + suggestions: response, + next: undefined, + skipLoading: true, + }, + { + type: 'RELATIONSHIPS_FETCH_REQUEST', + skipLoading: true, + ids: [response[0].account_id], + }, + ]; + await store.dispatch(fetchSuggestions()); + const actions = store.getActions(); + + expect(actions).toEqual(expectedActions); + }); + }); + + describe('with an unsuccessful API request', () => { + beforeEach(() => { + __stub((mock) => { + mock.onGet('/api/v1/truth/carousels/suggestions').networkError(); + }); + }); + + it('should dispatch the correct actions', async() => { + const expectedActions = [ + { type: 'SUGGESTIONS_V2_FETCH_REQUEST', skipLoading: true }, + { + type: 'SUGGESTIONS_V2_FETCH_FAIL', + error: new Error('Network Error'), + skipLoading: true, + skipAlert: true, + }, + ]; + + await store.dispatch(fetchSuggestions()); + const actions = store.getActions(); + + expect(actions).toEqual(expectedActions); + }); + }); + }); +}); diff --git a/app/soapbox/actions/auth.ts b/app/soapbox/actions/auth.ts index 40532a582..e21974116 100644 --- a/app/soapbox/actions/auth.ts +++ b/app/soapbox/actions/auth.ts @@ -180,8 +180,8 @@ export const verifyCredentials = (token: string, accountUrl?: string) => { return account; } else { if (getState().me === null) dispatch(fetchMeFail(error)); - dispatch({ type: VERIFY_CREDENTIALS_FAIL, token, error, skipAlert: true }); - return error; + dispatch({ type: VERIFY_CREDENTIALS_FAIL, token, error }); + throw error; } }); }; @@ -214,14 +214,6 @@ export const logIn = (username: string, password: string) => if ((error.response?.data as any).error === 'mfa_required') { // If MFA is required, throw the error and handle it in the component. throw error; - } else if ((error.response?.data as any).error === 'invalid_grant') { - // Mastodon returns this user-unfriendly error as a catch-all - // for everything from "bad request" to "wrong password". - // Assume our code is correct and it's a wrong password. - dispatch(snackbar.error(messages.invalidCredentials)); - } else if ((error.response?.data as any).error) { - // If the backend returns an error, display it. - dispatch(snackbar.error((error.response?.data as any).error)); } else { // Return "wrong password" message. dispatch(snackbar.error(messages.invalidCredentials)); diff --git a/app/soapbox/actions/me.ts b/app/soapbox/actions/me.ts index 4cb4b2350..074f5d4cc 100644 --- a/app/soapbox/actions/me.ts +++ b/app/soapbox/actions/me.ts @@ -6,7 +6,7 @@ import api from '../api'; import { loadCredentials } from './auth'; import { importFetchedAccount } from './importer'; -import type { AxiosError } from 'axios'; +import type { AxiosError, AxiosRequestHeaders } from 'axios'; import type { AppDispatch, RootState } from 'soapbox/store'; import type { APIEntity } from 'soapbox/types/entities'; @@ -62,12 +62,16 @@ const persistAuthAccount = (account: APIEntity, params: Record) => } }; -const patchMe = (params: Record) => +const patchMe = (params: Record, isFormData = false) => (dispatch: AppDispatch, getState: () => RootState) => { dispatch(patchMeRequest()); + const headers: AxiosRequestHeaders = isFormData ? { + 'Content-Type': 'multipart/form-data', + } : {}; + return api(getState) - .patch('/api/v1/accounts/update_credentials', params) + .patch('/api/v1/accounts/update_credentials', params, { headers }) .then(response => { persistAuthAccount(response.data, params); dispatch(patchMeSuccess(response.data)); diff --git a/app/soapbox/actions/moderation.tsx b/app/soapbox/actions/moderation.tsx index 69342277b..ea5861eca 100644 --- a/app/soapbox/actions/moderation.tsx +++ b/app/soapbox/actions/moderation.tsx @@ -44,7 +44,7 @@ const deactivateUserModal = (intl: IntlShape, accountId: string, afterConfirm = const name = state.accounts.get(accountId)!.username; dispatch(openModal('CONFIRM', { - icon: require('@tabler/icons/icons/user-off.svg'), + icon: require('@tabler/icons/user-off.svg'), heading: intl.formatMessage(messages.deactivateUserHeading, { acct }), message: intl.formatMessage(messages.deactivateUserPrompt, { acct }), confirm: intl.formatMessage(messages.deactivateUserConfirm, { name }), @@ -83,7 +83,7 @@ const deleteUserModal = (intl: IntlShape, accountId: string, afterConfirm = () = const checkbox = local ? intl.formatMessage(messages.deleteLocalUserCheckbox) : false; dispatch(openModal('CONFIRM', { - icon: require('@tabler/icons/icons/user-minus.svg'), + icon: require('@tabler/icons/user-minus.svg'), heading: intl.formatMessage(messages.deleteUserHeading, { acct }), message, confirm, @@ -106,7 +106,7 @@ const rejectUserModal = (intl: IntlShape, accountId: string, afterConfirm = () = const name = state.accounts.get(accountId)!.username; dispatch(openModal('CONFIRM', { - icon: require('@tabler/icons/icons/user-off.svg'), + icon: require('@tabler/icons/user-off.svg'), heading: intl.formatMessage(messages.rejectUserHeading, { acct }), message: intl.formatMessage(messages.rejectUserPrompt, { acct }), confirm: intl.formatMessage(messages.rejectUserConfirm, { name }), @@ -127,7 +127,7 @@ const toggleStatusSensitivityModal = (intl: IntlShape, statusId: string, sensiti const acct = state.accounts.get(accountId)!.acct; dispatch(openModal('CONFIRM', { - icon: require('@tabler/icons/icons/alert-triangle.svg'), + icon: require('@tabler/icons/alert-triangle.svg'), heading: intl.formatMessage(sensitive === false ? messages.markStatusSensitiveHeading : messages.markStatusNotSensitiveHeading), message: intl.formatMessage(sensitive === false ? messages.markStatusSensitivePrompt : messages.markStatusNotSensitivePrompt, { acct }), confirm: intl.formatMessage(sensitive === false ? messages.markStatusSensitiveConfirm : messages.markStatusNotSensitiveConfirm), @@ -148,7 +148,7 @@ const deleteStatusModal = (intl: IntlShape, statusId: string, afterConfirm = () const acct = state.accounts.get(accountId)!.acct; dispatch(openModal('CONFIRM', { - icon: require('@tabler/icons/icons/trash.svg'), + icon: require('@tabler/icons/trash.svg'), heading: intl.formatMessage(messages.deleteStatusHeading), message: intl.formatMessage(messages.deleteStatusPrompt, { acct }), confirm: intl.formatMessage(messages.deleteStatusConfirm), diff --git a/app/soapbox/actions/notifications.ts b/app/soapbox/actions/notifications.ts index 0e396b89a..adeb46bf9 100644 --- a/app/soapbox/actions/notifications.ts +++ b/app/soapbox/actions/notifications.ts @@ -89,6 +89,7 @@ const updateNotifications = (notification: APIEntity) => const updateNotificationsQueue = (notification: APIEntity, intlMessages: Record, intlLocale: string, curPath: string) => (dispatch: AppDispatch, getState: () => RootState) => { + if (!notification.type) return; // drop invalid notifications if (notification.type === 'pleroma:chat_mention') return; // Drop chat notifications, handle them per-chat const showAlert = getSettings(getState()).getIn(['notifications', 'alerts', notification.type]); diff --git a/app/soapbox/actions/suggestions.ts b/app/soapbox/actions/suggestions.ts index d82f81f40..86743f5aa 100644 --- a/app/soapbox/actions/suggestions.ts +++ b/app/soapbox/actions/suggestions.ts @@ -1,3 +1,5 @@ +import { AxiosResponse } from 'axios'; + import { isLoggedIn } from 'soapbox/utils/auth'; import { getFeatures } from 'soapbox/utils/features'; @@ -5,6 +7,7 @@ import api, { getLinks } from '../api'; import { fetchRelationships } from './accounts'; import { importFetchedAccounts } from './importer'; +import { insertSuggestionsIntoTimeline } from './timelines'; import type { AppDispatch, RootState } from 'soapbox/store'; import type { APIEntity } from 'soapbox/types/entities'; @@ -19,6 +22,10 @@ const SUGGESTIONS_V2_FETCH_REQUEST = 'SUGGESTIONS_V2_FETCH_REQUEST'; const SUGGESTIONS_V2_FETCH_SUCCESS = 'SUGGESTIONS_V2_FETCH_SUCCESS'; const SUGGESTIONS_V2_FETCH_FAIL = 'SUGGESTIONS_V2_FETCH_FAIL'; +const SUGGESTIONS_TRUTH_FETCH_REQUEST = 'SUGGESTIONS_TRUTH_FETCH_REQUEST'; +const SUGGESTIONS_TRUTH_FETCH_SUCCESS = 'SUGGESTIONS_TRUTH_FETCH_SUCCESS'; +const SUGGESTIONS_TRUTH_FETCH_FAIL = 'SUGGESTIONS_TRUTH_FETCH_FAIL'; + const fetchSuggestionsV1 = (params: Record = {}) => (dispatch: AppDispatch, getState: () => RootState) => { dispatch({ type: SUGGESTIONS_FETCH_REQUEST, skipLoading: true }); @@ -52,6 +59,48 @@ const fetchSuggestionsV2 = (params: Record = {}) => }); }; +export type SuggestedProfile = { + account_avatar: string + account_id: string + acct: string + display_name: string + note: string + verified: boolean +} + +const mapSuggestedProfileToAccount = (suggestedProfile: SuggestedProfile) => ({ + id: suggestedProfile.account_id, + avatar: suggestedProfile.account_avatar, + avatar_static: suggestedProfile.account_avatar, + acct: suggestedProfile.acct, + display_name: suggestedProfile.display_name, + note: suggestedProfile.note, + verified: suggestedProfile.verified, +}); + +const fetchTruthSuggestions = (params: Record = {}) => + (dispatch: AppDispatch, getState: () => RootState) => { + const next = getState().suggestions.next; + + dispatch({ type: SUGGESTIONS_V2_FETCH_REQUEST, skipLoading: true }); + + return api(getState) + .get(next ? next : '/api/v1/truth/carousels/suggestions', next ? {} : { params }) + .then((response: AxiosResponse) => { + const suggestedProfiles = response.data; + const next = getLinks(response).refs.find(link => link.rel === 'next')?.uri; + + const accounts = suggestedProfiles.map(mapSuggestedProfileToAccount); + dispatch(importFetchedAccounts(accounts)); + dispatch({ type: SUGGESTIONS_TRUTH_FETCH_SUCCESS, suggestions: suggestedProfiles, next, skipLoading: true }); + return suggestedProfiles; + }) + .catch(error => { + dispatch({ type: SUGGESTIONS_V2_FETCH_FAIL, error, skipLoading: true, skipAlert: true }); + throw error; + }); + }; + const fetchSuggestions = (params: Record = { limit: 50 }) => (dispatch: AppDispatch, getState: () => RootState) => { const state = getState(); @@ -59,17 +108,24 @@ const fetchSuggestions = (params: Record = { limit: 50 }) => const instance = state.instance; const features = getFeatures(instance); - if (!me) return; + if (!me) return null; - if (features.suggestionsV2) { - dispatch(fetchSuggestionsV2(params)) + if (features.truthSuggestions) { + return dispatch(fetchTruthSuggestions(params)) + .then((suggestions: APIEntity[]) => { + const accountIds = suggestions.map((account) => account.account_id); + dispatch(fetchRelationships(accountIds)); + }) + .catch(() => { }); + } else if (features.suggestionsV2) { + return dispatch(fetchSuggestionsV2(params)) .then((suggestions: APIEntity[]) => { const accountIds = suggestions.map(({ account }) => account.id); dispatch(fetchRelationships(accountIds)); }) .catch(() => { }); } else if (features.suggestions) { - dispatch(fetchSuggestionsV1(params)) + return dispatch(fetchSuggestionsV1(params)) .then((accounts: APIEntity[]) => { const accountIds = accounts.map(({ id }) => id); dispatch(fetchRelationships(accountIds)); @@ -77,9 +133,14 @@ const fetchSuggestions = (params: Record = { limit: 50 }) => .catch(() => { }); } else { // Do nothing + return null; } }; +const fetchSuggestionsForTimeline = () => (dispatch: AppDispatch, _getState: () => RootState) => { + dispatch(fetchSuggestions({ limit: 20 }))?.then(() => dispatch(insertSuggestionsIntoTimeline())); +}; + const dismissSuggestion = (accountId: string) => (dispatch: AppDispatch, getState: () => RootState) => { if (!isLoggedIn(getState)) return; @@ -100,8 +161,12 @@ export { SUGGESTIONS_V2_FETCH_REQUEST, SUGGESTIONS_V2_FETCH_SUCCESS, SUGGESTIONS_V2_FETCH_FAIL, + SUGGESTIONS_TRUTH_FETCH_REQUEST, + SUGGESTIONS_TRUTH_FETCH_SUCCESS, + SUGGESTIONS_TRUTH_FETCH_FAIL, fetchSuggestionsV1, fetchSuggestionsV2, fetchSuggestions, + fetchSuggestionsForTimeline, dismissSuggestion, }; diff --git a/app/soapbox/actions/timelines.ts b/app/soapbox/actions/timelines.ts index a962b068c..74622d180 100644 --- a/app/soapbox/actions/timelines.ts +++ b/app/soapbox/actions/timelines.ts @@ -12,21 +12,22 @@ import type { AxiosError } from 'axios'; import type { AppDispatch, RootState } from 'soapbox/store'; import type { APIEntity, Status } from 'soapbox/types/entities'; -const TIMELINE_UPDATE = 'TIMELINE_UPDATE'; -const TIMELINE_DELETE = 'TIMELINE_DELETE'; -const TIMELINE_CLEAR = 'TIMELINE_CLEAR'; +const TIMELINE_UPDATE = 'TIMELINE_UPDATE'; +const TIMELINE_DELETE = 'TIMELINE_DELETE'; +const TIMELINE_CLEAR = 'TIMELINE_CLEAR'; const TIMELINE_UPDATE_QUEUE = 'TIMELINE_UPDATE_QUEUE'; const TIMELINE_DEQUEUE = 'TIMELINE_DEQUEUE'; const TIMELINE_SCROLL_TOP = 'TIMELINE_SCROLL_TOP'; const TIMELINE_EXPAND_REQUEST = 'TIMELINE_EXPAND_REQUEST'; const TIMELINE_EXPAND_SUCCESS = 'TIMELINE_EXPAND_SUCCESS'; -const TIMELINE_EXPAND_FAIL = 'TIMELINE_EXPAND_FAIL'; +const TIMELINE_EXPAND_FAIL = 'TIMELINE_EXPAND_FAIL'; -const TIMELINE_CONNECT = 'TIMELINE_CONNECT'; +const TIMELINE_CONNECT = 'TIMELINE_CONNECT'; const TIMELINE_DISCONNECT = 'TIMELINE_DISCONNECT'; const TIMELINE_REPLACE = 'TIMELINE_REPLACE'; +const TIMELINE_INSERT = 'TIMELINE_INSERT'; const MAX_QUEUED_ITEMS = 40; @@ -110,9 +111,9 @@ const dequeueTimeline = (timelineId: string, expandFunc?: (lastStatusId: string) const deleteFromTimelines = (id: string) => (dispatch: AppDispatch, getState: () => RootState) => { - const accountId = getState().statuses.get(id)?.account; + const accountId = getState().statuses.get(id)?.account; const references = getState().statuses.filter(status => status.get('reblog') === id).map(status => [status.get('id'), status.get('account')]); - const reblogOf = getState().statuses.getIn([id, 'reblog'], null); + const reblogOf = getState().statuses.getIn([id, 'reblog'], null); dispatch({ type: TIMELINE_DELETE, @@ -127,7 +128,7 @@ const clearTimeline = (timeline: string) => (dispatch: AppDispatch) => dispatch({ type: TIMELINE_CLEAR, timeline }); -const noOp = () => {}; +const noOp = () => { }; const noOpAsync = () => () => new Promise(f => f(undefined)); const parseTags = (tags: Record = {}, mode: 'any' | 'all' | 'none') => { @@ -141,7 +142,7 @@ const replaceHomeTimeline = ( { maxId }: Record = {}, ) => (dispatch: AppDispatch, _getState: () => RootState) => { dispatch({ type: TIMELINE_REPLACE, accountId }); - dispatch(expandHomeTimeline({ accountId, maxId })); + dispatch(expandHomeTimeline({ accountId, maxId }, () => dispatch(insertSuggestionsIntoTimeline()))); }; const expandTimeline = (timelineId: string, path: string, params: Record = {}, done = noOp) => @@ -214,9 +215,9 @@ const expandGroupTimeline = (id: string, { maxId }: Record = {}, do const expandHashtagTimeline = (hashtag: string, { maxId, tags }: Record = {}, done = noOp) => { return expandTimeline(`hashtag:${hashtag}`, `/api/v1/timelines/tag/${hashtag}`, { max_id: maxId, - any: parseTags(tags, 'any'), - all: parseTags(tags, 'all'), - none: parseTags(tags, 'none'), + any: parseTags(tags, 'any'), + all: parseTags(tags, 'all'), + none: parseTags(tags, 'none'), }, done); }; @@ -259,6 +260,10 @@ const scrollTopTimeline = (timeline: string, top: boolean) => ({ top, }); +const insertSuggestionsIntoTimeline = () => (dispatch: AppDispatch, getState: () => RootState) => { + dispatch({ type: TIMELINE_INSERT, timeline: 'home' }); +}; + export { TIMELINE_UPDATE, TIMELINE_DELETE, @@ -272,6 +277,7 @@ export { TIMELINE_CONNECT, TIMELINE_DISCONNECT, TIMELINE_REPLACE, + TIMELINE_INSERT, MAX_QUEUED_ITEMS, processTimelineUpdate, updateTimeline, @@ -298,4 +304,5 @@ export { connectTimeline, disconnectTimeline, scrollTopTimeline, + insertSuggestionsIntoTimeline, }; diff --git a/app/soapbox/components/__tests__/account.test.tsx b/app/soapbox/components/__tests__/account.test.tsx index e7af7b8f0..7f1458349 100644 --- a/app/soapbox/components/__tests__/account.test.tsx +++ b/app/soapbox/components/__tests__/account.test.tsx @@ -5,6 +5,8 @@ import { render, screen } from '../../jest/test-helpers'; import { normalizeAccount } from '../../normalizers'; import Account from '../account'; +import type { ReducerAccount } from 'soapbox/reducers/accounts'; + describe('', () => { it('renders account name and username', () => { const account = normalizeAccount({ @@ -12,7 +14,7 @@ describe('', () => { acct: 'justin-username', display_name: 'Justin L', avatar: 'test.jpg', - }); + }) as ReducerAccount; const store = { accounts: ImmutableMap({ @@ -20,7 +22,7 @@ describe('', () => { }), }; - render(, null, store); + render(, undefined, store); expect(screen.getByTestId('account')).toHaveTextContent('Justin L'); expect(screen.getByTestId('account')).toHaveTextContent(/justin-username/i); }); @@ -33,7 +35,7 @@ describe('', () => { display_name: 'Justin L', avatar: 'test.jpg', verified: true, - }); + }) as ReducerAccount; const store = { accounts: ImmutableMap({ @@ -41,7 +43,7 @@ describe('', () => { }), }; - render(, null, store); + render(, undefined, store); expect(screen.getByTestId('verified-badge')).toBeInTheDocument(); }); @@ -52,7 +54,7 @@ describe('', () => { display_name: 'Justin L', avatar: 'test.jpg', verified: false, - }); + }) as ReducerAccount; const store = { accounts: ImmutableMap({ @@ -60,7 +62,7 @@ describe('', () => { }), }; - render(, null, store); + render(, undefined, store); expect(screen.queryAllByTestId('verified-badge')).toHaveLength(0); }); }); diff --git a/app/soapbox/components/__tests__/avatar.test.tsx b/app/soapbox/components/__tests__/avatar.test.tsx index 55abca520..56f592925 100644 --- a/app/soapbox/components/__tests__/avatar.test.tsx +++ b/app/soapbox/components/__tests__/avatar.test.tsx @@ -5,6 +5,8 @@ import { normalizeAccount } from 'soapbox/normalizers'; import { render, screen } from '../../jest/test-helpers'; import Avatar from '../avatar'; +import type { ReducerAccount } from 'soapbox/reducers/accounts'; + describe('', () => { const account = normalizeAccount({ username: 'alice', @@ -12,7 +14,7 @@ describe('', () => { display_name: 'Alice', avatar: '/animated/alice.gif', avatar_static: '/static/alice.jpg', - }); + }) as ReducerAccount; const size = 100; diff --git a/app/soapbox/components/__tests__/avatar_overlay.test.tsx b/app/soapbox/components/__tests__/avatar_overlay.test.tsx index b62d4eef8..105828556 100644 --- a/app/soapbox/components/__tests__/avatar_overlay.test.tsx +++ b/app/soapbox/components/__tests__/avatar_overlay.test.tsx @@ -1,25 +1,28 @@ -import { fromJS } from 'immutable'; import React from 'react'; +import { normalizeAccount } from 'soapbox/normalizers'; + import { render, screen } from '../../jest/test-helpers'; import AvatarOverlay from '../avatar_overlay'; +import type { ReducerAccount } from 'soapbox/reducers/accounts'; + describe(' { - const account = fromJS({ + const account = normalizeAccount({ username: 'alice', acct: 'alice', display_name: 'Alice', avatar: '/animated/alice.gif', avatar_static: '/static/alice.jpg', - }); + }) as ReducerAccount; - const friend = fromJS({ + const friend = normalizeAccount({ username: 'eve', acct: 'eve@blackhat.lair', display_name: 'Evelyn', avatar: '/animated/eve.gif', avatar_static: '/static/eve.jpg', - }); + }) as ReducerAccount; it('renders a overlay avatar', () => { render(); diff --git a/app/soapbox/components/__tests__/display_name.test.tsx b/app/soapbox/components/__tests__/display_name.test.tsx index 6d0a05ed5..4c1c1bd23 100644 --- a/app/soapbox/components/__tests__/display_name.test.tsx +++ b/app/soapbox/components/__tests__/display_name.test.tsx @@ -5,9 +5,11 @@ import { normalizeAccount } from 'soapbox/normalizers'; import { render, screen } from '../../jest/test-helpers'; import DisplayName from '../display-name'; +import type { ReducerAccount } from 'soapbox/reducers/accounts'; + describe('', () => { it('renders display name + account name', () => { - const account = normalizeAccount({ acct: 'bar@baz' }); + const account = normalizeAccount({ acct: 'bar@baz' }) as ReducerAccount; render(); expect(screen.getByTestId('display-name')).toHaveTextContent('bar@baz'); diff --git a/app/soapbox/components/__tests__/emoji_selector.test.tsx b/app/soapbox/components/__tests__/emoji_selector.test.tsx index 891e3e61c..c680d156e 100644 --- a/app/soapbox/components/__tests__/emoji_selector.test.tsx +++ b/app/soapbox/components/__tests__/emoji_selector.test.tsx @@ -6,6 +6,7 @@ import EmojiSelector from '../emoji_selector'; describe('', () => { it('renders correctly', () => { const children = ; + // @ts-ignore children.__proto__.addEventListener = () => {}; render(children); diff --git a/app/soapbox/components/__tests__/quoted-status.test.tsx b/app/soapbox/components/__tests__/quoted-status.test.tsx index 208a913b2..d57b59b30 100644 --- a/app/soapbox/components/__tests__/quoted-status.test.tsx +++ b/app/soapbox/components/__tests__/quoted-status.test.tsx @@ -4,6 +4,8 @@ import { render, screen, rootState } from '../../jest/test-helpers'; import { normalizeStatus, normalizeAccount } from '../../normalizers'; import QuotedStatus from '../quoted-status'; +import type { ReducerStatus } from 'soapbox/reducers/statuses'; + describe('', () => { it('renders content', () => { const account = normalizeAccount({ @@ -16,11 +18,11 @@ describe('', () => { account, content: 'hello world', contentHtml: 'hello world', - }); + }) as ReducerStatus; - const state = rootState.setIn(['accounts', '1', account]); + const state = rootState.setIn(['accounts', '1'], account); - render(, null, state); + render(, undefined, state); screen.getByText(/hello world/i); expect(screen.getByTestId('quoted-status')).toHaveTextContent(/hello world/i); }); diff --git a/app/soapbox/components/__tests__/scroll-top-button.test.tsx b/app/soapbox/components/__tests__/scroll-top-button.test.tsx index 89518b977..76e6b7c1c 100644 --- a/app/soapbox/components/__tests__/scroll-top-button.test.tsx +++ b/app/soapbox/components/__tests__/scroll-top-button.test.tsx @@ -28,7 +28,7 @@ describe('', () => { message={messages.queue} />, ); - expect(screen.getByText('Click to see 1 new post', { hidden: true })).toBeInTheDocument(); + expect(screen.getByText('Click to see 1 new post')).toBeInTheDocument(); render( ', () => { message={messages.queue} />, ); - expect(screen.getByText('Click to see 9999999 new posts', { hidden: true })).toBeInTheDocument(); + expect(screen.getByText('Click to see 9999999 new posts')).toBeInTheDocument(); }); }); diff --git a/app/soapbox/components/account.tsx b/app/soapbox/components/account.tsx index d6d076889..5456ff6fb 100644 --- a/app/soapbox/components/account.tsx +++ b/app/soapbox/components/account.tsx @@ -9,7 +9,7 @@ import { getAcct } from 'soapbox/utils/accounts'; import { displayFqn } from 'soapbox/utils/state'; import RelativeTimestamp from './relative_timestamp'; -import { Avatar, Emoji, HStack, Icon, IconButton, Text } from './ui'; +import { Avatar, Emoji, HStack, Icon, IconButton, Stack, Text } from './ui'; import type { Account as AccountEntity } from 'soapbox/types/entities'; @@ -57,7 +57,9 @@ interface IAccount { timestamp?: string | Date, timestampUrl?: string, futureTimestamp?: boolean, + withAccountNote?: boolean, withDate?: boolean, + withLinkToProfile?: boolean, withRelationship?: boolean, showEdit?: boolean, emoji?: string, @@ -78,7 +80,9 @@ const Account = ({ timestamp, timestampUrl, futureTimestamp = false, + withAccountNote = false, withDate = false, + withLinkToProfile = true, withRelationship = true, showEdit = false, emoji, @@ -154,12 +158,12 @@ const Account = ({ if (withDate) timestamp = account.created_at; - const LinkEl: any = showProfileHoverCard ? Link : 'div'; + const LinkEl: any = withLinkToProfile ? Link : 'div'; return (
- + {children}} @@ -202,35 +206,45 @@ const Account = ({ - - @{username} + + + @{username} - {account.favicon && ( - - )} + {account.favicon && ( + + )} - {(timestamp) ? ( - <> - · + {(timestamp) ? ( + <> + · - {timestampUrl ? ( - + {timestampUrl ? ( + + + + ) : ( - - ) : ( - - )} - - ) : null} + )} + + ) : null} - {showEdit ? ( - <> - · + {showEdit ? ( + <> + · - - - ) : null} - + + + ) : null} + + + {withAccountNote && ( + + )} +
diff --git a/app/soapbox/components/account_search.tsx b/app/soapbox/components/account_search.tsx index 3acda1152..adbb5501d 100644 --- a/app/soapbox/components/account_search.tsx +++ b/app/soapbox/components/account_search.tsx @@ -70,8 +70,8 @@ const AccountSearch: React.FC = ({ onSelected, ...rest }) => { />
- - + +
); diff --git a/app/soapbox/components/birthday_input.tsx b/app/soapbox/components/birthday_input.tsx index a1dc36c88..e263fb02e 100644 --- a/app/soapbox/components/birthday_input.tsx +++ b/app/soapbox/components/birthday_input.tsx @@ -70,7 +70,7 @@ const BirthdayInput: React.FC = ({ value, onChange, required })
= ({ value, onChange, required }) {intl.formatDate(date, { month: 'long' })} = ({ value, onChange, required })
= ({ value, onChange, required }) {intl.formatDate(date, { year: 'numeric' })} = ({ account, children, withDate = fal const joinedAt = createdAt ? (
- +
) : null; diff --git a/app/soapbox/components/domain.tsx b/app/soapbox/components/domain.tsx index 005848c89..22c8272de 100644 --- a/app/soapbox/components/domain.tsx +++ b/app/soapbox/components/domain.tsx @@ -21,7 +21,7 @@ const Domain: React.FC = ({ domain }) => { // const onBlockDomain = () => { // dispatch(openModal('CONFIRM', { - // icon: require('@tabler/icons/icons/ban.svg'), + // icon: require('@tabler/icons/ban.svg'), // heading: , // message: {domain} }} />, // confirm: intl.formatMessage(messages.blockDomainConfirm), @@ -41,7 +41,7 @@ const Domain: React.FC = ({ domain }) => {
- +
diff --git a/app/soapbox/components/dropdown_menu.tsx b/app/soapbox/components/dropdown_menu.tsx index b07412270..3118b0d2d 100644 --- a/app/soapbox/components/dropdown_menu.tsx +++ b/app/soapbox/components/dropdown_menu.tsx @@ -366,7 +366,7 @@ class Dropdown extends React.PureComponent { } render() { - const { src = require('@tabler/icons/icons/dots.svg'), items, title, disabled, dropdownPlacement, openDropdownId, openedViaKeyboard = false, pressed, text, children } = this.props; + const { src = require('@tabler/icons/dots.svg'), items, title, disabled, dropdownPlacement, openDropdownId, openedViaKeyboard = false, pressed, text, children } = this.props; const open = this.state.id === openDropdownId; return ( diff --git a/app/soapbox/components/error_boundary.tsx b/app/soapbox/components/error_boundary.tsx index c1025d465..f28fecd0c 100644 --- a/app/soapbox/components/error_boundary.tsx +++ b/app/soapbox/components/error_boundary.tsx @@ -120,7 +120,7 @@ class ErrorBoundary extends React.PureComponent { {logo ? ( {siteTitle} ) : ( - + )} diff --git a/app/soapbox/components/list.tsx b/app/soapbox/components/list.tsx index e7d858334..23ff05086 100644 --- a/app/soapbox/components/list.tsx +++ b/app/soapbox/components/list.tsx @@ -54,7 +54,7 @@ const ListItem: React.FC = ({ label, hint, children, onClick }) => {
{children} - +
) : renderChildren()} diff --git a/app/soapbox/components/media_gallery.js b/app/soapbox/components/media_gallery.js index 5e528d4be..4f16f5a73 100644 --- a/app/soapbox/components/media_gallery.js +++ b/app/soapbox/components/media_gallery.js @@ -149,7 +149,7 @@ class Item extends React.PureComponent { const attachmentIcon = ( ); @@ -602,7 +602,7 @@ class MediaGallery extends React.PureComponent { (visible || compact) ? ( diff --git a/app/soapbox/components/modal_root.js b/app/soapbox/components/modal_root.js index 842b66ba6..7eb25b9aa 100644 --- a/app/soapbox/components/modal_root.js +++ b/app/soapbox/components/modal_root.js @@ -78,7 +78,7 @@ class ModalRoot extends React.PureComponent { if (hasComposeContent && type === 'COMPOSE') { onOpenModal('CONFIRM', { - icon: require('@tabler/icons/icons/trash.svg'), + icon: require('@tabler/icons/trash.svg'), heading: isEditing ? : , message: isEditing ? : , confirm: intl.formatMessage(messages.confirm), diff --git a/app/soapbox/components/polls/__tests__/poll-footer.test.tsx b/app/soapbox/components/polls/__tests__/poll-footer.test.tsx index 7265f7e1c..29c841a0a 100644 --- a/app/soapbox/components/polls/__tests__/poll-footer.test.tsx +++ b/app/soapbox/components/polls/__tests__/poll-footer.test.tsx @@ -6,7 +6,7 @@ import { Provider } from 'react-redux'; import { __stub } from 'soapbox/api'; import { normalizePoll } from 'soapbox/normalizers/poll'; -import { mockStore, render, rootReducer, screen } from '../../../jest/test-helpers'; +import { mockStore, render, screen, rootState } from '../../../jest/test-helpers'; import PollFooter from '../poll-footer'; let poll = normalizePoll({ @@ -36,7 +36,7 @@ describe('', () => { }); const user = userEvent.setup(); - const store = mockStore(rootReducer(undefined, {})); + const store = mockStore(rootState); render( diff --git a/app/soapbox/components/polls/poll-option.tsx b/app/soapbox/components/polls/poll-option.tsx index 9b3da5cfa..b242f649b 100644 --- a/app/soapbox/components/polls/poll-option.tsx +++ b/app/soapbox/components/polls/poll-option.tsx @@ -85,7 +85,7 @@ const PollOptionText: React.FC = ({ poll, option, index, active aria-label={option.title} > {active && ( - + )} @@ -138,7 +138,7 @@ const PollOption: React.FC = (props): JSX.Element | null => { {voted ? ( diff --git a/app/soapbox/components/quoted-status.tsx b/app/soapbox/components/quoted-status.tsx index 5d6eb526e..e00ca10e5 100644 --- a/app/soapbox/components/quoted-status.tsx +++ b/app/soapbox/components/quoted-status.tsx @@ -116,7 +116,7 @@ const QuotedStatus: React.FC = ({ status, onCancel, compose }) => if (onCancel) { actions = { onActionClick: handleClose, - actionIcon: require('@tabler/icons/icons/x.svg'), + actionIcon: require('@tabler/icons/x.svg'), actionAlignment: 'top', actionTitle: intl.formatMessage(messages.cancel), }; @@ -137,6 +137,7 @@ const QuotedStatus: React.FC = ({ status, onCancel, compose }) => timestamp={status.created_at} withRelationship={false} showProfileHoverCard={!compose} + withLinkToProfile={!compose} /> {renderReplyMentions()} diff --git a/app/soapbox/components/scroll-top-button.tsx b/app/soapbox/components/scroll-top-button.tsx index 3652296ef..64c7c4629 100644 --- a/app/soapbox/components/scroll-top-button.tsx +++ b/app/soapbox/components/scroll-top-button.tsx @@ -34,6 +34,12 @@ const ScrollTopButton: React.FC = ({ const [scrolled, setScrolled] = useState(false); const autoload = settings.get('autoloadTimelines') === true; + const visible = count > 0 && scrolled; + + const classes = classNames('left-1/2 -translate-x-1/2 fixed top-20 z-50', { + 'hidden': !visible, + }); + const getScrollTop = (): number => { return (document.scrollingElement || document.documentElement).scrollTop; }; @@ -75,16 +81,10 @@ const ScrollTopButton: React.FC = ({ maybeUnload(); }, [count]); - const visible = count > 0 && scrolled; - - const classes = classNames('left-1/2 -translate-x-1/2 fixed top-20 z-50', { - 'hidden': !visible, - }); - return (
- + {(count > 0) && ( diff --git a/app/soapbox/components/sidebar-navigation.tsx b/app/soapbox/components/sidebar-navigation.tsx index 427b0ea30..583006070 100644 --- a/app/soapbox/components/sidebar-navigation.tsx +++ b/app/soapbox/components/sidebar-navigation.tsx @@ -43,7 +43,7 @@ const SidebarNavigation = () => { menu.push({ to: '/follow_requests', text: intl.formatMessage(messages.follow_requests), - icon: require('@tabler/icons/icons/user-plus.svg'), + icon: require('@tabler/icons/user-plus.svg'), count: followRequestsCount, }); } @@ -52,7 +52,7 @@ const SidebarNavigation = () => { menu.push({ to: '/bookmarks', text: intl.formatMessage(messages.bookmarks), - icon: require('@tabler/icons/icons/bookmark.svg'), + icon: require('@tabler/icons/bookmark.svg'), }); } @@ -60,14 +60,14 @@ const SidebarNavigation = () => { menu.push({ to: '/lists', text: intl.formatMessage(messages.lists), - icon: require('@tabler/icons/icons/list.svg'), + icon: require('@tabler/icons/list.svg'), }); } if (settings.get('isDeveloper')) { menu.push({ to: '/developers', - icon: require('@tabler/icons/icons/code.svg'), + icon: require('@tabler/icons/code.svg'), text: intl.formatMessage(messages.developers), }); } @@ -75,7 +75,7 @@ const SidebarNavigation = () => { if (account.staff) { menu.push({ to: '/soapbox/admin', - icon: require('@tabler/icons/icons/dashboard.svg'), + icon: require('@tabler/icons/dashboard.svg'), text: intl.formatMessage(messages.dashboard), count: dashboardCount, }); @@ -89,7 +89,7 @@ const SidebarNavigation = () => { if (features.publicTimeline) { menu.push({ to: '/timeline/local', - icon: features.federating ? require('@tabler/icons/icons/users.svg') : require('@tabler/icons/icons/world.svg'), + icon: features.federating ? require('@tabler/icons/users.svg') : require('@tabler/icons/world.svg'), text: features.federating ? instance.title : intl.formatMessage(messages.all), }); } @@ -113,7 +113,7 @@ const SidebarNavigation = () => { return ( } /> @@ -124,7 +124,7 @@ const SidebarNavigation = () => { return ( } /> ); @@ -138,13 +138,13 @@ const SidebarNavigation = () => {
} /> } /> @@ -152,7 +152,7 @@ const SidebarNavigation = () => { <> } /> @@ -161,13 +161,13 @@ const SidebarNavigation = () => { } /> } /> @@ -176,7 +176,7 @@ const SidebarNavigation = () => { {menu.length > 0 && ( } /> diff --git a/app/soapbox/components/sidebar_menu.tsx b/app/soapbox/components/sidebar_menu.tsx index 2940c5bfa..ee7ee1adc 100644 --- a/app/soapbox/components/sidebar_menu.tsx +++ b/app/soapbox/components/sidebar_menu.tsx @@ -84,7 +84,7 @@ const SidebarMenu: React.FC = (): JSX.Element | null => { const getAccount = makeGetAccount(); const instance = useAppSelector((state) => state.instance); const me = useAppSelector((state) => state.me); - const account = useAppSelector((state) => me ? getAccount(state, me) : null); + const account = useAppSelector((state) => me ? getAccount(state, me) : null); const otherAccounts: ImmutableList = useAppSelector((state) => getOtherAccounts(state)); const sidebarOpen = useAppSelector((state) => state.sidebar.sidebarOpen); const settings = useAppSelector((state) => getSettings(state)); @@ -121,7 +121,7 @@ const SidebarMenu: React.FC = (): JSX.Element | null => { const renderAccount = (account: AccountEntity) => (
- +
); @@ -158,7 +158,7 @@ const SidebarMenu: React.FC = (): JSX.Element | null => { @@ -166,7 +166,7 @@ const SidebarMenu: React.FC = (): JSX.Element | null => { - + @@ -177,7 +177,7 @@ const SidebarMenu: React.FC = (): JSX.Element | null => { { {otherAccounts.map(account => renderAccount(account))} - + {intl.formatMessage(messages.addAccount)}
@@ -208,7 +208,7 @@ const SidebarMenu: React.FC = (): JSX.Element | null => { @@ -216,7 +216,7 @@ const SidebarMenu: React.FC = (): JSX.Element | null => { {features.bookmarks && ( @@ -225,7 +225,7 @@ const SidebarMenu: React.FC = (): JSX.Element | null => { {features.lists && ( @@ -234,7 +234,7 @@ const SidebarMenu: React.FC = (): JSX.Element | null => { {settings.get('isDeveloper') && ( @@ -245,7 +245,7 @@ const SidebarMenu: React.FC = (): JSX.Element | null => { } onClick={onClose} /> @@ -264,21 +264,21 @@ const SidebarMenu: React.FC = (): JSX.Element | null => { @@ -286,7 +286,7 @@ const SidebarMenu: React.FC = (): JSX.Element | null => { {features.federating && ( @@ -295,7 +295,7 @@ const SidebarMenu: React.FC = (): JSX.Element | null => { {features.filters && ( @@ -304,7 +304,7 @@ const SidebarMenu: React.FC = (): JSX.Element | null => { {account.admin && ( @@ -313,7 +313,7 @@ const SidebarMenu: React.FC = (): JSX.Element | null => { {features.import && ( @@ -323,7 +323,7 @@ const SidebarMenu: React.FC = (): JSX.Element | null => { diff --git a/app/soapbox/components/status-action-button.tsx b/app/soapbox/components/status-action-button.tsx index 6bbd86fa8..0e837168d 100644 --- a/app/soapbox/components/status-action-button.tsx +++ b/app/soapbox/components/status-action-button.tsx @@ -1,7 +1,7 @@ import classNames from 'classnames'; import React from 'react'; -import { Text, Icon } from 'soapbox/components/ui'; +import { Text, Icon, Emoji } from 'soapbox/components/ui'; import { shortNumberFormat } from 'soapbox/utils/numbers'; const COLORS = { @@ -15,7 +15,7 @@ interface IStatusActionCounter { count: number, } -/** Action button numerical counter, eg "5" likes */ +/** Action button numerical counter, eg "5" likes. */ const StatusActionCounter: React.FC = ({ count = 0 }): JSX.Element => { return ( @@ -31,10 +31,11 @@ interface IStatusActionButton extends React.ButtonHTMLAttributes): JSX.Element => { - const { icon, className, iconClassName, active, color, filled = false, count = 0, ...filteredProps } = props; +const StatusActionButton = React.forwardRef((props, ref): JSX.Element => { + const { icon, className, iconClassName, active, color, filled = false, count = 0, emoji, ...filteredProps } = props; return ( diff --git a/app/soapbox/components/ui/modal/modal.tsx b/app/soapbox/components/ui/modal/modal.tsx index 3987d6afe..259783539 100644 --- a/app/soapbox/components/ui/modal/modal.tsx +++ b/app/soapbox/components/ui/modal/modal.tsx @@ -59,7 +59,7 @@ const Modal: React.FC = ({ cancelAction, cancelText, children, - closeIcon = require('@tabler/icons/icons/x.svg'), + closeIcon = require('@tabler/icons/x.svg'), closePosition = 'right', confirmationAction, confirmationDisabled, @@ -83,7 +83,7 @@ const Modal: React.FC = ({ }, [skipFocus, buttonRef]); return ( -
+
{title && ( diff --git a/app/soapbox/components/ui/stack/stack.tsx b/app/soapbox/components/ui/stack/stack.tsx index 3bb96d276..9ecb4a104 100644 --- a/app/soapbox/components/ui/stack/stack.tsx +++ b/app/soapbox/components/ui/stack/stack.tsx @@ -1,9 +1,10 @@ import classNames from 'classnames'; import React from 'react'; -type SIZES = 0.5 | 1 | 1.5 | 2 | 3 | 4 | 5 | 10 +type SIZES = 0 | 0.5 | 1 | 1.5 | 2 | 3 | 4 | 5 | 10 const spaces = { + 0: 'space-y-0', '0.5': 'space-y-0.5', 1: 'space-y-1', '1.5': 'space-y-1.5', diff --git a/app/soapbox/components/ui/streamfield/streamfield.tsx b/app/soapbox/components/ui/streamfield/streamfield.tsx index 902ae2873..140a194b6 100644 --- a/app/soapbox/components/ui/streamfield/streamfield.tsx +++ b/app/soapbox/components/ui/streamfield/streamfield.tsx @@ -74,7 +74,7 @@ const Streamfield: React.FC = ({ onRemoveItem(i)} title={intl.formatMessage(messages.remove)} /> @@ -86,7 +86,7 @@ const Streamfield: React.FC = ({ {onAddItem && ( - +
); diff --git a/app/soapbox/features/admin/components/report_status.tsx b/app/soapbox/features/admin/components/report_status.tsx index 7503675e4..8ec01792e 100644 --- a/app/soapbox/features/admin/components/report_status.tsx +++ b/app/soapbox/features/admin/components/report_status.tsx @@ -40,11 +40,11 @@ const ReportStatus: React.FC = ({ status }) => { return [{ text: intl.formatMessage(messages.viewStatus, { acct: `@${acct}` }), to: `/@${acct}/posts/${status.id}`, - icon: require('@tabler/icons/icons/pencil.svg'), + icon: require('@tabler/icons/pencil.svg'), }, { text: intl.formatMessage(messages.deleteStatus, { acct: `@${acct}` }), action: handleDeleteStatus, - icon: require('@tabler/icons/icons/trash.svg'), + icon: require('@tabler/icons/trash.svg'), destructive: true, }]; }; @@ -123,7 +123,7 @@ const ReportStatus: React.FC = ({ status }) => {
diff --git a/app/soapbox/features/admin/components/unapproved_account.tsx b/app/soapbox/features/admin/components/unapproved_account.tsx index ffd76fc30..b5a08c956 100644 --- a/app/soapbox/features/admin/components/unapproved_account.tsx +++ b/app/soapbox/features/admin/components/unapproved_account.tsx @@ -52,8 +52,8 @@ const UnapprovedAccount: React.FC = ({ accountId }) => {
{adminAccount?.invite_request || ''}
- - + +
); diff --git a/app/soapbox/features/aliases/components/account.tsx b/app/soapbox/features/aliases/components/account.tsx index adcd1b072..3d24c0543 100644 --- a/app/soapbox/features/aliases/components/account.tsx +++ b/app/soapbox/features/aliases/components/account.tsx @@ -48,7 +48,7 @@ const Account: React.FC = ({ accountId, aliases }) => { if (!added && accountId !== me) { button = (
- +
); } diff --git a/app/soapbox/features/aliases/components/search.tsx b/app/soapbox/features/aliases/components/search.tsx index 3720a6930..4d2a55a6a 100644 --- a/app/soapbox/features/aliases/components/search.tsx +++ b/app/soapbox/features/aliases/components/search.tsx @@ -54,7 +54,7 @@ const Search: React.FC = () => { />
- +
diff --git a/app/soapbox/features/audio/index.js b/app/soapbox/features/audio/index.js index 067856abf..2a6732ec9 100644 --- a/app/soapbox/features/audio/index.js +++ b/app/soapbox/features/audio/index.js @@ -491,8 +491,8 @@ class Audio extends React.PureComponent {
- - + +
@@ -522,7 +522,7 @@ class Audio extends React.PureComponent { download target='_blank' > - +
diff --git a/app/soapbox/features/auth_layout/index.tsx b/app/soapbox/features/auth_layout/index.tsx index 87026e4b4..d4f6517bd 100644 --- a/app/soapbox/features/auth_layout/index.tsx +++ b/app/soapbox/features/auth_layout/index.tsx @@ -54,7 +54,7 @@ const AuthLayout = () => {
diff --git a/app/soapbox/features/chats/components/chat-box.tsx b/app/soapbox/features/chats/components/chat-box.tsx index 0baabb43b..869764961 100644 --- a/app/soapbox/features/chats/components/chat-box.tsx +++ b/app/soapbox/features/chats/components/chat-box.tsx @@ -144,7 +144,7 @@ const ChatBox: React.FC = ({ chatId, onSetInputRef, autosize }) => {
@@ -155,7 +155,7 @@ const ChatBox: React.FC = ({ chatId, onSetInputRef, autosize }) => { const renderActionButton = () => { return canSubmit() ? ( diff --git a/app/soapbox/features/chats/components/chat-message-list.tsx b/app/soapbox/features/chats/components/chat-message-list.tsx index 935a3707d..70f843ebd 100644 --- a/app/soapbox/features/chats/components/chat-message-list.tsx +++ b/app/soapbox/features/chats/components/chat-message-list.tsx @@ -219,7 +219,7 @@ const ChatMessageList: React.FC = ({ chatId, chatMessageIds, a { text: intl.formatMessage(messages.delete), action: handleDeleteMessage(chatMessage.chat_id, chatMessage.id), - icon: require('@tabler/icons/icons/trash.svg'), + icon: require('@tabler/icons/trash.svg'), destructive: true, }, ]; @@ -228,7 +228,7 @@ const ChatMessageList: React.FC = ({ chatId, chatMessageIds, a menu.push({ text: intl.formatMessage(messages.report), action: handleReportUser(chatMessage.account_id), - icon: require('@tabler/icons/icons/flag.svg'), + icon: require('@tabler/icons/flag.svg'), }); } @@ -251,7 +251,7 @@ const ChatMessageList: React.FC = ({ chatId, chatMessageIds, a
diff --git a/app/soapbox/features/chats/components/chat-window.tsx b/app/soapbox/features/chats/components/chat-window.tsx index 5a71f6598..8b30d3ba8 100644 --- a/app/soapbox/features/chats/components/chat-window.tsx +++ b/app/soapbox/features/chats/components/chat-window.tsx @@ -98,7 +98,7 @@ const ChatWindow: React.FC = ({ idx, chatId, windowState }) => { @{getAcct(account, displayFqn)}
- +
diff --git a/app/soapbox/features/chats/components/chat.tsx b/app/soapbox/features/chats/components/chat.tsx index e2e4e90c1..13d2b7fee 100644 --- a/app/soapbox/features/chats/components/chat.tsx +++ b/app/soapbox/features/chats/components/chat.tsx @@ -44,7 +44,7 @@ const Chat: React.FC = ({ chatId, onClick }) => { {attachment && ( )} {content ? ( diff --git a/app/soapbox/features/community_timeline/components/column_settings.js b/app/soapbox/features/community_timeline/components/column_settings.js index a5bf9a91f..52781f1f4 100644 --- a/app/soapbox/features/community_timeline/components/column_settings.js +++ b/app/soapbox/features/community_timeline/components/column_settings.js @@ -31,7 +31,7 @@ class ColumnSettings extends React.PureComponent {
- +
diff --git a/app/soapbox/features/compose/components/compose_form.js b/app/soapbox/features/compose/components/compose_form.js index 69dffd7de..66010cfd3 100644 --- a/app/soapbox/features/compose/components/compose_form.js +++ b/app/soapbox/features/compose/components/compose_form.js @@ -270,14 +270,14 @@ class ComposeForm extends ImmutablePureComponent { } else if (this.props.privacy === 'direct') { publishText = ( <> - + {intl.formatMessage(messages.message)} ); } else if (this.props.privacy === 'private') { publishText = ( <> - + {intl.formatMessage(messages.publish)} ); diff --git a/app/soapbox/features/compose/components/emoji_picker_dropdown.js b/app/soapbox/features/compose/components/emoji_picker_dropdown.js index ca1fff018..675d87de5 100644 --- a/app/soapbox/features/compose/components/emoji_picker_dropdown.js +++ b/app/soapbox/features/compose/components/emoji_picker_dropdown.js @@ -365,7 +365,7 @@ class EmojiPickerDropdown extends React.PureComponent { 'pulse-loading': active && loading, })} alt='😀' - src={require('@tabler/icons/icons/mood-happy.svg')} + src={require('@tabler/icons/mood-happy.svg')} title={title} aria-label={title} aria-expanded={active} diff --git a/app/soapbox/features/compose/components/markdown_button.tsx b/app/soapbox/features/compose/components/markdown_button.tsx index 01b0620a0..7d0d56eb6 100644 --- a/app/soapbox/features/compose/components/markdown_button.tsx +++ b/app/soapbox/features/compose/components/markdown_button.tsx @@ -18,7 +18,7 @@ const MarkdownButton: React.FC = ({ active, onClick }) => { return ( = ({ active, unavailable, disabled, onCl return ( = ({ const [placement, setPlacement] = useState('bottom'); const options = [ - { icon: require('@tabler/icons/icons/world.svg'), value: 'public', text: intl.formatMessage(messages.public_short), meta: intl.formatMessage(messages.public_long) }, - { icon: require('@tabler/icons/icons/lock-open.svg'), value: 'unlisted', text: intl.formatMessage(messages.unlisted_short), meta: intl.formatMessage(messages.unlisted_long) }, - { icon: require('@tabler/icons/icons/lock.svg'), value: 'private', text: intl.formatMessage(messages.private_short), meta: intl.formatMessage(messages.private_long) }, - { icon: require('@tabler/icons/icons/mail.svg'), value: 'direct', text: intl.formatMessage(messages.direct_short), meta: intl.formatMessage(messages.direct_long) }, + { icon: require('@tabler/icons/world.svg'), value: 'public', text: intl.formatMessage(messages.public_short), meta: intl.formatMessage(messages.public_long) }, + { icon: require('@tabler/icons/lock-open.svg'), value: 'unlisted', text: intl.formatMessage(messages.unlisted_short), meta: intl.formatMessage(messages.unlisted_long) }, + { icon: require('@tabler/icons/lock.svg'), value: 'private', text: intl.formatMessage(messages.private_short), meta: intl.formatMessage(messages.private_long) }, + { icon: require('@tabler/icons/mail.svg'), value: 'direct', text: intl.formatMessage(messages.direct_short), meta: intl.formatMessage(messages.direct_long) }, ]; const handleToggle: React.MouseEventHandler = (e) => { diff --git a/app/soapbox/features/compose/components/reply_indicator.tsx b/app/soapbox/features/compose/components/reply_indicator.tsx index f47b0494b..b9c90e98f 100644 --- a/app/soapbox/features/compose/components/reply_indicator.tsx +++ b/app/soapbox/features/compose/components/reply_indicator.tsx @@ -26,7 +26,7 @@ const ReplyIndicator: React.FC = ({ status, hideActions, onCanc if (!hideActions && onCancel) { actions = { onActionClick: handleClick, - actionIcon: require('@tabler/icons/icons/x.svg'), + actionIcon: require('@tabler/icons/x.svg'), actionAlignment: 'top', actionTitle: 'Dismiss', }; @@ -39,6 +39,7 @@ const ReplyIndicator: React.FC = ({ status, hideActions, onCanc id={status.getIn(['account', 'id']) as string} timestamp={status.created_at} showProfileHoverCard={false} + withLinkToProfile={false} /> = ({ active, unavailable, disabl return ( { diff --git a/app/soapbox/features/compose/components/search.tsx b/app/soapbox/features/compose/components/search.tsx index e70786cb7..b51164f80 100644 --- a/app/soapbox/features/compose/components/search.tsx +++ b/app/soapbox/features/compose/components/search.tsx @@ -105,7 +105,7 @@ const Search = (props: ISearch) => { const makeMenu = () => [ { text: intl.formatMessage(messages.action, { query: value }), - icon: require('@tabler/icons/icons/search.svg'), + icon: require('@tabler/icons/search.svg'), action: handleSubmit, }, ]; @@ -140,12 +140,12 @@ const Search = (props: ISearch) => { onClick={handleClear} > diff --git a/app/soapbox/features/compose/components/spoiler_button.tsx b/app/soapbox/features/compose/components/spoiler_button.tsx index 6d9c1aa76..0bc009406 100644 --- a/app/soapbox/features/compose/components/spoiler_button.tsx +++ b/app/soapbox/features/compose/components/spoiler_button.tsx @@ -18,7 +18,7 @@ const SpoilerButton: React.FC = ({ active, onClick }) => { return ( = { 'application/x-freearc': fileZipIcon, @@ -157,7 +157,7 @@ const Upload: React.FC = (props) => {
} /> @@ -165,7 +165,7 @@ const Upload: React.FC = (props) => { {(mediaType !== 'unknown' && Boolean(props.media.get('url'))) && ( } /> )} diff --git a/app/soapbox/features/compose/components/upload_button.tsx b/app/soapbox/features/compose/components/upload_button.tsx index cc29b61aa..eac158af5 100644 --- a/app/soapbox/features/compose/components/upload_button.tsx +++ b/app/soapbox/features/compose/components/upload_button.tsx @@ -48,8 +48,8 @@ const UploadButton: React.FC = ({ } const src = onlyImages(attachmentTypes) - ? require('@tabler/icons/icons/photo.svg') - : require('@tabler/icons/icons/paperclip.svg'); + ? require('@tabler/icons/photo.svg') + : require('@tabler/icons/paperclip.svg'); return (
diff --git a/app/soapbox/features/crypto_donate/components/crypto_address.tsx b/app/soapbox/features/crypto_donate/components/crypto_address.tsx index afffd085a..1ecccf083 100644 --- a/app/soapbox/features/crypto_donate/components/crypto_address.tsx +++ b/app/soapbox/features/crypto_donate/components/crypto_address.tsx @@ -42,12 +42,12 @@ const CryptoAddress: React.FC = (props): JSX.Element => { - + {explorerUrl && ( - + )} diff --git a/app/soapbox/features/crypto_donate/components/detailed_crypto_address.tsx b/app/soapbox/features/crypto_donate/components/detailed_crypto_address.tsx index 3df4b40de..76b83c196 100644 --- a/app/soapbox/features/crypto_donate/components/detailed_crypto_address.tsx +++ b/app/soapbox/features/crypto_donate/components/detailed_crypto_address.tsx @@ -30,7 +30,7 @@ const DetailedCryptoAddress: React.FC = ({ address, tick
{title || ticker.toUpperCase()}
{explorerUrl && - + }
diff --git a/app/soapbox/features/developers/developers_menu.tsx b/app/soapbox/features/developers/developers_menu.tsx index 876ce6d10..b4dfdd9c4 100644 --- a/app/soapbox/features/developers/developers_menu.tsx +++ b/app/soapbox/features/developers/developers_menu.tsx @@ -32,7 +32,7 @@ const Developers = () => {
- + @@ -40,7 +40,7 @@ const Developers = () => { - + @@ -48,7 +48,7 @@ const Developers = () => { - + @@ -56,7 +56,7 @@ const Developers = () => { - + @@ -64,7 +64,7 @@ const Developers = () => { - + @@ -72,7 +72,7 @@ const Developers = () => {
; + return ( +
+ {this.renderContent()} +
+ ); } } diff --git a/app/soapbox/features/federation_restrictions/components/restricted_instance.tsx b/app/soapbox/features/federation_restrictions/components/restricted_instance.tsx index 789cb215f..7b2547d2b 100644 --- a/app/soapbox/features/federation_restrictions/components/restricted_instance.tsx +++ b/app/soapbox/features/federation_restrictions/components/restricted_instance.tsx @@ -24,20 +24,19 @@ const RestrictedInstance: React.FC = ({ host }) => { }; return ( -
- -
- -
-
+
+ + +
{remoteInstance.get('host')}
-
+
diff --git a/app/soapbox/features/federation_restrictions/index.tsx b/app/soapbox/features/federation_restrictions/index.tsx index 396f527a0..95adc8b25 100644 --- a/app/soapbox/features/federation_restrictions/index.tsx +++ b/app/soapbox/features/federation_restrictions/index.tsx @@ -40,17 +40,15 @@ const FederationRestrictions = () => { return ( -
- - {intl.formatMessage(messages.boxMessage, { siteTitle })} - -
+ + {intl.formatMessage(messages.boxMessage, { siteTitle })} + -
+
{hosts.map((host) => )} diff --git a/app/soapbox/features/feed-filtering/__tests__/feed-carousel.test.tsx b/app/soapbox/features/feed-filtering/__tests__/feed-carousel.test.tsx index 096682fa0..d7f439fa2 100644 --- a/app/soapbox/features/feed-filtering/__tests__/feed-carousel.test.tsx +++ b/app/soapbox/features/feed-filtering/__tests__/feed-carousel.test.tsx @@ -18,7 +18,7 @@ jest.mock('../../../hooks/useDimensions', () => ({ }; describe('', () => { - let store; + let store: any; describe('with "feedUserFiltering" disabled', () => { beforeEach(() => { @@ -35,7 +35,7 @@ describe('', () => { }); it('should render nothing', () => { - render(, null, store); + render(, undefined, store); expect(screen.queryAllByTestId('feed-carousel')).toHaveLength(0); }); @@ -56,11 +56,31 @@ describe('', () => { }); it('should render the Carousel', () => { - render(, null, store); + store.carousels = { + avatars: [ + { account_id: '1', acct: 'a', account_avatar: 'https://example.com/some.jpg' }, + ], + }; + + render(, undefined, store); expect(screen.queryAllByTestId('feed-carousel')).toHaveLength(1); }); + describe('with 0 avatars', () => { + beforeEach(() => { + store.carousels = { + avatars: [], + }; + }); + + it('renders the error message', () => { + render(, undefined, store); + + expect(screen.queryAllByTestId('feed-carousel-error')).toHaveLength(0); + }); + }); + describe('with a failed request to the API', () => { beforeEach(() => { store.carousels = { @@ -70,7 +90,7 @@ describe('', () => { }); it('renders the error message', () => { - render(, null, store); + render(, undefined, store); expect(screen.getByTestId('feed-carousel-error')).toBeInTheDocument(); }); @@ -110,7 +130,7 @@ describe('', () => { it('should render the correct prev/next buttons', async() => { const user = userEvent.setup(); - render(, null, store); + render(, undefined, store); await waitFor(() => { expect(screen.getByTestId('next-page')).toBeInTheDocument(); diff --git a/app/soapbox/features/feed-filtering/feed-carousel.tsx b/app/soapbox/features/feed-filtering/feed-carousel.tsx index 6a50f39df..59c6776ba 100644 --- a/app/soapbox/features/feed-filtering/feed-carousel.tsx +++ b/app/soapbox/features/feed-filtering/feed-carousel.tsx @@ -26,7 +26,7 @@ const CarouselItem = ({ avatar }: { avatar: any }) => {
{isSelected && (
- +
)} @@ -41,7 +41,7 @@ const CarouselItem = ({ avatar }: { avatar: any }) => { />
- {avatar.acct} + {avatar.acct}
); @@ -93,6 +93,10 @@ const FeedCarousel = () => { ); } + if (avatars.length === 0) { + return null; + } + return (
@@ -104,7 +108,7 @@ const FeedCarousel = () => { onClick={handlePrevPage} className='bg-white/85 backdrop-blur rounded-full h-8 w-8 flex items-center justify-center' > - +
@@ -140,7 +144,7 @@ const FeedCarousel = () => { onClick={handleNextPage} className='bg-white/85 backdrop-blur rounded-full h-8 w-8 flex items-center justify-center' > - +
diff --git a/app/soapbox/features/feed-suggestions/feed-suggestions.tsx b/app/soapbox/features/feed-suggestions/feed-suggestions.tsx new file mode 100644 index 000000000..a5740abf9 --- /dev/null +++ b/app/soapbox/features/feed-suggestions/feed-suggestions.tsx @@ -0,0 +1,92 @@ +import React from 'react'; +import { defineMessages, useIntl } from 'react-intl'; +import { Link } from 'react-router-dom'; + +import VerificationBadge from 'soapbox/components/verification_badge'; +import { useAccount, useAppSelector } from 'soapbox/hooks'; + +import { Card, CardBody, CardTitle, HStack, Stack, Text } from '../../components/ui'; +import ActionButton from '../ui/components/action-button'; + +import type { Account } from 'soapbox/types/entities'; + +const messages = defineMessages({ + heading: { id: 'feedSuggestions.heading', defaultMessage: 'Suggested profiles' }, + viewAll: { id: 'feedSuggestions.viewAll', defaultMessage: 'View all' }, +}); + +const SuggestionItem = ({ accountId }: { accountId: string }) => { + const account = useAccount(accountId) as Account; + + return ( + + + + {account.acct} + + + + + + {account.verified && } + + + @{account.acct} + + + + +
+ +
+
+ ); +}; + +const FeedSuggestions = () => { + const intl = useIntl(); + const suggestedProfiles = useAppSelector((state) => state.suggestions.items); + + return ( + + + + + + {intl.formatMessage(messages.viewAll)} + + + + + + {suggestedProfiles.slice(0, 4).map((suggestedProfile) => ( + + ))} + + + + ); +}; + +export default FeedSuggestions; diff --git a/app/soapbox/features/follow-recommendations/index.tsx b/app/soapbox/features/follow-recommendations/index.tsx new file mode 100644 index 000000000..7fda03c7a --- /dev/null +++ b/app/soapbox/features/follow-recommendations/index.tsx @@ -0,0 +1,82 @@ +import debounce from 'lodash/debounce'; +import React, { useEffect } from 'react'; +import { defineMessages, FormattedMessage, useIntl } from 'react-intl'; + +import { fetchSuggestions } from 'soapbox/actions/suggestions'; +import ScrollableList from 'soapbox/components/scrollable_list'; +import { Stack, Text } from 'soapbox/components/ui'; +import AccountContainer from 'soapbox/containers/account_container'; +import Column from 'soapbox/features/ui/components/column'; +import { useAppDispatch, useAppSelector, useFeatures } from 'soapbox/hooks'; + +const messages = defineMessages({ + heading: { id: 'followRecommendations.heading', defaultMessage: 'Suggested profiles' }, +}); + +const FollowRecommendations: React.FC = () => { + const dispatch = useAppDispatch(); + const intl = useIntl(); + const features = useFeatures(); + + const suggestions = useAppSelector((state) => state.suggestions.items); + const hasMore = useAppSelector((state) => !!state.suggestions.next); + const isLoading = useAppSelector((state) => state.suggestions.isLoading); + + const handleLoadMore = debounce(() => { + if (isLoading) { + return null; + } + + return dispatch(fetchSuggestions({ limit: 20 })); + }, 300); + + useEffect(() => { + dispatch(fetchSuggestions({ limit: 20 })); + }, []); + + if (suggestions.size === 0 && !isLoading) { + return ( + + + + + + ); + } + + return ( + + + + {features.truthSuggestions ? ( + suggestions.map((suggestedProfile) => ( + + )) + ) : ( + suggestions.map((suggestion) => ( + + )) + )} + + + + ); +}; + +export default FollowRecommendations; diff --git a/app/soapbox/features/follow_recommendations/components/account.tsx b/app/soapbox/features/follow_recommendations/components/account.tsx deleted file mode 100644 index 67bb18f50..000000000 --- a/app/soapbox/features/follow_recommendations/components/account.tsx +++ /dev/null @@ -1,46 +0,0 @@ -import React from 'react'; - -import Avatar from 'soapbox/components/avatar'; -import DisplayName from 'soapbox/components/display-name'; -import Permalink from 'soapbox/components/permalink'; -import ActionButton from 'soapbox/features/ui/components/action-button'; -import { useAppSelector } from 'soapbox/hooks'; -import { makeGetAccount } from 'soapbox/selectors'; - -const getAccount = makeGetAccount(); - -const getFirstSentence = (str: string) => { - const arr = str.split(/(([.?!]+\s)|[.。?!\n•])/); - - return arr[0]; -}; - -interface IAccount { - id: string, -} - -const Account: React.FC = ({ id }) => { - const account = useAppSelector((state) => getAccount(state, id)); - - if (!account) return null; - - return ( -
-
- -
- - - -
{getFirstSentence(account.get('note_plain'))}
-
- -
- -
-
-
- ); -}; - -export default Account; diff --git a/app/soapbox/features/follow_recommendations/components/follow_recommendations_container.tsx b/app/soapbox/features/follow_recommendations/components/follow_recommendations_container.tsx deleted file mode 100644 index c3f198f94..000000000 --- a/app/soapbox/features/follow_recommendations/components/follow_recommendations_container.tsx +++ /dev/null @@ -1,30 +0,0 @@ -import React from 'react'; -import { FormattedMessage } from 'react-intl'; - -import { Button } from 'soapbox/components/ui'; - -import FollowRecommendationsList from './follow_recommendations_list'; - -interface IFollowRecommendationsContainer { - onDone: () => void, -} - -const FollowRecommendationsContainer: React.FC = ({ onDone }) => ( -
-
-

-

-

-
- - - -
- -
-
-); - -export default FollowRecommendationsContainer; diff --git a/app/soapbox/features/follow_recommendations/components/follow_recommendations_list.tsx b/app/soapbox/features/follow_recommendations/components/follow_recommendations_list.tsx deleted file mode 100644 index e9e295d58..000000000 --- a/app/soapbox/features/follow_recommendations/components/follow_recommendations_list.tsx +++ /dev/null @@ -1,44 +0,0 @@ -import React, { useEffect } from 'react'; -import { FormattedMessage } from 'react-intl'; -import { useDispatch } from 'react-redux'; - -import { fetchSuggestions } from 'soapbox/actions/suggestions'; -import { Spinner } from 'soapbox/components/ui'; -import { useAppSelector } from 'soapbox/hooks'; - -import Account from './account'; - -const FollowRecommendationsList: React.FC = () => { - const dispatch = useDispatch(); - - const suggestions = useAppSelector((state) => state.suggestions.items); - const isLoading = useAppSelector((state) => state.suggestions.isLoading); - - useEffect(() => { - if (suggestions.size === 0) { - dispatch(fetchSuggestions()); - } - }, []); - - if (isLoading) { - return ( -
- -
- ); - } - - return ( -
- {suggestions.size > 0 ? suggestions.map((suggestion) => ( - - )) : ( -
- -
- )} -
- ); -}; - -export default FollowRecommendationsList; diff --git a/app/soapbox/features/follow_recommendations/index.tsx b/app/soapbox/features/follow_recommendations/index.tsx deleted file mode 100644 index 444504532..000000000 --- a/app/soapbox/features/follow_recommendations/index.tsx +++ /dev/null @@ -1,22 +0,0 @@ -import React from 'react'; -import { useHistory } from 'react-router-dom'; - -import Column from 'soapbox/features/ui/components/column'; - -import FollowRecommendationsContainer from './components/follow_recommendations_container'; - -const FollowRecommendations: React.FC = () => { - const history = useHistory(); - - const onDone = () => { - history.push('/'); - }; - - return ( - - - - ); -}; - -export default FollowRecommendations; diff --git a/app/soapbox/features/follow_requests/components/account_authorize.tsx b/app/soapbox/features/follow_requests/components/account_authorize.tsx index ff66df26b..4355b8f46 100644 --- a/app/soapbox/features/follow_requests/components/account_authorize.tsx +++ b/app/soapbox/features/follow_requests/components/account_authorize.tsx @@ -51,8 +51,8 @@ const AccountAuthorize: React.FC = ({ id }) => {
-
-
+
+
); diff --git a/app/soapbox/features/groups/removed_accounts/index.js b/app/soapbox/features/groups/removed_accounts/index.js index e5d0dae41..10aa20333 100644 --- a/app/soapbox/features/groups/removed_accounts/index.js +++ b/app/soapbox/features/groups/removed_accounts/index.js @@ -82,7 +82,7 @@ class GroupRemovedAccounts extends ImmutablePureComponent { {accountIds.map(id => ())} diff --git a/app/soapbox/features/groups/timeline/components/header.js b/app/soapbox/features/groups/timeline/components/header.js index 9cb26eae3..c08210afd 100644 --- a/app/soapbox/features/groups/timeline/components/header.js +++ b/app/soapbox/features/groups/timeline/components/header.js @@ -51,17 +51,17 @@ class Header extends ImmutablePureComponent { { text: intl.formatMessage(messages.edit), to: `/groups/${group.get('id')}/edit`, - icon: require('@tabler/icons/icons/edit.svg'), + icon: require('@tabler/icons/edit.svg'), }, { text: intl.formatMessage(messages.removed_accounts), to: `/groups/${group.get('id')}/removed_accounts`, - icon: require('@tabler/icons/icons/trash.svg'), + icon: require('@tabler/icons/trash.svg'), destructive: true, }, ]; - return ; + return ; } render() { diff --git a/app/soapbox/features/home_timeline/components/column_settings.js b/app/soapbox/features/home_timeline/components/column_settings.js index 78ca71919..a643c7e17 100644 --- a/app/soapbox/features/home_timeline/components/column_settings.js +++ b/app/soapbox/features/home_timeline/components/column_settings.js @@ -31,7 +31,7 @@ class ColumnSettings extends React.PureComponent {
- +
diff --git a/app/soapbox/features/landing_page/__tests__/landing_page.test.tsx b/app/soapbox/features/landing_page/__tests__/landing_page.test.tsx index 02b9a4fe0..a52dbd975 100644 --- a/app/soapbox/features/landing_page/__tests__/landing_page.test.tsx +++ b/app/soapbox/features/landing_page/__tests__/landing_page.test.tsx @@ -17,7 +17,7 @@ describe('', () => { }, }); - render(, null, state); + render(, undefined, state); expect(screen.queryByTestId('registrations-open')).toBeInTheDocument(); expect(screen.queryByTestId('registrations-closed')).not.toBeInTheDocument(); @@ -34,7 +34,7 @@ describe('', () => { }, }); - render(, null, state); + render(, undefined, state); expect(screen.queryByTestId('registrations-closed')).toBeInTheDocument(); expect(screen.queryByTestId('registrations-open')).not.toBeInTheDocument(); @@ -59,7 +59,7 @@ describe('', () => { }, }], rootReducer); - render(, null, state); + render(, undefined, state); expect(screen.queryByTestId('registrations-pepe')).toBeInTheDocument(); expect(screen.queryByTestId('registrations-open')).not.toBeInTheDocument(); @@ -81,7 +81,7 @@ describe('', () => { }, }], rootReducer); - render(, null, state); + render(, undefined, state); expect(screen.queryByTestId('registrations-closed')).toBeInTheDocument(); expect(screen.queryByTestId('registrations-pepe')).not.toBeInTheDocument(); diff --git a/app/soapbox/features/list_adder/components/list.tsx b/app/soapbox/features/list_adder/components/list.tsx index 822833476..c9358c98e 100644 --- a/app/soapbox/features/list_adder/components/list.tsx +++ b/app/soapbox/features/list_adder/components/list.tsx @@ -30,14 +30,14 @@ const List: React.FC = ({ listId }) => { let button; if (added) { - button = ; + button = ; } else { - button = ; + button = ; } return (
- + {list.title} diff --git a/app/soapbox/features/list_editor/components/account.tsx b/app/soapbox/features/list_editor/components/account.tsx index f3c52d9f3..79916ead2 100644 --- a/app/soapbox/features/list_editor/components/account.tsx +++ b/app/soapbox/features/list_editor/components/account.tsx @@ -34,9 +34,9 @@ const Account: React.FC = ({ accountId }) => { let button; if (isAdded) { - button = ; + button = ; } else { - button = ; + button = ; } return ( diff --git a/app/soapbox/features/list_editor/components/search.tsx b/app/soapbox/features/list_editor/components/search.tsx index edd78250f..4326ffa93 100644 --- a/app/soapbox/features/list_editor/components/search.tsx +++ b/app/soapbox/features/list_editor/components/search.tsx @@ -45,7 +45,7 @@ const Search = () => { placeholder={intl.formatMessage(messages.search)} />
- +
diff --git a/app/soapbox/features/list_timeline/index.tsx b/app/soapbox/features/list_timeline/index.tsx index f9d1e6f24..90f2be274 100644 --- a/app/soapbox/features/list_timeline/index.tsx +++ b/app/soapbox/features/list_timeline/index.tsx @@ -49,7 +49,7 @@ const ListTimeline: React.FC = () => { // const handleDeleteClick = () => { // dispatch(openModal('CONFIRM', { - // icon: require('@tabler/icons/icons/trash.svg'), + // icon: require('@tabler/icons/trash.svg'), // heading: intl.formatMessage(messages.deleteHeading), // message: intl.formatMessage(messages.deleteMessage), // confirm: intl.formatMessage(messages.deleteConfirm), diff --git a/app/soapbox/features/lists/index.tsx b/app/soapbox/features/lists/index.tsx index 187c05218..e2843f77a 100644 --- a/app/soapbox/features/lists/index.tsx +++ b/app/soapbox/features/lists/index.tsx @@ -93,12 +93,12 @@ const Lists: React.FC = () => { > {lists.map((list: any) => ( - + {list.title} - - + + ))} diff --git a/app/soapbox/features/notifications/components/__tests__/notification.test.tsx b/app/soapbox/features/notifications/components/__tests__/notification.test.tsx index 14c43f50c..eacca0f99 100644 --- a/app/soapbox/features/notifications/components/__tests__/notification.test.tsx +++ b/app/soapbox/features/notifications/components/__tests__/notification.test.tsx @@ -33,10 +33,12 @@ describe('', () => { describe('grouped notifications', () => { it('renders a grouped follow notification for more than 2', async() => { - const { notification, state } = normalize(require('soapbox/__fixtures__/notification-follow.json')); - const groupedNotification = { ...notification.toJS(), total_count: 5 }; + const { notification, state } = normalize({ + ...require('soapbox/__fixtures__/notification-follow.json'), + total_count: 5, + }); - render(, undefined, state); + render(, undefined, state); expect(screen.getByTestId('notification')).toBeInTheDocument(); expect(screen.getByTestId('account')).toContainHTML('neko@rdrama.cc'); @@ -44,10 +46,12 @@ describe('', () => { }); it('renders a grouped follow notification for 1', async() => { - const { notification, state } = normalize(require('soapbox/__fixtures__/notification-follow.json')); - const groupedNotification = { ...notification.toJS(), total_count: 2 }; + const { notification, state } = normalize({ + ...require('soapbox/__fixtures__/notification-follow.json'), + total_count: 2, + }); - render(, undefined, state); + render(, undefined, state); expect(screen.getByTestId('notification')).toBeInTheDocument(); expect(screen.getByTestId('account')).toContainHTML('neko@rdrama.cc'); diff --git a/app/soapbox/features/notifications/components/clear_column_button.js b/app/soapbox/features/notifications/components/clear_column_button.js index ebb27cfbe..709deab78 100644 --- a/app/soapbox/features/notifications/components/clear_column_button.js +++ b/app/soapbox/features/notifications/components/clear_column_button.js @@ -12,7 +12,7 @@ export default class ClearColumnButton extends React.PureComponent { render() { return ( - + ); } diff --git a/app/soapbox/features/notifications/components/column_settings.js b/app/soapbox/features/notifications/components/column_settings.js index 63093ec78..b71e8fa30 100644 --- a/app/soapbox/features/notifications/components/column_settings.js +++ b/app/soapbox/features/notifications/components/column_settings.js @@ -60,7 +60,7 @@ class ColumnSettings extends React.PureComponent {
- +
diff --git a/app/soapbox/features/notifications/components/filter_bar.js b/app/soapbox/features/notifications/components/filter_bar.js index 6384b7788..a656ce290 100644 --- a/app/soapbox/features/notifications/components/filter_bar.js +++ b/app/soapbox/features/notifications/components/filter_bar.js @@ -51,19 +51,19 @@ class NotificationFilterBar extends React.PureComponent { }); } else { items.push({ - text: , + text: , title: intl.formatMessage(messages.mentions), action: this.onClick('mention'), name: 'mention', }); items.push({ - text: , + text: , title: intl.formatMessage(messages.favourites), action: this.onClick('favourite'), name: 'favourite', }); if (supportsEmojiReacts) items.push({ - text: , + text: , title: intl.formatMessage(messages.emoji_reacts), action: this.onClick('pleroma:emoji_reaction'), name: 'pleroma:emoji_reaction', @@ -75,19 +75,19 @@ class NotificationFilterBar extends React.PureComponent { name: 'reblog', }); items.push({ - text: , + text: , title: intl.formatMessage(messages.polls), action: this.onClick('poll'), name: 'poll', }); items.push({ - text: , + text: , title: intl.formatMessage(messages.statuses), action: this.onClick('status'), name: 'status', }); items.push({ - text: , + text: , title: intl.formatMessage(messages.follows), action: this.onClick('follow'), name: 'follow', diff --git a/app/soapbox/features/notifications/components/follow_request.js b/app/soapbox/features/notifications/components/follow_request.js index 4c386227e..be781a948 100644 --- a/app/soapbox/features/notifications/components/follow_request.js +++ b/app/soapbox/features/notifications/components/follow_request.js @@ -49,8 +49,8 @@ class FollowRequest extends ImmutablePureComponent {
- - + +
diff --git a/app/soapbox/features/notifications/components/notification.tsx b/app/soapbox/features/notifications/components/notification.tsx index dda887919..9f2c02778 100644 --- a/app/soapbox/features/notifications/components/notification.tsx +++ b/app/soapbox/features/notifications/components/notification.tsx @@ -9,12 +9,12 @@ import { HStack, Text, Emoji } from 'soapbox/components/ui'; import AccountContainer from 'soapbox/containers/account_container'; import StatusContainer from 'soapbox/containers/status_container'; import { useAppSelector } from 'soapbox/hooks'; +import { NotificationType, validType } from 'soapbox/utils/notification'; import type { ScrollPosition } from 'soapbox/components/status'; -import type { NotificationType } from 'soapbox/normalizers/notification'; import type { Account, Status, Notification as NotificationEntity } from 'soapbox/types/entities'; -const notificationForScreenReader = (intl: ReturnType, message: string, timestamp: Date) => { +const notificationForScreenReader = (intl: IntlShape, message: string, timestamp: Date) => { const output = [message]; output.push(intl.formatDate(timestamp, { hour: '2-digit', minute: '2-digit', month: 'short', day: 'numeric' })); @@ -35,20 +35,20 @@ const buildLink = (account: Account): JSX.Element => ( ); const icons: Record = { - follow: require('@tabler/icons/icons/user-plus.svg'), - follow_request: require('@tabler/icons/icons/user-plus.svg'), - mention: require('@tabler/icons/icons/at.svg'), - favourite: require('@tabler/icons/icons/heart.svg'), - reblog: require('@tabler/icons/icons/repeat.svg'), - status: require('@tabler/icons/icons/bell-ringing.svg'), - poll: require('@tabler/icons/icons/chart-bar.svg'), - move: require('@tabler/icons/icons/briefcase.svg'), - 'pleroma:chat_mention': require('@tabler/icons/icons/messages.svg'), - 'pleroma:emoji_reaction': require('@tabler/icons/icons/mood-happy.svg'), - user_approved: require('@tabler/icons/icons/user-plus.svg'), + follow: require('@tabler/icons/user-plus.svg'), + follow_request: require('@tabler/icons/user-plus.svg'), + mention: require('@tabler/icons/at.svg'), + favourite: require('@tabler/icons/heart.svg'), + reblog: require('@tabler/icons/repeat.svg'), + status: require('@tabler/icons/bell-ringing.svg'), + poll: require('@tabler/icons/chart-bar.svg'), + move: require('@tabler/icons/briefcase.svg'), + 'pleroma:chat_mention': require('@tabler/icons/messages.svg'), + 'pleroma:emoji_reaction': require('@tabler/icons/mood-happy.svg'), + user_approved: require('@tabler/icons/user-plus.svg'), }; -const messages: Record = defineMessages({ +const messages: Record = defineMessages({ follow: { id: 'notification.follow', defaultMessage: '{name} followed you', @@ -82,7 +82,7 @@ const messages: Record = defineMess defaultMessage: '{name} moved to {targetName}', }, 'pleroma:chat_mention': { - id: 'notification.chat_mention', + id: 'notification.pleroma:chat_mention', defaultMessage: '{name} sent you a message', }, 'pleroma:emoji_reaction': { @@ -128,16 +128,14 @@ const buildMessage = ( interface INotificaton { hidden?: boolean, notification: NotificationEntity, - onMoveUp: (notificationId: string) => void, - onMoveDown: (notificationId: string) => void, - onMention: (account: Account) => void, - onFavourite: (status: Status) => void, - onReblog: (status: Status, e?: KeyboardEvent) => void, - onToggleHidden: (status: Status) => void, + onMoveUp?: (notificationId: string) => void, + onMoveDown?: (notificationId: string) => void, + onMention?: (account: Account) => void, + onFavourite?: (status: Status) => void, + onReblog?: (status: Status, e?: KeyboardEvent) => void, + onToggleHidden?: (status: Status) => void, getScrollPosition?: () => ScrollPosition | undefined, updateScrollBottom?: (bottom: number) => void, - cacheMediaWidth: () => void, - cachedMediaWidth: number, siteTitle?: string, } @@ -180,35 +178,39 @@ const Notification: React.FC = (props) => { const handleMention = (e?: KeyboardEvent) => { e?.preventDefault(); - if (account && typeof account === 'object') { + if (props.onMention && account && typeof account === 'object') { props.onMention(account); } }; const handleHotkeyFavourite = (e?: KeyboardEvent) => { - if (status && typeof status === 'object') { + if (props.onFavourite && status && typeof status === 'object') { props.onFavourite(status); } }; const handleHotkeyBoost = (e?: KeyboardEvent) => { - if (status && typeof status === 'object') { + if (props.onReblog && status && typeof status === 'object') { props.onReblog(status, e); } }; const handleHotkeyToggleHidden = (e?: KeyboardEvent) => { - if (status && typeof status === 'object') { + if (props.onToggleHidden && status && typeof status === 'object') { props.onToggleHidden(status); } }; const handleMoveUp = () => { - onMoveUp(notification.id); + if (onMoveUp) { + onMoveUp(notification.id); + } }; const handleMoveDown = () => { - onMoveDown(notification.id); + if (onMoveDown) { + onMoveDown(notification.id); + } }; const renderIcon = (): React.ReactNode => { @@ -219,7 +221,7 @@ const Notification: React.FC = (props) => { className='w-4 h-4 flex-none' /> ); - } else if (type) { + } else if (validType(type)) { return ( = (props) => { contextType='notifications' getScrollPosition={props.getScrollPosition} updateScrollBottom={props.updateScrollBottom} - cachedMediaWidth={props.cachedMediaWidth} - cacheMediaWidth={props.cacheMediaWidth} /> ) : null; default: @@ -279,27 +279,25 @@ const Notification: React.FC = (props) => { const targetName = notification.target && typeof notification.target === 'object' ? notification.target.acct : ''; - const message: React.ReactNode = type && account && typeof account === 'object' ? buildMessage(intl, type, account, notification.total_count, targetName, instance.title) : null; + const message: React.ReactNode = validType(type) && account && typeof account === 'object' ? buildMessage(intl, type, account, notification.total_count, targetName, instance.title) : null; + + const ariaLabel = validType(type) ? ( + notificationForScreenReader( + intl, + intl.formatMessage(messages[type], { + name: account && typeof account === 'object' ? account.acct : '', + targetName, + }), + notification.created_at, + ) + ) : ''; return (
diff --git a/app/soapbox/features/notifications/containers/column_settings_container.js b/app/soapbox/features/notifications/containers/column_settings_container.js index 7e01f2fca..6375e59f5 100644 --- a/app/soapbox/features/notifications/containers/column_settings_container.js +++ b/app/soapbox/features/notifications/containers/column_settings_container.js @@ -42,7 +42,7 @@ const mapDispatchToProps = (dispatch, { intl }) => ({ onClear() { dispatch(openModal('CONFIRM', { - icon: require('@tabler/icons/icons/eraser.svg'), + icon: require('@tabler/icons/eraser.svg'), heading: intl.formatMessage(messages.clearHeading), message: intl.formatMessage(messages.clearMessage), confirm: intl.formatMessage(messages.clearConfirm), diff --git a/app/soapbox/features/notifications/index.js b/app/soapbox/features/notifications/index.js index 5ac0877d1..834bb39cb 100644 --- a/app/soapbox/features/notifications/index.js +++ b/app/soapbox/features/notifications/index.js @@ -47,6 +47,7 @@ const mapStateToProps = state => { return { showFilterBar: settings.getIn(['notifications', 'quickFilter', 'show']), + activeFilter: settings.getIn(['notifications', 'quickFilter', 'active']), notifications: getNotifications(state), isLoading: state.getIn(['notifications', 'isLoading'], true), isUnread: state.getIn(['notifications', 'unread']) > 0, @@ -62,6 +63,7 @@ class Notifications extends React.PureComponent { static propTypes = { notifications: ImmutablePropTypes.list.isRequired, showFilterBar: PropTypes.bool.isRequired, + activeFilter: PropTypes.string, dispatch: PropTypes.func.isRequired, intl: PropTypes.object.isRequired, isLoading: PropTypes.bool, @@ -143,8 +145,11 @@ class Notifications extends React.PureComponent { } render() { - const { intl, notifications, isLoading, hasMore, showFilterBar, totalQueuedNotificationsCount } = this.props; - const emptyMessage = ; + const { intl, notifications, isLoading, hasMore, showFilterBar, totalQueuedNotificationsCount, activeFilter } = this.props; + + const emptyMessage = activeFilter === 'all' + ? + : ; let scrollableContent = null; diff --git a/app/soapbox/features/onboarding/steps/avatar-selection-step.tsx b/app/soapbox/features/onboarding/steps/avatar-selection-step.tsx index 5278ed529..4593406bb 100644 --- a/app/soapbox/features/onboarding/steps/avatar-selection-step.tsx +++ b/app/soapbox/features/onboarding/steps/avatar-selection-step.tsx @@ -108,7 +108,7 @@ const AvatarSelectionStep = ({ onNext }: { onNext: () => void }) => { })} disabled={isSubmitting} > - + diff --git a/app/soapbox/features/onboarding/steps/completed-step.tsx b/app/soapbox/features/onboarding/steps/completed-step.tsx index 60f6fba13..b6637589c 100644 --- a/app/soapbox/features/onboarding/steps/completed-step.tsx +++ b/app/soapbox/features/onboarding/steps/completed-step.tsx @@ -7,7 +7,7 @@ const CompletedStep = ({ onComplete }: { onComplete: () => void }) => ( - + diff --git a/app/soapbox/features/onboarding/steps/cover-photo-selection-step.tsx b/app/soapbox/features/onboarding/steps/cover-photo-selection-step.tsx index 9efd311e8..5bc7d898f 100644 --- a/app/soapbox/features/onboarding/steps/cover-photo-selection-step.tsx +++ b/app/soapbox/features/onboarding/steps/cover-photo-selection-step.tsx @@ -120,7 +120,7 @@ const CoverPhotoSelectionStep = ({ onNext }: { onNext: () => void }) => { })} disabled={isSubmitting} > - + diff --git a/app/soapbox/features/onboarding/steps/suggested-accounts-step.tsx b/app/soapbox/features/onboarding/steps/suggested-accounts-step.tsx index 6b52270c5..d7340b163 100644 --- a/app/soapbox/features/onboarding/steps/suggested-accounts-step.tsx +++ b/app/soapbox/features/onboarding/steps/suggested-accounts-step.tsx @@ -45,6 +45,7 @@ const SuggestedAccountsStep = ({ onNext }: { onNext: () => void }) => { // @ts-ignore: TS thinks `id` is passed to , but it isn't id={suggestion.account} showProfileHoverCard={false} + withLinkToProfile={false} />
))} diff --git a/app/soapbox/features/public_layout/components/header.tsx b/app/soapbox/features/public_layout/components/header.tsx index bb952e406..1813c7d8a 100644 --- a/app/soapbox/features/public_layout/components/header.tsx +++ b/app/soapbox/features/public_layout/components/header.tsx @@ -8,7 +8,7 @@ import { fetchInstance } from 'soapbox/actions/instance'; import { openModal } from 'soapbox/actions/modals'; import SiteLogo from 'soapbox/components/site-logo'; import { Button, Form, HStack, IconButton, Input, Tooltip } from 'soapbox/components/ui'; -import { useAppSelector, useFeatures, useSoapboxConfig } from 'soapbox/hooks'; +import { useAppSelector, useFeatures, useSoapboxConfig, useOwnAccount } from 'soapbox/hooks'; import Sonar from './sonar'; @@ -27,6 +27,7 @@ const Header = () => { const dispatch = useDispatch(); const intl = useIntl(); + const account = useOwnAccount(); const soapboxConfig = useSoapboxConfig(); const pepeEnabled = soapboxConfig.getIn(['extensions', 'pepe', 'enabled']) === true; const { links } = soapboxConfig; @@ -67,7 +68,7 @@ const Header = () => { }); }; - if (shouldRedirect) return ; + if (account && shouldRedirect) return ; if (mfaToken) return ; return ( @@ -81,7 +82,7 @@ const Header = () => { @@ -145,7 +146,7 @@ const Header = () => { diff --git a/app/soapbox/features/public_timeline/components/column_settings.js b/app/soapbox/features/public_timeline/components/column_settings.js index a2b2ca6f8..1d7022fa4 100644 --- a/app/soapbox/features/public_timeline/components/column_settings.js +++ b/app/soapbox/features/public_timeline/components/column_settings.js @@ -31,7 +31,7 @@ class ColumnSettings extends React.PureComponent {
- +
diff --git a/app/soapbox/features/remote_timeline/index.tsx b/app/soapbox/features/remote_timeline/index.tsx index d6443fc86..e19284891 100644 --- a/app/soapbox/features/remote_timeline/index.tsx +++ b/app/soapbox/features/remote_timeline/index.tsx @@ -68,7 +68,7 @@ const RemoteTimeline: React.FC = ({ params }) => { {instance && } {!pinned && - + = ({ accountId, author }) => { let button; if (added) { - button = ; + button = ; } else { - button = ; + button = ; } return ( diff --git a/app/soapbox/features/scheduled_statuses/components/scheduled_status_action_bar.tsx b/app/soapbox/features/scheduled_statuses/components/scheduled_status_action_bar.tsx index 7b44805d4..dd73b8945 100644 --- a/app/soapbox/features/scheduled_statuses/components/scheduled_status_action_bar.tsx +++ b/app/soapbox/features/scheduled_statuses/components/scheduled_status_action_bar.tsx @@ -34,7 +34,7 @@ const ScheduledStatusActionBar: React.FC = ({ status dispatch(cancelScheduledStatus(status.id)); } else { dispatch(openModal('CONFIRM', { - icon: require('@tabler/icons/icons/calendar-stats.svg'), + icon: require('@tabler/icons/calendar-stats.svg'), heading: intl.formatMessage(messages.deleteHeading), message: intl.formatMessage(messages.deleteMessage), confirm: intl.formatMessage(messages.deleteConfirm), @@ -49,7 +49,7 @@ const ScheduledStatusActionBar: React.FC = ({ status diff --git a/app/soapbox/features/status/components/action-bar.tsx b/app/soapbox/features/status/components/action-bar.tsx index 5c270c082..a61ab9acb 100644 --- a/app/soapbox/features/status/components/action-bar.tsx +++ b/app/soapbox/features/status/components/action-bar.tsx @@ -6,7 +6,7 @@ import { withRouter, RouteComponentProps } from 'react-router-dom'; import { openModal } from 'soapbox/actions/modals'; import EmojiButtonWrapper from 'soapbox/components/emoji-button-wrapper'; -import { HStack, IconButton } from 'soapbox/components/ui'; +import { HStack, IconButton, Emoji, Text } from 'soapbox/components/ui'; import DropdownMenuContainer from 'soapbox/containers/dropdown_menu_container'; import { isUserTouching } from 'soapbox/is_mobile'; import { getReactForStatus } from 'soapbox/utils/emoji_reacts'; @@ -372,14 +372,14 @@ class ActionBar extends React.PureComponent { menu.push({ text: intl.formatMessage(messages.copy), action: this.handleCopy, - icon: require('@tabler/icons/icons/link.svg'), + icon: require('@tabler/icons/link.svg'), }); if (features.embeds) { menu.push({ text: intl.formatMessage(messages.embed), action: this.handleEmbed, - icon: require('@tabler/icons/icons/share.svg'), + icon: require('@tabler/icons/share.svg'), }); } } @@ -389,7 +389,7 @@ class ActionBar extends React.PureComponent { menu.push({ text: intl.formatMessage(status.bookmarked ? messages.unbookmark : messages.bookmark), action: this.handleBookmarkClick, - icon: require(status.bookmarked ? '@tabler/icons/icons/bookmark-off.svg' : '@tabler/icons/icons/bookmark.svg'), + icon: status.bookmarked ? require('@tabler/icons/bookmark-off.svg') : require('@tabler/icons/bookmark.svg'), }); } @@ -400,7 +400,7 @@ class ActionBar extends React.PureComponent { menu.push({ text: intl.formatMessage(status.pinned ? messages.unpin : messages.pin), action: this.handlePinClick, - icon: require(mutingConversation ? '@tabler/icons/icons/pinned-off.svg' : '@tabler/icons/icons/pin.svg'), + icon: mutingConversation ? require('@tabler/icons/pinned-off.svg') : require('@tabler/icons/pin.svg'), }); menu.push(null); @@ -408,7 +408,7 @@ class ActionBar extends React.PureComponent { menu.push({ text: intl.formatMessage(status.reblogged ? messages.cancel_reblog_private : messages.reblog_private), action: this.handleReblogClick, - icon: require('@tabler/icons/icons/repeat.svg'), + icon: require('@tabler/icons/repeat.svg'), }); menu.push(null); @@ -417,26 +417,26 @@ class ActionBar extends React.PureComponent { menu.push({ text: intl.formatMessage(mutingConversation ? messages.unmuteConversation : messages.muteConversation), action: this.handleConversationMuteClick, - icon: require(mutingConversation ? '@tabler/icons/icons/bell.svg' : '@tabler/icons/icons/bell-off.svg'), + icon: mutingConversation ? require('@tabler/icons/bell.svg') : require('@tabler/icons/bell-off.svg'), }); menu.push(null); menu.push({ text: intl.formatMessage(messages.delete), action: this.handleDeleteClick, - icon: require('@tabler/icons/icons/trash.svg'), + icon: require('@tabler/icons/trash.svg'), destructive: true, }); if (features.editStatuses) { menu.push({ text: intl.formatMessage(messages.edit), action: this.handleEditClick, - icon: require('@tabler/icons/icons/edit.svg'), + icon: require('@tabler/icons/edit.svg'), }); } else { menu.push({ text: intl.formatMessage(messages.redraft), action: this.handleRedraftClick, - icon: require('@tabler/icons/icons/edit.svg'), + icon: require('@tabler/icons/edit.svg'), destructive: true, }); } @@ -444,20 +444,20 @@ class ActionBar extends React.PureComponent { menu.push({ text: intl.formatMessage(messages.mention, { name: username }), action: this.handleMentionClick, - icon: require('@tabler/icons/icons/at.svg'), + icon: require('@tabler/icons/at.svg'), }); // if (status.getIn(['account', 'pleroma', 'accepts_chat_messages'], false) === true) { // menu.push({ // text: intl.formatMessage(messages.chat, { name: username }), // action: this.handleChatClick, - // icon: require('@tabler/icons/icons/messages.svg'), + // icon: require('@tabler/icons/messages.svg'), // }); // } else { // menu.push({ // text: intl.formatMessage(messages.direct, { name: username }), // action: this.handleDirectClick, - // icon: require('@tabler/icons/icons/mail.svg'), + // icon: require('@tabler/icons/mail.svg'), // }); // } @@ -465,17 +465,17 @@ class ActionBar extends React.PureComponent { menu.push({ text: intl.formatMessage(messages.mute, { name: username }), action: this.handleMuteClick, - icon: require('@tabler/icons/icons/circle-x.svg'), + icon: require('@tabler/icons/circle-x.svg'), }); menu.push({ text: intl.formatMessage(messages.block, { name: username }), action: this.handleBlockClick, - icon: require('@tabler/icons/icons/ban.svg'), + icon: require('@tabler/icons/ban.svg'), }); menu.push({ text: intl.formatMessage(messages.report, { name: username }), action: this.handleReport, - icon: require('@tabler/icons/icons/flag.svg'), + icon: require('@tabler/icons/flag.svg'), }); } @@ -486,37 +486,37 @@ class ActionBar extends React.PureComponent { menu.push({ text: intl.formatMessage(messages.admin_account, { name: username }), href: `/pleroma/admin/#/users/${status.getIn(['account', 'id'])}/`, - icon: require('@tabler/icons/icons/gavel.svg'), + icon: require('@tabler/icons/gavel.svg'), }); menu.push({ text: intl.formatMessage(messages.admin_status), href: `/pleroma/admin/#/statuses/${status.id}/`, - icon: require('@tabler/icons/icons/pencil.svg'), + icon: require('@tabler/icons/pencil.svg'), }); } menu.push({ text: intl.formatMessage(status.sensitive === false ? messages.markStatusSensitive : messages.markStatusNotSensitive), action: this.handleToggleStatusSensitivity, - icon: require('@tabler/icons/icons/alert-triangle.svg'), + icon: require('@tabler/icons/alert-triangle.svg'), }); if (!ownAccount) { menu.push({ text: intl.formatMessage(messages.deactivateUser, { name: username }), action: this.handleDeactivateUser, - icon: require('@tabler/icons/icons/user-off.svg'), + icon: require('@tabler/icons/user-off.svg'), }); menu.push({ text: intl.formatMessage(messages.deleteUser, { name: username }), action: this.handleDeleteUser, - icon: require('@tabler/icons/icons/user-minus.svg'), + icon: require('@tabler/icons/user-minus.svg'), destructive: true, }); menu.push({ text: intl.formatMessage(messages.deleteStatus), action: this.handleDeleteStatus, - icon: require('@tabler/icons/icons/trash.svg'), + icon: require('@tabler/icons/trash.svg'), destructive: true, }); } @@ -525,12 +525,12 @@ class ActionBar extends React.PureComponent { const canShare = ('share' in navigator) && status.visibility === 'public'; - let reblogIcon = require('@tabler/icons/icons/repeat.svg'); + let reblogIcon = require('@tabler/icons/repeat.svg'); if (status.visibility === 'direct') { - reblogIcon = require('@tabler/icons/icons/mail.svg'); + reblogIcon = require('@tabler/icons/mail.svg'); } else if (status.visibility === 'private') { - reblogIcon = require('@tabler/icons/icons/lock.svg'); + reblogIcon = require('@tabler/icons/lock.svg'); } const reblog_disabled = (status.visibility === 'direct' || status.visibility === 'private'); @@ -538,11 +538,11 @@ class ActionBar extends React.PureComponent { const reblogMenu: Menu = [{ text: intl.formatMessage(status.reblogged ? messages.cancel_reblog_private : messages.reblog), action: this.handleReblogClick, - icon: require('@tabler/icons/icons/repeat.svg'), + icon: require('@tabler/icons/repeat.svg'), }, { text: intl.formatMessage(messages.quotePost), action: this.handleQuoteClick, - icon: require('@tabler/icons/icons/quote.svg'), + icon: require('@tabler/icons/quote.svg'), }]; const reblogButton = ( @@ -563,7 +563,7 @@ class ActionBar extends React.PureComponent { { {features.emojiReacts ? ( - + {meEmojiReact ? ( + + ) : ( + + )} ) : ( { 'text-accent-300 hover:text-accent-300': Boolean(meEmojiReact), })} title={meEmojiTitle} - src={require('@tabler/icons/icons/heart.svg')} + src={require('@tabler/icons/heart.svg')} iconClassName={classNames({ 'fill-accent-300': Boolean(meEmojiReact), })} @@ -615,7 +632,7 @@ class ActionBar extends React.PureComponent { {canShare && ( { )} diff --git a/app/soapbox/features/status/components/card.tsx b/app/soapbox/features/status/components/card.tsx index 9aeeda38a..90ddc27e3 100644 --- a/app/soapbox/features/status/components/card.tsx +++ b/app/soapbox/features/status/components/card.tsx @@ -156,7 +156,7 @@ const Card: React.FC = ({
{title}

{trimmedDescription}

- {card.provider_name} + {card.provider_name}
); @@ -184,10 +184,10 @@ const Card: React.FC = ({ if (embedded) { embed = renderVideo(); } else { - let iconVariant = require('@tabler/icons/icons/player-play.svg'); + let iconVariant = require('@tabler/icons/player-play.svg'); if (card.type === 'photo') { - iconVariant = require('@tabler/icons/icons/zoom-in.svg'); + iconVariant = require('@tabler/icons/zoom-in.svg'); } embed = ( @@ -214,7 +214,7 @@ const Card: React.FC = ({ className='text-gray-400 hover:text-gray-600' > @@ -242,7 +242,7 @@ const Card: React.FC = ({ } else { embed = (
- +
); } diff --git a/app/soapbox/features/status/components/detailed-status.tsx b/app/soapbox/features/status/components/detailed-status.tsx index 8745e6188..393fc58fe 100644 --- a/app/soapbox/features/status/components/detailed-status.tsx +++ b/app/soapbox/features/status/components/detailed-status.tsx @@ -120,9 +120,9 @@ class DetailedStatus extends ImmutablePureComponent; + statusTypeIcon = ; } else if (status.visibility === 'private') { - statusTypeIcon = ; + statusTypeIcon = ; } return ( diff --git a/app/soapbox/features/status/components/status-interaction-bar.tsx b/app/soapbox/features/status/components/status-interaction-bar.tsx index 6f121780b..72cb061db 100644 --- a/app/soapbox/features/status/components/status-interaction-bar.tsx +++ b/app/soapbox/features/status/components/status-interaction-bar.tsx @@ -73,7 +73,7 @@ const StatusInteractionBar: React.FC = ({ status }): JSX. @@ -104,7 +104,7 @@ const StatusInteractionBar: React.FC = ({ status }): JSX. 'text-accent-300': true, 'cursor-default': !features.exposableReactions, })} - src={require('@tabler/icons/icons/heart.svg')} + src={require('@tabler/icons/heart.svg')} iconClassName='fill-accent-300' role='presentation' onClick={features.exposableReactions ? handleOpenFavouritesModal : undefined} diff --git a/app/soapbox/features/status/containers/detailed_status_container.js b/app/soapbox/features/status/containers/detailed_status_container.js index a88d9e7cd..be3b22d43 100644 --- a/app/soapbox/features/status/containers/detailed_status_container.js +++ b/app/soapbox/features/status/containers/detailed_status_container.js @@ -135,7 +135,7 @@ const mapDispatchToProps = (dispatch, { intl }) => ({ dispatch(deleteStatus(status.get('id'), withRedraft)); } else { dispatch(openModal('CONFIRM', { - icon: withRedraft ? require('@tabler/icons/icons/edit.svg') : require('@tabler/icons/icons/trash.svg'), + icon: withRedraft ? require('@tabler/icons/edit.svg') : require('@tabler/icons/trash.svg'), heading: intl.formatMessage(withRedraft ? messages.redraftHeading : messages.deleteHeading), message: intl.formatMessage(withRedraft ? messages.redraftMessage : messages.deleteMessage), confirm: intl.formatMessage(withRedraft ? messages.redraftConfirm : messages.deleteConfirm), @@ -172,7 +172,7 @@ const mapDispatchToProps = (dispatch, { intl }) => ({ onBlock(status) { const account = status.get('account'); dispatch(openModal('CONFIRM', { - icon: require('@tabler/icons/icons/ban.svg'), + icon: require('@tabler/icons/ban.svg'), heading: , message: @{account.get('acct')} }} />, confirm: intl.formatMessage(messages.blockConfirm), diff --git a/app/soapbox/features/status/index.tsx b/app/soapbox/features/status/index.tsx index b27be7e5b..cc0ce6fcc 100644 --- a/app/soapbox/features/status/index.tsx +++ b/app/soapbox/features/status/index.tsx @@ -321,7 +321,7 @@ class Status extends ImmutablePureComponent { dispatch(deleteStatus(status.id, withRedraft)); } else { dispatch(openModal('CONFIRM', { - icon: withRedraft ? require('@tabler/icons/icons/edit.svg') : require('@tabler/icons/icons/trash.svg'), + icon: withRedraft ? require('@tabler/icons/edit.svg') : require('@tabler/icons/trash.svg'), heading: intl.formatMessage(withRedraft ? messages.redraftHeading : messages.deleteHeading), message: intl.formatMessage(withRedraft ? messages.redraftMessage : messages.deleteMessage), confirm: intl.formatMessage(withRedraft ? messages.redraftConfirm : messages.deleteConfirm), @@ -409,7 +409,7 @@ class Status extends ImmutablePureComponent { if (!account || typeof account !== 'object') return; dispatch(openModal('CONFIRM', { - icon: require('@tabler/icons/icons/ban.svg'), + icon: require('@tabler/icons/ban.svg'), heading: , message: @{account.acct} }} />, confirm: intl.formatMessage(messages.blockConfirm), diff --git a/app/soapbox/features/ui/__tests__/index.test.tsx b/app/soapbox/features/ui/__tests__/index.test.tsx index 5a3164996..c28c21589 100644 --- a/app/soapbox/features/ui/__tests__/index.test.tsx +++ b/app/soapbox/features/ui/__tests__/index.test.tsx @@ -15,12 +15,12 @@ const TestableComponent = () => ( Sign in {/* WrappedRount will redirect to /login for logged out users... which will resolve to the route above! */} - + null} /> ); describe('', () => { - let store; + let store: any; beforeEach(() => { store = { diff --git a/app/soapbox/features/ui/components/__tests__/compose-button.test.tsx b/app/soapbox/features/ui/components/__tests__/compose-button.test.tsx index 86b9b84bd..c98b7aa50 100644 --- a/app/soapbox/features/ui/components/__tests__/compose-button.test.tsx +++ b/app/soapbox/features/ui/components/__tests__/compose-button.test.tsx @@ -1,17 +1,15 @@ import { fireEvent, render, screen } from '@testing-library/react'; -import { Map as ImmutableMap } from 'immutable'; import React from 'react'; import { IntlProvider } from 'react-intl'; import { Provider } from 'react-redux'; import '@testing-library/jest-dom'; import { MODAL_OPEN } from 'soapbox/actions/modals'; -import { mockStore } from 'soapbox/jest/test-helpers'; -import rootReducer from 'soapbox/reducers'; +import { mockStore, rootState } from 'soapbox/jest/test-helpers'; import ComposeButton from '../compose-button'; -const store = mockStore(rootReducer(ImmutableMap(), {})); +const store = mockStore(rootState); const renderComposeButton = () => { render( diff --git a/app/soapbox/features/ui/components/__tests__/cta-banner.test.tsx b/app/soapbox/features/ui/components/__tests__/cta-banner.test.tsx index cc4c118e6..dbda24b55 100644 --- a/app/soapbox/features/ui/components/__tests__/cta-banner.test.tsx +++ b/app/soapbox/features/ui/components/__tests__/cta-banner.test.tsx @@ -14,7 +14,7 @@ describe('', () => { it('renders empty', () => { const store = { me: true }; - render(, null, store); + render(, undefined, store); expect(screen.queryAllByTestId('cta-banner')).toHaveLength(0); }); }); @@ -23,7 +23,7 @@ describe('', () => { it('renders empty', () => { const store = { soapbox: ImmutableMap({ singleUserMode: true }) }; - render(, null, store); + render(, undefined, store); expect(screen.queryAllByTestId('cta-banner')).toHaveLength(0); }); }); diff --git a/app/soapbox/features/ui/components/__tests__/subscribe-button.test.tsx b/app/soapbox/features/ui/components/__tests__/subscribe-button.test.tsx index 3dea16d97..d0ec92f96 100644 --- a/app/soapbox/features/ui/components/__tests__/subscribe-button.test.tsx +++ b/app/soapbox/features/ui/components/__tests__/subscribe-button.test.tsx @@ -5,7 +5,9 @@ import { render, screen } from '../../../../jest/test-helpers'; import { normalizeAccount, normalizeRelationship } from '../../../../normalizers'; import SubscribeButton from '../subscription-button'; -let account = { +import type { ReducerAccount } from 'soapbox/reducers/accounts'; + +const justin = { id: '1', acct: 'justin-username', display_name: 'Justin L', @@ -13,13 +15,13 @@ let account = { }; describe('', () => { - let store; + let store: any; describe('with "accountNotifies" disabled', () => { it('renders nothing', () => { - account = normalizeAccount({ ...account, relationship: normalizeRelationship({ following: true }) }); + const account = normalizeAccount({ ...justin, relationship: normalizeRelationship({ following: true }) }) as ReducerAccount; - render(, null, store); + render(, undefined, store); expect(screen.queryAllByTestId('icon-button')).toHaveLength(0); }); }); diff --git a/app/soapbox/features/ui/components/__tests__/trends-panel.test.tsx b/app/soapbox/features/ui/components/__tests__/trends-panel.test.tsx index 03ae48553..487a84bfb 100644 --- a/app/soapbox/features/ui/components/__tests__/trends-panel.test.tsx +++ b/app/soapbox/features/ui/components/__tests__/trends-panel.test.tsx @@ -23,7 +23,7 @@ describe('', () => { })(), }; - render(, null, store); + render(, undefined, store); expect(screen.getByTestId('hashtag')).toHaveTextContent(/hashtag 1/i); expect(screen.getByTestId('hashtag')).toHaveTextContent(/180 people talking/i); expect(screen.getByTestId('sparklines')).toBeInTheDocument(); @@ -46,7 +46,7 @@ describe('', () => { })(), }; - render(, null, store); + render(, undefined, store); expect(screen.queryAllByTestId('hashtag')).toHaveLength(2); }); @@ -67,7 +67,7 @@ describe('', () => { })(), }; - render(, null, store); + render(, undefined, store); expect(screen.queryAllByTestId('hashtag')).toHaveLength(1); }); @@ -79,7 +79,7 @@ describe('', () => { })(), }; - render(, null, store); + render(, undefined, store); expect(screen.queryAllByTestId('hashtag')).toHaveLength(0); }); }); diff --git a/app/soapbox/features/ui/components/__tests__/who-to-follow-panel.test.tsx b/app/soapbox/features/ui/components/__tests__/who-to-follow-panel.test.tsx index 56e4f8422..84a645514 100644 --- a/app/soapbox/features/ui/components/__tests__/who-to-follow-panel.test.tsx +++ b/app/soapbox/features/ui/components/__tests__/who-to-follow-panel.test.tsx @@ -24,7 +24,7 @@ describe('', () => { }, }; - render(, null, store); + render(, undefined, store); expect(screen.getByTestId('account')).toHaveTextContent(/my name/i); }); @@ -58,7 +58,7 @@ describe('', () => { }, }; - render(, null, store); + render(, undefined, store); expect(screen.queryAllByTestId('account')).toHaveLength(2); }); @@ -92,7 +92,7 @@ describe('', () => { }, }; - render(, null, store); + render(, undefined, store); expect(screen.queryAllByTestId('account')).toHaveLength(1); }); @@ -117,7 +117,7 @@ describe('', () => { }, }; - render(, null, store); + render(, undefined, store); expect(screen.queryAllByTestId('account')).toHaveLength(0); }); }); diff --git a/app/soapbox/features/ui/components/accordion.tsx b/app/soapbox/features/ui/components/accordion.tsx index 40afbf7b1..32eb9da0c 100644 --- a/app/soapbox/features/ui/components/accordion.tsx +++ b/app/soapbox/features/ui/components/accordion.tsx @@ -32,7 +32,7 @@ const Accordion: React.FC = ({ headline, children, menu, expanded =
{menu && (
- +
)}
diff --git a/app/soapbox/features/ui/components/compose_modal.tsx b/app/soapbox/features/ui/components/compose_modal.tsx index 470c04b69..8b8abc342 100644 --- a/app/soapbox/features/ui/components/compose_modal.tsx +++ b/app/soapbox/features/ui/components/compose_modal.tsx @@ -30,7 +30,7 @@ const ComposeModal: React.FC = ({ onClose }) => { const onClickClose = () => { if (composeText) { dispatch(openModal('CONFIRM', { - icon: require('@tabler/icons/icons/trash.svg'), + icon: require('@tabler/icons/trash.svg'), heading: , message: , confirm: intl.formatMessage(messages.confirm), diff --git a/app/soapbox/features/ui/components/instance_info_panel.tsx b/app/soapbox/features/ui/components/instance_info_panel.tsx index 4c2462e10..3467455b3 100644 --- a/app/soapbox/features/ui/components/instance_info_panel.tsx +++ b/app/soapbox/features/ui/components/instance_info_panel.tsx @@ -43,7 +43,7 @@ const InstanceInfoPanel: React.FC = ({ host }) => { ); diff --git a/app/soapbox/features/ui/components/instance_moderation_panel.tsx b/app/soapbox/features/ui/components/instance_moderation_panel.tsx index ed97495f1..3ea9cf715 100644 --- a/app/soapbox/features/ui/components/instance_moderation_panel.tsx +++ b/app/soapbox/features/ui/components/instance_moderation_panel.tsx @@ -37,7 +37,7 @@ const InstanceModerationPanel: React.FC = ({ host }) = return [{ text: intl.formatMessage(messages.editFederation), action: handleEditFederation, - icon: require('@tabler/icons/icons/edit.svg'), + icon: require('@tabler/icons/edit.svg'), }]; }; @@ -47,7 +47,7 @@ const InstanceModerationPanel: React.FC = ({ host }) = } action={account?.admin ? ( - + ) : undefined} > diff --git a/app/soapbox/features/ui/components/media_modal.js b/app/soapbox/features/ui/components/media_modal.js index 111bbede1..dcc670d15 100644 --- a/app/soapbox/features/ui/components/media_modal.js +++ b/app/soapbox/features/ui/components/media_modal.js @@ -121,13 +121,13 @@ class MediaModal extends ImmutablePureComponent { const leftNav = media.size > 1 && ( ); const rightNav = media.size > 1 && ( ); @@ -252,7 +252,7 @@ class MediaModal extends ImmutablePureComponent {
- + {leftNav} {rightNav} diff --git a/app/soapbox/features/ui/components/modals/landing-page-modal.tsx b/app/soapbox/features/ui/components/modals/landing-page-modal.tsx index d3e9b8be5..22a733f60 100644 --- a/app/soapbox/features/ui/components/modals/landing-page-modal.tsx +++ b/app/soapbox/features/ui/components/modals/landing-page-modal.tsx @@ -44,7 +44,7 @@ const LandingPageModal: React.FC = ({ onClose }) => { target='_blank' className='p-3 space-x-3 flex items-center rounded-md dark:hover:bg-slate-900/50 hover:bg-gray-50' > - + {intl.formatMessage(messages.helpCenter)} diff --git a/app/soapbox/features/ui/components/modals/report-modal/__tests__/report-modal.test.tsx b/app/soapbox/features/ui/components/modals/report-modal/__tests__/report-modal.test.tsx index 1fe62d7f2..a2dee08b5 100644 --- a/app/soapbox/features/ui/components/modals/report-modal/__tests__/report-modal.test.tsx +++ b/app/soapbox/features/ui/components/modals/report-modal/__tests__/report-modal.test.tsx @@ -9,7 +9,7 @@ import { normalizeAccount, normalizeStatus } from '../../../../../../normalizers import ReportModal from '../report-modal'; describe('', () => { - let store; + let store: any; beforeEach(() => { const rules = require('soapbox/__fixtures__/rules.json'); diff --git a/app/soapbox/features/ui/components/modals/report-modal/report-modal.tsx b/app/soapbox/features/ui/components/modals/report-modal/report-modal.tsx index 39575beb4..cd4f1ff08 100644 --- a/app/soapbox/features/ui/components/modals/report-modal/report-modal.tsx +++ b/app/soapbox/features/ui/components/modals/report-modal/report-modal.tsx @@ -49,6 +49,7 @@ const SelectedStatus = ({ statusId }: { statusId: string }) => { diff --git a/app/soapbox/features/ui/components/modals/report-modal/steps/other-actions-step.tsx b/app/soapbox/features/ui/components/modals/report-modal/steps/other-actions-step.tsx index f22cde28b..7ce82995d 100644 --- a/app/soapbox/features/ui/components/modals/report-modal/steps/other-actions-step.tsx +++ b/app/soapbox/features/ui/components/modals/report-modal/steps/other-actions-step.tsx @@ -67,7 +67,7 @@ const OtherActionsStep = ({ account }: IOtherActionsStep) => {
); diff --git a/app/soapbox/features/ui/util/async-components.ts b/app/soapbox/features/ui/util/async-components.ts index a6379b130..30420cf27 100644 --- a/app/soapbox/features/ui/util/async-components.ts +++ b/app/soapbox/features/ui/util/async-components.ts @@ -455,7 +455,7 @@ export function WhoToFollowPanel() { } export function FollowRecommendations() { - return import(/* webpackChunkName: "features/follow_recommendations" */'../../follow_recommendations'); + return import(/* webpackChunkName: "features/follow-recommendations" */'../../follow-recommendations'); } export function Directory() { diff --git a/app/soapbox/features/verification/__tests__/index.test.tsx b/app/soapbox/features/verification/__tests__/index.test.tsx index 32182f515..e24aee442 100644 --- a/app/soapbox/features/verification/__tests__/index.test.tsx +++ b/app/soapbox/features/verification/__tests__/index.test.tsx @@ -14,7 +14,7 @@ const TestableComponent = () => ( ); -const renderComponent = (store) => render( +const renderComponent = (store: any) => render( , {}, store, @@ -22,7 +22,7 @@ const renderComponent = (store) => render( ); describe('', () => { - let store; + let store: any; beforeEach(() => { store = { diff --git a/app/soapbox/features/verification/__tests__/registration.test.tsx b/app/soapbox/features/verification/__tests__/registration.test.tsx index f82c0dab4..fbde2fce3 100644 --- a/app/soapbox/features/verification/__tests__/registration.test.tsx +++ b/app/soapbox/features/verification/__tests__/registration.test.tsx @@ -18,7 +18,7 @@ describe('', () => { mock.onPost('/api/v1/pepe/accounts').reply(200, {}); mock.onPost('/api/v1/apps').reply(200, {}); mock.onPost('/oauth/token').reply(200, {}); - mock.onPost('/api/v1/accounts/verify_credentials').reply(200, {}); + mock.onGet('/api/v1/accounts/verify_credentials').reply(200, { id: '123' }); mock.onGet('/api/v1/instance').reply(200, {}); }); }); diff --git a/app/soapbox/features/verification/email_passthru.tsx b/app/soapbox/features/verification/email_passthru.tsx index ebe36e5f0..2211e6d96 100644 --- a/app/soapbox/features/verification/email_passthru.tsx +++ b/app/soapbox/features/verification/email_passthru.tsx @@ -33,7 +33,7 @@ const Success = () => { return ( - + {intl.formatMessage(messages.emailConfirmedHeading)} @@ -49,7 +49,7 @@ const GenericFail = () => { return ( - + {intl.formatMessage(messages.genericFailHeading)} @@ -65,7 +65,7 @@ const TokenNotFound = () => { return ( - + {intl.formatMessage(messages.tokenNotFoundHeading)} @@ -82,7 +82,7 @@ const TokenExpired = () => { return ( - + {intl.formatMessage(messages.tokenExpiredHeading)} diff --git a/app/soapbox/features/verification/registration.tsx b/app/soapbox/features/verification/registration.tsx index 02aea214c..a06d49963 100644 --- a/app/soapbox/features/verification/registration.tsx +++ b/app/soapbox/features/verification/registration.tsx @@ -109,7 +109,7 @@ const Registration = () => { value={username} onChange={handleInputChange} required - icon={require('@tabler/icons/icons/at.svg')} + icon={require('@tabler/icons/at.svg')} /> diff --git a/app/soapbox/features/verification/steps/__tests__/age-verification.test.tsx b/app/soapbox/features/verification/steps/__tests__/age-verification.test.tsx index 7dd835313..f310a0741 100644 --- a/app/soapbox/features/verification/steps/__tests__/age-verification.test.tsx +++ b/app/soapbox/features/verification/steps/__tests__/age-verification.test.tsx @@ -8,7 +8,7 @@ import { fireEvent, render, screen } from 'soapbox/jest/test-helpers'; import AgeVerification from '../age-verification'; describe('', () => { - let store; + let store: any; beforeEach(() => { store = { diff --git a/app/soapbox/features/verification/steps/email-verification.tsx b/app/soapbox/features/verification/steps/email-verification.tsx index b8c1810b1..9ee87cbee 100644 --- a/app/soapbox/features/verification/steps/email-verification.tsx +++ b/app/soapbox/features/verification/steps/email-verification.tsx @@ -37,7 +37,7 @@ const EmailSent: React.FC = ({ handleSubmit }) => { return (
- +
We sent you an email diff --git a/app/soapbox/features/video/index.js b/app/soapbox/features/video/index.js index 0bcb094d7..d4250029b 100644 --- a/app/soapbox/features/video/index.js +++ b/app/soapbox/features/video/index.js @@ -589,8 +589,8 @@ class Video extends React.PureComponent {
- - + +
@@ -613,10 +613,10 @@ class Video extends React.PureComponent {
- {(sensitive && !onCloseVideo) && } - {(!fullscreen && onOpenVideo) && } - {/* onCloseVideo && */} - + {(sensitive && !onCloseVideo) && } + {(!fullscreen && onOpenVideo) && } + {/* onCloseVideo && */} +
diff --git a/app/soapbox/hooks/__tests__/useDimensions.test.ts b/app/soapbox/hooks/__tests__/useDimensions.test.ts index c437f1394..0adee42e4 100644 --- a/app/soapbox/hooks/__tests__/useDimensions.test.ts +++ b/app/soapbox/hooks/__tests__/useDimensions.test.ts @@ -6,7 +6,7 @@ let listener: ((rect: any) => void) | undefined = undefined; (window as any).ResizeObserver = class ResizeObserver { - constructor(ls) { + constructor(ls: any) { listener = ls; } @@ -63,7 +63,7 @@ describe('useDimensions()', () => { disconnect() { disconnect(); } - + }; const { result, unmount } = renderHook(() => useDimensions()); diff --git a/app/soapbox/jest/test-helpers.tsx b/app/soapbox/jest/test-helpers.tsx index 459049b52..657919b5a 100644 --- a/app/soapbox/jest/test-helpers.tsx +++ b/app/soapbox/jest/test-helpers.tsx @@ -1,3 +1,4 @@ +import { configureMockStore } from '@jedmao/redux-mock-store'; import { render, RenderOptions } from '@testing-library/react'; import { merge } from 'immutable'; import React, { FC, ReactElement } from 'react'; @@ -5,18 +6,19 @@ import { IntlProvider } from 'react-intl'; import { Provider } from 'react-redux'; import { MemoryRouter } from 'react-router-dom'; import { Action, applyMiddleware, createStore } from 'redux'; -import configureMockStore from 'redux-mock-store'; import thunk from 'redux-thunk'; import '@testing-library/jest-dom'; import NotificationsContainer from '../features/ui/containers/notifications_container'; import { default as rootReducer } from '../reducers'; +import type { AnyAction } from 'redux'; +import type { AppDispatch } from 'soapbox/store'; + // Mock Redux // https://redux.js.org/recipes/writing-tests/ -const middlewares = [thunk]; -const mockStore = configureMockStore(middlewares); -let rootState = rootReducer(undefined, {} as Action); +const rootState = rootReducer(undefined, {} as Action); +const mockStore = configureMockStore([thunk]); /** Apply actions to the state, one at a time. */ const applyActions = (state: any, actions: any, reducer: any) => { @@ -26,13 +28,14 @@ const applyActions = (state: any, actions: any, reducer: any) => { const createTestStore = (initialState: any) => createStore(rootReducer, initialState, applyMiddleware(thunk)); const TestApp: FC = ({ children, storeProps, routerProps = {} }) => { - let store: any; + let store: ReturnType; + let appState = rootState; if (storeProps) { - rootState = merge(rootState, storeProps); - store = createTestStore(rootState); + appState = merge(rootState, storeProps); + store = createTestStore(appState); } else { - store = createTestStore(rootState); + store = createTestStore(appState); } const props = { diff --git a/app/soapbox/locales/ar.json b/app/soapbox/locales/ar.json index d1e705697..a508846d9 100644 --- a/app/soapbox/locales/ar.json +++ b/app/soapbox/locales/ar.json @@ -706,7 +706,7 @@ "notification.birthday": "{name} has a birthday today", "notification.birthday.more": "{count} more {count, plural, one {friend} other {friends}}", "notification.birthday_plural": "{name} and {more} have birthday today", - "notification.chat_mention": "{name} sent you a message", + "notification.pleroma:chat_mention": "{name} sent you a message", "notification.favourite": "أُعجِب {name} بمنشورك", "notification.follow": "{name} يتابعك", "notification.follow_request": "{name} has requested to follow you", diff --git a/app/soapbox/locales/ast.json b/app/soapbox/locales/ast.json index ef5c65bd9..8ddb7bcaa 100644 --- a/app/soapbox/locales/ast.json +++ b/app/soapbox/locales/ast.json @@ -706,7 +706,7 @@ "notification.birthday": "{name} has a birthday today", "notification.birthday.more": "{count} more {count, plural, one {friend} other {friends}}", "notification.birthday_plural": "{name} and {more} have birthday today", - "notification.chat_mention": "{name} sent you a message", + "notification.pleroma:chat_mention": "{name} sent you a message", "notification.favourite": "{name} favorited your post", "notification.follow": "{name} siguióte", "notification.follow_request": "{name} has requested to follow you", diff --git a/app/soapbox/locales/bg.json b/app/soapbox/locales/bg.json index 4e937e97c..296e6b6b3 100644 --- a/app/soapbox/locales/bg.json +++ b/app/soapbox/locales/bg.json @@ -706,7 +706,7 @@ "notification.birthday": "{name} has a birthday today", "notification.birthday.more": "{count} more {count, plural, one {friend} other {friends}}", "notification.birthday_plural": "{name} and {more} have birthday today", - "notification.chat_mention": "{name} sent you a message", + "notification.pleroma:chat_mention": "{name} sent you a message", "notification.favourite": "{name} хареса твоята публикация", "notification.follow": "{name} те последва", "notification.follow_request": "{name} has requested to follow you", diff --git a/app/soapbox/locales/bn.json b/app/soapbox/locales/bn.json index c030722fa..adc441285 100644 --- a/app/soapbox/locales/bn.json +++ b/app/soapbox/locales/bn.json @@ -706,7 +706,7 @@ "notification.birthday": "{name} has a birthday today", "notification.birthday.more": "{count} more {count, plural, one {friend} other {friends}}", "notification.birthday_plural": "{name} and {more} have birthday today", - "notification.chat_mention": "{name} sent you a message", + "notification.pleroma:chat_mention": "{name} sent you a message", "notification.favourite": "{name} আপনার কার্যক্রম পছন্দ করেছেন", "notification.follow": "{name} আপনাকে অনুসরণ করেছেন", "notification.follow_request": "{name} has requested to follow you", diff --git a/app/soapbox/locales/br.json b/app/soapbox/locales/br.json index 9bec55d5b..4ee233e15 100644 --- a/app/soapbox/locales/br.json +++ b/app/soapbox/locales/br.json @@ -706,7 +706,7 @@ "notification.birthday": "{name} has a birthday today", "notification.birthday.more": "{count} more {count, plural, one {friend} other {friends}}", "notification.birthday_plural": "{name} and {more} have birthday today", - "notification.chat_mention": "{name} sent you a message", + "notification.pleroma:chat_mention": "{name} sent you a message", "notification.favourite": "{name} favorited your post", "notification.follow": "{name} followed you", "notification.follow_request": "{name} has requested to follow you", diff --git a/app/soapbox/locales/ca.json b/app/soapbox/locales/ca.json index e36ad89bc..3007d4446 100644 --- a/app/soapbox/locales/ca.json +++ b/app/soapbox/locales/ca.json @@ -706,7 +706,7 @@ "notification.birthday": "{name} has a birthday today", "notification.birthday.more": "{count} more {count, plural, one {friend} other {friends}}", "notification.birthday_plural": "{name} and {more} have birthday today", - "notification.chat_mention": "{name} t'ha enviat un missatge", + "notification.pleroma:chat_mention": "{name} t'ha enviat un missatge", "notification.favourite": "{name} ha afavorit el teu estat", "notification.follow": "{name} t'ha seguit", "notification.follow_request": "{name} ha sol·licitat seguir-te", diff --git a/app/soapbox/locales/co.json b/app/soapbox/locales/co.json index 79214836a..d57318943 100644 --- a/app/soapbox/locales/co.json +++ b/app/soapbox/locales/co.json @@ -706,7 +706,7 @@ "notification.birthday": "{name} has a birthday today", "notification.birthday.more": "{count} more {count, plural, one {friend} other {friends}}", "notification.birthday_plural": "{name} and {more} have birthday today", - "notification.chat_mention": "{name} sent you a message", + "notification.pleroma:chat_mention": "{name} sent you a message", "notification.favourite": "{name} hà aghjuntu u vostru statutu à i so favuriti", "notification.follow": "{name} v'hà seguitatu", "notification.follow_request": "{name} has requested to follow you", diff --git a/app/soapbox/locales/cs.json b/app/soapbox/locales/cs.json index 155e1fa95..3e5e5c77a 100644 --- a/app/soapbox/locales/cs.json +++ b/app/soapbox/locales/cs.json @@ -706,7 +706,7 @@ "notification.birthday": "{name} has a birthday today", "notification.birthday.more": "{count} more {count, plural, one {friend} other {friends}}", "notification.birthday_plural": "{name} and {more} have birthday today", - "notification.chat_mention": "{name} Vám poslal/a zprávu", + "notification.pleroma:chat_mention": "{name} Vám poslal/a zprávu", "notification.favourite": "{name} si oblíbil/a váš příspěvek", "notification.follow": "{name} vás začal/a sledovat", "notification.follow_request": "{name} has requested to follow you", diff --git a/app/soapbox/locales/cy.json b/app/soapbox/locales/cy.json index bfc9c701b..b27bbc575 100644 --- a/app/soapbox/locales/cy.json +++ b/app/soapbox/locales/cy.json @@ -706,7 +706,7 @@ "notification.birthday": "{name} has a birthday today", "notification.birthday.more": "{count} more {count, plural, one {friend} other {friends}}", "notification.birthday_plural": "{name} and {more} have birthday today", - "notification.chat_mention": "{name} sent you a message", + "notification.pleroma:chat_mention": "{name} sent you a message", "notification.favourite": "hoffodd {name} eich tŵt", "notification.follow": "dilynodd {name} chi", "notification.follow_request": "{name} has requested to follow you", diff --git a/app/soapbox/locales/da.json b/app/soapbox/locales/da.json index a935d51cf..16ac072a2 100644 --- a/app/soapbox/locales/da.json +++ b/app/soapbox/locales/da.json @@ -706,7 +706,7 @@ "notification.birthday": "{name} has a birthday today", "notification.birthday.more": "{count} more {count, plural, one {friend} other {friends}}", "notification.birthday_plural": "{name} and {more} have birthday today", - "notification.chat_mention": "{name} sent you a message", + "notification.pleroma:chat_mention": "{name} sent you a message", "notification.favourite": "{name} favoriserede din status", "notification.follow": "{name} fulgte dig", "notification.follow_request": "{name} has requested to follow you", diff --git a/app/soapbox/locales/de.json b/app/soapbox/locales/de.json index 366373390..2fcb8e5f0 100644 --- a/app/soapbox/locales/de.json +++ b/app/soapbox/locales/de.json @@ -706,7 +706,7 @@ "notification.birthday": "{name} has a birthday today", "notification.birthday.more": "{count} more {count, plural, one {friend} other {friends}}", "notification.birthday_plural": "{name} and {more} have birthday today", - "notification.chat_mention": "{name} hat dir eine Nachricht gesendet", + "notification.pleroma:chat_mention": "{name} hat dir eine Nachricht gesendet", "notification.favourite": "{name} hat deinen Beitrag favorisiert", "notification.follow": "{name} folgt dir", "notification.follow_request": "{name} möchte dir folgen", diff --git a/app/soapbox/locales/defaultMessages.json b/app/soapbox/locales/defaultMessages.json index e9c48411f..c5730c2e8 100644 --- a/app/soapbox/locales/defaultMessages.json +++ b/app/soapbox/locales/defaultMessages.json @@ -4318,7 +4318,7 @@ }, { "defaultMessage": "{name} sent you a message", - "id": "notification.chat_mention" + "id": "notification.pleroma:chat_mention" }, { "defaultMessage": "{name} reacted to your post", diff --git a/app/soapbox/locales/el.json b/app/soapbox/locales/el.json index b601e68e8..9ee73f0df 100644 --- a/app/soapbox/locales/el.json +++ b/app/soapbox/locales/el.json @@ -706,7 +706,7 @@ "notification.birthday": "{name} has a birthday today", "notification.birthday.more": "{count} more {count, plural, one {friend} other {friends}}", "notification.birthday_plural": "{name} and {more} have birthday today", - "notification.chat_mention": "{name} sent you a message", + "notification.pleroma:chat_mention": "{name} sent you a message", "notification.favourite": "Ο/Η {name} σημείωσε ως αγαπημένη την κατάστασή σου", "notification.follow": "Ο/Η {name} σε ακολούθησε", "notification.follow_request": "{name} has requested to follow you", diff --git a/app/soapbox/locales/en-Shaw.json b/app/soapbox/locales/en-Shaw.json index 027855309..bf0663c44 100644 --- a/app/soapbox/locales/en-Shaw.json +++ b/app/soapbox/locales/en-Shaw.json @@ -706,7 +706,7 @@ "notification.birthday": "{name} has a birthday today", "notification.birthday.more": "{count} more {count, plural, one {friend} other {friends}}", "notification.birthday_plural": "{name} and {more} have birthday today", - "notification.chat_mention": "{name} 𐑕𐑧𐑯𐑑 𐑿 𐑩 𐑥𐑧𐑕𐑦𐑡", + "notification.pleroma:chat_mention": "{name} 𐑕𐑧𐑯𐑑 𐑿 𐑩 𐑥𐑧𐑕𐑦𐑡", "notification.favourite": "{name} 𐑤𐑲𐑒𐑑 𐑘𐑹 𐑐𐑴𐑕𐑑", "notification.follow": "{name} 𐑓𐑪𐑤𐑴𐑛 𐑿", "notification.follow_request": "{name} 𐑣𐑨𐑟 𐑮𐑦𐑒𐑢𐑧𐑕𐑑𐑩𐑛 𐑑 𐑓𐑪𐑤𐑴 𐑿", diff --git a/app/soapbox/locales/en.json b/app/soapbox/locales/en.json index 9a1af5b43..2d226e81d 100644 --- a/app/soapbox/locales/en.json +++ b/app/soapbox/locales/en.json @@ -712,7 +712,7 @@ "notification.birthday": "{name} has a birthday today", "notification.birthday.more": "{count} more {count, plural, one {friend} other {friends}}", "notification.birthday_plural": "{name} and {more} have birthday today", - "notification.chat_mention": "{name} sent you a message", + "notification.pleroma:chat_mention": "{name} sent you a message", "notification.favourite": "{name} liked your post", "notification.follow": "{name} followed you", "notification.follow_request": "{name} has requested to follow you", diff --git a/app/soapbox/locales/eo.json b/app/soapbox/locales/eo.json index 4c3bd6166..7b4b89c5f 100644 --- a/app/soapbox/locales/eo.json +++ b/app/soapbox/locales/eo.json @@ -706,7 +706,7 @@ "notification.birthday": "{name} has a birthday today", "notification.birthday.more": "{count} more {count, plural, one {friend} other {friends}}", "notification.birthday_plural": "{name} and {more} have birthday today", - "notification.chat_mention": "{name} sent you a message", + "notification.pleroma:chat_mention": "{name} sent you a message", "notification.favourite": "{name} stelumis vian mesaĝon", "notification.follow": "{name} eksekvis vin", "notification.follow_request": "{name} has requested to follow you", diff --git a/app/soapbox/locales/es-AR.json b/app/soapbox/locales/es-AR.json index eb56879a0..8590459b6 100644 --- a/app/soapbox/locales/es-AR.json +++ b/app/soapbox/locales/es-AR.json @@ -706,7 +706,7 @@ "notification.birthday": "{name} has a birthday today", "notification.birthday.more": "{count} more {count, plural, one {friend} other {friends}}", "notification.birthday_plural": "{name} and {more} have birthday today", - "notification.chat_mention": "{name} sent you a message", + "notification.pleroma:chat_mention": "{name} sent you a message", "notification.favourite": "{name} marcó tu estado como favorito", "notification.follow": "{name} te empezó a seguir", "notification.follow_request": "{name} has requested to follow you", diff --git a/app/soapbox/locales/es.json b/app/soapbox/locales/es.json index c4a3e99cb..9c8e6432a 100644 --- a/app/soapbox/locales/es.json +++ b/app/soapbox/locales/es.json @@ -706,7 +706,7 @@ "notification.birthday": "{name} has a birthday today", "notification.birthday.more": "{count} more {count, plural, one {friend} other {friends}}", "notification.birthday_plural": "{name} and {more} have birthday today", - "notification.chat_mention": "{name} sent you a message", + "notification.pleroma:chat_mention": "{name} sent you a message", "notification.favourite": "{name} marcó tu estado como favorito", "notification.follow": "{name} te empezó a seguir", "notification.follow_request": "{name} has requested to follow you", diff --git a/app/soapbox/locales/et.json b/app/soapbox/locales/et.json index 636be30e0..954dbb96c 100644 --- a/app/soapbox/locales/et.json +++ b/app/soapbox/locales/et.json @@ -706,7 +706,7 @@ "notification.birthday": "{name} has a birthday today", "notification.birthday.more": "{count} more {count, plural, one {friend} other {friends}}", "notification.birthday_plural": "{name} and {more} have birthday today", - "notification.chat_mention": "{name} sent you a message", + "notification.pleroma:chat_mention": "{name} sent you a message", "notification.favourite": "{name} märkis su staatuse lemmikuks", "notification.follow": "{name} jälgib sind", "notification.follow_request": "{name} has requested to follow you", diff --git a/app/soapbox/locales/eu.json b/app/soapbox/locales/eu.json index a16e4332b..3041d4be7 100644 --- a/app/soapbox/locales/eu.json +++ b/app/soapbox/locales/eu.json @@ -706,7 +706,7 @@ "notification.birthday": "{name} has a birthday today", "notification.birthday.more": "{count} more {count, plural, one {friend} other {friends}}", "notification.birthday_plural": "{name} and {more} have birthday today", - "notification.chat_mention": "{name} sent you a message", + "notification.pleroma:chat_mention": "{name} sent you a message", "notification.favourite": "{name}(e)k zure mezua gogoko du", "notification.follow": "{name}(e)k jarraitzen zaitu", "notification.follow_request": "{name} has requested to follow you", diff --git a/app/soapbox/locales/fa.json b/app/soapbox/locales/fa.json index b9e9da44d..2b65e24c7 100644 --- a/app/soapbox/locales/fa.json +++ b/app/soapbox/locales/fa.json @@ -706,7 +706,7 @@ "notification.birthday": "{name} has a birthday today", "notification.birthday.more": "{count} more {count, plural, one {friend} other {friends}}", "notification.birthday_plural": "{name} and {more} have birthday today", - "notification.chat_mention": "{name} sent you a message", + "notification.pleroma:chat_mention": "{name} sent you a message", "notification.favourite": "‫{name}‬ نوشتهٔ شما را پسندید", "notification.follow": "‫{name}‬ پیگیر شما شد", "notification.follow_request": "{name} has requested to follow you", diff --git a/app/soapbox/locales/fi.json b/app/soapbox/locales/fi.json index d806c2fc6..b8896b3f9 100644 --- a/app/soapbox/locales/fi.json +++ b/app/soapbox/locales/fi.json @@ -706,7 +706,7 @@ "notification.birthday": "{name} has a birthday today", "notification.birthday.more": "{count} more {count, plural, one {friend} other {friends}}", "notification.birthday_plural": "{name} and {more} have birthday today", - "notification.chat_mention": "{name} sent you a message", + "notification.pleroma:chat_mention": "{name} sent you a message", "notification.favourite": "{name} tykkäsi tilastasi", "notification.follow": "{name} seurasi sinua", "notification.follow_request": "{name} has requested to follow you", diff --git a/app/soapbox/locales/fr.json b/app/soapbox/locales/fr.json index 373c89021..3c7d73308 100644 --- a/app/soapbox/locales/fr.json +++ b/app/soapbox/locales/fr.json @@ -706,7 +706,7 @@ "notification.birthday": "{name} has a birthday today", "notification.birthday.more": "{count} more {count, plural, one {friend} other {friends}}", "notification.birthday_plural": "{name} and {more} have birthday today", - "notification.chat_mention": "{name} sent you a message", + "notification.pleroma:chat_mention": "{name} sent you a message", "notification.favourite": "{name} a ajouté à ses favoris :", "notification.follow": "{name} vous suit", "notification.follow_request": "{name} has requested to follow you", diff --git a/app/soapbox/locales/ga.json b/app/soapbox/locales/ga.json index eb21a107f..0cf874018 100644 --- a/app/soapbox/locales/ga.json +++ b/app/soapbox/locales/ga.json @@ -706,7 +706,7 @@ "notification.birthday": "{name} has a birthday today", "notification.birthday.more": "{count} more {count, plural, one {friend} other {friends}}", "notification.birthday_plural": "{name} and {more} have birthday today", - "notification.chat_mention": "{name} sent you a message", + "notification.pleroma:chat_mention": "{name} sent you a message", "notification.favourite": "{name} favorited your post", "notification.follow": "{name} followed you", "notification.follow_request": "{name} has requested to follow you", diff --git a/app/soapbox/locales/gl.json b/app/soapbox/locales/gl.json index 3ea35cb9f..95ee2cbbc 100644 --- a/app/soapbox/locales/gl.json +++ b/app/soapbox/locales/gl.json @@ -706,7 +706,7 @@ "notification.birthday": "{name} has a birthday today", "notification.birthday.more": "{count} more {count, plural, one {friend} other {friends}}", "notification.birthday_plural": "{name} and {more} have birthday today", - "notification.chat_mention": "{name} sent you a message", + "notification.pleroma:chat_mention": "{name} sent you a message", "notification.favourite": "{name} marcou como favorito o seu estado", "notification.follow": "{name} está a seguila", "notification.follow_request": "{name} has requested to follow you", diff --git a/app/soapbox/locales/he.json b/app/soapbox/locales/he.json index 66d636c1d..7b20f137a 100644 --- a/app/soapbox/locales/he.json +++ b/app/soapbox/locales/he.json @@ -706,7 +706,7 @@ "notification.birthday": "{name} has a birthday today", "notification.birthday.more": "{count} more {count, plural, one {friend} other {friends}}", "notification.birthday_plural": "{name} and {more} have birthday today", - "notification.chat_mention": "{name} שלח לך הודעה", + "notification.pleroma:chat_mention": "{name} שלח לך הודעה", "notification.favourite": "הפוסט שלך חובב על ידי {name}", "notification.follow": "{name} במעקב אחרייך", "notification.follow_request": "{name} ביקש לעקוב אחריך", diff --git a/app/soapbox/locales/hi.json b/app/soapbox/locales/hi.json index cbc84692c..26deafba5 100644 --- a/app/soapbox/locales/hi.json +++ b/app/soapbox/locales/hi.json @@ -706,7 +706,7 @@ "notification.birthday": "{name} has a birthday today", "notification.birthday.more": "{count} more {count, plural, one {friend} other {friends}}", "notification.birthday_plural": "{name} and {more} have birthday today", - "notification.chat_mention": "{name} sent you a message", + "notification.pleroma:chat_mention": "{name} sent you a message", "notification.favourite": "{name} favorited your post", "notification.follow": "{name} followed you", "notification.follow_request": "{name} has requested to follow you", diff --git a/app/soapbox/locales/hr.json b/app/soapbox/locales/hr.json index ca5451121..68e3fe114 100644 --- a/app/soapbox/locales/hr.json +++ b/app/soapbox/locales/hr.json @@ -706,7 +706,7 @@ "notification.birthday": "{name} has a birthday today", "notification.birthday.more": "{count} more {count, plural, one {friend} other {friends}}", "notification.birthday_plural": "{name} and {more} have birthday today", - "notification.chat_mention": "{name} sent you a message", + "notification.pleroma:chat_mention": "{name} sent you a message", "notification.favourite": "{name} je lajkao tvoj status", "notification.follow": "{name} te sada slijedi", "notification.follow_request": "{name} has requested to follow you", diff --git a/app/soapbox/locales/hu.json b/app/soapbox/locales/hu.json index 0d5b56411..032c16b8d 100644 --- a/app/soapbox/locales/hu.json +++ b/app/soapbox/locales/hu.json @@ -706,7 +706,7 @@ "notification.birthday": "{name} has a birthday today", "notification.birthday.more": "{count} more {count, plural, one {friend} other {friends}}", "notification.birthday_plural": "{name} and {more} have birthday today", - "notification.chat_mention": "{name} sent you a message", + "notification.pleroma:chat_mention": "{name} sent you a message", "notification.favourite": "{name} kedvencnek jelölte egy tülködet", "notification.follow": "{name} követ téged", "notification.follow_request": "{name} has requested to follow you", diff --git a/app/soapbox/locales/hy.json b/app/soapbox/locales/hy.json index c2638e2d4..cabc205ad 100644 --- a/app/soapbox/locales/hy.json +++ b/app/soapbox/locales/hy.json @@ -706,7 +706,7 @@ "notification.birthday": "{name} has a birthday today", "notification.birthday.more": "{count} more {count, plural, one {friend} other {friends}}", "notification.birthday_plural": "{name} and {more} have birthday today", - "notification.chat_mention": "{name} sent you a message", + "notification.pleroma:chat_mention": "{name} sent you a message", "notification.favourite": "{name} հավանեց թութդ", "notification.follow": "{name} սկսեց հետեւել քեզ", "notification.follow_request": "{name} has requested to follow you", diff --git a/app/soapbox/locales/id.json b/app/soapbox/locales/id.json index 904f73cc5..6d86cbb8c 100644 --- a/app/soapbox/locales/id.json +++ b/app/soapbox/locales/id.json @@ -706,7 +706,7 @@ "notification.birthday": "{name} has a birthday today", "notification.birthday.more": "{count} more {count, plural, one {friend} other {friends}}", "notification.birthday_plural": "{name} and {more} have birthday today", - "notification.chat_mention": "{name} sent you a message", + "notification.pleroma:chat_mention": "{name} sent you a message", "notification.favourite": "{name} menyukai status anda", "notification.follow": "{name} mengikuti anda", "notification.follow_request": "{name} has requested to follow you", diff --git a/app/soapbox/locales/io.json b/app/soapbox/locales/io.json index f85f36a5a..5c351dc99 100644 --- a/app/soapbox/locales/io.json +++ b/app/soapbox/locales/io.json @@ -706,7 +706,7 @@ "notification.birthday": "{name} has a birthday today", "notification.birthday.more": "{count} more {count, plural, one {friend} other {friends}}", "notification.birthday_plural": "{name} and {more} have birthday today", - "notification.chat_mention": "{name} sent you a message", + "notification.pleroma:chat_mention": "{name} sent you a message", "notification.favourite": "{name} favorizis tua mesajo", "notification.follow": "{name} sequeskis tu", "notification.follow_request": "{name} has requested to follow you", diff --git a/app/soapbox/locales/it.json b/app/soapbox/locales/it.json index 6972de6c1..8f03e6a7d 100644 --- a/app/soapbox/locales/it.json +++ b/app/soapbox/locales/it.json @@ -706,7 +706,7 @@ "notification.birthday": "{name} oggi festeggia il compleanno", "notification.birthday.more": "{count} e {count, plural, un {friend} più {friends}}", "notification.birthday_plural": "{name} e {more} oggi festeggiano il compleanno", - "notification.chat_mention": "{name} ti ha spedito un messaggio", + "notification.pleroma:chat_mention": "{name} ti ha spedito un messaggio", "notification.favourite": "{name} ha apprezzato il contenuto", "notification.follow": "{name} adesso ti segue", "notification.follow_request": "{name} ha chiesto di seguirti", diff --git a/app/soapbox/locales/ja.json b/app/soapbox/locales/ja.json index 931c89326..c40c65de3 100644 --- a/app/soapbox/locales/ja.json +++ b/app/soapbox/locales/ja.json @@ -706,7 +706,7 @@ "notification.birthday": "{name} has a birthday today", "notification.birthday.more": "{count} more {count, plural, one {friend} other {friends}}", "notification.birthday_plural": "{name} and {more} have birthday today", - "notification.chat_mention": "{name}さんがあなたにメッセージを送りました", + "notification.pleroma:chat_mention": "{name}さんがあなたにメッセージを送りました", "notification.favourite": "{name}さんがあなたの投稿をお気に入りに登録しました", "notification.follow": "{name}さんにフォローされました", "notification.follow_request": "{name} has requested to follow you", diff --git a/app/soapbox/locales/ka.json b/app/soapbox/locales/ka.json index 950b4e69c..d0146522d 100644 --- a/app/soapbox/locales/ka.json +++ b/app/soapbox/locales/ka.json @@ -706,7 +706,7 @@ "notification.birthday": "{name} has a birthday today", "notification.birthday.more": "{count} more {count, plural, one {friend} other {friends}}", "notification.birthday_plural": "{name} and {more} have birthday today", - "notification.chat_mention": "{name} sent you a message", + "notification.pleroma:chat_mention": "{name} sent you a message", "notification.favourite": "{name}-მა თქვენი სტატუსი აქცია ფავორიტად", "notification.follow": "{name} გამოგყვათ", "notification.follow_request": "{name} has requested to follow you", diff --git a/app/soapbox/locales/kk.json b/app/soapbox/locales/kk.json index 40f4f25ac..8620007e2 100644 --- a/app/soapbox/locales/kk.json +++ b/app/soapbox/locales/kk.json @@ -706,7 +706,7 @@ "notification.birthday": "{name} has a birthday today", "notification.birthday.more": "{count} more {count, plural, one {friend} other {friends}}", "notification.birthday_plural": "{name} and {more} have birthday today", - "notification.chat_mention": "{name} sent you a message", + "notification.pleroma:chat_mention": "{name} sent you a message", "notification.favourite": "{name} жазбаңызды таңдаулыға қосты", "notification.follow": "{name} сізге жазылды", "notification.follow_request": "{name} has requested to follow you", diff --git a/app/soapbox/locales/ko.json b/app/soapbox/locales/ko.json index 55bc1e1bb..25b771202 100644 --- a/app/soapbox/locales/ko.json +++ b/app/soapbox/locales/ko.json @@ -706,7 +706,7 @@ "notification.birthday": "{name} has a birthday today", "notification.birthday.more": "{count} more {count, plural, one {friend} other {friends}}", "notification.birthday_plural": "{name} and {more} have birthday today", - "notification.chat_mention": "{name} sent you a message", + "notification.pleroma:chat_mention": "{name} sent you a message", "notification.favourite": "{name}님이 즐겨찾기 했습니다", "notification.follow": "{name}님이 나를 팔로우 했습니다", "notification.follow_request": "{name} has requested to follow you", diff --git a/app/soapbox/locales/lt.json b/app/soapbox/locales/lt.json index ff62cbf65..27c086ab8 100644 --- a/app/soapbox/locales/lt.json +++ b/app/soapbox/locales/lt.json @@ -706,7 +706,7 @@ "notification.birthday": "{name} has a birthday today", "notification.birthday.more": "{count} more {count, plural, one {friend} other {friends}}", "notification.birthday_plural": "{name} and {more} have birthday today", - "notification.chat_mention": "{name} sent you a message", + "notification.pleroma:chat_mention": "{name} sent you a message", "notification.favourite": "{name} favorited your post", "notification.follow": "{name} followed you", "notification.follow_request": "{name} has requested to follow you", diff --git a/app/soapbox/locales/lv.json b/app/soapbox/locales/lv.json index c97bca375..51352659c 100644 --- a/app/soapbox/locales/lv.json +++ b/app/soapbox/locales/lv.json @@ -706,7 +706,7 @@ "notification.birthday": "{name} has a birthday today", "notification.birthday.more": "{count} more {count, plural, one {friend} other {friends}}", "notification.birthday_plural": "{name} and {more} have birthday today", - "notification.chat_mention": "{name} sent you a message", + "notification.pleroma:chat_mention": "{name} sent you a message", "notification.favourite": "{name} favorited your post", "notification.follow": "{name} followed you", "notification.follow_request": "{name} has requested to follow you", diff --git a/app/soapbox/locales/mk.json b/app/soapbox/locales/mk.json index 8d017fb27..c8919a214 100644 --- a/app/soapbox/locales/mk.json +++ b/app/soapbox/locales/mk.json @@ -706,7 +706,7 @@ "notification.birthday": "{name} has a birthday today", "notification.birthday.more": "{count} more {count, plural, one {friend} other {friends}}", "notification.birthday_plural": "{name} and {more} have birthday today", - "notification.chat_mention": "{name} sent you a message", + "notification.pleroma:chat_mention": "{name} sent you a message", "notification.favourite": "{name} favorited your post", "notification.follow": "{name} followed you", "notification.follow_request": "{name} has requested to follow you", diff --git a/app/soapbox/locales/ms.json b/app/soapbox/locales/ms.json index dc75e0a32..b6e701fcd 100644 --- a/app/soapbox/locales/ms.json +++ b/app/soapbox/locales/ms.json @@ -706,7 +706,7 @@ "notification.birthday": "{name} has a birthday today", "notification.birthday.more": "{count} more {count, plural, one {friend} other {friends}}", "notification.birthday_plural": "{name} and {more} have birthday today", - "notification.chat_mention": "{name} sent you a message", + "notification.pleroma:chat_mention": "{name} sent you a message", "notification.favourite": "{name} favorited your post", "notification.follow": "{name} followed you", "notification.follow_request": "{name} has requested to follow you", diff --git a/app/soapbox/locales/nl.json b/app/soapbox/locales/nl.json index 47795ef3d..0e3ea550c 100644 --- a/app/soapbox/locales/nl.json +++ b/app/soapbox/locales/nl.json @@ -706,7 +706,7 @@ "notification.birthday": "{name} has a birthday today", "notification.birthday.more": "{count} more {count, plural, one {friend} other {friends}}", "notification.birthday_plural": "{name} and {more} have birthday today", - "notification.chat_mention": "{name} sent you a message", + "notification.pleroma:chat_mention": "{name} sent you a message", "notification.favourite": "{name} voegde jouw toot als favoriet toe", "notification.follow": "{name} volgt jou nu", "notification.follow_request": "{name} has requested to follow you", diff --git a/app/soapbox/locales/nn.json b/app/soapbox/locales/nn.json index 26e4c3134..62adfaba4 100644 --- a/app/soapbox/locales/nn.json +++ b/app/soapbox/locales/nn.json @@ -706,7 +706,7 @@ "notification.birthday": "{name} has a birthday today", "notification.birthday.more": "{count} more {count, plural, one {friend} other {friends}}", "notification.birthday_plural": "{name} and {more} have birthday today", - "notification.chat_mention": "{name} sent you a message", + "notification.pleroma:chat_mention": "{name} sent you a message", "notification.favourite": "{name} likte din status", "notification.follow": "{name} fulgte deg", "notification.follow_request": "{name} has requested to follow you", diff --git a/app/soapbox/locales/no.json b/app/soapbox/locales/no.json index fe86be051..827d16b33 100644 --- a/app/soapbox/locales/no.json +++ b/app/soapbox/locales/no.json @@ -706,7 +706,7 @@ "notification.birthday": "{name} has a birthday today", "notification.birthday.more": "{count} more {count, plural, one {friend} other {friends}}", "notification.birthday_plural": "{name} and {more} have birthday today", - "notification.chat_mention": "{name} sent you a message", + "notification.pleroma:chat_mention": "{name} sent you a message", "notification.favourite": "{name} likte din status", "notification.follow": "{name} fulgte deg", "notification.follow_request": "{name} has requested to follow you", diff --git a/app/soapbox/locales/oc.json b/app/soapbox/locales/oc.json index 64b471abc..6ba11c35d 100644 --- a/app/soapbox/locales/oc.json +++ b/app/soapbox/locales/oc.json @@ -706,7 +706,7 @@ "notification.birthday": "{name} has a birthday today", "notification.birthday.more": "{count} more {count, plural, one {friend} other {friends}}", "notification.birthday_plural": "{name} and {more} have birthday today", - "notification.chat_mention": "{name} sent you a message", + "notification.pleroma:chat_mention": "{name} sent you a message", "notification.favourite": "{name} a ajustat a sos favorits", "notification.follow": "{name} vos sèc", "notification.follow_request": "{name} has requested to follow you", diff --git a/app/soapbox/locales/pl.json b/app/soapbox/locales/pl.json index 1184a91f6..6e31746f7 100644 --- a/app/soapbox/locales/pl.json +++ b/app/soapbox/locales/pl.json @@ -749,7 +749,7 @@ "notification.birthday": "{name} ma dziś urodziny", "notification.birthday.more": "{count} {count, plural, one {znajomy} other {więcej znajomych}}", "notification.birthday_plural": "{name} i {more} mają dziś urodziny", - "notification.chat_mention": "{name} wysłał(a) Ci wiadomośść", + "notification.pleroma:chat_mention": "{name} wysłał(a) Ci wiadomośść", "notification.favourite": "{name} dodał(a) Twój wpis do ulubionych", "notification.follow": "{name} zaczął(-ęła) Cię śledzić", "notification.follow_request": "{name} poprosił(a) Cię o możliwość śledzenia", diff --git a/app/soapbox/locales/pt-BR.json b/app/soapbox/locales/pt-BR.json index f0b0a19df..76b2e4b84 100644 --- a/app/soapbox/locales/pt-BR.json +++ b/app/soapbox/locales/pt-BR.json @@ -706,7 +706,7 @@ "notification.birthday": "{name} has a birthday today", "notification.birthday.more": "{count} more {count, plural, one {friend} other {friends}}", "notification.birthday_plural": "{name} and {more} have birthday today", - "notification.chat_mention": "{name} sent you a message", + "notification.pleroma:chat_mention": "{name} sent you a message", "notification.favourite": "{name} adicionou a sua postagem aos favoritos", "notification.follow": "{name} te seguiu", "notification.follow_request": "{name} has requested to follow you", diff --git a/app/soapbox/locales/pt.json b/app/soapbox/locales/pt.json index 4cc86daad..5c8c51bb9 100644 --- a/app/soapbox/locales/pt.json +++ b/app/soapbox/locales/pt.json @@ -706,7 +706,7 @@ "notification.birthday": "{name} has a birthday today", "notification.birthday.more": "{count} more {count, plural, one {friend} other {friends}}", "notification.birthday_plural": "{name} and {more} have birthday today", - "notification.chat_mention": "{name} enviou-te uma mensagem", + "notification.pleroma:chat_mention": "{name} enviou-te uma mensagem", "notification.favourite": "{name} gostou desta publicação", "notification.follow": "{name} começou a seguir-te", "notification.follow_request": "{name} pediu para te seguir", diff --git a/app/soapbox/locales/ro.json b/app/soapbox/locales/ro.json index 2f49f24ce..488ce486a 100644 --- a/app/soapbox/locales/ro.json +++ b/app/soapbox/locales/ro.json @@ -706,7 +706,7 @@ "notification.birthday": "{name} has a birthday today", "notification.birthday.more": "{count} more {count, plural, one {friend} other {friends}}", "notification.birthday_plural": "{name} and {more} have birthday today", - "notification.chat_mention": "{name} sent you a message", + "notification.pleroma:chat_mention": "{name} sent you a message", "notification.favourite": "{name} a adăugat statusul tău la favorite", "notification.follow": "{name} te urmărește", "notification.follow_request": "{name} has requested to follow you", diff --git a/app/soapbox/locales/ru.json b/app/soapbox/locales/ru.json index b4d0b3e2d..90b3827b0 100644 --- a/app/soapbox/locales/ru.json +++ b/app/soapbox/locales/ru.json @@ -706,7 +706,7 @@ "notification.birthday": "{name} has a birthday today", "notification.birthday.more": "{count} more {count, plural, one {friend} other {friends}}", "notification.birthday_plural": "{name} and {more} have birthday today", - "notification.chat_mention": "{name} sent you a message", + "notification.pleroma:chat_mention": "{name} sent you a message", "notification.favourite": "{name} понравился Ваш статус", "notification.follow": "{name} подписался (-лась) на вас", "notification.follow_request": "{name} has requested to follow you", diff --git a/app/soapbox/locales/sk.json b/app/soapbox/locales/sk.json index 7a81a02c4..023f86526 100644 --- a/app/soapbox/locales/sk.json +++ b/app/soapbox/locales/sk.json @@ -706,7 +706,7 @@ "notification.birthday": "{name} has a birthday today", "notification.birthday.more": "{count} more {count, plural, one {friend} other {friends}}", "notification.birthday_plural": "{name} and {more} have birthday today", - "notification.chat_mention": "{name} sent you a message", + "notification.pleroma:chat_mention": "{name} sent you a message", "notification.favourite": "{name} si obľúbil/a tvoj príspevok", "notification.follow": "{name} ťa začal/a následovať", "notification.follow_request": "{name} has requested to follow you", diff --git a/app/soapbox/locales/sl.json b/app/soapbox/locales/sl.json index d1710325d..30a90754b 100644 --- a/app/soapbox/locales/sl.json +++ b/app/soapbox/locales/sl.json @@ -706,7 +706,7 @@ "notification.birthday": "{name} has a birthday today", "notification.birthday.more": "{count} more {count, plural, one {friend} other {friends}}", "notification.birthday_plural": "{name} and {more} have birthday today", - "notification.chat_mention": "{name} sent you a message", + "notification.pleroma:chat_mention": "{name} sent you a message", "notification.favourite": "{name} je vzljubil/a vaš status", "notification.follow": "{name} vam sledi", "notification.follow_request": "{name} has requested to follow you", diff --git a/app/soapbox/locales/sq.json b/app/soapbox/locales/sq.json index 1c0a23d21..494b9ce8d 100644 --- a/app/soapbox/locales/sq.json +++ b/app/soapbox/locales/sq.json @@ -706,7 +706,7 @@ "notification.birthday": "{name} has a birthday today", "notification.birthday.more": "{count} more {count, plural, one {friend} other {friends}}", "notification.birthday_plural": "{name} and {more} have birthday today", - "notification.chat_mention": "{name} sent you a message", + "notification.pleroma:chat_mention": "{name} sent you a message", "notification.favourite": "{name} parapëlqeu gjendjen tuaj", "notification.follow": "{name} zuri t’ju ndjekë", "notification.follow_request": "{name} has requested to follow you", diff --git a/app/soapbox/locales/sr-Latn.json b/app/soapbox/locales/sr-Latn.json index ccf0c8ef1..952e0d360 100644 --- a/app/soapbox/locales/sr-Latn.json +++ b/app/soapbox/locales/sr-Latn.json @@ -706,7 +706,7 @@ "notification.birthday": "{name} has a birthday today", "notification.birthday.more": "{count} more {count, plural, one {friend} other {friends}}", "notification.birthday_plural": "{name} and {more} have birthday today", - "notification.chat_mention": "{name} sent you a message", + "notification.pleroma:chat_mention": "{name} sent you a message", "notification.favourite": "{name} je stavio Vaš status kao omiljeni", "notification.follow": "{name} Vas je zapratio", "notification.follow_request": "{name} has requested to follow you", diff --git a/app/soapbox/locales/sr.json b/app/soapbox/locales/sr.json index 140a2738c..b9e8d84ac 100644 --- a/app/soapbox/locales/sr.json +++ b/app/soapbox/locales/sr.json @@ -706,7 +706,7 @@ "notification.birthday": "{name} has a birthday today", "notification.birthday.more": "{count} more {count, plural, one {friend} other {friends}}", "notification.birthday_plural": "{name} and {more} have birthday today", - "notification.chat_mention": "{name} sent you a message", + "notification.pleroma:chat_mention": "{name} sent you a message", "notification.favourite": "{name} је ставио/ла Ваш статус као омиљени", "notification.follow": "{name} Вас је запратио/ла", "notification.follow_request": "{name} has requested to follow you", diff --git a/app/soapbox/locales/sv.json b/app/soapbox/locales/sv.json index a57d57e8f..dedaa4651 100644 --- a/app/soapbox/locales/sv.json +++ b/app/soapbox/locales/sv.json @@ -706,7 +706,7 @@ "notification.birthday": "{name} has a birthday today", "notification.birthday.more": "{count} more {count, plural, one {friend} other {friends}}", "notification.birthday_plural": "{name} and {more} have birthday today", - "notification.chat_mention": "{name} sent you a message", + "notification.pleroma:chat_mention": "{name} sent you a message", "notification.favourite": "{name} favoriserade din status", "notification.follow": "{name} följer dig", "notification.follow_request": "{name} has requested to follow you", diff --git a/app/soapbox/locales/ta.json b/app/soapbox/locales/ta.json index 69c44f84f..536bff964 100644 --- a/app/soapbox/locales/ta.json +++ b/app/soapbox/locales/ta.json @@ -706,7 +706,7 @@ "notification.birthday": "{name} has a birthday today", "notification.birthday.more": "{count} more {count, plural, one {friend} other {friends}}", "notification.birthday_plural": "{name} and {more} have birthday today", - "notification.chat_mention": "{name} sent you a message", + "notification.pleroma:chat_mention": "{name} sent you a message", "notification.favourite": "{name} ஆர்வம் கொண்டவர், உங்கள் நிலை", "notification.follow": "{name} நீங்கள் தொடர்ந்து வந்தீர்கள்", "notification.follow_request": "{name} has requested to follow you", diff --git a/app/soapbox/locales/te.json b/app/soapbox/locales/te.json index 6b34989f9..1e1311a4b 100644 --- a/app/soapbox/locales/te.json +++ b/app/soapbox/locales/te.json @@ -706,7 +706,7 @@ "notification.birthday": "{name} has a birthday today", "notification.birthday.more": "{count} more {count, plural, one {friend} other {friends}}", "notification.birthday_plural": "{name} and {more} have birthday today", - "notification.chat_mention": "{name} sent you a message", + "notification.pleroma:chat_mention": "{name} sent you a message", "notification.favourite": "{name} మీ స్టేటస్ ను ఇష్టపడ్డారు", "notification.follow": "{name} మిమ్మల్ని అనుసరిస్తున్నారు", "notification.follow_request": "{name} has requested to follow you", diff --git a/app/soapbox/locales/th.json b/app/soapbox/locales/th.json index c509dd4a3..cfc6d8396 100644 --- a/app/soapbox/locales/th.json +++ b/app/soapbox/locales/th.json @@ -706,7 +706,7 @@ "notification.birthday": "{name} has a birthday today", "notification.birthday.more": "{count} more {count, plural, one {friend} other {friends}}", "notification.birthday_plural": "{name} and {more} have birthday today", - "notification.chat_mention": "{name} sent you a message", + "notification.pleroma:chat_mention": "{name} sent you a message", "notification.favourite": "{name} ได้ชื่นชอบสถานะของคุณ", "notification.follow": "{name} ได้ติดตามคุณ", "notification.follow_request": "{name} has requested to follow you", diff --git a/app/soapbox/locales/tr.json b/app/soapbox/locales/tr.json index 45c7c02b0..2cb0e84dc 100644 --- a/app/soapbox/locales/tr.json +++ b/app/soapbox/locales/tr.json @@ -706,7 +706,7 @@ "notification.birthday": "{name} has a birthday today", "notification.birthday.more": "{count} more {count, plural, one {friend} other {friends}}", "notification.birthday_plural": "{name} and {more} have birthday today", - "notification.chat_mention": "{name} sent you a message", + "notification.pleroma:chat_mention": "{name} sent you a message", "notification.favourite": "{name} senin durumunu favorilere ekledi", "notification.follow": "{name} seni takip ediyor", "notification.follow_request": "{name} has requested to follow you", diff --git a/app/soapbox/locales/uk.json b/app/soapbox/locales/uk.json index bf601a95b..fb950161d 100644 --- a/app/soapbox/locales/uk.json +++ b/app/soapbox/locales/uk.json @@ -706,7 +706,7 @@ "notification.birthday": "{name} has a birthday today", "notification.birthday.more": "{count} more {count, plural, one {friend} other {friends}}", "notification.birthday_plural": "{name} and {more} have birthday today", - "notification.chat_mention": "{name} sent you a message", + "notification.pleroma:chat_mention": "{name} sent you a message", "notification.favourite": "{name} вподобав(-ла) ваш допис", "notification.follow": "{name} підписався(-лась) на Вас", "notification.follow_request": "{name} відправив(-ла) запит на підписку", diff --git a/app/soapbox/locales/zh-CN.json b/app/soapbox/locales/zh-CN.json index 0ec6a2e0f..7a5aeb1f1 100644 --- a/app/soapbox/locales/zh-CN.json +++ b/app/soapbox/locales/zh-CN.json @@ -706,7 +706,7 @@ "notification.birthday": "{name} has a birthday today", "notification.birthday.more": "{count} more {count, plural, one {friend} other {friends}}", "notification.birthday_plural": "{name} and {more} have birthday today", - "notification.chat_mention": "{name} 回复了你", + "notification.pleroma:chat_mention": "{name} 回复了你", "notification.favourite": "{name} 赞了你的帖文", "notification.follow": "{name} 开始关注你", "notification.follow_request": "{name} 请求关注你", diff --git a/app/soapbox/locales/zh-HK.json b/app/soapbox/locales/zh-HK.json index b163f6675..65462c72f 100644 --- a/app/soapbox/locales/zh-HK.json +++ b/app/soapbox/locales/zh-HK.json @@ -706,7 +706,7 @@ "notification.birthday": "{name} has a birthday today", "notification.birthday.more": "{count} more {count, plural, one {friend} other {friends}}", "notification.birthday_plural": "{name} and {more} have birthday today", - "notification.chat_mention": "{name} sent you a message", + "notification.pleroma:chat_mention": "{name} sent you a message", "notification.favourite": "{name} 收藏了你的文章", "notification.follow": "{name} 開始關注你", "notification.follow_request": "{name} has requested to follow you", diff --git a/app/soapbox/locales/zh-TW.json b/app/soapbox/locales/zh-TW.json index 5eade39d5..09ba5c840 100644 --- a/app/soapbox/locales/zh-TW.json +++ b/app/soapbox/locales/zh-TW.json @@ -706,7 +706,7 @@ "notification.birthday": "{name} has a birthday today", "notification.birthday.more": "{count} more {count, plural, one {friend} other {friends}}", "notification.birthday_plural": "{name} and {more} have birthday today", - "notification.chat_mention": "{name} sent you a message", + "notification.pleroma:chat_mention": "{name} sent you a message", "notification.favourite": "{name} 把你的嘟文加入了最愛", "notification.follow": "{name} 關注了你", "notification.follow_request": "{name} has requested to follow you", diff --git a/app/soapbox/normalizers/__tests__/account.test.ts b/app/soapbox/normalizers/__tests__/account.test.ts index b78017e06..b5f4f5a75 100644 --- a/app/soapbox/normalizers/__tests__/account.test.ts +++ b/app/soapbox/normalizers/__tests__/account.test.ts @@ -47,6 +47,13 @@ describe('normalizeAccount()', () => { expect(result.birthday).toEqual('1993-07-03'); }); + it('normalizes undefined birthday to empty string', () => { + const account = require('soapbox/__fixtures__/mastodon-account.json'); + const result = normalizeAccount(account); + + expect(result.birthday).toEqual(''); + }); + it('normalizes Pleroma legacy fields', () => { const account = require('soapbox/__fixtures__/pleroma-2.2.2-account.json'); const result = normalizeAccount(account); @@ -147,9 +154,9 @@ describe('normalizeAccount()', () => { const result = normalizeAccount(account); const field = result.fields.get(1); - expect(field.name_emojified).toBe('Soapbox :ablobcatrainbow:'); - expect(field.value_emojified).toBe('https://soapbox.pub :soapbox:'); - expect(field.value_plain).toBe('https://soapbox.pub :soapbox:'); + expect(field?.name_emojified).toBe('Soapbox :ablobcatrainbow:'); + expect(field?.value_emojified).toBe('https://soapbox.pub :soapbox:'); + expect(field?.value_plain).toBe('https://soapbox.pub :soapbox:'); }); it('adds default avatar and banner to GoToSocial account', () => { diff --git a/app/soapbox/normalizers/__tests__/poll.test.ts b/app/soapbox/normalizers/__tests__/poll.test.ts index 31691f484..8acf2ece4 100644 --- a/app/soapbox/normalizers/__tests__/poll.test.ts +++ b/app/soapbox/normalizers/__tests__/poll.test.ts @@ -38,11 +38,11 @@ describe('normalizePoll()', () => { const result = normalizePoll(poll); // Emojifies poll options - expect(result.options.get(1).title_emojified) + expect(result.options.get(1)?.title_emojified) .toEqual('Custom emoji :gleason_excited: '); // Parses emojis as Immutable.Record's expect(ImmutableRecord.isRecord(result.emojis.get(0))).toBe(true); - expect(result.emojis.get(1).shortcode).toEqual('soapbox'); + expect(result.emojis.get(1)?.shortcode).toEqual('soapbox'); }); }); diff --git a/app/soapbox/normalizers/__tests__/status.test.ts b/app/soapbox/normalizers/__tests__/status.test.ts index ac9358f51..43336d00f 100644 --- a/app/soapbox/normalizers/__tests__/status.test.ts +++ b/app/soapbox/normalizers/__tests__/status.test.ts @@ -2,6 +2,8 @@ import { Record as ImmutableRecord, fromJS } from 'immutable'; import { normalizeStatus } from '../status'; +import type { Poll, Card } from 'soapbox/types/entities'; + describe('normalizeStatus()', () => { it('adds base fields', () => { const status = {}; @@ -42,8 +44,8 @@ describe('normalizeStatus()', () => { const result = normalizeStatus(status).mentions; expect(result.size).toBe(1); - expect(result.get(0).toJS()).toMatchObject(expected); - expect(result.get(0).id).toEqual('106801667066418367'); + expect(result.get(0)?.toJS()).toMatchObject(expected); + expect(result.get(0)?.id).toEqual('106801667066418367'); expect(ImmutableRecord.isRecord(result.get(0))).toBe(true); }); @@ -101,8 +103,7 @@ describe('normalizeStatus()', () => { const result = normalizeStatus(status).media_attachments; expect(result.size).toBe(4); - expect(result.get(0).text_url).toBe(undefined); - expect(result.get(1).meta).toEqual(fromJS({})); + expect(result.get(1)?.meta).toEqual(fromJS({})); expect(result.getIn([1, 'pleroma', 'mime_type'])).toBe('application/x-nes-rom'); expect(ImmutableRecord.isRecord(result.get(3))).toBe(true); }); @@ -147,6 +148,7 @@ describe('normalizeStatus()', () => { it('normalizes poll and poll options', () => { const status = { poll: { options: [{ title: 'Apples' }] } }; const result = normalizeStatus(status); + const poll = result.poll as Poll; const expected = { options: [{ title: 'Apples', votes_count: 0 }], @@ -159,46 +161,49 @@ describe('normalizeStatus()', () => { voted: false, }; - expect(ImmutableRecord.isRecord(result.poll)).toBe(true); - expect(ImmutableRecord.isRecord(result.poll.options.get(0))).toBe(true); - expect(result.poll.toJS()).toMatchObject(expected); - expect(result.poll.expires_at instanceof Date).toBe(true); + expect(ImmutableRecord.isRecord(poll)).toBe(true); + expect(ImmutableRecord.isRecord(poll.options.get(0))).toBe(true); + expect(poll.toJS()).toMatchObject(expected); + expect(poll.expires_at instanceof Date).toBe(true); }); it('normalizes a Pleroma logged-out poll', () => { const status = require('soapbox/__fixtures__/pleroma-status-with-poll.json'); const result = normalizeStatus(status); + const poll = result.poll as Poll; // Adds logged-in fields - expect(result.poll.voted).toBe(false); - expect(result.poll.own_votes).toBe(null); + expect(poll.voted).toBe(false); + expect(poll.own_votes).toBe(null); }); it('normalizes poll with emojis', () => { const status = require('soapbox/__fixtures__/pleroma-status-with-poll-with-emojis.json'); const result = normalizeStatus(status); + const poll = result.poll as Poll; // Emojifies poll options - expect(result.poll.options.get(1).title_emojified) + expect(poll.options.get(1)?.title_emojified) .toEqual('Custom emoji :gleason_excited: '); // Parses emojis as Immutable.Record's - expect(ImmutableRecord.isRecord(result.poll.emojis.get(0))).toBe(true); - expect(result.poll.emojis.get(1).shortcode).toEqual('soapbox'); + expect(ImmutableRecord.isRecord(poll.emojis.get(0))).toBe(true); + expect(poll.emojis.get(1)?.shortcode).toEqual('soapbox'); }); it('normalizes a card', () => { const status = require('soapbox/__fixtures__/status-with-card.json'); const result = normalizeStatus(status); + const card = result.card as Card; - expect(ImmutableRecord.isRecord(result.card)).toBe(true); - expect(result.card.type).toEqual('link'); - expect(result.card.provider_url).toEqual('https://soapbox.pub'); + expect(ImmutableRecord.isRecord(card)).toBe(true); + expect(card.type).toEqual('link'); + expect(card.provider_url).toEqual('https://soapbox.pub'); }); it('preserves Truth Social external_video_id', () => { const status = require('soapbox/__fixtures__/truthsocial-status-with-external-video.json'); const result = normalizeStatus(status); - expect(result.media_attachments.get(0).external_video_id).toBe('vwfnq9'); + expect(result.media_attachments.get(0)?.external_video_id).toBe('vwfnq9'); }); }); diff --git a/app/soapbox/normalizers/account.ts b/app/soapbox/normalizers/account.ts index 784ba08aa..1a519b8a8 100644 --- a/app/soapbox/normalizers/account.ts +++ b/app/soapbox/normalizers/account.ts @@ -24,7 +24,7 @@ export const AccountRecord = ImmutableRecord({ acct: '', avatar: '', avatar_static: '', - birthday: undefined as string | undefined, + birthday: '', bot: false, created_at: new Date(), discoverable: false, @@ -261,6 +261,12 @@ const normalizeDiscoverable = (account: ImmutableMap) => { return account.set('discoverable', discoverable); }; +/** Normalize undefined/null birthday to empty string. */ +const fixBirthday = (account: ImmutableMap) => { + const birthday = account.get('birthday'); + return account.set('birthday', birthday || ''); +}; + export const normalizeAccount = (account: Record) => { return AccountRecord( ImmutableMap(fromJS(account)).withMutations(account => { @@ -280,6 +286,7 @@ export const normalizeAccount = (account: Record) => { addStaffFields(account); fixUsername(account); fixDisplayName(account); + fixBirthday(account); addInternalFields(account); }), ); diff --git a/app/soapbox/normalizers/attachment.ts b/app/soapbox/normalizers/attachment.ts index 06fba73ad..23cce3686 100644 --- a/app/soapbox/normalizers/attachment.ts +++ b/app/soapbox/normalizers/attachment.ts @@ -46,8 +46,18 @@ const normalizeUrls = (attachment: ImmutableMap) => { return attachment.mergeWith(mergeDefined, base); }; +// Ensure meta is not null +const normalizeMeta = (attachment: ImmutableMap) => { + const meta = ImmutableMap().merge(attachment.get('meta')); + + return attachment.set('meta', meta); +}; + export const normalizeAttachment = (attachment: Record) => { return AttachmentRecord( - normalizeUrls(ImmutableMap(fromJS(attachment))), + ImmutableMap(fromJS(attachment)).withMutations((attachment: ImmutableMap) => { + normalizeUrls(attachment); + normalizeMeta(attachment); + }), ); }; diff --git a/app/soapbox/normalizers/notification.ts b/app/soapbox/normalizers/notification.ts index 2bac3f2b3..9b34278b6 100644 --- a/app/soapbox/normalizers/notification.ts +++ b/app/soapbox/normalizers/notification.ts @@ -11,19 +11,6 @@ import { import type { Account, Status, EmbeddedEntity } from 'soapbox/types/entities'; -export type NotificationType = - 'follow' - | 'follow_request' - | 'mention' - | 'reblog' - | 'favourite' - | 'poll' - | 'status' - | 'move' - | 'pleroma:chat_mention' - | 'pleroma:emoji_reaction' - | 'user_approved'; - // https://docs.joinmastodon.org/entities/notification/ export const NotificationRecord = ImmutableRecord({ account: null as EmbeddedEntity, @@ -33,7 +20,7 @@ export const NotificationRecord = ImmutableRecord({ id: '', status: null as EmbeddedEntity, target: null as EmbeddedEntity, // move - type: '' as NotificationType | '', + type: '', total_count: null as number | null, // grouped notifications }); diff --git a/app/soapbox/normalizers/soapbox/__tests__/soapbox_config-test.ts b/app/soapbox/normalizers/soapbox/__tests__/soapbox_config-test.ts index 65c4291f8..e48198ecc 100644 --- a/app/soapbox/normalizers/soapbox/__tests__/soapbox_config-test.ts +++ b/app/soapbox/normalizers/soapbox/__tests__/soapbox_config-test.ts @@ -32,6 +32,6 @@ describe('normalizeSoapboxConfig()', () => { const result = normalizeSoapboxConfig(require('soapbox/__fixtures__/spinster-soapbox.json')); expect(ImmutableRecord.isRecord(result.promoPanel)).toBe(true); expect(ImmutableRecord.isRecord(result.promoPanel.items.get(0))).toBe(true); - expect(result.promoPanel.items.get(2).icon).toBe('question-circle'); + expect(result.promoPanel.items.get(2)?.icon).toBe('question-circle'); }); }); diff --git a/app/soapbox/reducers/__tests__/accounts.test.ts b/app/soapbox/reducers/__tests__/accounts.test.ts index 647bb676a..02baa6d92 100644 --- a/app/soapbox/reducers/__tests__/accounts.test.ts +++ b/app/soapbox/reducers/__tests__/accounts.test.ts @@ -23,7 +23,7 @@ describe('accounts reducer', () => { const action = { type: ACCOUNT_IMPORT, account }; const result = reducer(undefined, action).get('106801667066418367'); - expect(result.moved).toBe('107945464165013501'); + expect(result?.moved).toBe('107945464165013501'); }); }); }); diff --git a/app/soapbox/reducers/__tests__/alerts.test.ts b/app/soapbox/reducers/__tests__/alerts.test.ts index 306ab2fcd..441cf2d8d 100644 --- a/app/soapbox/reducers/__tests__/alerts.test.ts +++ b/app/soapbox/reducers/__tests__/alerts.test.ts @@ -11,7 +11,7 @@ import reducer from '../alerts'; describe('alerts reducer', () => { it('should return the initial state', () => { - expect(reducer(undefined, {})).toEqual(ImmutableList()); + expect(reducer(undefined, {} as any)).toEqual(ImmutableList()); }); describe('ALERT_SHOW', () => { diff --git a/app/soapbox/reducers/__tests__/carousels.test.ts b/app/soapbox/reducers/__tests__/carousels.test.ts index 45e87c8ff..2745b078d 100644 --- a/app/soapbox/reducers/__tests__/carousels.test.ts +++ b/app/soapbox/reducers/__tests__/carousels.test.ts @@ -19,7 +19,7 @@ describe('carousels reducer', () => { describe('CAROUSEL_AVATAR_REQUEST', () => { it('sets "isLoading" to "true"', () => { - const initialState = { isLoading: false, avatars: [] }; + const initialState = { isLoading: false, avatars: [], error: false }; const action = { type: CAROUSEL_AVATAR_REQUEST }; expect(reducer(initialState, action).isLoading).toEqual(true); }); @@ -39,7 +39,7 @@ describe('carousels reducer', () => { describe('CAROUSEL_AVATAR_FAIL', () => { it('sets "isLoading" to "true"', () => { - const initialState = { isLoading: true, avatars: [] }; + const initialState = { isLoading: true, avatars: [], error: false }; const action = { type: CAROUSEL_AVATAR_FAIL }; const result = reducer(initialState, action); diff --git a/app/soapbox/reducers/__tests__/compose.test.ts b/app/soapbox/reducers/__tests__/compose.test.ts index a1d40fe7c..bb6906c6d 100644 --- a/app/soapbox/reducers/__tests__/compose.test.ts +++ b/app/soapbox/reducers/__tests__/compose.test.ts @@ -200,7 +200,7 @@ describe('compose reducer', () => { }); it('should handle COMPOSE_SENSITIVITY_CHANGE on Mark Sensitive click, don\'t toggle if spoiler active', () => { - const state = ReducerRecord({ spoiler: true, sensitive: true, idempotencyKey: null }); + const state = ReducerRecord({ spoiler: true, sensitive: true, idempotencyKey: '' }); const action = { type: actions.COMPOSE_SENSITIVITY_CHANGE, }; @@ -297,12 +297,12 @@ describe('compose reducer', () => { }); it('should handle COMPOSE_SUBMIT_SUCCESS', () => { - const state = ReducerRecord({ default_privacy: null, privacy: 'public' }); + const state = ReducerRecord({ default_privacy: 'public', privacy: 'private' }); const action = { type: actions.COMPOSE_SUBMIT_SUCCESS, }; expect(reducer(state, action).toJS()).toMatchObject({ - privacy: null, + privacy: 'public', }); }); diff --git a/app/soapbox/reducers/__tests__/contexts.test.ts b/app/soapbox/reducers/__tests__/contexts.test.ts index 901763091..29e9e3c07 100644 --- a/app/soapbox/reducers/__tests__/contexts.test.ts +++ b/app/soapbox/reducers/__tests__/contexts.test.ts @@ -2,6 +2,7 @@ import { Map as ImmutableMap, OrderedSet as ImmutableOrderedSet, fromJS, + is, } from 'immutable'; import { STATUS_IMPORT } from 'soapbox/actions/importer'; @@ -111,7 +112,7 @@ describe('contexts reducer', () => { }) as ImmutableMap>, }); - expect(reducer(state, action)).toEqual(expected); + expect(is(reducer(state, action), expected)).toBe(true); }); }); }); diff --git a/app/soapbox/reducers/__tests__/custom_emojis.test.ts b/app/soapbox/reducers/__tests__/custom_emojis.test.ts index 43fec78ec..e2991d5fb 100644 --- a/app/soapbox/reducers/__tests__/custom_emojis.test.ts +++ b/app/soapbox/reducers/__tests__/custom_emojis.test.ts @@ -4,6 +4,6 @@ import reducer from '../custom_emojis'; describe('custom_emojis reducer', () => { it('should return the initial state', () => { - expect(reducer(undefined, {})).toEqual(ImmutableList()); + expect(reducer(undefined, {} as any)).toEqual(ImmutableList()); }); }); diff --git a/app/soapbox/reducers/__tests__/group_editor.test.ts b/app/soapbox/reducers/__tests__/group_editor.test.ts index 73c9e1b6a..516b6df43 100644 --- a/app/soapbox/reducers/__tests__/group_editor.test.ts +++ b/app/soapbox/reducers/__tests__/group_editor.test.ts @@ -4,7 +4,7 @@ import reducer from '../group_editor'; describe('group_editor reducer', () => { it('should return the initial state', () => { - expect(reducer(undefined, {})).toEqual(ImmutableMap({ + expect(reducer(undefined, {} as any)).toEqual(ImmutableMap({ groupId: null, isSubmitting: false, isChanged: false, diff --git a/app/soapbox/reducers/__tests__/group_lists.test.ts b/app/soapbox/reducers/__tests__/group_lists.test.ts index fa5c21eea..46527f682 100644 --- a/app/soapbox/reducers/__tests__/group_lists.test.ts +++ b/app/soapbox/reducers/__tests__/group_lists.test.ts @@ -4,7 +4,7 @@ import reducer from '../group_lists'; describe('group_lists reducer', () => { it('should return the initial state', () => { - expect(reducer(undefined, {})).toEqual(ImmutableMap({ + expect(reducer(undefined, {} as any)).toEqual(ImmutableMap({ featured: ImmutableList(), member: ImmutableList(), admin: ImmutableList(), diff --git a/app/soapbox/reducers/__tests__/group_relationships.test.ts b/app/soapbox/reducers/__tests__/group_relationships.test.ts index 17cabf3c2..31e3e354f 100644 --- a/app/soapbox/reducers/__tests__/group_relationships.test.ts +++ b/app/soapbox/reducers/__tests__/group_relationships.test.ts @@ -4,6 +4,6 @@ import reducer from '../group_relationships'; describe('group_relationships reducer', () => { it('should return the initial state', () => { - expect(reducer(undefined, {})).toEqual(ImmutableMap()); + expect(reducer(undefined, {} as any)).toEqual(ImmutableMap()); }); }); diff --git a/app/soapbox/reducers/__tests__/groups.test.ts b/app/soapbox/reducers/__tests__/groups.test.ts index 94a1a6ffe..05b88402f 100644 --- a/app/soapbox/reducers/__tests__/groups.test.ts +++ b/app/soapbox/reducers/__tests__/groups.test.ts @@ -4,6 +4,6 @@ import reducer from '../groups'; describe('groups reducer', () => { it('should return the initial state', () => { - expect(reducer(undefined, {})).toEqual(ImmutableMap()); + expect(reducer(undefined, {} as any)).toEqual(ImmutableMap()); }); }); diff --git a/app/soapbox/reducers/__tests__/index.test.ts b/app/soapbox/reducers/__tests__/index.test.ts index 15572f337..e5674e91b 100644 --- a/app/soapbox/reducers/__tests__/index.test.ts +++ b/app/soapbox/reducers/__tests__/index.test.ts @@ -4,7 +4,7 @@ import reducer from '..'; describe('root reducer', () => { it('should return the initial state', () => { - const result = reducer(undefined, {}); + const result = reducer(undefined, {} as any); expect(ImmutableRecord.isRecord(result)).toBe(true); expect(result.accounts.get('')).toBe(undefined); expect(result.instance.version).toEqual('0.0.0'); diff --git a/app/soapbox/reducers/__tests__/meta.test.ts b/app/soapbox/reducers/__tests__/meta.test.ts index d318b4a30..272116391 100644 --- a/app/soapbox/reducers/__tests__/meta.test.ts +++ b/app/soapbox/reducers/__tests__/meta.test.ts @@ -6,7 +6,7 @@ import reducer from '../meta'; describe('meta reducer', () => { it('should return the initial state', () => { - const result = reducer(undefined, {}); + const result = reducer(undefined, {} as any); expect(ImmutableRecord.isRecord(result)).toBe(true); expect(result.instance_fetch_failed).toBe(false); expect(result.swUpdating).toBe(false); diff --git a/app/soapbox/reducers/__tests__/mutes.test.ts b/app/soapbox/reducers/__tests__/mutes.test.ts index 411db10c6..66a866958 100644 --- a/app/soapbox/reducers/__tests__/mutes.test.ts +++ b/app/soapbox/reducers/__tests__/mutes.test.ts @@ -9,7 +9,7 @@ import reducer from '../mutes'; describe('mutes reducer', () => { it('should return the initial state', () => { - expect(reducer(undefined, {}).toJS()).toEqual({ + expect(reducer(undefined, {} as any).toJS()).toEqual({ new: { isSubmitting: false, accountId: null, diff --git a/app/soapbox/reducers/__tests__/onboarding.test.ts b/app/soapbox/reducers/__tests__/onboarding.test.ts index 95ecdf755..69b4b1b21 100644 --- a/app/soapbox/reducers/__tests__/onboarding.test.ts +++ b/app/soapbox/reducers/__tests__/onboarding.test.ts @@ -4,7 +4,7 @@ import reducer from '../onboarding'; describe('onboarding reducer', () => { it('should return the initial state', () => { - expect(reducer(undefined, {})).toEqual({ + expect(reducer(undefined, {} as any)).toEqual({ needsOnboarding: false, }); }); @@ -12,7 +12,7 @@ describe('onboarding reducer', () => { describe('ONBOARDING_START', () => { it('sets "needsOnboarding" to "true"', () => { const initialState = { needsOnboarding: false }; - const action = { type: ONBOARDING_START }; + const action = { type: ONBOARDING_START } as any; expect(reducer(initialState, action).needsOnboarding).toEqual(true); }); }); @@ -20,7 +20,7 @@ describe('onboarding reducer', () => { describe('ONBOARDING_END', () => { it('sets "needsOnboarding" to "false"', () => { const initialState = { needsOnboarding: true }; - const action = { type: ONBOARDING_END }; + const action = { type: ONBOARDING_END } as any; expect(reducer(initialState, action).needsOnboarding).toEqual(false); }); }); diff --git a/app/soapbox/reducers/__tests__/rules.test.ts b/app/soapbox/reducers/__tests__/rules.test.ts index 151516a83..25f8575ed 100644 --- a/app/soapbox/reducers/__tests__/rules.test.ts +++ b/app/soapbox/reducers/__tests__/rules.test.ts @@ -15,14 +15,14 @@ describe('rules reducer', () => { describe('RULES_FETCH_REQUEST', () => { it('sets "needsOnboarding" to "true"', () => { - const action = { type: RULES_FETCH_REQUEST }; + const action = { type: RULES_FETCH_REQUEST } as any; expect(reducer(initialState, action).isLoading).toEqual(true); }); }); describe('ONBOARDING_END', () => { it('sets "needsOnboarding" to "false"', () => { - const action = { type: RULES_FETCH_SUCCESS, payload: [{ id: '123' }] }; + const action = { type: RULES_FETCH_SUCCESS, payload: [{ id: '123' }] } as any; const result = reducer(initialState, action); expect(result.isLoading).toEqual(false); expect(result.items[0].id).toEqual('123'); diff --git a/app/soapbox/reducers/__tests__/settings.test.ts b/app/soapbox/reducers/__tests__/settings.test.ts index b4574d55c..5b065fd4c 100644 --- a/app/soapbox/reducers/__tests__/settings.test.ts +++ b/app/soapbox/reducers/__tests__/settings.test.ts @@ -4,7 +4,7 @@ import reducer from '../settings'; describe('settings reducer', () => { it('should return the initial state', () => { - expect(reducer(undefined, {})).toEqual(ImmutableMap({ + expect(reducer(undefined, {} as any)).toEqual(ImmutableMap({ saved: true, })); }); diff --git a/app/soapbox/reducers/__tests__/statuses.test.ts b/app/soapbox/reducers/__tests__/statuses.test.ts index fb245062a..06d82c871 100644 --- a/app/soapbox/reducers/__tests__/statuses.test.ts +++ b/app/soapbox/reducers/__tests__/statuses.test.ts @@ -1,7 +1,6 @@ import { Map as ImmutableMap, Record as ImmutableRecord, - fromJS, } from 'immutable'; import { STATUS_IMPORT } from 'soapbox/actions/importer'; @@ -11,12 +10,13 @@ import { STATUS_DELETE_REQUEST, STATUS_DELETE_FAIL, } from 'soapbox/actions/statuses'; +import { normalizeStatus } from 'soapbox/normalizers'; -import reducer from '../statuses'; +import reducer, { ReducerStatus } from '../statuses'; describe('statuses reducer', () => { it('should return the initial state', () => { - expect(reducer(undefined, {})).toEqual(ImmutableMap()); + expect(reducer(undefined, {} as any)).toEqual(ImmutableMap()); }); describe('STATUS_IMPORT', () => { @@ -35,7 +35,7 @@ describe('statuses reducer', () => { const expected = ['NEETzsche', 'alex', 'Lumeinshin', 'sneeden']; const result = reducer(undefined, action) - .getIn(['AFChectaqZjmOVkXZ2', 'mentions']) + .get('AFChectaqZjmOVkXZ2')?.mentions .map(mention => mention.get('username')) .toJS(); @@ -84,19 +84,18 @@ describe('statuses reducer', () => { remote_url: null, }]; - expect(state.getIn(['017eeb0e-e5e7-98fe-6b2b-ad02349251fb', 'media_attachments']).toJS()).toMatchObject(expected); + expect(state.get('017eeb0e-e5e7-98fe-6b2b-ad02349251fb')?.media_attachments.toJS()).toMatchObject(expected); }); it('fixes Pleroma attachments', () => { const status = require('soapbox/__fixtures__/pleroma-status-with-attachments.json'); const action = { type: STATUS_IMPORT, status }; const state = reducer(undefined, action); - const result = state.get('AGNkA21auFR5lnEAHw').media_attachments; + const result = state.get('AGNkA21auFR5lnEAHw')?.media_attachments; - expect(result.size).toBe(4); - expect(result.get(0).text_url).toBe(undefined); - expect(result.get(1).meta).toEqual(ImmutableMap()); - expect(result.getIn([1, 'pleroma', 'mime_type'])).toBe('application/x-nes-rom'); + expect(result?.size).toBe(4); + expect(result?.get(1)?.meta).toEqual(ImmutableMap()); + expect(result?.getIn([1, 'pleroma', 'mime_type'])).toBe('application/x-nes-rom'); }); it('hides CWs', () => { @@ -160,7 +159,9 @@ Promoting free speech, even for people and ideas you dislike`; describe('STATUS_CREATE_REQUEST', () => { it('increments the replies_count of its parent', () => { - const state = fromJS({ '123': { replies_count: 4 } }); + const state = ImmutableMap({ + '123': normalizeStatus({ replies_count: 4 }) as ReducerStatus, + }); const action = { type: STATUS_CREATE_REQUEST, @@ -174,7 +175,9 @@ Promoting free speech, even for people and ideas you dislike`; describe('STATUS_CREATE_FAIL', () => { it('decrements the replies_count of its parent', () => { - const state = fromJS({ '123': { replies_count: 5 } }); + const state = ImmutableMap({ + '123': normalizeStatus({ replies_count: 5 }) as ReducerStatus, + }); const action = { type: STATUS_CREATE_FAIL, @@ -188,7 +191,9 @@ Promoting free speech, even for people and ideas you dislike`; describe('STATUS_DELETE_REQUEST', () => { it('decrements the replies_count of its parent', () => { - const state = fromJS({ '123': { replies_count: 4 } }); + const state = ImmutableMap({ + '123': normalizeStatus({ replies_count: 4 }) as ReducerStatus, + }); const action = { type: STATUS_DELETE_REQUEST, @@ -200,7 +205,9 @@ Promoting free speech, even for people and ideas you dislike`; }); it('gracefully does nothing if no parent', () => { - const state = fromJS({ '123': { replies_count: 4 } }); + const state = ImmutableMap({ + '123': normalizeStatus({ replies_count: 4 }) as ReducerStatus, + }); const action = { type: STATUS_DELETE_REQUEST, @@ -214,7 +221,9 @@ Promoting free speech, even for people and ideas you dislike`; describe('STATUS_DELETE_FAIL', () => { it('decrements the replies_count of its parent', () => { - const state = fromJS({ '123': { replies_count: 4 } }); + const state = ImmutableMap({ + '123': normalizeStatus({ replies_count: 4 }) as ReducerStatus, + }); const action = { type: STATUS_DELETE_FAIL, @@ -226,7 +235,9 @@ Promoting free speech, even for people and ideas you dislike`; }); it('gracefully does nothing if no parent', () => { - const state = fromJS({ '123': { replies_count: 4 } }); + const state = ImmutableMap({ + '123': normalizeStatus({ replies_count: 4 }) as ReducerStatus, + }); const action = { type: STATUS_DELETE_FAIL, diff --git a/app/soapbox/reducers/__tests__/trends.test.ts b/app/soapbox/reducers/__tests__/trends.test.ts index 644654038..25330d770 100644 --- a/app/soapbox/reducers/__tests__/trends.test.ts +++ b/app/soapbox/reducers/__tests__/trends.test.ts @@ -2,7 +2,7 @@ import reducer from '../trends'; describe('trends reducer', () => { it('should return the initial state', () => { - expect(reducer(undefined, {}).toJS()).toEqual({ + expect(reducer(undefined, {} as any).toJS()).toEqual({ items: [], isLoading: false, }); diff --git a/app/soapbox/reducers/account_notes.ts b/app/soapbox/reducers/account_notes.ts index f5d753ee3..0f30b8d60 100644 --- a/app/soapbox/reducers/account_notes.ts +++ b/app/soapbox/reducers/account_notes.ts @@ -10,13 +10,13 @@ import { import type { AnyAction } from 'redux'; -const EditRecord = ImmutableRecord({ +export const EditRecord = ImmutableRecord({ isSubmitting: false, - account: null, + account: null as string | null, comment: '', }); -const ReducerRecord = ImmutableRecord({ +export const ReducerRecord = ImmutableRecord({ edit: EditRecord(), }); diff --git a/app/soapbox/reducers/index.ts b/app/soapbox/reducers/index.ts index 7f33dad1c..72b33f785 100644 --- a/app/soapbox/reducers/index.ts +++ b/app/soapbox/reducers/index.ts @@ -134,7 +134,6 @@ export const StateRecord = ImmutableRecord( }, {}), ); -// @ts-ignore: This type is fine but TS thinks it's wrong const appReducer = combineReducers(reducers, StateRecord); // Clear the state (mostly) when the user logs out diff --git a/app/soapbox/reducers/suggestions.ts b/app/soapbox/reducers/suggestions.ts index fc095113f..8335ff9ec 100644 --- a/app/soapbox/reducers/suggestions.ts +++ b/app/soapbox/reducers/suggestions.ts @@ -10,8 +10,11 @@ import { SUGGESTIONS_V2_FETCH_REQUEST, SUGGESTIONS_V2_FETCH_SUCCESS, SUGGESTIONS_V2_FETCH_FAIL, + SUGGESTIONS_TRUTH_FETCH_SUCCESS, } from 'soapbox/actions/suggestions'; +import { SuggestedProfile } from '../actions/suggestions'; + import type { AnyAction } from 'redux'; import type { APIEntity } from 'soapbox/types/entities'; @@ -53,6 +56,14 @@ const importSuggestions = (state: State, suggestions: APIEntities, next: string }); }; +const importTruthSuggestions = (state: State, suggestions: SuggestedProfile[], next: string | null) => { + return state.withMutations(state => { + state.update('items', items => items.concat(suggestions.map(x => ({ ...x, account: x.account_id })).map(suggestion => SuggestionRecord(suggestion)))); + state.set('isLoading', false); + state.set('next', next); + }); +}; + const dismissAccount = (state: State, accountId: string) => { return state.update('items', items => items.filterNot(item => item.account === accountId)); }; @@ -70,6 +81,8 @@ export default function suggestionsReducer(state: State = ReducerRecord(), actio return importAccounts(state, action.accounts); case SUGGESTIONS_V2_FETCH_SUCCESS: return importSuggestions(state, action.suggestions, action.next); + case SUGGESTIONS_TRUTH_FETCH_SUCCESS: + return importTruthSuggestions(state, action.suggestions, action.next); case SUGGESTIONS_FETCH_FAIL: case SUGGESTIONS_V2_FETCH_FAIL: return state.set('isLoading', false); diff --git a/app/soapbox/reducers/timelines.ts b/app/soapbox/reducers/timelines.ts index a1f33417f..05961ba71 100644 --- a/app/soapbox/reducers/timelines.ts +++ b/app/soapbox/reducers/timelines.ts @@ -5,6 +5,7 @@ import { Record as ImmutableRecord, fromJS, } from 'immutable'; +import sample from 'lodash/sample'; import { ACCOUNT_BLOCK_SUCCESS, @@ -30,6 +31,7 @@ import { MAX_QUEUED_ITEMS, TIMELINE_SCROLL_TOP, TIMELINE_REPLACE, + TIMELINE_INSERT, } from '../actions/timelines'; import type { AnyAction } from 'redux'; @@ -37,7 +39,7 @@ import type { StatusVisibility } from 'soapbox/normalizers/status'; import type { APIEntity, Status } from 'soapbox/types/entities'; const TRUNCATE_LIMIT = 40; -const TRUNCATE_SIZE = 20; +const TRUNCATE_SIZE = 20; const TimelineRecord = ImmutableRecord({ unread: 0, @@ -115,7 +117,7 @@ const expandNormalizedTimeline = (state: State, timelineId: string, statuses: Im }; const updateTimeline = (state: State, timelineId: string, statusId: string) => { - const top = state.get(timelineId)?.top; + const top = state.get(timelineId)?.top; const oldIds = state.get(timelineId)?.items || ImmutableOrderedSet(); const unread = state.get(timelineId)?.unread || 0; @@ -135,8 +137,8 @@ const updateTimeline = (state: State, timelineId: string, statusId: string) => { }; const updateTimelineQueue = (state: State, timelineId: string, statusId: string) => { - const queuedIds = state.get(timelineId)?.queuedItems || ImmutableOrderedSet(); - const listedIds = state.get(timelineId)?.items || ImmutableOrderedSet(); + const queuedIds = state.get(timelineId)?.queuedItems || ImmutableOrderedSet(); + const listedIds = state.get(timelineId)?.items || ImmutableOrderedSet(); const queuedCount = state.get(timelineId)?.totalQueuedItemsCount || 0; if (queuedIds.includes(statusId)) return state; @@ -353,6 +355,15 @@ export default function timelines(state: State = initialState, action: AnyAction timeline.set('items', ImmutableOrderedSet([])); })) .update('home', TimelineRecord(), timeline => timeline.set('feedAccountId', action.accountId)); + case TIMELINE_INSERT: + return state.update(action.timeline, TimelineRecord(), timeline => timeline.withMutations(timeline => { + timeline.update('items', oldIds => { + const oldIdsArray = oldIds.toArray(); + const positionInTimeline = sample([5, 6, 7, 8, 9]) as number; + oldIdsArray.splice(positionInTimeline, 0, `末suggestions-${oldIds.last()}`); + return ImmutableOrderedSet(oldIdsArray); + }); + })); default: return state; } diff --git a/app/soapbox/reducers/user_lists.ts b/app/soapbox/reducers/user_lists.ts index 99483a854..fc86cceb2 100644 --- a/app/soapbox/reducers/user_lists.ts +++ b/app/soapbox/reducers/user_lists.ts @@ -54,7 +54,7 @@ import { import type { APIEntity } from 'soapbox/types/entities'; -const ListRecord = ImmutableRecord({ +export const ListRecord = ImmutableRecord({ next: null as string | null, items: ImmutableOrderedSet(), isLoading: false, @@ -72,7 +72,7 @@ const ReactionListRecord = ImmutableRecord({ isLoading: false, }); -const ReducerRecord = ImmutableRecord({ +export const ReducerRecord = ImmutableRecord({ followers: ImmutableMap(), following: ImmutableMap(), reblogged_by: ImmutableMap(), @@ -90,7 +90,7 @@ const ReducerRecord = ImmutableRecord({ }); type State = ReturnType; -type List = ReturnType; +export type List = ReturnType; type Reaction = ReturnType; type ReactionList = ReturnType; type Items = ImmutableOrderedSet; diff --git a/app/soapbox/service_worker/web_push_locales.js b/app/soapbox/service_worker/web_push_locales.js index 1265f3cfa..172bbe4b5 100644 --- a/app/soapbox/service_worker/web_push_locales.js +++ b/app/soapbox/service_worker/web_push_locales.js @@ -20,6 +20,12 @@ filenames.forEach(filename => { 'notification.mention': full['notification.mention'] || '', 'notification.reblog': full['notification.reblog'] || '', 'notification.poll': full['notification.poll'] || '', + 'notification.status': full['notification.status'] || '', + 'notification.move': full['notification.move'] || '', + 'notification.user_approved': full['notification.user_approved'] || '', + + 'notification.pleroma:chat_mention': full['notification.pleroma:chat_mention'] || '', + 'notification.pleroma:emoji_reaction': full['notification.pleroma:emoji_reaction'] || '', 'status.show_more': full['status.show_more'] || '', 'status.reblog': full['status.reblog'] || '', diff --git a/app/soapbox/utils/__tests__/accounts.test.ts b/app/soapbox/utils/__tests__/accounts.test.ts index cafedce35..878d278dd 100644 --- a/app/soapbox/utils/__tests__/accounts.test.ts +++ b/app/soapbox/utils/__tests__/accounts.test.ts @@ -4,11 +4,13 @@ import { getDomain, } from '../accounts'; +import type { ReducerAccount } from 'soapbox/reducers/accounts'; + describe('getDomain', () => { const account = AccountRecord({ acct: 'alice', url: 'https://party.com/users/alice', - }); + }) as ReducerAccount; it('returns the domain', () => { expect(getDomain(account)).toEqual('party.com'); }); diff --git a/app/soapbox/utils/__tests__/numbers.test.tsx b/app/soapbox/utils/__tests__/numbers.test.tsx index 63c45b26b..a0edf41fe 100644 --- a/app/soapbox/utils/__tests__/numbers.test.tsx +++ b/app/soapbox/utils/__tests__/numbers.test.tsx @@ -10,28 +10,28 @@ test('isIntegerId()', () => { expect(isIntegerId('-1764036199')).toBe(true); expect(isIntegerId('106801667066418367')).toBe(true); expect(isIntegerId('9v5bmRalQvjOy0ECcC')).toBe(false); - expect(isIntegerId(null)).toBe(false); - expect(isIntegerId(undefined)).toBe(false); + expect(isIntegerId(null as any)).toBe(false); + expect(isIntegerId(undefined as any)).toBe(false); }); describe('shortNumberFormat', () => { test('handles non-numbers', () => { - render(
{shortNumberFormat('not-number')}
, null, null); + render(
{shortNumberFormat('not-number')}
, undefined, null); expect(screen.getByTestId('num')).toHaveTextContent('•'); }); test('formats numbers under 1,000', () => { - render(
{shortNumberFormat(555)}
, null, null); + render(
{shortNumberFormat(555)}
, undefined, null); expect(screen.getByTestId('num')).toHaveTextContent('555'); }); test('formats numbers under 1,000,000', () => { - render(
{shortNumberFormat(5555)}
, null, null); + render(
{shortNumberFormat(5555)}
, undefined, null); expect(screen.getByTestId('num')).toHaveTextContent('5.6K'); }); test('formats numbers over 1,000,000', () => { - render(
{shortNumberFormat(5555555)}
, null, null); + render(
{shortNumberFormat(5555555)}
, undefined, null); expect(screen.getByTestId('num')).toHaveTextContent('5.6M'); }); }); diff --git a/app/soapbox/utils/__tests__/status.test.ts b/app/soapbox/utils/__tests__/status.test.ts index 4556382de..2bc803ee5 100644 --- a/app/soapbox/utils/__tests__/status.test.ts +++ b/app/soapbox/utils/__tests__/status.test.ts @@ -1,4 +1,3 @@ -import { fromJS } from 'immutable'; import { normalizeStatus } from 'soapbox/normalizers/status'; @@ -7,9 +6,11 @@ import { defaultMediaVisibility, } from '../status'; +import type { ReducerStatus } from 'soapbox/reducers/statuses'; + describe('hasIntegerMediaIds()', () => { it('returns true for a Pleroma deleted status', () => { - const status = normalizeStatus(fromJS(require('soapbox/__fixtures__/pleroma-status-deleted.json'))); + const status = normalizeStatus(require('soapbox/__fixtures__/pleroma-status-deleted.json')) as ReducerStatus; expect(hasIntegerMediaIds(status)).toBe(true); }); }); @@ -20,17 +21,17 @@ describe('defaultMediaVisibility()', () => { }); it('hides sensitive media by default', () => { - const status = normalizeStatus({ sensitive: true }); + const status = normalizeStatus({ sensitive: true }) as ReducerStatus; expect(defaultMediaVisibility(status, 'default')).toBe(false); }); it('hides media when displayMedia is hide_all', () => { - const status = normalizeStatus({}); + const status = normalizeStatus({}) as ReducerStatus; expect(defaultMediaVisibility(status, 'hide_all')).toBe(false); }); it('shows sensitive media when displayMedia is show_all', () => { - const status = normalizeStatus({ sensitive: true }); + const status = normalizeStatus({ sensitive: true }) as ReducerStatus; expect(defaultMediaVisibility(status, 'show_all')).toBe(true); }); }); diff --git a/app/soapbox/utils/__tests__/tailwind.test.ts b/app/soapbox/utils/__tests__/tailwind.test.ts index 822408393..3c359ecc0 100644 --- a/app/soapbox/utils/__tests__/tailwind.test.ts +++ b/app/soapbox/utils/__tests__/tailwind.test.ts @@ -4,7 +4,7 @@ import { toTailwind, fromLegacyColors, expandPalette } from '../tailwind'; describe('toTailwind()', () => { it('handles empty Soapbox config', () => { - const soapboxConfig = ImmutableMap(); + const soapboxConfig = ImmutableMap(); const result = toTailwind(soapboxConfig); const expected = ImmutableMap({ colors: ImmutableMap() }); expect(result).toEqual(expected); diff --git a/app/soapbox/utils/__tests__/timelines.test.ts b/app/soapbox/utils/__tests__/timelines.test.ts index df48bdae9..852a76ef6 100644 --- a/app/soapbox/utils/__tests__/timelines.test.ts +++ b/app/soapbox/utils/__tests__/timelines.test.ts @@ -4,70 +4,72 @@ import { normalizeStatus } from 'soapbox/normalizers/status'; import { shouldFilter } from '../timelines'; +import type { ReducerStatus } from 'soapbox/reducers/statuses'; + describe('shouldFilter', () => { it('returns false under normal circumstances', () => { const columnSettings = fromJS({}); - const status = normalizeStatus(fromJS({})); + const status = normalizeStatus({}) as ReducerStatus; expect(shouldFilter(status, columnSettings)).toBe(false); }); it('reblog: returns true when `shows.reblog == false`', () => { const columnSettings = fromJS({ shows: { reblog: false } }); - const status = normalizeStatus(fromJS({ reblog: {} })); + const status = normalizeStatus({ reblog: {} }) as ReducerStatus; expect(shouldFilter(status, columnSettings)).toBe(true); }); it('reblog: returns false when `shows.reblog == true`', () => { const columnSettings = fromJS({ shows: { reblog: true } }); - const status = normalizeStatus(fromJS({ reblog: {} })); + const status = normalizeStatus({ reblog: {} }) as ReducerStatus; expect(shouldFilter(status, columnSettings)).toBe(false); }); it('reply: returns true when `shows.reply == false`', () => { const columnSettings = fromJS({ shows: { reply: false } }); - const status = normalizeStatus(fromJS({ in_reply_to_id: '1234' })); + const status = normalizeStatus({ in_reply_to_id: '1234' }) as ReducerStatus; expect(shouldFilter(status, columnSettings)).toBe(true); }); it('reply: returns false when `shows.reply == true`', () => { const columnSettings = fromJS({ shows: { reply: true } }); - const status = normalizeStatus(fromJS({ in_reply_to_id: '1234' })); + const status = normalizeStatus({ in_reply_to_id: '1234' }) as ReducerStatus; expect(shouldFilter(status, columnSettings)).toBe(false); }); it('direct: returns true when `shows.direct == false`', () => { const columnSettings = fromJS({ shows: { direct: false } }); - const status = normalizeStatus(fromJS({ visibility: 'direct' })); + const status = normalizeStatus({ visibility: 'direct' }) as ReducerStatus; expect(shouldFilter(status, columnSettings)).toBe(true); }); it('direct: returns false when `shows.direct == true`', () => { const columnSettings = fromJS({ shows: { direct: true } }); - const status = normalizeStatus(fromJS({ visibility: 'direct' })); + const status = normalizeStatus({ visibility: 'direct' }) as ReducerStatus; expect(shouldFilter(status, columnSettings)).toBe(false); }); it('direct: returns false for a public post when `shows.direct == false`', () => { const columnSettings = fromJS({ shows: { direct: false } }); - const status = normalizeStatus(fromJS({ visibility: 'public' })); + const status = normalizeStatus({ visibility: 'public' }) as ReducerStatus; expect(shouldFilter(status, columnSettings)).toBe(false); }); it('multiple settings', () => { const columnSettings = fromJS({ shows: { reblog: false, reply: false, direct: false } }); - const status = normalizeStatus(fromJS({ reblog: null, in_reply_to_id: null, visibility: 'direct' })); + const status = normalizeStatus({ reblog: null, in_reply_to_id: null, visibility: 'direct' }) as ReducerStatus; expect(shouldFilter(status, columnSettings)).toBe(true); }); it('multiple settings', () => { const columnSettings = fromJS({ shows: { reblog: false, reply: true, direct: false } }); - const status = normalizeStatus(fromJS({ reblog: null, in_reply_to_id: '1234', visibility: 'public' })); + const status = normalizeStatus({ reblog: null, in_reply_to_id: '1234', visibility: 'public' }) as ReducerStatus; expect(shouldFilter(status, columnSettings)).toBe(false); }); it('multiple settings', () => { const columnSettings = fromJS({ shows: { reblog: true, reply: false, direct: true } }); - const status = normalizeStatus(fromJS({ reblog: {}, in_reply_to_id: '1234', visibility: 'direct' })); + const status = normalizeStatus({ reblog: {}, in_reply_to_id: '1234', visibility: 'direct' }) as ReducerStatus; expect(shouldFilter(status, columnSettings)).toBe(true); }); }); diff --git a/app/soapbox/utils/features.ts b/app/soapbox/utils/features.ts index 6f4a77ddf..0afe0c254 100644 --- a/app/soapbox/utils/features.ts +++ b/app/soapbox/utils/features.ts @@ -148,9 +148,7 @@ const getInstanceFeatures = (instance: Instance) => { * @see POST /api/v1/accounts * @see PATCH /api/v1/accounts/update_credentials */ - // birthdays: v.software === PLEROMA && gte(v.version, '2.4.50'), - // FIXME: temporarily disabled until they can be deleted on the backend. - birthdays: false, + birthdays: v.software === PLEROMA && v.build === SOAPBOX && gte(v.version, '2.4.50'), /** Whether people who blocked you are visible through the API. */ blockersVisible: features.includes('blockers_visible'), @@ -579,6 +577,11 @@ const getInstanceFeatures = (instance: Instance) => { v.software === TRUTHSOCIAL, ]), + /** + * Supports Truth suggestions. + */ + truthSuggestions: v.software === TRUTHSOCIAL, + /** * Whether the backend allows adding users you don't follow to lists. * @see POST /api/v1/lists/:id/accounts diff --git a/app/soapbox/utils/notification.ts b/app/soapbox/utils/notification.ts new file mode 100644 index 000000000..635d16f29 --- /dev/null +++ b/app/soapbox/utils/notification.ts @@ -0,0 +1,25 @@ +/** Notification types known to Soapbox. */ +const NOTIFICATION_TYPES = [ + 'follow', + 'follow_request', + 'mention', + 'reblog', + 'favourite', + 'poll', + 'status', + 'move', + 'pleroma:chat_mention', + 'pleroma:emoji_reaction', + 'user_approved', +] as const; + +type NotificationType = typeof NOTIFICATION_TYPES[number]; + +/** Ensure the Notification is a valid, known type. */ +const validType = (type: string): type is NotificationType => NOTIFICATION_TYPES.includes(type as any); + +export { + NOTIFICATION_TYPES, + NotificationType, + validType, +}; diff --git a/app/styles/about.scss b/app/styles/about.scss index 5e2753feb..038e34ec8 100644 --- a/app/styles/about.scss +++ b/app/styles/about.scss @@ -52,7 +52,7 @@ $fluid-breakpoint: $maximum-width + 20px; .container { width: 100%; - max-width: 1440px; + max-width: 1280px; @media screen and (max-width: $no-gap-breakpoint) { padding: 0; @@ -82,7 +82,7 @@ $fluid-breakpoint: $maximum-width + 20px; .header-container { display: flex; - width: 1440px; + width: 1280px; align-items: stretch; justify-content: center; flex-wrap: nowrap; diff --git a/app/styles/application.scss b/app/styles/application.scss index 1dcd2efd5..f27ab386e 100644 --- a/app/styles/application.scss +++ b/app/styles/application.scss @@ -67,7 +67,6 @@ @import 'components/backups'; @import 'components/crypto-donate'; @import 'components/remote-timeline'; -@import 'components/federation-restrictions'; @import 'components/aliases'; @import 'components/icon'; @import 'components/radio-button'; diff --git a/app/styles/components/federation-restrictions.scss b/app/styles/components/federation-restrictions.scss deleted file mode 100644 index 4bc42ff94..000000000 --- a/app/styles/components/federation-restrictions.scss +++ /dev/null @@ -1,69 +0,0 @@ -.federation-restrictions { - padding-top: 15px; - - .slist .item-list > article { - padding: 0 20px; - - &:last-child { - padding-bottom: 15px; - } - } -} - -.restricted-instance { - &__header { - padding: 10px 0; - display: flex; - text-decoration: none; - color: var(--primary-text-color); - } - - &__icon { - width: 16px; - - .svg-icon svg { - stroke-width: 1.3; - } - } - - &--expanded &__icon i.fa { - transform: translateX(-3px); - } - - &--reject &__host { - text-decoration: line-through; - } - - &__restrictions { - height: 0; - overflow: hidden; - } - - &--expanded &__restrictions { - height: auto; - } - - .instance-restrictions { - padding: 5px 0 5px 15px; - border-left: 3px solid hsla(var(--primary-text-color_hsl), 0.4); - color: var(--primary-text-color--faint); - margin-bottom: 15px; - - .federation-restriction { - padding: 7px 0; - font-size: 14px; - } - - &__message { - margin-bottom: 10px; - - i.fa { - padding-right: 10px; - } - - &:last-child { - margin-bottom: 0; - } - } - } -} diff --git a/app/styles/footer.scss b/app/styles/footer.scss index e73994922..835d40061 100644 --- a/app/styles/footer.scss +++ b/app/styles/footer.scss @@ -15,7 +15,7 @@ .footer-container { display: flex; - width: 1440px; + width: 1280px; align-items: center; padding: 0 20px; flex-direction: column-reverse; diff --git a/docs/administration/deploy-at-scale.md b/docs/administration/deploy-at-scale.md new file mode 100644 index 000000000..cbc231ac6 --- /dev/null +++ b/docs/administration/deploy-at-scale.md @@ -0,0 +1,125 @@ +# Deploying Soapbox at scale + +Fortunately Soapbox is just static files! +HTML, CSS, and JS is as scalable as it gets, but there are some additional considerations when deploying at scale. + +This guide is intended for users with a lot of traffic, who need to serve Soapbox behind a load-balancer. + +## Getting or building Soapbox + +The best way to get Soapbox builds is from a GitLab CI job. +The official build URL is here: + +``` +https://gitlab.com/soapbox-pub/soapbox-fe/-/jobs/artifacts/develop/download?job=build-production +``` + +(Note that `develop` in that URL can be replaced with any git ref, eg `v2.0.0`, and thus will be updated with the latest zip whenever a new commit is pushed to `develop`.) + +### Producing a custom build + +If you'd like to customize Soapbox, we recommend forking it on GitLab and having GitLab CI produce the build for you at your own URL. + +You may be interested in [build configuration options](../development/build-config) for customization and compile-time options. + +## Load-balanced Nginx + +A common way to deploy Soapbox at scale is with multiple Nginx servers behind a load-balancer. +The load-balancer could run HAProxy, be a Cloudflare load-balancer, or even be another Nginx. + +Each Nginx should have the latest Soapbox deployed on it, while the load-balancer distributes traffic to each Nginx. + +Soapbox is an [SPA (single-page application)](https://en.wikipedia.org/wiki/Single-page_application), meaning Nginx should serve the same `index.html` for every route except build files and known API paths. + +Loosely, that can be achieved like this: + +```nginx +location / { + root /opt/soapbox/static; + try_files $uri index.html; +} + +location ~ ^/(api|oauth|admin) { + proxy_pass http://127.0.0.1:3000; +} +``` + +We recommend trying [`mastodon.conf`](https://gitlab.com/soapbox-pub/soapbox-fe/-/blob/develop/installation/mastodon.conf) as a starting point. +It is fine-tuned, includes support for federation, and should work with any backend. + +## The ServiceWorker + +Soapbox ships with a ServiceWorker, `sw.js`, as part of its build. + +ServiceWorkers enable native app-like functionality on the site, including: + +- Offline support. +- Native push notifications. +- "Add to home screen" prompt. + +Overall, the ServiceWorker offers a better experience for users. +However it requires careful planning for deployments, because it has an unprecedented level of control over the browser. + +Here are some surprising things ServiceWorkers can do: + +- Serve a different page for any URL on the domain, even if no such file/page has been deployed. +- Serve an outdated file even after clearing your browser cache. + +To help mitigate ServiceWorker issues, it's important to follow the directions in this guide regarding the order of files deployed and caching. + +It is also possible to omit `sw.js` from your deployment if you aren't ready for it, but beware that simply removing the file won't cause the ServiceWorker to disappear from users' devices. +You should deploy a [no-op ServiceWorker](https://developer.chrome.com/docs/workbox/remove-buggy-service-workers/) for that. + +## Deploying files in order + +Soapbox files depend on one-another, so it's important they're deployed in the following order: + +1. `packs/` is deployed to _all servers_ first. +2. `index.html` is deployed to _all servers_ next. +3. `sw.js` (and everything else) is deployed to _all servers_ last. + +_"All servers"_ is stressed because with a load-balanced deployment, it's important to wait between each step so things don't get out of sync. + +Files in `packs/` are generated with [contenthash filenames](https://webpack.js.org/guides/caching/#output-filenames), so a new deployment won't interfere with the running deployment. +It is safe to merge directories with "overwrite" or "skip" mode. + +The `index.html` contains hardcoded paths to files in `packs/`, so it must be deployed after all `packs/` have been uploaded. +New index files will overwrite the existing one on each server. + +Finally, `sw.js` should be deployed, overwriting the existing one on each server. +It is dependent on `index.html`, and if deployed too soon, the ServiceWorker could cache an outdated `index.html` leaving users stuck on an old version of your website. + +## Cache considerations + +Build files in `packs/` have [unique filenames](https://webpack.js.org/guides/caching/#output-filenames) based on their content. +They are considered **idempotent** and may be cached forever. +You could even consider deploying these to an S3-compatible CDN. + +However, **all other files else should not be cached at all**. + +Please ensure that your Nginx configuration does not return `cache-control` headers on the index of your website (or any other page that serves Soapbox), and you _must not enable edge caching_ in Nginx or third-party services like Cloudflare. + +Furthermore, `sw.js` must not be cached at the edge. + +Failure to do this could lead to improper ServiceWorker functioning upon new deployments, leaving users stuck on a malfunctioning version of the site. + +## Server Side Rendering (SSR) + +AKA "why don't links to my website show a preview when posted on Facebook/Twitter/Slack/etc"? + +Deploying with Nginx means that you forego the link preview functionality offered by Pleroma and Mastodon, since Soapbox has no knowledge of the backend whatsoever. + +This problem has no official solution, but we have some ideas: + +1. Serve different content to link crawlers based on their `user-agent`. +2. Inject metadata into `index.html` somehow based on the URL. + +The first solution is probably the most straightforward, and can be achieved in Nginx like so: + +```nginx +if ($http_user_agent ~* "googlebot|bingbot|yandex|baiduspider|twitterbot|facebookexternalhit|rogerbot|linkedinbot|embedly|quora link preview|showyoubot|outbrain|pinterest\/0\.|pinterestbot|slackbot|vkShare|W3C_Validator|whatsapp") { + # TODO: route to backend? +} +``` + +See [this snippet](https://gist.github.com/thoop/8165802) for more information. diff --git a/jest.config.js b/jest.config.js index e86307f93..468401c51 100644 --- a/jest.config.js +++ b/jest.config.js @@ -33,17 +33,21 @@ module.exports = { '/node_modules', '/app', ], + 'moduleNameMapper': { + // https://github.com/uuidjs/uuid/pull/616#issuecomment-1111012599 + '^uuid$': require.resolve('uuid'), + }, 'testMatch': ['**/*/__tests__/**/?(*.|*-)+(test).(ts|js)?(x)'], 'testEnvironment': 'jsdom', 'transformIgnorePatterns': [ // FIXME: react-sticky-box doesn't provide a CJS build, so transform it for now // https://github.com/codecks-io/react-sticky-box/issues/79 - `/node_modules/(?!(react-sticky-box|.+\\.(${ASSET_EXTS})))`, + `/node_modules/(?!(react-sticky-box|.+\\.(${ASSET_EXTS})$))`, // Ignore node_modules, except static assets - // `/node_modules/(?!.+\\.(${ASSET_EXTS}))`, + // `/node_modules/(?!.+\\.(${ASSET_EXTS})$)`, ], 'transform': { '\\.[jt]sx?$': 'babel-jest', - [`.+\\.(${ASSET_EXTS})$`]: '/jest/assetTransformer.js', + [`\\.(${ASSET_EXTS})$`]: '/jest/assetTransformer.js', }, }; diff --git a/jest/assetTransformer.js b/jest/assetTransformer.js index db42b2a2f..9043107a3 100644 --- a/jest/assetTransformer.js +++ b/jest/assetTransformer.js @@ -5,6 +5,8 @@ const path = require('path'); // Tries to do basically what Webpack does module.exports = { process(src, filename, config, options) { - return `module.exports = "https://soapbox.test/assets/${path.basename(filename)}";`; + return { + code: `module.exports = "https://soapbox.test/assets/${path.basename(filename)}";`, + }; }, }; diff --git a/package.json b/package.json index 47098b26b..92f8a1600 100644 --- a/package.json +++ b/package.json @@ -53,7 +53,7 @@ "@fontsource/inter": "^4.5.1", "@fontsource/roboto": "^4.5.0", "@gamestdio/websocket": "^0.3.2", - "@jest/globals": "^27.5.1", + "@jest/globals": "^28.1.2", "@lcdp/offline-plugin": "^5.1.0", "@metamask/providers": "^9.0.0", "@popperjs/core": "^2.11.5", @@ -67,13 +67,13 @@ "@sentry/browser": "^7.2.0", "@sentry/react": "^7.2.0", "@sentry/tracing": "^7.2.0", - "@tabler/icons": "^1.71.0", + "@tabler/icons": "^1.73.0", "@tailwindcss/forms": "^0.4.0", "@tailwindcss/typography": "^0.5.1", "@testing-library/react": "^12.1.4", "@types/escape-html": "^1.0.1", "@types/http-link-header": "^1.0.3", - "@types/jest": "^27.4.1", + "@types/jest": "^28.1.4", "@types/lodash": "^4.14.180", "@types/object-assign": "^4.0.30", "@types/object-fit-images": "^3.2.3", @@ -91,7 +91,7 @@ "@types/uuid": "^8.3.4", "array-includes": "^3.1.5", "autoprefixer": "^10.4.2", - "axios": "^0.27.2", + "axios": "^1.0.0-alpha.1", "axios-mock-adapter": "^1.21.1", "babel-loader": "^8.2.5", "babel-plugin-lodash": "^3.3.4", @@ -167,6 +167,7 @@ "react-popper": "^2.3.0", "react-redux": "^7.2.5", "react-router-dom": "^5.3.0", + "react-router-scroll-4": "^1.0.0-beta.2", "react-simple-pull-to-refresh": "^1.3.0", "react-sparklines": "^1.7.0", "react-sticky-box": "^1.0.2", @@ -201,13 +202,14 @@ "wicg-inert": "^3.1.1" }, "devDependencies": { + "@jedmao/redux-mock-store": "^3.0.5", "@testing-library/jest-dom": "^5.16.4", "@testing-library/react-hooks": "^8.0.1", "@testing-library/user-event": "^14.0.3", "@typescript-eslint/eslint-plugin": "^5.15.0", "@typescript-eslint/parser": "^5.15.0", "babel-eslint": "^10.1.0", - "babel-jest": "^28.1.0", + "babel-jest": "^28.1.2", "cross-env": "^7.0.3", "danger": "^11.0.7", "eslint": "^7.0.0", @@ -219,17 +221,17 @@ "eslint-plugin-react-hooks": "^4.2.0", "fake-indexeddb": "^3.1.7", "husky": "^7.0.2", - "jest": "^27.5.1", - "jest-junit": "^13.2.0", + "jest": "^28.1.2", + "jest-environment-jsdom": "^28.1.2", + "jest-junit": "^14.0.0", "lint-staged": ">=10", "raf": "^3.4.1", "react-intl-translations-manager": "^5.0.3", - "redux-mock-store": "^1.5.4", "stylelint": "^13.7.2", "stylelint-config-standard": "^22.0.0", "stylelint-scss": "^3.18.0", "tailwindcss": "^3.0.15", - "ts-jest": "^27.1.4", + "ts-jest": "^28.0.5", "webpack-dev-server": "^4.9.1", "yargs": "^16.0.3" } diff --git a/tailwind.config.js b/tailwind.config.js index 7ac10feee..45644a143 100644 --- a/tailwind.config.js +++ b/tailwind.config.js @@ -8,7 +8,7 @@ module.exports = { sm: '581px', md: '768px', lg: '976px', - xl: '1440px', + xl: '1280px', }, extend: { fontSize: { diff --git a/tsconfig.json b/tsconfig.json index 8989bd57e..dba721d72 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -14,6 +14,5 @@ "experimentalDecorators": true, "esModuleInterop": true, "typeRoots": [ "./types", "./node_modules/@types"] - }, - "exclude": ["node_modules", "types", "**/*.test.*", "**/__mocks__/*", "**/__tests__/*"] + } } diff --git a/types/redux-immutable/index.d.ts b/types/redux-immutable/index.d.ts index 80d00209a..fbaecd198 100644 --- a/types/redux-immutable/index.d.ts +++ b/types/redux-immutable/index.d.ts @@ -13,5 +13,5 @@ declare module 'redux-immutable' { export function combineReducers(reducers: ReducersMapObject, getDefaultState?: () => Collection.Keyed): Reducer; export function combineReducers(reducers: ReducersMapObject, getDefaultState?: () => Collection.Indexed): Reducer; export function combineReducers(reducers: ReducersMapObject, getDefaultState?: () => Collection.Indexed): Reducer; - export function combineReducers(reducers: ReducersMapObject, getDefaultState?: Record.Factory): Reducer; + export function combineReducers(reducers: ReducersMapObject, getDefaultState?: Record.Factory): Reducer>>; } diff --git a/webpack/shared.js b/webpack/shared.js index 9dee79de1..fb8308ee4 100644 --- a/webpack/shared.js +++ b/webpack/shared.js @@ -145,9 +145,6 @@ module.exports = { 'node_modules', ], alias: { - // Override tabler's package.json to allow importing .svg files directly - // https://stackoverflow.com/a/35990101/8811886 - '@tabler': resolve('node_modules', '@tabler'), 'icons': resolve('app', 'icons'), 'custom': resolve('custom'), }, diff --git a/yarn.lock b/yarn.lock index 5db73d9ab..6d6828864 100644 --- a/yarn.lock +++ b/yarn.lock @@ -45,7 +45,7 @@ resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.17.10.tgz#711dc726a492dfc8be8220028b1b92482362baab" integrity sha512-GZt/TCsG70Ms19gfZO1tM4CVnXsPgEPBCpJu+Qz3L0LUDsY5nZqFZglIoPC1kIYOtNBZlrnFT+klg12vFGZXrw== -"@babel/core@>=7.9.0", "@babel/core@^7.7.2", "@babel/core@^7.9.0": +"@babel/core@>=7.9.0", "@babel/core@^7.9.0": version "7.15.5" resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.15.5.tgz#f8ed9ace730722544609f90c9bb49162dc3bf5b9" integrity sha512-pYgXxiwAgQpgM1bNkZsDEq85f0ggXMA5L7c+o3tskGMh2BunCI9QUwB9Z4jpvXUOuMdyGKiGKQiRe11VS6Jzvg== @@ -66,27 +66,6 @@ semver "^6.3.0" source-map "^0.5.0" -"@babel/core@^7.1.0", "@babel/core@^7.12.3", "@babel/core@^7.8.0": - version "7.17.8" - resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.17.8.tgz#3dac27c190ebc3a4381110d46c80e77efe172e1a" - integrity sha512-OdQDV/7cRBtJHLSOBqqbYNkOcydOgnX59TZx4puf41fzcVtN3e/4yqY8lMQsK+5X2lJtAdmA+6OHqsj1hBJ4IQ== - dependencies: - "@ampproject/remapping" "^2.1.0" - "@babel/code-frame" "^7.16.7" - "@babel/generator" "^7.17.7" - "@babel/helper-compilation-targets" "^7.17.7" - "@babel/helper-module-transforms" "^7.17.7" - "@babel/helpers" "^7.17.8" - "@babel/parser" "^7.17.8" - "@babel/template" "^7.16.7" - "@babel/traverse" "^7.17.3" - "@babel/types" "^7.17.0" - convert-source-map "^1.7.0" - debug "^4.1.0" - gensync "^1.0.0-beta.2" - json5 "^2.1.2" - semver "^6.3.0" - "@babel/core@^7.11.6", "@babel/core@^7.18.2": version "7.18.2" resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.18.2.tgz#87b2fcd7cce9becaa7f5acebdc4f09f3dd19d876" @@ -108,6 +87,27 @@ json5 "^2.2.1" semver "^6.3.0" +"@babel/core@^7.12.3": + version "7.17.8" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.17.8.tgz#3dac27c190ebc3a4381110d46c80e77efe172e1a" + integrity sha512-OdQDV/7cRBtJHLSOBqqbYNkOcydOgnX59TZx4puf41fzcVtN3e/4yqY8lMQsK+5X2lJtAdmA+6OHqsj1hBJ4IQ== + dependencies: + "@ampproject/remapping" "^2.1.0" + "@babel/code-frame" "^7.16.7" + "@babel/generator" "^7.17.7" + "@babel/helper-compilation-targets" "^7.17.7" + "@babel/helper-module-transforms" "^7.17.7" + "@babel/helpers" "^7.17.8" + "@babel/parser" "^7.17.8" + "@babel/template" "^7.16.7" + "@babel/traverse" "^7.17.3" + "@babel/types" "^7.17.0" + convert-source-map "^1.7.0" + debug "^4.1.0" + gensync "^1.0.0-beta.2" + json5 "^2.1.2" + semver "^6.3.0" + "@babel/generator@^7.15.4", "@babel/generator@^7.17.3", "@babel/generator@^7.17.7": version "7.17.7" resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.17.7.tgz#8da2599beb4a86194a3b24df6c085931d9ee45ad" @@ -1603,113 +1603,134 @@ resolved "https://registry.yarnpkg.com/@istanbuljs/schema/-/schema-0.1.3.tgz#e45e384e4b8ec16bce2fd903af78450f6bf7ec98" integrity sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA== -"@jest/console@^27.5.1": - version "27.5.1" - resolved "https://registry.yarnpkg.com/@jest/console/-/console-27.5.1.tgz#260fe7239602fe5130a94f1aa386eff54b014bba" - integrity sha512-kZ/tNpS3NXn0mlXXXPNuDZnb4c0oZ20r4K5eemM2k30ZC3G0T02nXUvyhf5YdbXWHPEJLc9qGLxEZ216MdL+Zg== +"@jedmao/redux-mock-store@^3.0.5": + version "3.0.5" + resolved "https://registry.yarnpkg.com/@jedmao/redux-mock-store/-/redux-mock-store-3.0.5.tgz#015fa4fc96bfc02b61ca221d9ea0476b78c70c97" + integrity sha512-zNcVCd5/ekSMdQWk64CqTPM24D9Lo59st9KvS+fljGpQXV4SliB7Vo0NFQIgvQJWPYeeobdngnrGy0XbCaARNw== + +"@jest/console@^28.1.1": + version "28.1.1" + resolved "https://registry.yarnpkg.com/@jest/console/-/console-28.1.1.tgz#305f8ca50b6e70413839f54c0e002b60a0f2fd7d" + integrity sha512-0RiUocPVFEm3WRMOStIHbRWllG6iW6E3/gUPnf4lkrVFyXIIDeCe+vlKeYyFOMhB2EPE6FLFCNADSOOQMaqvyA== dependencies: - "@jest/types" "^27.5.1" + "@jest/types" "^28.1.1" "@types/node" "*" chalk "^4.0.0" - jest-message-util "^27.5.1" - jest-util "^27.5.1" + jest-message-util "^28.1.1" + jest-util "^28.1.1" slash "^3.0.0" -"@jest/core@^27.5.1": - version "27.5.1" - resolved "https://registry.yarnpkg.com/@jest/core/-/core-27.5.1.tgz#267ac5f704e09dc52de2922cbf3af9edcd64b626" - integrity sha512-AK6/UTrvQD0Cd24NSqmIA6rKsu0tKIxfiCducZvqxYdmMisOYAsdItspT+fQDQYARPf8XgjAFZi0ogW2agH5nQ== +"@jest/core@^28.1.2": + version "28.1.2" + resolved "https://registry.yarnpkg.com/@jest/core/-/core-28.1.2.tgz#eac519b9acbd154313854b8823a47b5c645f785a" + integrity sha512-Xo4E+Sb/nZODMGOPt2G3cMmCBqL4/W2Ijwr7/mrXlq4jdJwcFQ/9KrrJZT2adQRk2otVBXXOz1GRQ4Z5iOgvRQ== dependencies: - "@jest/console" "^27.5.1" - "@jest/reporters" "^27.5.1" - "@jest/test-result" "^27.5.1" - "@jest/transform" "^27.5.1" - "@jest/types" "^27.5.1" + "@jest/console" "^28.1.1" + "@jest/reporters" "^28.1.2" + "@jest/test-result" "^28.1.1" + "@jest/transform" "^28.1.2" + "@jest/types" "^28.1.1" "@types/node" "*" ansi-escapes "^4.2.1" chalk "^4.0.0" - emittery "^0.8.1" + ci-info "^3.2.0" exit "^0.1.2" graceful-fs "^4.2.9" - jest-changed-files "^27.5.1" - jest-config "^27.5.1" - jest-haste-map "^27.5.1" - jest-message-util "^27.5.1" - jest-regex-util "^27.5.1" - jest-resolve "^27.5.1" - jest-resolve-dependencies "^27.5.1" - jest-runner "^27.5.1" - jest-runtime "^27.5.1" - jest-snapshot "^27.5.1" - jest-util "^27.5.1" - jest-validate "^27.5.1" - jest-watcher "^27.5.1" + jest-changed-files "^28.0.2" + jest-config "^28.1.2" + jest-haste-map "^28.1.1" + jest-message-util "^28.1.1" + jest-regex-util "^28.0.2" + jest-resolve "^28.1.1" + jest-resolve-dependencies "^28.1.2" + jest-runner "^28.1.2" + jest-runtime "^28.1.2" + jest-snapshot "^28.1.2" + jest-util "^28.1.1" + jest-validate "^28.1.1" + jest-watcher "^28.1.1" micromatch "^4.0.4" + pretty-format "^28.1.1" rimraf "^3.0.0" slash "^3.0.0" strip-ansi "^6.0.0" -"@jest/environment@^27.5.1": - version "27.5.1" - resolved "https://registry.yarnpkg.com/@jest/environment/-/environment-27.5.1.tgz#d7425820511fe7158abbecc010140c3fd3be9c74" - integrity sha512-/WQjhPJe3/ghaol/4Bq480JKXV/Rfw8nQdN7f41fM8VDHLcxKXou6QyXAh3EFr9/bVG3x74z1NWDkP87EiY8gA== +"@jest/environment@^28.1.2": + version "28.1.2" + resolved "https://registry.yarnpkg.com/@jest/environment/-/environment-28.1.2.tgz#94a052c0c5f9f8c8e6d13ea6da78dbc5d7d9b85b" + integrity sha512-I0CR1RUMmOzd0tRpz10oUfaChBWs+/Hrvn5xYhMEF/ZqrDaaeHwS8yDBqEWCrEnkH2g+WE/6g90oBv3nKpcm8Q== dependencies: - "@jest/fake-timers" "^27.5.1" - "@jest/types" "^27.5.1" + "@jest/fake-timers" "^28.1.2" + "@jest/types" "^28.1.1" "@types/node" "*" - jest-mock "^27.5.1" + jest-mock "^28.1.1" -"@jest/fake-timers@^27.5.1": - version "27.5.1" - resolved "https://registry.yarnpkg.com/@jest/fake-timers/-/fake-timers-27.5.1.tgz#76979745ce0579c8a94a4678af7a748eda8ada74" - integrity sha512-/aPowoolwa07k7/oM3aASneNeBGCmGQsc3ugN4u6s4C/+s5M64MFo/+djTdiwcbQlRfFElGuDXWzaWj6QgKObQ== +"@jest/expect-utils@^28.1.1": + version "28.1.1" + resolved "https://registry.yarnpkg.com/@jest/expect-utils/-/expect-utils-28.1.1.tgz#d84c346025b9f6f3886d02c48a6177e2b0360587" + integrity sha512-n/ghlvdhCdMI/hTcnn4qV57kQuV9OTsZzH1TTCVARANKhl6hXJqLKUkwX69ftMGpsbpt96SsDD8n8LD2d9+FRw== dependencies: - "@jest/types" "^27.5.1" - "@sinonjs/fake-timers" "^8.0.1" + jest-get-type "^28.0.2" + +"@jest/expect@^28.1.2": + version "28.1.2" + resolved "https://registry.yarnpkg.com/@jest/expect/-/expect-28.1.2.tgz#0b25acedff46e1e1e5606285306c8a399c12534f" + integrity sha512-HBzyZBeFBiOelNbBKN0pilWbbrGvwDUwAqMC46NVJmWm8AVkuE58NbG1s7DR4cxFt4U5cVLxofAoHxgvC5MyOw== + dependencies: + expect "^28.1.1" + jest-snapshot "^28.1.2" + +"@jest/fake-timers@^28.1.2": + version "28.1.2" + resolved "https://registry.yarnpkg.com/@jest/fake-timers/-/fake-timers-28.1.2.tgz#d49e8ee4e02ba85a6e844a52a5e7c59c23e3b76f" + integrity sha512-xSYEI7Y0D5FbZN2LsCUj/EKRR1zfQYmGuAUVh6xTqhx7V5JhjgMcK5Pa0iR6WIk0GXiHDe0Ke4A+yERKE9saqg== + dependencies: + "@jest/types" "^28.1.1" + "@sinonjs/fake-timers" "^9.1.2" "@types/node" "*" - jest-message-util "^27.5.1" - jest-mock "^27.5.1" - jest-util "^27.5.1" + jest-message-util "^28.1.1" + jest-mock "^28.1.1" + jest-util "^28.1.1" -"@jest/globals@^27.5.1": - version "27.5.1" - resolved "https://registry.yarnpkg.com/@jest/globals/-/globals-27.5.1.tgz#7ac06ce57ab966566c7963431cef458434601b2b" - integrity sha512-ZEJNB41OBQQgGzgyInAv0UUfDDj3upmHydjieSxFvTRuZElrx7tXg/uVQ5hYVEwiXs3+aMsAeEc9X7xiSKCm4Q== +"@jest/globals@^28.1.2": + version "28.1.2" + resolved "https://registry.yarnpkg.com/@jest/globals/-/globals-28.1.2.tgz#92fab296e337c7309c25e4202fb724f62249d83f" + integrity sha512-cz0lkJVDOtDaYhvT3Fv2U1B6FtBnV+OpEyJCzTHM1fdoTsU4QNLAt/H4RkiwEUU+dL4g/MFsoTuHeT2pvbo4Hg== dependencies: - "@jest/environment" "^27.5.1" - "@jest/types" "^27.5.1" - expect "^27.5.1" + "@jest/environment" "^28.1.2" + "@jest/expect" "^28.1.2" + "@jest/types" "^28.1.1" -"@jest/reporters@^27.5.1": - version "27.5.1" - resolved "https://registry.yarnpkg.com/@jest/reporters/-/reporters-27.5.1.tgz#ceda7be96170b03c923c37987b64015812ffec04" - integrity sha512-cPXh9hWIlVJMQkVk84aIvXuBB4uQQmFqZiacloFuGiP3ah1sbCxCosidXFDfqG8+6fO1oR2dTJTlsOy4VFmUfw== +"@jest/reporters@^28.1.2": + version "28.1.2" + resolved "https://registry.yarnpkg.com/@jest/reporters/-/reporters-28.1.2.tgz#0327be4ce4d0d9ae49e7908656f89669d0c2a260" + integrity sha512-/whGLhiwAqeCTmQEouSigUZJPVl7sW8V26EiboImL+UyXznnr1a03/YZ2BX8OlFw0n+Zlwu+EZAITZtaeRTxyA== dependencies: "@bcoe/v8-coverage" "^0.2.3" - "@jest/console" "^27.5.1" - "@jest/test-result" "^27.5.1" - "@jest/transform" "^27.5.1" - "@jest/types" "^27.5.1" + "@jest/console" "^28.1.1" + "@jest/test-result" "^28.1.1" + "@jest/transform" "^28.1.2" + "@jest/types" "^28.1.1" + "@jridgewell/trace-mapping" "^0.3.13" "@types/node" "*" chalk "^4.0.0" collect-v8-coverage "^1.0.0" exit "^0.1.2" - glob "^7.1.2" + glob "^7.1.3" graceful-fs "^4.2.9" istanbul-lib-coverage "^3.0.0" istanbul-lib-instrument "^5.1.0" istanbul-lib-report "^3.0.0" istanbul-lib-source-maps "^4.0.0" istanbul-reports "^3.1.3" - jest-haste-map "^27.5.1" - jest-resolve "^27.5.1" - jest-util "^27.5.1" - jest-worker "^27.5.1" + jest-message-util "^28.1.1" + jest-util "^28.1.1" + jest-worker "^28.1.1" slash "^3.0.0" - source-map "^0.6.0" string-length "^4.0.1" + strip-ansi "^6.0.0" terminal-link "^2.0.0" - v8-to-istanbul "^8.1.0" + v8-to-istanbul "^9.0.1" "@jest/schemas@^28.0.2": version "28.0.2" @@ -1718,103 +1739,60 @@ dependencies: "@sinclair/typebox" "^0.23.3" -"@jest/source-map@^27.5.1": - version "27.5.1" - resolved "https://registry.yarnpkg.com/@jest/source-map/-/source-map-27.5.1.tgz#6608391e465add4205eae073b55e7f279e04e8cf" - integrity sha512-y9NIHUYF3PJRlHk98NdC/N1gl88BL08aQQgu4k4ZopQkCw9t9cV8mtl3TV8b/YCB8XaVTFrmUTAJvjsntDireg== +"@jest/source-map@^28.1.2": + version "28.1.2" + resolved "https://registry.yarnpkg.com/@jest/source-map/-/source-map-28.1.2.tgz#7fe832b172b497d6663cdff6c13b0a920e139e24" + integrity sha512-cV8Lx3BeStJb8ipPHnqVw/IM2VCMWO3crWZzYodSIkxXnRcXJipCdx1JCK0K5MsJJouZQTH73mzf4vgxRaH9ww== dependencies: + "@jridgewell/trace-mapping" "^0.3.13" callsites "^3.0.0" graceful-fs "^4.2.9" - source-map "^0.6.0" -"@jest/test-result@^27.5.1": - version "27.5.1" - resolved "https://registry.yarnpkg.com/@jest/test-result/-/test-result-27.5.1.tgz#56a6585fa80f7cdab72b8c5fc2e871d03832f5bb" - integrity sha512-EW35l2RYFUcUQxFJz5Cv5MTOxlJIQs4I7gxzi2zVU7PJhOwfYq1MdC5nhSmYjX1gmMmLPvB3sIaC+BkcHRBfag== +"@jest/test-result@^28.1.1": + version "28.1.1" + resolved "https://registry.yarnpkg.com/@jest/test-result/-/test-result-28.1.1.tgz#c6f18d1bbb01aa88925dd687872a75f8414b317a" + integrity sha512-hPmkugBktqL6rRzwWAtp1JtYT4VHwv8OQ+9lE5Gymj6dHzubI/oJHMUpPOt8NrdVWSrz9S7bHjJUmv2ggFoUNQ== dependencies: - "@jest/console" "^27.5.1" - "@jest/types" "^27.5.1" + "@jest/console" "^28.1.1" + "@jest/types" "^28.1.1" "@types/istanbul-lib-coverage" "^2.0.0" collect-v8-coverage "^1.0.0" -"@jest/test-sequencer@^27.5.1": - version "27.5.1" - resolved "https://registry.yarnpkg.com/@jest/test-sequencer/-/test-sequencer-27.5.1.tgz#4057e0e9cea4439e544c6353c6affe58d095745b" - integrity sha512-LCheJF7WB2+9JuCS7VB/EmGIdQuhtqjRNI9A43idHv3E4KltCTsPsLxvdaubFHSYwY/fNjMWjl6vNRhDiN7vpQ== +"@jest/test-sequencer@^28.1.1": + version "28.1.1" + resolved "https://registry.yarnpkg.com/@jest/test-sequencer/-/test-sequencer-28.1.1.tgz#f594ee2331df75000afe0d1ae3237630ecec732e" + integrity sha512-nuL+dNSVMcWB7OOtgb0EGH5AjO4UBCt68SLP08rwmC+iRhyuJWS9MtZ/MpipxFwKAlHFftbMsydXqWre8B0+XA== dependencies: - "@jest/test-result" "^27.5.1" + "@jest/test-result" "^28.1.1" graceful-fs "^4.2.9" - jest-haste-map "^27.5.1" - jest-runtime "^27.5.1" - -"@jest/transform@^27.5.1": - version "27.5.1" - resolved "https://registry.yarnpkg.com/@jest/transform/-/transform-27.5.1.tgz#6c3501dcc00c4c08915f292a600ece5ecfe1f409" - integrity sha512-ipON6WtYgl/1329g5AIJVbUuEh0wZVbdpGwC99Jw4LwuoBNS95MVphU6zOeD9pDkon+LLbFL7lOQRapbB8SCHw== - dependencies: - "@babel/core" "^7.1.0" - "@jest/types" "^27.5.1" - babel-plugin-istanbul "^6.1.1" - chalk "^4.0.0" - convert-source-map "^1.4.0" - fast-json-stable-stringify "^2.0.0" - graceful-fs "^4.2.9" - jest-haste-map "^27.5.1" - jest-regex-util "^27.5.1" - jest-util "^27.5.1" - micromatch "^4.0.4" - pirates "^4.0.4" + jest-haste-map "^28.1.1" slash "^3.0.0" - source-map "^0.6.1" - write-file-atomic "^3.0.0" -"@jest/transform@^28.1.0": - version "28.1.0" - resolved "https://registry.yarnpkg.com/@jest/transform/-/transform-28.1.0.tgz#224a3c9ba4cc98e2ff996c0a89a2d59db15c74ce" - integrity sha512-omy2xe5WxlAfqmsTjTPxw+iXRTRnf+NtX0ToG+4S0tABeb4KsKmPUHq5UBuwunHg3tJRwgEQhEp0M/8oiatLEA== +"@jest/transform@^28.1.2": + version "28.1.2" + resolved "https://registry.yarnpkg.com/@jest/transform/-/transform-28.1.2.tgz#b367962c53fd53821269bde050ce373e111327c1" + integrity sha512-3o+lKF6iweLeJFHBlMJysdaPbpoMmtbHEFsjzSv37HIq/wWt5ijTeO2Yf7MO5yyczCopD507cNwNLeX8Y/CuIg== dependencies: "@babel/core" "^7.11.6" - "@jest/types" "^28.1.0" - "@jridgewell/trace-mapping" "^0.3.7" + "@jest/types" "^28.1.1" + "@jridgewell/trace-mapping" "^0.3.13" babel-plugin-istanbul "^6.1.1" chalk "^4.0.0" convert-source-map "^1.4.0" fast-json-stable-stringify "^2.0.0" graceful-fs "^4.2.9" - jest-haste-map "^28.1.0" + jest-haste-map "^28.1.1" jest-regex-util "^28.0.2" - jest-util "^28.1.0" + jest-util "^28.1.1" micromatch "^4.0.4" pirates "^4.0.4" slash "^3.0.0" write-file-atomic "^4.0.1" -"@jest/types@^27.1.1": - version "27.1.1" - resolved "https://registry.yarnpkg.com/@jest/types/-/types-27.1.1.tgz#77a3fc014f906c65752d12123a0134359707c0ad" - integrity sha512-yqJPDDseb0mXgKqmNqypCsb85C22K1aY5+LUxh7syIM9n/b0AsaltxNy+o6tt29VcfGDpYEve175bm3uOhcehA== - dependencies: - "@types/istanbul-lib-coverage" "^2.0.0" - "@types/istanbul-reports" "^3.0.0" - "@types/node" "*" - "@types/yargs" "^16.0.0" - chalk "^4.0.0" - -"@jest/types@^27.5.1": - version "27.5.1" - resolved "https://registry.yarnpkg.com/@jest/types/-/types-27.5.1.tgz#3c79ec4a8ba61c170bf937bcf9e98a9df175ec80" - integrity sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw== - dependencies: - "@types/istanbul-lib-coverage" "^2.0.0" - "@types/istanbul-reports" "^3.0.0" - "@types/node" "*" - "@types/yargs" "^16.0.0" - chalk "^4.0.0" - -"@jest/types@^28.1.0": - version "28.1.0" - resolved "https://registry.yarnpkg.com/@jest/types/-/types-28.1.0.tgz#508327a89976cbf9bd3e1cc74641a29fd7dfd519" - integrity sha512-xmEggMPr317MIOjjDoZ4ejCSr9Lpbt/u34+dvc99t7DS8YirW5rwZEhzKPC2BMUFkUhI48qs6qLUSGw5FuL0GA== +"@jest/types@^28.1.1": + version "28.1.1" + resolved "https://registry.yarnpkg.com/@jest/types/-/types-28.1.1.tgz#d059bbc80e6da6eda9f081f293299348bd78ee0b" + integrity sha512-vRXVqSg1VhDnB8bWcmvLzmg0Bt9CRKVgHPXqYwvWMX3TvAjeO+nRuK6+VdTKCtWOvYlmkF/HqNAL/z+N3B53Kw== dependencies: "@jest/schemas" "^28.0.2" "@types/istanbul-lib-coverage" "^2.0.0" @@ -1863,7 +1841,15 @@ "@jridgewell/resolve-uri" "^3.0.3" "@jridgewell/sourcemap-codec" "^1.4.10" -"@jridgewell/trace-mapping@^0.3.7", "@jridgewell/trace-mapping@^0.3.9": +"@jridgewell/trace-mapping@^0.3.12", "@jridgewell/trace-mapping@^0.3.13": + version "0.3.14" + resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.14.tgz#b231a081d8f66796e475ad588a1ef473112701ed" + integrity sha512-bJWEfQ9lPTvm3SneWwRFVLzrh6nhjwqw7TUFFBEMzwvg7t7PCDenf2lDwqo4NQXzdpgBXyFgDWnQA+2vkruksQ== + dependencies: + "@jridgewell/resolve-uri" "^3.0.3" + "@jridgewell/sourcemap-codec" "^1.4.10" + +"@jridgewell/trace-mapping@^0.3.9": version "0.3.13" resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.13.tgz#dcfe3e95f224c8fe97a87a5235defec999aa92ea" integrity sha512-o1xbKhp9qnIAoHJSWd6KlCZfqslL4valSF81H8ImioOAxluWYWOpWkpyktY2vnt4tbrX9XYaxovq6cgowaJp2w== @@ -2257,10 +2243,10 @@ dependencies: type-detect "4.0.8" -"@sinonjs/fake-timers@^8.0.1": - version "8.1.0" - resolved "https://registry.yarnpkg.com/@sinonjs/fake-timers/-/fake-timers-8.1.0.tgz#3fdc2b6cb58935b21bfb8d1625eb1300484316e7" - integrity sha512-OAPJUAtgeINhh/TAlUID4QTs53Njm7xzddaVlEs/SXwgtiD1tW22zAB/W1wdqfrpmikgaWQ9Fw6Ws+hsiRm5Vg== +"@sinonjs/fake-timers@^9.1.2": + version "9.1.2" + resolved "https://registry.yarnpkg.com/@sinonjs/fake-timers/-/fake-timers-9.1.2.tgz#4eaab737fab77332ab132d396a3c0d364bd0ea8c" + integrity sha512-BPS4ynJW/o92PUR4wgriz2Ud5gpST5vz6GQfMixEDK0Z8ZCUv2M7SkBLykH56T++Xs+8ln9zTGbOvNGIe02/jw== dependencies: "@sinonjs/commons" "^1.7.0" @@ -2279,10 +2265,10 @@ remark "^13.0.0" unist-util-find-all-after "^3.0.2" -"@tabler/icons@^1.71.0": - version "1.71.0" - resolved "https://registry.yarnpkg.com/@tabler/icons/-/icons-1.71.0.tgz#74d771aa18487ea92af07c67048e411ada0f0427" - integrity sha512-hOeXAWSXGgT2S8O9QrRTomEq6YE1AtuXrcOy5DgGVI93xub1JnGSA3Z9gZzuND4pSJ+Ee+geI5u8hTYbfIsuGw== +"@tabler/icons@^1.73.0": + version "1.73.0" + resolved "https://registry.yarnpkg.com/@tabler/icons/-/icons-1.73.0.tgz#26d81858baf41be939504e1f9b4b32835eda6fdb" + integrity sha512-MhAHFzVj79ZWlAIRD++7Mk55PZsdlEdkfkjO3DD257mqj8iJZQRAQtkx2UFJXVs2mMrcOUu1qtj4rlVC8BfnKA== "@tailwindcss/forms@^0.4.0": version "0.4.0" @@ -2351,10 +2337,10 @@ resolved "https://registry.yarnpkg.com/@testing-library/user-event/-/user-event-14.0.3.tgz#463667596122c13d997f70b73426947ab71de962" integrity sha512-zIgBG5CxfXbMsm4wBS6iQC3TBNMZk16O25i4shS9MM+eSG7PZHrsBF6LFIesUkepkZ3QKKgstB2/Nola6nvy4A== -"@tootallnate/once@1": - version "1.1.2" - resolved "https://registry.yarnpkg.com/@tootallnate/once/-/once-1.1.2.tgz#ccb91445360179a04e7fe6aff78c00ffc1eeaf82" - integrity sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw== +"@tootallnate/once@2": + version "2.0.0" + resolved "https://registry.yarnpkg.com/@tootallnate/once/-/once-2.0.0.tgz#f544a148d3ab35801c1f633a7441fd87c2e484bf" + integrity sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A== "@trysound/sax@0.2.0": version "0.2.0" @@ -2366,7 +2352,7 @@ resolved "https://registry.yarnpkg.com/@types/aria-query/-/aria-query-4.2.2.tgz#ed4e0ad92306a704f9fb132a0cfcf77486dbe2bc" integrity sha512-HnYpAE1Y6kRyKM/XkEuiRQhTHvkzMBurTHnpFLYLBGPIylZNPs9jJcuOOYWxPLJCSEtmZT0Y8rHDokKN7rRTig== -"@types/babel__core@^7.0.0", "@types/babel__core@^7.1.12", "@types/babel__core@^7.1.14": +"@types/babel__core@^7.1.12", "@types/babel__core@^7.1.14": version "7.1.19" resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.1.19.tgz#7b497495b7d1b4812bdb9d02804d0576f43ee460" integrity sha512-WEOTgRsbYkvA/KCsDwVEGkd7WAr1e3g31VHQ8zy5gul/V1qKullU/BU5I68X5v7V3GnB9eotmom4v5a5gjxorw== @@ -2403,7 +2389,7 @@ "@babel/parser" "^7.1.0" "@babel/types" "^7.0.0" -"@types/babel__traverse@*", "@types/babel__traverse@^7.0.4", "@types/babel__traverse@^7.0.6": +"@types/babel__traverse@*", "@types/babel__traverse@^7.0.6": version "7.14.2" resolved "https://registry.yarnpkg.com/@types/babel__traverse/-/babel__traverse-7.14.2.tgz#ffcd470bbb3f8bf30481678fb5502278ca833a43" integrity sha512-K2waXdXBi2302XUdcHcR1jCeU0LL4TD9HRs/gk0N2Xvrht+G/BfJa4QObBQZfhMdxiCpV3COl5Nfq4uKTeTnJA== @@ -2517,7 +2503,7 @@ dependencies: "@types/node" "*" -"@types/graceful-fs@^4.1.2", "@types/graceful-fs@^4.1.3": +"@types/graceful-fs@^4.1.3": version "4.1.5" resolved "https://registry.yarnpkg.com/@types/graceful-fs/-/graceful-fs-4.1.5.tgz#21ffba0d98da4350db64891f92a9e5db3cdb4e15" integrity sha512-anKkLmZZ+xm4p8JWBf4hElkM4XR+EZeA2M9BAkkTldmcyDY4mbdIJnRghDJH3Ov5ooY7/UAoENtmdMSkaAd7Cw== @@ -2585,7 +2571,7 @@ dependencies: "@types/istanbul-lib-report" "*" -"@types/jest@*", "@types/jest@^27.4.1": +"@types/jest@*": version "27.4.1" resolved "https://registry.yarnpkg.com/@types/jest/-/jest-27.4.1.tgz#185cbe2926eaaf9662d340cc02e548ce9e11ab6d" integrity sha512-23iPJADSmicDVrWk+HT58LMJtzLAnB2AgIzplQuq/bSrGaxCrlvRFjGbXmamnnk/mAmCdLStiGqggu28ocUyiw== @@ -2593,6 +2579,23 @@ jest-matcher-utils "^27.0.0" pretty-format "^27.0.0" +"@types/jest@^28.1.4": + version "28.1.4" + resolved "https://registry.yarnpkg.com/@types/jest/-/jest-28.1.4.tgz#a11ee6c8fd0b52c19c9c18138b78bbcc201dad5a" + integrity sha512-telv6G5N7zRJiLcI3Rs3o+ipZ28EnE+7EvF0pSrt2pZOMnAVI/f+6/LucDxOvcBcTeTL3JMF744BbVQAVBUQRA== + dependencies: + jest-matcher-utils "^28.0.0" + pretty-format "^28.0.0" + +"@types/jsdom@^16.2.4": + version "16.2.14" + resolved "https://registry.yarnpkg.com/@types/jsdom/-/jsdom-16.2.14.tgz#26fe9da6a8870715b154bb84cd3b2e53433d8720" + integrity sha512-6BAy1xXEmMuHeAJ4Fv4yXKwBDTGTOseExKE3OaHiNycdHdZw59KfYzrt0DkDluvwmik1HRt6QS7bImxUmpSy+w== + dependencies: + "@types/node" "*" + "@types/parse5" "*" + "@types/tough-cookie" "*" + "@types/json-schema@*", "@types/json-schema@^7.0.5", "@types/json-schema@^7.0.8": version "7.0.9" resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.9.tgz#97edc9037ea0c38585320b28964dde3b39e4660d" @@ -2655,6 +2658,11 @@ resolved "https://registry.yarnpkg.com/@types/parse-json/-/parse-json-4.0.0.tgz#2f8bb441434d163b35fb8ffdccd7138927ffb8c0" integrity sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA== +"@types/parse5@*": + version "6.0.3" + resolved "https://registry.yarnpkg.com/@types/parse5/-/parse5-6.0.3.tgz#705bb349e789efa06f43f128cef51240753424cb" + integrity sha512-SuT16Q1K51EAVPz1K29DJ/sXjhSQ0zjvsypYJ6tlwVsRV9jwW5Adq2ch8Dq8kDBCkYnELS7N7VNCSB5nC56t/g== + "@types/prettier@^2.1.5": version "2.3.2" resolved "https://registry.yarnpkg.com/@types/prettier/-/prettier-2.3.2.tgz#fc8c2825e4ed2142473b4a81064e6e081463d1b3" @@ -2848,6 +2856,11 @@ dependencies: "@types/jest" "*" +"@types/tough-cookie@*": + version "4.0.2" + resolved "https://registry.yarnpkg.com/@types/tough-cookie/-/tough-cookie-4.0.2.tgz#6286b4c7228d58ab7866d19716f3696e03a09397" + integrity sha512-Q5vtl1W5ue16D+nIaW8JWebSSraJVlK+EthKn7e7UcD4KWsaSJ8BqGPXNaPghgtcn/fhvrN17Tv8ksUsQpiplw== + "@types/unist@*", "@types/unist@^2.0.0", "@types/unist@^2.0.2": version "2.0.6" resolved "https://registry.yarnpkg.com/@types/unist/-/unist-2.0.6.tgz#250a7b16c3b91f672a24552ec64678eeb1d3a08d" @@ -2870,13 +2883,6 @@ resolved "https://registry.yarnpkg.com/@types/yargs-parser/-/yargs-parser-21.0.0.tgz#0c60e537fa790f5f9472ed2776c2b71ec117351b" integrity sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA== -"@types/yargs@^16.0.0": - version "16.0.4" - resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-16.0.4.tgz#26aad98dd2c2a38e421086ea9ad42b9e51642977" - integrity sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw== - dependencies: - "@types/yargs-parser" "*" - "@types/yargs@^17.0.8": version "17.0.10" resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-17.0.10.tgz#591522fce85d8739bca7b8bb90d048e4478d186a" @@ -3124,11 +3130,16 @@ resolved "https://registry.yarnpkg.com/@xtuc/long/-/long-4.2.2.tgz#d291c6a4e97989b5c61d9acf396ae4fe133a718d" integrity sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ== -abab@^2.0.3, abab@^2.0.5: +abab@^2.0.5: version "2.0.5" resolved "https://registry.yarnpkg.com/abab/-/abab-2.0.5.tgz#c0b678fb32d60fc1219c784d6a826fe385aeb79a" integrity sha512-9IK9EadsbHo6jLWIpxpR6pL0sazTXV6+SQv25ZB+F7Bj9mJNaOc4nCRabwd5M/JwmUa8idz6Eci6eKfJryPs6Q== +abab@^2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/abab/-/abab-2.0.6.tgz#41b80f2c871d19686216b82309231cfd3cb3d291" + integrity sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA== + abort-controller@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/abort-controller/-/abort-controller-3.0.0.tgz#eaf54d53b62bae4138e809ca225c8439a6efb392" @@ -3194,7 +3205,7 @@ acorn@^7.0.0, acorn@^7.1.1, acorn@^7.4.0: resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.4.1.tgz#feaed255973d2e77555b83dbc08851a6c63520fa" integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A== -acorn@^8.0.4, acorn@^8.2.4, acorn@^8.4.1: +acorn@^8.0.4, acorn@^8.4.1: version "8.5.0" resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.5.0.tgz#4512ccb99b3698c752591e9bb4472e38ad43cee2" integrity sha512-yXbYeFy+jUuYd3/CDcg2NkIYE991XYX/bje7LmjJigUciaeO1JR4XxXgCIV1/Zc/dRuFEyw1L0pbA+qynJkW5Q== @@ -3506,13 +3517,14 @@ axios-mock-adapter@^1.21.1: fast-deep-equal "^3.1.3" is-buffer "^2.0.5" -axios@^0.27.2: - version "0.27.2" - resolved "https://registry.yarnpkg.com/axios/-/axios-0.27.2.tgz#207658cc8621606e586c85db4b41a750e756d972" - integrity sha512-t+yRIyySRTp/wua5xEr+z1q60QmLq8ABsS5O9Me1AsE5dfKqgnCFzwiCZZ/cGNd1lq4/7akDWMxdhVlucjmnOQ== +axios@^1.0.0-alpha.1: + version "1.0.0-alpha.1" + resolved "https://registry.yarnpkg.com/axios/-/axios-1.0.0-alpha.1.tgz#ce69c17ca7605d01787ca754dd906e6fccdf71ee" + integrity sha512-p+meG161943WT+K7sJYquHR46xxi/z0tk7vnSmEf/LrfEAyiP+0uTMMYk1OEo1IRF18oGRhnFxN1y8fLcXaTMw== dependencies: - follow-redirects "^1.14.9" + follow-redirects "^1.15.0" form-data "^4.0.0" + proxy-from-env "^1.1.0" axobject-query@^2.2.0: version "2.2.0" @@ -3531,29 +3543,15 @@ babel-eslint@^10.1.0: eslint-visitor-keys "^1.0.0" resolve "^1.12.0" -babel-jest@^27.5.1: - version "27.5.1" - resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-27.5.1.tgz#a1bf8d61928edfefd21da27eb86a695bfd691444" - integrity sha512-cdQ5dXjGRd0IBRATiQ4mZGlGlRE8kJpjPOixdNRdT+m3UcNqmYWN6rK6nvtXYfY3D76cb8s/O1Ss8ea24PIwcg== +babel-jest@^28.1.2: + version "28.1.2" + resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-28.1.2.tgz#2b37fb81439f14d34d8b2cc4a4bd7efabf9acbfe" + integrity sha512-pfmoo6sh4L/+5/G2OOfQrGJgvH7fTa1oChnuYH2G/6gA+JwDvO8PELwvwnofKBMNrQsam0Wy/Rw+QSrBNewq2Q== dependencies: - "@jest/transform" "^27.5.1" - "@jest/types" "^27.5.1" + "@jest/transform" "^28.1.2" "@types/babel__core" "^7.1.14" babel-plugin-istanbul "^6.1.1" - babel-preset-jest "^27.5.1" - chalk "^4.0.0" - graceful-fs "^4.2.9" - slash "^3.0.0" - -babel-jest@^28.1.0: - version "28.1.0" - resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-28.1.0.tgz#95a67f8e2e7c0042e7b3ad3951b8af41a533b5ea" - integrity sha512-zNKk0yhDZ6QUwfxh9k07GII6siNGMJWVUU49gmFj5gfdqDKLqa2RArXOF2CODp4Dr7dLxN2cvAV+667dGJ4b4w== - dependencies: - "@jest/transform" "^28.1.0" - "@types/babel__core" "^7.1.14" - babel-plugin-istanbul "^6.1.1" - babel-preset-jest "^28.0.2" + babel-preset-jest "^28.1.1" chalk "^4.0.0" graceful-fs "^4.2.9" slash "^3.0.0" @@ -3586,20 +3584,10 @@ babel-plugin-istanbul@^6.1.1: istanbul-lib-instrument "^5.0.4" test-exclude "^6.0.0" -babel-plugin-jest-hoist@^27.5.1: - version "27.5.1" - resolved "https://registry.yarnpkg.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-27.5.1.tgz#9be98ecf28c331eb9f5df9c72d6f89deb8181c2e" - integrity sha512-50wCwD5EMNW4aRpOwtqzyZHIewTYNxLA4nhB+09d8BIssfNfzBRhkBIHiaPv1Si226TQSvp8gxAJm2iY2qs2hQ== - dependencies: - "@babel/template" "^7.3.3" - "@babel/types" "^7.3.3" - "@types/babel__core" "^7.0.0" - "@types/babel__traverse" "^7.0.6" - -babel-plugin-jest-hoist@^28.0.2: - version "28.0.2" - resolved "https://registry.yarnpkg.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-28.0.2.tgz#9307d03a633be6fc4b1a6bc5c3a87e22bd01dd3b" - integrity sha512-Kizhn/ZL+68ZQHxSnHyuvJv8IchXD62KQxV77TBDV/xoBFBOfgRAk97GNs6hXdTTCiVES9nB2I6+7MXXrk5llQ== +babel-plugin-jest-hoist@^28.1.1: + version "28.1.1" + resolved "https://registry.yarnpkg.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-28.1.1.tgz#5e055cdcc47894f28341f87f5e35aad2df680b11" + integrity sha512-NovGCy5Hn25uMJSAU8FaHqzs13cFoOI4lhIujiepssjCKRsAo3TA734RDWSGxuFTsUJXerYOqQQodlxgmtqbzw== dependencies: "@babel/template" "^7.3.3" "@babel/types" "^7.3.3" @@ -3706,20 +3694,12 @@ babel-preset-current-node-syntax@^1.0.0: "@babel/plugin-syntax-optional-chaining" "^7.8.3" "@babel/plugin-syntax-top-level-await" "^7.8.3" -babel-preset-jest@^27.5.1: - version "27.5.1" - resolved "https://registry.yarnpkg.com/babel-preset-jest/-/babel-preset-jest-27.5.1.tgz#91f10f58034cb7989cb4f962b69fa6eef6a6bc81" - integrity sha512-Nptf2FzlPCWYuJg41HBqXVT8ym6bXOevuCTbhxlUpjwtysGaIWFvDEjp4y+G7fl13FgOdjs7P/DmErqH7da0Ag== +babel-preset-jest@^28.1.1: + version "28.1.1" + resolved "https://registry.yarnpkg.com/babel-preset-jest/-/babel-preset-jest-28.1.1.tgz#5b6e5e69f963eb2d70f739c607b8f723c0ee75e4" + integrity sha512-FCq9Oud0ReTeWtcneYf/48981aTfXYuB9gbU4rBNNJVBSQ6ssv7E6v/qvbBxtOWwZFXjLZwpg+W3q7J6vhH25g== dependencies: - babel-plugin-jest-hoist "^27.5.1" - babel-preset-current-node-syntax "^1.0.0" - -babel-preset-jest@^28.0.2: - version "28.0.2" - resolved "https://registry.yarnpkg.com/babel-preset-jest/-/babel-preset-jest-28.0.2.tgz#d8210fe4e46c1017e9fa13d7794b166e93aa9f89" - integrity sha512-sYzXIdgIXXroJTFeB3S6sNDWtlJ2dllCdTEsnZ65ACrMojj3hVNFRmnJ1HZtomGi+Be7aqpY/HJ92fr8OhKVkQ== - dependencies: - babel-plugin-jest-hoist "^28.0.2" + babel-plugin-jest-hoist "^28.1.1" babel-preset-current-node-syntax "^1.0.0" bail@^1.0.0: @@ -4115,11 +4095,6 @@ chrome-trace-event@^1.0.2: resolved "https://registry.yarnpkg.com/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz#1015eced4741e15d06664a957dbbf50d041e26ac" integrity sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg== -ci-info@^3.1.1: - version "3.2.0" - resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-3.2.0.tgz#2876cb948a498797b5236f0095bc057d0dca38b6" - integrity sha512-dVqRX7fLUm8J6FgHJ418XuIgDLZDkYcDFTeL6TA2gt5WlIZUQrrH6EZrNClwT/H0FateUsZkGIOPRrLbP+PR9A== - ci-info@^3.2.0: version "3.3.0" resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-3.3.0.tgz#b4ed1fb6818dea4803a55c623041f9165d2066b2" @@ -4565,10 +4540,10 @@ csso@^4.2.0: dependencies: css-tree "^1.1.2" -cssom@^0.4.4: - version "0.4.4" - resolved "https://registry.yarnpkg.com/cssom/-/cssom-0.4.4.tgz#5a66cf93d2d0b661d80bf6a44fb65f5c2e4e0a10" - integrity sha512-p3pvU7r1MyyqbTk+WbNJIgJjG2VmTIaB10rI93LzVPrmDJKkzKYMtxxyAvQXR/NS6otuzveI7+7BBq3SjBS2mw== +cssom@^0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/cssom/-/cssom-0.5.0.tgz#d254fa92cd8b6fbd83811b9fbaed34663cc17c36" + integrity sha512-iKuQcq+NdHqlAcwUY0o/HL69XQrUaQdMjmStJ8JFmUaiiQErlhrmuigkg/CU4E2J0IyUKUrMAgl36TvN67MqTw== cssom@~0.3.6: version "0.3.8" @@ -4643,14 +4618,14 @@ danger@^11.0.7: require-from-string "^2.0.2" supports-hyperlinks "^1.0.1" -data-urls@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/data-urls/-/data-urls-2.0.0.tgz#156485a72963a970f5d5821aaf642bef2bf2db9b" - integrity sha512-X5eWTSXO/BJmpdIKCRuKUgSCgAN0OwliVK3yPKbwIWU1Tdw5BRajxlzMidvh+gwko9AfQ9zIj52pzF91Q3YAvQ== +data-urls@^3.0.1: + version "3.0.2" + resolved "https://registry.yarnpkg.com/data-urls/-/data-urls-3.0.2.tgz#9cf24a477ae22bcef5cd5f6f0bfbc1d2d3be9143" + integrity sha512-Jy/tj3ldjZJo63sVAvg6LHt2mHvl4V6AgRAmNDtLdm7faqtsx+aJG42rsyCo9JCoRVKwPFzKlIPx3DIibwSIaQ== dependencies: - abab "^2.0.3" - whatwg-mimetype "^2.3.0" - whatwg-url "^8.0.0" + abab "^2.0.6" + whatwg-mimetype "^3.0.0" + whatwg-url "^11.0.0" date-fns@^2.0.1, date-fns@^2.24.0: version "2.28.0" @@ -4705,7 +4680,7 @@ decamelize@^1.1.0, decamelize@^1.2.0: resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" integrity sha1-9lNNFRSCabIDUue+4m9QH5oZEpA= -decimal.js@^10.2.1: +decimal.js@^10.3.1: version "10.3.1" resolved "https://registry.yarnpkg.com/decimal.js/-/decimal.js-10.3.1.tgz#d8c3a444a9c6774ba60ca6ad7261c3a94fd5e783" integrity sha512-V0pfhfr8suzyPGOx3nmq4aHqabehUZn6Ch9kyFpV79TGDTWFmHqUqXdabR7QHqxzrYolF4+tVmJhUG4OURg5dQ== @@ -4838,6 +4813,11 @@ diff-sequences@^27.5.1: resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-27.5.1.tgz#eaecc0d327fd68c8d9672a1e64ab8dccb2ef5327" integrity sha512-k1gCAXAsNgLwEL+Y8Wvl+M6oEFj5bgazfZULpS5CneoPPXRaCCW7dm+q21Ky2VEE5X+VeRDBVg1Pcvvsr4TtNQ== +diff-sequences@^28.1.1: + version "28.1.1" + resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-28.1.1.tgz#9989dc731266dc2903457a70e996f3a041913ac6" + integrity sha512-FU0iFaH/E23a+a718l8Qa/19bF9p06kgE0KipMOMadwa3SjnaElKzPaUC0vnibs6/B/9ni97s61mcejk8W1fQw== + dir-glob@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-3.0.1.tgz#56dbf73d992a4a93ba1584f4534063fd2e41717f" @@ -4929,12 +4909,12 @@ domexception@^1.0.1: dependencies: webidl-conversions "^4.0.2" -domexception@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/domexception/-/domexception-2.0.1.tgz#fb44aefba793e1574b0af6aed2801d057529f304" - integrity sha512-yxJ2mFy/sibVQlu5qHjOkf9J3K6zgmCxgJ94u2EdvDOV09H+32LtRswEcUsmUWN72pVLOEnTSRaIVVzVQgS0dg== +domexception@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/domexception/-/domexception-4.0.0.tgz#4ad1be56ccadc86fc76d033353999a8037d03673" + integrity sha512-A2is4PLG+eeSfoTMA95/s4pvAoSo2mKtiM5jlHkAVewmiO8ISFTFKZjH7UAM1Atli/OT/7JHOrJRJiMKUZKYBw== dependencies: - webidl-conversions "^5.0.0" + webidl-conversions "^7.0.0" domhandler@^2.3.0: version "2.4.2" @@ -5022,10 +5002,10 @@ electron-to-chromium@^1.4.84: resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.103.tgz#abfe376a4d70fa1e1b4b353b95df5d6dfd05da3a" integrity sha512-c/uKWR1Z/W30Wy/sx3dkZoj4BijbXX85QKWu9jJfjho3LBAXNEGAEW3oWiGb+dotA6C6BzCTxL2/aLes7jlUeg== -emittery@^0.8.1: - version "0.8.1" - resolved "https://registry.yarnpkg.com/emittery/-/emittery-0.8.1.tgz#bb23cc86d03b30aa75a7f734819dee2e1ba70860" - integrity sha512-uDfvUjVrfGJJhymx/kz6prltenw1u7WrCg1oa94zYY8xxVpLLUu045LAT0dhDZdXG58/EpPL/5kA180fQ/qudg== +emittery@^0.10.2: + version "0.10.2" + resolved "https://registry.yarnpkg.com/emittery/-/emittery-0.10.2.tgz#902eec8aedb8c41938c46e9385e9db7e03182933" + integrity sha512-aITqOwnLanpHLNXZJENbOgjUBeHocD+xsSJmNrjovKBW5HbSpW3d1pEls7GFQPUWXiwG9+0P4GtHfEqC/4M0Iw== emoji-datasource@5.0.0: version "5.0.0" @@ -5587,15 +5567,16 @@ expand-tilde@^2.0.2: dependencies: homedir-polyfill "^1.0.1" -expect@^27.5.1: - version "27.5.1" - resolved "https://registry.yarnpkg.com/expect/-/expect-27.5.1.tgz#83ce59f1e5bdf5f9d2b94b61d2050db48f3fef74" - integrity sha512-E1q5hSUG2AmYQwQJ041nvgpkODHQvB+RKlB4IYdru6uJsyFTRyZAP463M+1lINorwbqAmUggi6+WwkD8lCS/Dw== +expect@^28.1.1: + version "28.1.1" + resolved "https://registry.yarnpkg.com/expect/-/expect-28.1.1.tgz#ca6fff65f6517cf7220c2e805a49c19aea30b420" + integrity sha512-/AANEwGL0tWBwzLNOvO0yUdy2D52jVdNXppOqswC49sxMN2cPWsGCQdzuIf9tj6hHoBQzNvx75JUYuQAckPo3w== dependencies: - "@jest/types" "^27.5.1" - jest-get-type "^27.5.1" - jest-matcher-utils "^27.5.1" - jest-message-util "^27.5.1" + "@jest/expect-utils" "^28.1.1" + jest-get-type "^28.0.2" + jest-matcher-utils "^28.1.1" + jest-message-util "^28.1.1" + jest-util "^28.1.1" express@^4.17.3: version "4.18.1" @@ -5827,10 +5808,10 @@ follow-redirects@^1.0.0: resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.14.4.tgz#838fdf48a8bbdd79e52ee51fb1c94e3ed98b9379" integrity sha512-zwGkiSXC1MUJG/qmeIFH2HBJx9u0V46QGUe3YR1fXG8bXQxq7fLj0RjLZQ5nubr9qNJUZrH+xUcwXEoXNpfS+g== -follow-redirects@^1.14.9: - version "1.14.9" - resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.14.9.tgz#dd4ea157de7bfaf9ea9b3fbd85aa16951f78d8d7" - integrity sha512-MQDfihBQYMcyy5dhRDJUHcw7lb2Pv/TuE6xP1vyraLukNDHKbDxDNaOE3NbCAdKQApno+GPRyo1YAp89yCjK4w== +follow-redirects@^1.15.0: + version "1.15.1" + resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.1.tgz#0ca6a452306c9b276e4d3127483e29575e207ad5" + integrity sha512-yLAMQs+k0b2m7cVxpS1VKJVvoz7SS9Td1zss3XRwXj+ZDH00RJgnuLx7E44wx02kQLrdM3aOOy+FpzS7+8OizA== foreach@^2.0.5: version "2.0.5" @@ -5863,15 +5844,6 @@ form-data@^2.5.0: combined-stream "^1.0.6" mime-types "^2.1.12" -form-data@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/form-data/-/form-data-3.0.1.tgz#ebd53791b78356a99af9a300d4282c4d5eb9755f" - integrity sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg== - dependencies: - asynckit "^0.4.0" - combined-stream "^1.0.8" - mime-types "^2.1.12" - form-data@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/form-data/-/form-data-4.0.0.tgz#93919daeaf361ee529584b9b31664dc12c9fa452" @@ -6310,12 +6282,12 @@ hpack.js@^2.1.6: readable-stream "^2.0.1" wbuf "^1.1.0" -html-encoding-sniffer@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/html-encoding-sniffer/-/html-encoding-sniffer-2.0.1.tgz#42a6dc4fd33f00281176e8b23759ca4e4fa185f3" - integrity sha512-D5JbOMBIR/TVZkubHT+OyT2705QvogUW4IBn6nHd756OwieSF9aDYFj4dv6HHEVGYbHaLETa3WggZYWWMyy3ZQ== +html-encoding-sniffer@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/html-encoding-sniffer/-/html-encoding-sniffer-3.0.0.tgz#2cb1a8cf0db52414776e5b2a7a04d5dd98158de9" + integrity sha512-oWv4T4yJ52iKrufjnyZPkrN0CH3QnrUqdB6In1g5Fe1mia8GmF36gnfNySxoZtxD5+NmYw1EElVXiBk93UeskA== dependencies: - whatwg-encoding "^1.0.5" + whatwg-encoding "^2.0.0" html-entities@^2.3.2: version "2.3.2" @@ -6427,12 +6399,12 @@ http-proxy-agent@^2.1.0: agent-base "4" debug "3.1.0" -http-proxy-agent@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz#8a8c8ef7f5932ccf953c296ca8291b95aa74aa3a" - integrity sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg== +http-proxy-agent@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz#5129800203520d434f142bc78ff3c170800f2b43" + integrity sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w== dependencies: - "@tootallnate/once" "1" + "@tootallnate/once" "2" agent-base "6" debug "4" @@ -6499,6 +6471,13 @@ iconv-lite@0.4.24: dependencies: safer-buffer ">= 2.1.2 < 3" +iconv-lite@0.6.3: + version "0.6.3" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.6.3.tgz#a52f80bf38da1952eb5c681790719871a1a72501" + integrity sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw== + dependencies: + safer-buffer ">= 2.1.2 < 3.0.0" + icss-utils@^5.0.0, icss-utils@^5.1.0: version "5.1.0" resolved "https://registry.yarnpkg.com/icss-utils/-/icss-utils-5.1.0.tgz#c6be6858abd013d768e98366ae47e25d5887b1ae" @@ -6667,7 +6646,7 @@ intl@^1.2.5: resolved "https://registry.yarnpkg.com/intl/-/intl-1.2.5.tgz#82244a2190c4e419f8371f5aa34daa3420e2abde" integrity sha1-giRKIZDE5Bn4Nx9ao02qNCDiq94= -invariant@^2.2.2: +invariant@^2.2.2, invariant@^2.2.4: version "2.2.4" resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6" integrity sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA== @@ -6742,13 +6721,6 @@ is-callable@^1.1.4, is-callable@^1.2.4: resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.4.tgz#47301d58dd0259407865547853df6d61fe471945" integrity sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w== -is-ci@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/is-ci/-/is-ci-3.0.0.tgz#c7e7be3c9d8eef7d0fa144390bd1e4b88dc4c994" - integrity sha512-kDXyttuLeslKAHYL/K28F2YkM3x5jvFPEw3yXbRptXydjD9rpLEz+C5K5iutY9ZiUu6AP41JdvRQwF4Iqs4ZCQ== - dependencies: - ci-info "^3.1.1" - is-core-module@^2.2.0, is-core-module@^2.5.0: version "2.6.0" resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.6.0.tgz#d7553b2526fe59b92ba3e40c8df757ec8a709e19" @@ -7051,85 +7023,82 @@ istanbul-reports@^3.1.3: html-escaper "^2.0.0" istanbul-lib-report "^3.0.0" -jest-changed-files@^27.5.1: - version "27.5.1" - resolved "https://registry.yarnpkg.com/jest-changed-files/-/jest-changed-files-27.5.1.tgz#a348aed00ec9bf671cc58a66fcbe7c3dfd6a68f5" - integrity sha512-buBLMiByfWGCoMsLLzGUUSpAmIAGnbR2KJoMN10ziLhOLvP4e0SlypHnAel8iqQXTrcbmfEY9sSqae5sgUsTvw== +jest-changed-files@^28.0.2: + version "28.0.2" + resolved "https://registry.yarnpkg.com/jest-changed-files/-/jest-changed-files-28.0.2.tgz#7d7810660a5bd043af9e9cfbe4d58adb05e91531" + integrity sha512-QX9u+5I2s54ZnGoMEjiM2WeBvJR2J7w/8ZUmH2um/WLAuGAYFQcsVXY9+1YL6k0H/AGUdH8pXUAv6erDqEsvIA== dependencies: - "@jest/types" "^27.5.1" execa "^5.0.0" throat "^6.0.1" -jest-circus@^27.5.1: - version "27.5.1" - resolved "https://registry.yarnpkg.com/jest-circus/-/jest-circus-27.5.1.tgz#37a5a4459b7bf4406e53d637b49d22c65d125ecc" - integrity sha512-D95R7x5UtlMA5iBYsOHFFbMD/GVA4R/Kdq15f7xYWUfWHBto9NYRsOvnSauTgdF+ogCpJ4tyKOXhUifxS65gdw== +jest-circus@^28.1.2: + version "28.1.2" + resolved "https://registry.yarnpkg.com/jest-circus/-/jest-circus-28.1.2.tgz#0d5a5623eccb244efe87d1edc365696e4fcf80ce" + integrity sha512-E2vdPIJG5/69EMpslFhaA46WkcrN74LI5V/cSJ59L7uS8UNoXbzTxmwhpi9XrIL3zqvMt5T0pl5k2l2u2GwBNQ== dependencies: - "@jest/environment" "^27.5.1" - "@jest/test-result" "^27.5.1" - "@jest/types" "^27.5.1" + "@jest/environment" "^28.1.2" + "@jest/expect" "^28.1.2" + "@jest/test-result" "^28.1.1" + "@jest/types" "^28.1.1" "@types/node" "*" chalk "^4.0.0" co "^4.6.0" dedent "^0.7.0" - expect "^27.5.1" is-generator-fn "^2.0.0" - jest-each "^27.5.1" - jest-matcher-utils "^27.5.1" - jest-message-util "^27.5.1" - jest-runtime "^27.5.1" - jest-snapshot "^27.5.1" - jest-util "^27.5.1" - pretty-format "^27.5.1" + jest-each "^28.1.1" + jest-matcher-utils "^28.1.1" + jest-message-util "^28.1.1" + jest-runtime "^28.1.2" + jest-snapshot "^28.1.2" + jest-util "^28.1.1" + pretty-format "^28.1.1" slash "^3.0.0" stack-utils "^2.0.3" throat "^6.0.1" -jest-cli@^27.5.1: - version "27.5.1" - resolved "https://registry.yarnpkg.com/jest-cli/-/jest-cli-27.5.1.tgz#278794a6e6458ea8029547e6c6cbf673bd30b145" - integrity sha512-Hc6HOOwYq4/74/c62dEE3r5elx8wjYqxY0r0G/nFrLDPMFRu6RA/u8qINOIkvhxG7mMQ5EJsOGfRpI8L6eFUVw== +jest-cli@^28.1.2: + version "28.1.2" + resolved "https://registry.yarnpkg.com/jest-cli/-/jest-cli-28.1.2.tgz#b89012e5bad14135e71b1628b85475d3773a1bbc" + integrity sha512-l6eoi5Do/IJUXAFL9qRmDiFpBeEJAnjJb1dcd9i/VWfVWbp3mJhuH50dNtX67Ali4Ecvt4eBkWb4hXhPHkAZTw== dependencies: - "@jest/core" "^27.5.1" - "@jest/test-result" "^27.5.1" - "@jest/types" "^27.5.1" + "@jest/core" "^28.1.2" + "@jest/test-result" "^28.1.1" + "@jest/types" "^28.1.1" chalk "^4.0.0" exit "^0.1.2" graceful-fs "^4.2.9" import-local "^3.0.2" - jest-config "^27.5.1" - jest-util "^27.5.1" - jest-validate "^27.5.1" + jest-config "^28.1.2" + jest-util "^28.1.1" + jest-validate "^28.1.1" prompts "^2.0.1" - yargs "^16.2.0" + yargs "^17.3.1" -jest-config@^27.5.1: - version "27.5.1" - resolved "https://registry.yarnpkg.com/jest-config/-/jest-config-27.5.1.tgz#5c387de33dca3f99ad6357ddeccd91bf3a0e4a41" - integrity sha512-5sAsjm6tGdsVbW9ahcChPAFCk4IlkQUknH5AvKjuLTSlcO/wCZKyFdn7Rg0EkC+OGgWODEy2hDpWB1PgzH0JNA== +jest-config@^28.1.2: + version "28.1.2" + resolved "https://registry.yarnpkg.com/jest-config/-/jest-config-28.1.2.tgz#ba00ad30caf62286c86e7c1099e915218a0ac8c6" + integrity sha512-g6EfeRqddVbjPVBVY4JWpUY4IvQoFRIZcv4V36QkqzE0IGhEC/VkugFeBMAeUE7PRgC8KJF0yvJNDeQRbamEVA== dependencies: - "@babel/core" "^7.8.0" - "@jest/test-sequencer" "^27.5.1" - "@jest/types" "^27.5.1" - babel-jest "^27.5.1" + "@babel/core" "^7.11.6" + "@jest/test-sequencer" "^28.1.1" + "@jest/types" "^28.1.1" + babel-jest "^28.1.2" chalk "^4.0.0" ci-info "^3.2.0" deepmerge "^4.2.2" - glob "^7.1.1" + glob "^7.1.3" graceful-fs "^4.2.9" - jest-circus "^27.5.1" - jest-environment-jsdom "^27.5.1" - jest-environment-node "^27.5.1" - jest-get-type "^27.5.1" - jest-jasmine2 "^27.5.1" - jest-regex-util "^27.5.1" - jest-resolve "^27.5.1" - jest-runner "^27.5.1" - jest-util "^27.5.1" - jest-validate "^27.5.1" + jest-circus "^28.1.2" + jest-environment-node "^28.1.2" + jest-get-type "^28.0.2" + jest-regex-util "^28.0.2" + jest-resolve "^28.1.1" + jest-runner "^28.1.2" + jest-util "^28.1.1" + jest-validate "^28.1.1" micromatch "^4.0.4" parse-json "^5.2.0" - pretty-format "^27.5.1" + pretty-format "^28.1.1" slash "^3.0.0" strip-json-comments "^3.1.1" @@ -7143,135 +7112,108 @@ jest-diff@^27.5.1: jest-get-type "^27.5.1" pretty-format "^27.5.1" -jest-docblock@^27.5.1: - version "27.5.1" - resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-27.5.1.tgz#14092f364a42c6108d42c33c8cf30e058e25f6c0" - integrity sha512-rl7hlABeTsRYxKiUfpHrQrG4e2obOiTQWfMEH3PxPjOtdsfLQO4ReWSZaQ7DETm4xu07rl4q/h4zcKXyU0/OzQ== +jest-diff@^28.1.1: + version "28.1.1" + resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-28.1.1.tgz#1a3eedfd81ae79810931c63a1d0f201b9120106c" + integrity sha512-/MUUxeR2fHbqHoMMiffe/Afm+U8U4olFRJ0hiVG2lZatPJcnGxx292ustVu7bULhjV65IYMxRdploAKLbcrsyg== + dependencies: + chalk "^4.0.0" + diff-sequences "^28.1.1" + jest-get-type "^28.0.2" + pretty-format "^28.1.1" + +jest-docblock@^28.1.1: + version "28.1.1" + resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-28.1.1.tgz#6f515c3bf841516d82ecd57a62eed9204c2f42a8" + integrity sha512-3wayBVNiOYx0cwAbl9rwm5kKFP8yHH3d/fkEaL02NPTkDojPtheGB7HZSFY4wzX+DxyrvhXz0KSCVksmCknCuA== dependencies: detect-newline "^3.0.0" -jest-each@^27.5.1: - version "27.5.1" - resolved "https://registry.yarnpkg.com/jest-each/-/jest-each-27.5.1.tgz#5bc87016f45ed9507fed6e4702a5b468a5b2c44e" - integrity sha512-1Ff6p+FbhT/bXQnEouYy00bkNSY7OUpfIcmdl8vZ31A1UUaurOLPA8a8BbJOF2RDUElwJhmeaV7LnagI+5UwNQ== +jest-each@^28.1.1: + version "28.1.1" + resolved "https://registry.yarnpkg.com/jest-each/-/jest-each-28.1.1.tgz#ba5238dacf4f31d9fe23ddc2c44c01e7c23885c4" + integrity sha512-A042rqh17ZvEhRceDMi784ppoXR7MWGDEKTXEZXb4svt0eShMZvijGxzKsx+yIjeE8QYmHPrnHiTSQVhN4nqaw== dependencies: - "@jest/types" "^27.5.1" + "@jest/types" "^28.1.1" chalk "^4.0.0" - jest-get-type "^27.5.1" - jest-util "^27.5.1" - pretty-format "^27.5.1" + jest-get-type "^28.0.2" + jest-util "^28.1.1" + pretty-format "^28.1.1" -jest-environment-jsdom@^27.5.1: - version "27.5.1" - resolved "https://registry.yarnpkg.com/jest-environment-jsdom/-/jest-environment-jsdom-27.5.1.tgz#ea9ccd1fc610209655a77898f86b2b559516a546" - integrity sha512-TFBvkTC1Hnnnrka/fUb56atfDtJ9VMZ94JkjTbggl1PEpwrYtUBKMezB3inLmWqQsXYLcMwNoDQwoBTAvFfsfw== +jest-environment-jsdom@^28.1.2: + version "28.1.2" + resolved "https://registry.yarnpkg.com/jest-environment-jsdom/-/jest-environment-jsdom-28.1.2.tgz#d3fe82ef8f900c34ab582df7d3002c5079e3d8ab" + integrity sha512-Ujhx/xFZGVPuxAVpseQ7KqdBErenuWH3Io2HujkGOKMS2VWmpnTGYHzv+73p21QJ9yYQlJkeg06rTe1svV+u0g== dependencies: - "@jest/environment" "^27.5.1" - "@jest/fake-timers" "^27.5.1" - "@jest/types" "^27.5.1" + "@jest/environment" "^28.1.2" + "@jest/fake-timers" "^28.1.2" + "@jest/types" "^28.1.1" + "@types/jsdom" "^16.2.4" "@types/node" "*" - jest-mock "^27.5.1" - jest-util "^27.5.1" - jsdom "^16.6.0" + jest-mock "^28.1.1" + jest-util "^28.1.1" + jsdom "^19.0.0" -jest-environment-node@^27.5.1: - version "27.5.1" - resolved "https://registry.yarnpkg.com/jest-environment-node/-/jest-environment-node-27.5.1.tgz#dedc2cfe52fab6b8f5714b4808aefa85357a365e" - integrity sha512-Jt4ZUnxdOsTGwSRAfKEnE6BcwsSPNOijjwifq5sDFSA2kesnXTvNqKHYgM0hDq3549Uf/KzdXNYn4wMZJPlFLw== +jest-environment-node@^28.1.2: + version "28.1.2" + resolved "https://registry.yarnpkg.com/jest-environment-node/-/jest-environment-node-28.1.2.tgz#3e2eb47f6d173b0648d5f7c717cb1c26651d5c8a" + integrity sha512-oYsZz9Qw27XKmOgTtnl0jW7VplJkN2oeof+SwAwKFQacq3CLlG9u4kTGuuLWfvu3J7bVutWlrbEQMOCL/jughw== dependencies: - "@jest/environment" "^27.5.1" - "@jest/fake-timers" "^27.5.1" - "@jest/types" "^27.5.1" + "@jest/environment" "^28.1.2" + "@jest/fake-timers" "^28.1.2" + "@jest/types" "^28.1.1" "@types/node" "*" - jest-mock "^27.5.1" - jest-util "^27.5.1" + jest-mock "^28.1.1" + jest-util "^28.1.1" jest-get-type@^27.5.1: version "27.5.1" resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-27.5.1.tgz#3cd613c507b0f7ace013df407a1c1cd578bcb4f1" integrity sha512-2KY95ksYSaK7DMBWQn6dQz3kqAf3BB64y2udeG+hv4KfSOb9qwcYQstTJc1KCbsix+wLZWZYN8t7nwX3GOBLRw== -jest-haste-map@^27.5.1: - version "27.5.1" - resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-27.5.1.tgz#9fd8bd7e7b4fa502d9c6164c5640512b4e811e7f" - integrity sha512-7GgkZ4Fw4NFbMSDSpZwXeBiIbx+t/46nJ2QitkOjvwPYyZmqttu2TDSimMHP1EkPOi4xUZAN1doE5Vd25H4Jng== - dependencies: - "@jest/types" "^27.5.1" - "@types/graceful-fs" "^4.1.2" - "@types/node" "*" - anymatch "^3.0.3" - fb-watchman "^2.0.0" - graceful-fs "^4.2.9" - jest-regex-util "^27.5.1" - jest-serializer "^27.5.1" - jest-util "^27.5.1" - jest-worker "^27.5.1" - micromatch "^4.0.4" - walker "^1.0.7" - optionalDependencies: - fsevents "^2.3.2" +jest-get-type@^28.0.2: + version "28.0.2" + resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-28.0.2.tgz#34622e628e4fdcd793d46db8a242227901fcf203" + integrity sha512-ioj2w9/DxSYHfOm5lJKCdcAmPJzQXmbM/Url3rhlghrPvT3tt+7a/+oXc9azkKmLvoiXjtV83bEWqi+vs5nlPA== -jest-haste-map@^28.1.0: - version "28.1.0" - resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-28.1.0.tgz#6c1ee2daf1c20a3e03dbd8e5b35c4d73d2349cf0" - integrity sha512-xyZ9sXV8PtKi6NCrJlmq53PyNVHzxmcfXNVvIRHpHmh1j/HChC4pwKgyjj7Z9us19JMw8PpQTJsFWOsIfT93Dw== +jest-haste-map@^28.1.1: + version "28.1.1" + resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-28.1.1.tgz#471685f1acd365a9394745bb97c8fc16289adca3" + integrity sha512-ZrRSE2o3Ezh7sb1KmeLEZRZ4mgufbrMwolcFHNRSjKZhpLa8TdooXOOFlSwoUzlbVs1t0l7upVRW2K7RWGHzbQ== dependencies: - "@jest/types" "^28.1.0" + "@jest/types" "^28.1.1" "@types/graceful-fs" "^4.1.3" "@types/node" "*" anymatch "^3.0.3" fb-watchman "^2.0.0" graceful-fs "^4.2.9" jest-regex-util "^28.0.2" - jest-util "^28.1.0" - jest-worker "^28.1.0" + jest-util "^28.1.1" + jest-worker "^28.1.1" micromatch "^4.0.4" - walker "^1.0.7" + walker "^1.0.8" optionalDependencies: fsevents "^2.3.2" -jest-jasmine2@^27.5.1: - version "27.5.1" - resolved "https://registry.yarnpkg.com/jest-jasmine2/-/jest-jasmine2-27.5.1.tgz#a037b0034ef49a9f3d71c4375a796f3b230d1ac4" - integrity sha512-jtq7VVyG8SqAorDpApwiJJImd0V2wv1xzdheGHRGyuT7gZm6gG47QEskOlzsN1PG/6WNaCo5pmwMHDf3AkG2pQ== - dependencies: - "@jest/environment" "^27.5.1" - "@jest/source-map" "^27.5.1" - "@jest/test-result" "^27.5.1" - "@jest/types" "^27.5.1" - "@types/node" "*" - chalk "^4.0.0" - co "^4.6.0" - expect "^27.5.1" - is-generator-fn "^2.0.0" - jest-each "^27.5.1" - jest-matcher-utils "^27.5.1" - jest-message-util "^27.5.1" - jest-runtime "^27.5.1" - jest-snapshot "^27.5.1" - jest-util "^27.5.1" - pretty-format "^27.5.1" - throat "^6.0.1" - -jest-junit@^13.2.0: - version "13.2.0" - resolved "https://registry.yarnpkg.com/jest-junit/-/jest-junit-13.2.0.tgz#66eeb86429aafac8c1745a70f44ace185aacb943" - integrity sha512-B0XNlotl1rdsvFZkFfoa19mc634+rrd8E4Sskb92Bb8MmSXeWV9XJGUyctunZS1W410uAxcyYuPUGVnbcOH8cg== +jest-junit@^14.0.0: + version "14.0.0" + resolved "https://registry.yarnpkg.com/jest-junit/-/jest-junit-14.0.0.tgz#f69fc31bab32224848f443480c2c808fccb2a802" + integrity sha512-kALvBDegstTROfDGXH71UGD7k5g7593Y1wuX1wpWT+QTYcBbmtuGOA8UlAt56zo/B2eMIOcaOVEON3j0VXVa4g== dependencies: mkdirp "^1.0.4" strip-ansi "^6.0.1" uuid "^8.3.2" xml "^1.0.1" -jest-leak-detector@^27.5.1: - version "27.5.1" - resolved "https://registry.yarnpkg.com/jest-leak-detector/-/jest-leak-detector-27.5.1.tgz#6ec9d54c3579dd6e3e66d70e3498adf80fde3fb8" - integrity sha512-POXfWAMvfU6WMUXftV4HolnJfnPOGEu10fscNCA76KBpRRhcMN2c8d3iT2pxQS3HLbA+5X4sOUPzYO2NUyIlHQ== +jest-leak-detector@^28.1.1: + version "28.1.1" + resolved "https://registry.yarnpkg.com/jest-leak-detector/-/jest-leak-detector-28.1.1.tgz#537f37afd610a4b3f4cab15e06baf60484548efb" + integrity sha512-4jvs8V8kLbAaotE+wFR7vfUGf603cwYtFf1/PYEsyX2BAjSzj8hQSVTP6OWzseTl0xL6dyHuKs2JAks7Pfubmw== dependencies: - jest-get-type "^27.5.1" - pretty-format "^27.5.1" + jest-get-type "^28.0.2" + pretty-format "^28.1.1" -jest-matcher-utils@^27.0.0, jest-matcher-utils@^27.5.1: +jest-matcher-utils@^27.0.0: version "27.5.1" resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-27.5.1.tgz#9c0cdbda8245bc22d2331729d1091308b40cf8ab" integrity sha512-z2uTx/T6LBaCoNWNFWwChLBKYxTMcGBRjAt+2SbP929/Fflb9aa5LGma654Rz8z9HLxsrUaYzxE9T/EFIL/PAw== @@ -7281,27 +7223,37 @@ jest-matcher-utils@^27.0.0, jest-matcher-utils@^27.5.1: jest-get-type "^27.5.1" pretty-format "^27.5.1" -jest-message-util@^27.5.1: - version "27.5.1" - resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-27.5.1.tgz#bdda72806da10d9ed6425e12afff38cd1458b6cf" - integrity sha512-rMyFe1+jnyAAf+NHwTclDz0eAaLkVDdKVHHBFWsBWHnnh5YeJMNWWsv7AbFYXfK3oTqvL7VTWkhNLu1jX24D+g== +jest-matcher-utils@^28.0.0, jest-matcher-utils@^28.1.1: + version "28.1.1" + resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-28.1.1.tgz#a7c4653c2b782ec96796eb3088060720f1e29304" + integrity sha512-NPJPRWrbmR2nAJ+1nmnfcKKzSwgfaciCCrYZzVnNoxVoyusYWIjkBMNvu0RHJe7dNj4hH3uZOPZsQA+xAYWqsw== + dependencies: + chalk "^4.0.0" + jest-diff "^28.1.1" + jest-get-type "^28.0.2" + pretty-format "^28.1.1" + +jest-message-util@^28.1.1: + version "28.1.1" + resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-28.1.1.tgz#60aa0b475cfc08c8a9363ed2fb9108514dd9ab89" + integrity sha512-xoDOOT66fLfmTRiqkoLIU7v42mal/SqwDKvfmfiWAdJMSJiU+ozgluO7KbvoAgiwIrrGZsV7viETjc8GNrA/IQ== dependencies: "@babel/code-frame" "^7.12.13" - "@jest/types" "^27.5.1" + "@jest/types" "^28.1.1" "@types/stack-utils" "^2.0.0" chalk "^4.0.0" graceful-fs "^4.2.9" micromatch "^4.0.4" - pretty-format "^27.5.1" + pretty-format "^28.1.1" slash "^3.0.0" stack-utils "^2.0.3" -jest-mock@^27.5.1: - version "27.5.1" - resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-27.5.1.tgz#19948336d49ef4d9c52021d34ac7b5f36ff967d6" - integrity sha512-K4jKbY1d4ENhbrG2zuPWaQBvDly+iZ2yAW+T1fATN78hc0sInwn7wZB8XtlNnvHug5RMwV897Xm4LqmPM4e2Og== +jest-mock@^28.1.1: + version "28.1.1" + resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-28.1.1.tgz#37903d269427fa1ef5b2447be874e1c62a39a371" + integrity sha512-bDCb0FjfsmKweAvE09dZT59IMkzgN0fYBH6t5S45NoJfd2DHkS3ySG2K+hucortryhO3fVuXdlxWcbtIuV/Skw== dependencies: - "@jest/types" "^27.5.1" + "@jest/types" "^28.1.1" "@types/node" "*" jest-pnp-resolver@^1.2.2: @@ -7309,191 +7261,154 @@ jest-pnp-resolver@^1.2.2: resolved "https://registry.yarnpkg.com/jest-pnp-resolver/-/jest-pnp-resolver-1.2.2.tgz#b704ac0ae028a89108a4d040b3f919dfddc8e33c" integrity sha512-olV41bKSMm8BdnuMsewT4jqlZ8+3TCARAXjZGT9jcoSnrfUnRCqnMoF9XEeoWjbzObpqF9dRhHQj0Xb9QdF6/w== -jest-regex-util@^27.5.1: - version "27.5.1" - resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-27.5.1.tgz#4da143f7e9fd1e542d4aa69617b38e4a78365b95" - integrity sha512-4bfKq2zie+x16okqDXjXn9ql2B0dScQu+vcwe4TvFVhkVyuWLqpZrZtXxLLWoXYgn0E87I6r6GRYHF7wFZBUvg== - jest-regex-util@^28.0.2: version "28.0.2" resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-28.0.2.tgz#afdc377a3b25fb6e80825adcf76c854e5bf47ead" integrity sha512-4s0IgyNIy0y9FK+cjoVYoxamT7Zeo7MhzqRGx7YDYmaQn1wucY9rotiGkBzzcMXTtjrCAP/f7f+E0F7+fxPNdw== -jest-resolve-dependencies@^27.5.1: - version "27.5.1" - resolved "https://registry.yarnpkg.com/jest-resolve-dependencies/-/jest-resolve-dependencies-27.5.1.tgz#d811ecc8305e731cc86dd79741ee98fed06f1da8" - integrity sha512-QQOOdY4PE39iawDn5rzbIePNigfe5B9Z91GDD1ae/xNDlu9kaat8QQ5EKnNmVWPV54hUdxCVwwj6YMgR2O7IOg== +jest-resolve-dependencies@^28.1.2: + version "28.1.2" + resolved "https://registry.yarnpkg.com/jest-resolve-dependencies/-/jest-resolve-dependencies-28.1.2.tgz#ca528858e0c6642d5a1dda8fc7cda10230c275bc" + integrity sha512-OXw4vbOZuyRTBi3tapWBqdyodU+T33ww5cPZORuTWkg+Y8lmsxQlVu3MWtJh6NMlKRTHQetF96yGPv01Ye7Mbg== dependencies: - "@jest/types" "^27.5.1" - jest-regex-util "^27.5.1" - jest-snapshot "^27.5.1" + jest-regex-util "^28.0.2" + jest-snapshot "^28.1.2" -jest-resolve@^27.5.1: - version "27.5.1" - resolved "https://registry.yarnpkg.com/jest-resolve/-/jest-resolve-27.5.1.tgz#a2f1c5a0796ec18fe9eb1536ac3814c23617b384" - integrity sha512-FFDy8/9E6CV83IMbDpcjOhumAQPDyETnU2KZ1O98DwTnz8AOBsW/Xv3GySr1mOZdItLR+zDZ7I/UdTFbgSOVCw== +jest-resolve@^28.1.1: + version "28.1.1" + resolved "https://registry.yarnpkg.com/jest-resolve/-/jest-resolve-28.1.1.tgz#bc2eaf384abdcc1aaf3ba7c50d1adf01e59095e5" + integrity sha512-/d1UbyUkf9nvsgdBildLe6LAD4DalgkgZcKd0nZ8XUGPyA/7fsnaQIlKVnDiuUXv/IeZhPEDrRJubVSulxrShA== dependencies: - "@jest/types" "^27.5.1" chalk "^4.0.0" graceful-fs "^4.2.9" - jest-haste-map "^27.5.1" + jest-haste-map "^28.1.1" jest-pnp-resolver "^1.2.2" - jest-util "^27.5.1" - jest-validate "^27.5.1" + jest-util "^28.1.1" + jest-validate "^28.1.1" resolve "^1.20.0" resolve.exports "^1.1.0" slash "^3.0.0" -jest-runner@^27.5.1: - version "27.5.1" - resolved "https://registry.yarnpkg.com/jest-runner/-/jest-runner-27.5.1.tgz#071b27c1fa30d90540805c5645a0ec167c7b62e5" - integrity sha512-g4NPsM4mFCOwFKXO4p/H/kWGdJp9V8kURY2lX8Me2drgXqG7rrZAx5kv+5H7wtt/cdFIjhqYx1HrlqWHaOvDaQ== +jest-runner@^28.1.2: + version "28.1.2" + resolved "https://registry.yarnpkg.com/jest-runner/-/jest-runner-28.1.2.tgz#f293409592a62234285a71237e38499a3554e350" + integrity sha512-6/k3DlAsAEr5VcptCMdhtRhOoYClZQmxnVMZvZ/quvPGRpN7OBQYPIC32tWSgOnbgqLXNs5RAniC+nkdFZpD4A== dependencies: - "@jest/console" "^27.5.1" - "@jest/environment" "^27.5.1" - "@jest/test-result" "^27.5.1" - "@jest/transform" "^27.5.1" - "@jest/types" "^27.5.1" + "@jest/console" "^28.1.1" + "@jest/environment" "^28.1.2" + "@jest/test-result" "^28.1.1" + "@jest/transform" "^28.1.2" + "@jest/types" "^28.1.1" "@types/node" "*" chalk "^4.0.0" - emittery "^0.8.1" + emittery "^0.10.2" graceful-fs "^4.2.9" - jest-docblock "^27.5.1" - jest-environment-jsdom "^27.5.1" - jest-environment-node "^27.5.1" - jest-haste-map "^27.5.1" - jest-leak-detector "^27.5.1" - jest-message-util "^27.5.1" - jest-resolve "^27.5.1" - jest-runtime "^27.5.1" - jest-util "^27.5.1" - jest-worker "^27.5.1" - source-map-support "^0.5.6" + jest-docblock "^28.1.1" + jest-environment-node "^28.1.2" + jest-haste-map "^28.1.1" + jest-leak-detector "^28.1.1" + jest-message-util "^28.1.1" + jest-resolve "^28.1.1" + jest-runtime "^28.1.2" + jest-util "^28.1.1" + jest-watcher "^28.1.1" + jest-worker "^28.1.1" + source-map-support "0.5.13" throat "^6.0.1" -jest-runtime@^27.5.1: - version "27.5.1" - resolved "https://registry.yarnpkg.com/jest-runtime/-/jest-runtime-27.5.1.tgz#4896003d7a334f7e8e4a53ba93fb9bcd3db0a1af" - integrity sha512-o7gxw3Gf+H2IGt8fv0RiyE1+r83FJBRruoA+FXrlHw6xEyBsU8ugA6IPfTdVyA0w8HClpbK+DGJxH59UrNMx8A== +jest-runtime@^28.1.2: + version "28.1.2" + resolved "https://registry.yarnpkg.com/jest-runtime/-/jest-runtime-28.1.2.tgz#d68f34f814a848555a345ceda23289f14d59a688" + integrity sha512-i4w93OsWzLOeMXSi9epmakb2+3z0AchZtUQVF1hesBmcQQy4vtaql5YdVe9KexdJaVRyPDw8DoBR0j3lYsZVYw== dependencies: - "@jest/environment" "^27.5.1" - "@jest/fake-timers" "^27.5.1" - "@jest/globals" "^27.5.1" - "@jest/source-map" "^27.5.1" - "@jest/test-result" "^27.5.1" - "@jest/transform" "^27.5.1" - "@jest/types" "^27.5.1" + "@jest/environment" "^28.1.2" + "@jest/fake-timers" "^28.1.2" + "@jest/globals" "^28.1.2" + "@jest/source-map" "^28.1.2" + "@jest/test-result" "^28.1.1" + "@jest/transform" "^28.1.2" + "@jest/types" "^28.1.1" chalk "^4.0.0" cjs-module-lexer "^1.0.0" collect-v8-coverage "^1.0.0" execa "^5.0.0" glob "^7.1.3" graceful-fs "^4.2.9" - jest-haste-map "^27.5.1" - jest-message-util "^27.5.1" - jest-mock "^27.5.1" - jest-regex-util "^27.5.1" - jest-resolve "^27.5.1" - jest-snapshot "^27.5.1" - jest-util "^27.5.1" + jest-haste-map "^28.1.1" + jest-message-util "^28.1.1" + jest-mock "^28.1.1" + jest-regex-util "^28.0.2" + jest-resolve "^28.1.1" + jest-snapshot "^28.1.2" + jest-util "^28.1.1" slash "^3.0.0" strip-bom "^4.0.0" -jest-serializer@^27.5.1: - version "27.5.1" - resolved "https://registry.yarnpkg.com/jest-serializer/-/jest-serializer-27.5.1.tgz#81438410a30ea66fd57ff730835123dea1fb1f64" - integrity sha512-jZCyo6iIxO1aqUxpuBlwTDMkzOAJS4a3eYz3YzgxxVQFwLeSA7Jfq5cbqCY+JLvTDrWirgusI/0KwxKMgrdf7w== +jest-snapshot@^28.1.2: + version "28.1.2" + resolved "https://registry.yarnpkg.com/jest-snapshot/-/jest-snapshot-28.1.2.tgz#93d31b87b11b384f5946fe0767541496135f8d52" + integrity sha512-wzrieFttZYfLvrCVRJxX+jwML2YTArOUqFpCoSVy1QUapx+LlV9uLbV/mMEhYj4t7aMeE9aSQFHSvV/oNoDAMA== dependencies: - "@types/node" "*" - graceful-fs "^4.2.9" - -jest-snapshot@^27.5.1: - version "27.5.1" - resolved "https://registry.yarnpkg.com/jest-snapshot/-/jest-snapshot-27.5.1.tgz#b668d50d23d38054a51b42c4039cab59ae6eb6a1" - integrity sha512-yYykXI5a0I31xX67mgeLw1DZ0bJB+gpq5IpSuCAoyDi0+BhgU/RIrL+RTzDmkNTchvDFWKP8lp+w/42Z3us5sA== - dependencies: - "@babel/core" "^7.7.2" + "@babel/core" "^7.11.6" "@babel/generator" "^7.7.2" "@babel/plugin-syntax-typescript" "^7.7.2" "@babel/traverse" "^7.7.2" - "@babel/types" "^7.0.0" - "@jest/transform" "^27.5.1" - "@jest/types" "^27.5.1" - "@types/babel__traverse" "^7.0.4" + "@babel/types" "^7.3.3" + "@jest/expect-utils" "^28.1.1" + "@jest/transform" "^28.1.2" + "@jest/types" "^28.1.1" + "@types/babel__traverse" "^7.0.6" "@types/prettier" "^2.1.5" babel-preset-current-node-syntax "^1.0.0" chalk "^4.0.0" - expect "^27.5.1" + expect "^28.1.1" graceful-fs "^4.2.9" - jest-diff "^27.5.1" - jest-get-type "^27.5.1" - jest-haste-map "^27.5.1" - jest-matcher-utils "^27.5.1" - jest-message-util "^27.5.1" - jest-util "^27.5.1" + jest-diff "^28.1.1" + jest-get-type "^28.0.2" + jest-haste-map "^28.1.1" + jest-matcher-utils "^28.1.1" + jest-message-util "^28.1.1" + jest-util "^28.1.1" natural-compare "^1.4.0" - pretty-format "^27.5.1" - semver "^7.3.2" + pretty-format "^28.1.1" + semver "^7.3.5" -jest-util@^27.0.0: - version "27.2.0" - resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-27.2.0.tgz#bfccb85cfafae752257319e825a5b8d4ada470dc" - integrity sha512-T5ZJCNeFpqcLBpx+Hl9r9KoxBCUqeWlJ1Htli+vryigZVJ1vuLB9j35grEBASp4R13KFkV7jM52bBGnArpJN6A== +jest-util@^28.0.0, jest-util@^28.1.1: + version "28.1.1" + resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-28.1.1.tgz#ff39e436a1aca397c0ab998db5a51ae2b7080d05" + integrity sha512-FktOu7ca1DZSyhPAxgxB6hfh2+9zMoJ7aEQA759Z6p45NuO8mWcqujH+UdHlCm/V6JTWwDztM2ITCzU1ijJAfw== dependencies: - "@jest/types" "^27.1.1" - "@types/node" "*" - chalk "^4.0.0" - graceful-fs "^4.2.4" - is-ci "^3.0.0" - picomatch "^2.2.3" - -jest-util@^27.5.1: - version "27.5.1" - resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-27.5.1.tgz#3ba9771e8e31a0b85da48fe0b0891fb86c01c2f9" - integrity sha512-Kv2o/8jNvX1MQ0KGtw480E/w4fBCDOnH6+6DmeKi6LZUIlKA5kwY0YNdlzaWTiVgxqAqik11QyxDOKk543aKXw== - dependencies: - "@jest/types" "^27.5.1" + "@jest/types" "^28.1.1" "@types/node" "*" chalk "^4.0.0" ci-info "^3.2.0" graceful-fs "^4.2.9" picomatch "^2.2.3" -jest-util@^28.1.0: - version "28.1.0" - resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-28.1.0.tgz#d54eb83ad77e1dd441408738c5a5043642823be5" - integrity sha512-qYdCKD77k4Hwkose2YBEqQk7PzUf/NSE+rutzceduFveQREeH6b+89Dc9+wjX9dAwHcgdx4yedGA3FQlU/qCTA== +jest-validate@^28.1.1: + version "28.1.1" + resolved "https://registry.yarnpkg.com/jest-validate/-/jest-validate-28.1.1.tgz#59b7b339b3c85b5144bd0c06ad3600f503a4acc8" + integrity sha512-Kpf6gcClqFCIZ4ti5++XemYJWUPCFUW+N2gknn+KgnDf549iLul3cBuKVe1YcWRlaF8tZV8eJCap0eECOEE3Ug== dependencies: - "@jest/types" "^28.1.0" - "@types/node" "*" - chalk "^4.0.0" - ci-info "^3.2.0" - graceful-fs "^4.2.9" - picomatch "^2.2.3" - -jest-validate@^27.5.1: - version "27.5.1" - resolved "https://registry.yarnpkg.com/jest-validate/-/jest-validate-27.5.1.tgz#9197d54dc0bdb52260b8db40b46ae668e04df067" - integrity sha512-thkNli0LYTmOI1tDB3FI1S1RTp/Bqyd9pTarJwL87OIBFuqEb5Apv5EaApEudYg4g86e3CT6kM0RowkhtEnCBQ== - dependencies: - "@jest/types" "^27.5.1" + "@jest/types" "^28.1.1" camelcase "^6.2.0" chalk "^4.0.0" - jest-get-type "^27.5.1" + jest-get-type "^28.0.2" leven "^3.1.0" - pretty-format "^27.5.1" + pretty-format "^28.1.1" -jest-watcher@^27.5.1: - version "27.5.1" - resolved "https://registry.yarnpkg.com/jest-watcher/-/jest-watcher-27.5.1.tgz#71bd85fb9bde3a2c2ec4dc353437971c43c642a2" - integrity sha512-z676SuD6Z8o8qbmEGhoEUFOM1+jfEiL3DXHK/xgEiG2EyNYfFG60jluWcupY6dATjfEsKQuibReS1djInQnoVw== +jest-watcher@^28.1.1: + version "28.1.1" + resolved "https://registry.yarnpkg.com/jest-watcher/-/jest-watcher-28.1.1.tgz#533597fb3bfefd52b5cd115cd916cffd237fb60c" + integrity sha512-RQIpeZ8EIJMxbQrXpJQYIIlubBnB9imEHsxxE41f54ZwcqWLysL/A0ZcdMirf+XsMn3xfphVQVV4EW0/p7i7Ug== dependencies: - "@jest/test-result" "^27.5.1" - "@jest/types" "^27.5.1" + "@jest/test-result" "^28.1.1" + "@jest/types" "^28.1.1" "@types/node" "*" ansi-escapes "^4.2.1" chalk "^4.0.0" - jest-util "^27.5.1" + emittery "^0.10.2" + jest-util "^28.1.1" string-length "^4.0.1" jest-worker@^27.0.6: @@ -7505,32 +7420,24 @@ jest-worker@^27.0.6: merge-stream "^2.0.0" supports-color "^8.0.0" -jest-worker@^27.5.1: - version "27.5.1" - resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-27.5.1.tgz#8d146f0900e8973b106b6f73cc1e9a8cb86f8db0" - integrity sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg== +jest-worker@^28.1.1: + version "28.1.1" + resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-28.1.1.tgz#3480c73247171dfd01eda77200f0063ab6a3bf28" + integrity sha512-Au7slXB08C6h+xbJPp7VIb6U0XX5Kc9uel/WFc6/rcTzGiaVCBRngBExSYuXSLFPULPSYU3cJ3ybS988lNFQhQ== dependencies: "@types/node" "*" merge-stream "^2.0.0" supports-color "^8.0.0" -jest-worker@^28.1.0: - version "28.1.0" - resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-28.1.0.tgz#ced54757a035e87591e1208253a6e3aac1a855e5" - integrity sha512-ZHwM6mNwaWBR52Snff8ZvsCTqQsvhCxP/bT1I6T6DAnb6ygkshsyLQIMxFwHpYxht0HOoqt23JlC01viI7T03A== +jest@^28.1.2: + version "28.1.2" + resolved "https://registry.yarnpkg.com/jest/-/jest-28.1.2.tgz#451ff24081ce31ca00b07b60c61add13aa96f8eb" + integrity sha512-Tuf05DwLeCh2cfWCQbcz9UxldoDyiR1E9Igaei5khjonKncYdc6LDfynKCEWozK0oLE3GD+xKAo2u8x/0s6GOg== dependencies: - "@types/node" "*" - merge-stream "^2.0.0" - supports-color "^8.0.0" - -jest@^27.5.1: - version "27.5.1" - resolved "https://registry.yarnpkg.com/jest/-/jest-27.5.1.tgz#dadf33ba70a779be7a6fc33015843b51494f63fc" - integrity sha512-Yn0mADZB89zTtjkPJEXwrac3LHudkQMR+Paqa8uxJHCBr9agxztUifWCyiYrjhMPBoUVBjyny0I7XH6ozDr7QQ== - dependencies: - "@jest/core" "^27.5.1" + "@jest/core" "^28.1.2" + "@jest/types" "^28.1.1" import-local "^3.0.2" - jest-cli "^27.5.1" + jest-cli "^28.1.2" js-base64@^2.1.9: version "2.6.4" @@ -7582,23 +7489,23 @@ jsdoc@~3.6.7: taffydb "2.6.2" underscore "~1.13.1" -jsdom@^16.6.0: - version "16.7.0" - resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-16.7.0.tgz#918ae71965424b197c819f8183a754e18977b710" - integrity sha512-u9Smc2G1USStM+s/x1ru5Sxrl6mPYCbByG1U/hUmqaVsm4tbNyS7CicOSRyuGQYZhTu0h84qkZZQ/I+dzizSVw== +jsdom@^19.0.0: + version "19.0.0" + resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-19.0.0.tgz#93e67c149fe26816d38a849ea30ac93677e16b6a" + integrity sha512-RYAyjCbxy/vri/CfnjUWJQQtZ3LKlLnDqj+9XLNnJPgEGeirZs3hllKR20re8LUZ6o1b1X4Jat+Qd26zmP41+A== dependencies: abab "^2.0.5" - acorn "^8.2.4" + acorn "^8.5.0" acorn-globals "^6.0.0" - cssom "^0.4.4" + cssom "^0.5.0" cssstyle "^2.3.0" - data-urls "^2.0.0" - decimal.js "^10.2.1" - domexception "^2.0.1" + data-urls "^3.0.1" + decimal.js "^10.3.1" + domexception "^4.0.0" escodegen "^2.0.0" - form-data "^3.0.0" - html-encoding-sniffer "^2.0.1" - http-proxy-agent "^4.0.1" + form-data "^4.0.0" + html-encoding-sniffer "^3.0.0" + http-proxy-agent "^5.0.0" https-proxy-agent "^5.0.0" is-potential-custom-element-name "^1.0.1" nwsapi "^2.2.0" @@ -7607,13 +7514,13 @@ jsdom@^16.6.0: symbol-tree "^3.2.4" tough-cookie "^4.0.0" w3c-hr-time "^1.0.2" - w3c-xmlserializer "^2.0.0" - webidl-conversions "^6.1.0" - whatwg-encoding "^1.0.5" - whatwg-mimetype "^2.3.0" - whatwg-url "^8.5.0" - ws "^7.4.6" - xml-name-validator "^3.0.0" + w3c-xmlserializer "^3.0.0" + webidl-conversions "^7.0.0" + whatwg-encoding "^2.0.0" + whatwg-mimetype "^3.0.0" + whatwg-url "^10.0.0" + ws "^8.2.3" + xml-name-validator "^4.0.0" jsesc@^2.5.1: version "2.5.2" @@ -7668,13 +7575,6 @@ json-stable-stringify@^1.0.1: dependencies: jsonify "~0.0.0" -json5@2.x: - version "2.2.0" - resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.0.tgz#2dfefe720c6ba525d9ebd909950f0515316c89a3" - integrity sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA== - dependencies: - minimist "^1.2.5" - json5@^0.5.0: version "0.5.1" resolved "https://registry.yarnpkg.com/json5/-/json5-0.5.1.tgz#1eade7acc012034ad84e2396767ead9fa5495821" @@ -9445,6 +9345,16 @@ pretty-format@^27.0.0, pretty-format@^27.0.2, pretty-format@^27.5.1: ansi-styles "^5.0.0" react-is "^17.0.1" +pretty-format@^28.0.0, pretty-format@^28.1.1: + version "28.1.1" + resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-28.1.1.tgz#f731530394e0f7fcd95aba6b43c50e02d86b95cb" + integrity sha512-wwJbVTGFHeucr5Jw2bQ9P+VYHyLdAqedFLEkdQUVaBF/eiidDwH5OpilINq4mEfhbCjLnirt6HTTDhv1HaTIQw== + dependencies: + "@jest/schemas" "^28.0.2" + ansi-regex "^5.0.1" + ansi-styles "^5.0.0" + react-is "^18.0.0" + prettyjson@^1.2.1: version "1.2.5" resolved "https://registry.yarnpkg.com/prettyjson/-/prettyjson-1.2.5.tgz#ef3cfffcc70505c032abc59785884b4027031835" @@ -9501,6 +9411,11 @@ proxy-addr@~2.0.7: forwarded "0.2.0" ipaddr.js "1.9.1" +proxy-from-env@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz#e102f16ca355424865755d2c9e8ea4f24d58c3e2" + integrity sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg== + psl@^1.1.33: version "1.8.0" resolved "https://registry.yarnpkg.com/psl/-/psl-1.8.0.tgz#9326f8bcfb013adcc005fdff056acce020e51c24" @@ -9727,6 +9642,11 @@ react-is@^17.0.1: resolved "https://registry.yarnpkg.com/react-is/-/react-is-17.0.2.tgz#e691d4a8e9c789365655539ab372762b0efb54f0" integrity sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w== +react-is@^18.0.0: + version "18.2.0" + resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.2.0.tgz#199431eeaaa2e09f86427efbb4f1473edb47609b" + integrity sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w== + react-lifecycles-compat@^3.0.4: version "3.0.4" resolved "https://registry.yarnpkg.com/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz#4f1a273afdfc8f3488a8c516bfda78f872352362" @@ -9811,6 +9731,14 @@ react-router-dom@^5.3.0: tiny-invariant "^1.0.2" tiny-warning "^1.0.0" +react-router-scroll-4@^1.0.0-beta.2: + version "1.0.0-beta.2" + resolved "https://registry.yarnpkg.com/react-router-scroll-4/-/react-router-scroll-4-1.0.0-beta.2.tgz#d887063ec0f66124aaf450158dd158ff7d3dc279" + integrity sha512-K67Dnm75naSBs/WYc2CDNxqU+eE8iA3I0wSCArgGSHb0xR/7AUcgUEXtCxrQYVTogXvjVK60gmwYvOyRQ6fuBA== + dependencies: + scroll-behavior "^0.9.1" + warning "^3.0.0" + react-router@5.2.1: version "5.2.1" resolved "https://registry.yarnpkg.com/react-router/-/react-router-5.2.1.tgz#4d2e4e9d5ae9425091845b8dbc6d9d276239774d" @@ -10014,13 +9942,6 @@ redux-immutable@^4.0.0: resolved "https://registry.yarnpkg.com/redux-immutable/-/redux-immutable-4.0.0.tgz#3a1a32df66366462b63691f0e1dc35e472bbc9f3" integrity sha1-Ohoy32Y2ZGK2NpHw4dw15HK7yfM= -redux-mock-store@^1.5.4: - version "1.5.4" - resolved "https://registry.yarnpkg.com/redux-mock-store/-/redux-mock-store-1.5.4.tgz#90d02495fd918ddbaa96b83aef626287c9ab5872" - integrity sha512-xmcA0O/tjCLXhh9Fuiq6pMrJCwFRaouA8436zcikdIpYWWCjU76CRk+i2bHx8EeiSiMGnB85/lZdU3wIJVXHTA== - dependencies: - lodash.isplainobject "^4.0.6" - redux-thunk@^2.2.0: version "2.3.0" resolved "https://registry.yarnpkg.com/redux-thunk/-/redux-thunk-2.3.0.tgz#51c2c19a185ed5187aaa9a2d08b666d0d6467622" @@ -10364,7 +10285,7 @@ safe-buffer@5.2.1, safe-buffer@>=5.1.0, safe-buffer@^5.0.1, safe-buffer@^5.1.0, resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== -"safer-buffer@>= 2.1.2 < 3": +"safer-buffer@>= 2.1.2 < 3", "safer-buffer@>= 2.1.2 < 3.0.0": version "2.1.2" resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== @@ -10427,6 +10348,14 @@ schema-utils@^4.0.0: ajv-formats "^2.1.1" ajv-keywords "^5.0.0" +scroll-behavior@^0.9.1: + version "0.9.12" + resolved "https://registry.yarnpkg.com/scroll-behavior/-/scroll-behavior-0.9.12.tgz#1c22d273ec4ce6cd4714a443fead50227da9424c" + integrity sha512-18sirtyq1P/VsBX6O/vgw20Np+ngduFXEMO4/NDFXabdOKBL2kjPVUpz1y0+jm99EWwFJafxf5/tCyMeXt9Xyg== + dependencies: + dom-helpers "^3.4.0" + invariant "^2.2.4" + select-hose@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/select-hose/-/select-hose-2.0.0.tgz#625d8658f865af43ec962bfc376a37359a4994ca" @@ -10639,7 +10568,15 @@ source-map-resolve@^0.6.0: atob "^2.1.2" decode-uri-component "^0.2.0" -source-map-support@^0.5.20, source-map-support@^0.5.6, source-map-support@~0.5.20: +source-map-support@0.5.13: + version "0.5.13" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.13.tgz#31b24a9c2e73c2de85066c0feb7d44767ed52932" + integrity sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w== + dependencies: + buffer-from "^1.0.0" + source-map "^0.6.0" + +source-map-support@^0.5.20, source-map-support@~0.5.20: version "0.5.20" resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.20.tgz#12166089f8f5e5e8c56926b377633392dd2cb6c9" integrity sha512-n1lZZ8Ve4ksRqizaBQgxXDgKwttHDhyfQjA6YZZn8+AroHbsIz+JjwxQDxbp+7y5OYCI8t1Yk7etjD9CRd2hIw== @@ -10657,7 +10594,7 @@ source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.0, source-map@~0.6.1: resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== -source-map@^0.7.3, source-map@~0.7.2: +source-map@~0.7.2: version "0.7.3" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.7.3.tgz#5302f8169031735226544092e64981f751750383" integrity sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ== @@ -10776,6 +10713,15 @@ string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.2: is-fullwidth-code-point "^3.0.0" strip-ansi "^6.0.0" +string-width@^4.2.3: + version "4.2.3" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" + integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== + dependencies: + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.1" + string.prototype.matchall@^4.0.5: version "4.0.5" resolved "https://registry.yarnpkg.com/string.prototype.matchall/-/string.prototype.matchall-4.0.5.tgz#59370644e1db7e4c0c045277690cf7b01203c4da" @@ -11289,6 +11235,13 @@ tr46@^2.1.0: dependencies: punycode "^2.1.1" +tr46@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/tr46/-/tr46-3.0.0.tgz#555c4e297a950617e8eeddef633c87d4d9d6cbf9" + integrity sha512-l7FvfAHlcmulp8kr+flpQZmVwtu7nfRV7NZujtN0OqES8EL4O4e0qqzL0DC5gAvx/ZC/9lk6rhcUwYvkBnBnYA== + dependencies: + punycode "^2.1.1" + tr46@~0.0.3: version "0.0.3" resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a" @@ -11304,19 +11257,19 @@ trough@^1.0.0: resolved "https://registry.yarnpkg.com/trough/-/trough-1.0.5.tgz#b8b639cefad7d0bb2abd37d433ff8293efa5f406" integrity sha512-rvuRbTarPXmMb79SmzEp8aqXNKcK+y0XaB298IXueQ8I2PsrATcPBCSPyK/dDNa2iWOhKlfNnOjdAOTBU/nkFA== -ts-jest@^27.1.4: - version "27.1.4" - resolved "https://registry.yarnpkg.com/ts-jest/-/ts-jest-27.1.4.tgz#84d42cf0f4e7157a52e7c64b1492c46330943e00" - integrity sha512-qjkZlVPWVctAezwsOD1OPzbZ+k7zA5z3oxII4dGdZo5ggX/PL7kvwTM0pXTr10fAtbiVpJaL3bWd502zAhpgSQ== +ts-jest@^28.0.5: + version "28.0.5" + resolved "https://registry.yarnpkg.com/ts-jest/-/ts-jest-28.0.5.tgz#31776f768fba6dfc8c061d488840ed0c8eeac8b9" + integrity sha512-Sx9FyP9pCY7pUzQpy4FgRZf2bhHY3za576HMKJFs+OnQ9jS96Du5vNsDKkyedQkik+sEabbKAnCliv9BEsHZgQ== dependencies: bs-logger "0.x" fast-json-stable-stringify "2.x" - jest-util "^27.0.0" - json5 "2.x" + jest-util "^28.0.0" + json5 "^2.2.1" lodash.memoize "4.x" make-error "1.x" semver "7.x" - yargs-parser "20.x" + yargs-parser "^21.0.1" ts-loader@^9.3.0: version "9.3.0" @@ -11640,14 +11593,14 @@ v8-compile-cache@^2.0.3, v8-compile-cache@^2.3.0: resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz#2de19618c66dc247dcfb6f99338035d8245a2cee" integrity sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA== -v8-to-istanbul@^8.1.0: - version "8.1.1" - resolved "https://registry.yarnpkg.com/v8-to-istanbul/-/v8-to-istanbul-8.1.1.tgz#77b752fd3975e31bbcef938f85e9bd1c7a8d60ed" - integrity sha512-FGtKtv3xIpR6BYhvgH8MI/y78oT7d8Au3ww4QIxymrCtZEh5b8gCw2siywE+puhEmuWKDtmfrvF5UlB298ut3w== +v8-to-istanbul@^9.0.1: + version "9.0.1" + resolved "https://registry.yarnpkg.com/v8-to-istanbul/-/v8-to-istanbul-9.0.1.tgz#b6f994b0b5d4ef255e17a0d17dc444a9f5132fa4" + integrity sha512-74Y4LqY74kLE6IFyIjPtkSTWzUZmj8tdHT9Ii/26dvQ6K9Dl2NbEfj0XgU2sHCtKgt5VupqhlO/5aWuqS+IY1w== dependencies: + "@jridgewell/trace-mapping" "^0.3.12" "@types/istanbul-lib-coverage" "^2.0.1" convert-source-map "^1.6.0" - source-map "^0.7.3" validate-npm-package-license@^3.0.1: version "3.0.4" @@ -11692,14 +11645,14 @@ w3c-hr-time@^1.0.2: dependencies: browser-process-hrtime "^1.0.0" -w3c-xmlserializer@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/w3c-xmlserializer/-/w3c-xmlserializer-2.0.0.tgz#3e7104a05b75146cc60f564380b7f683acf1020a" - integrity sha512-4tzD0mF8iSiMiNs30BiLO3EpfGLZUT2MSX/G+o7ZywDzliWQ3OPtTZ0PTC3B3ca1UAf4cJMHB+2Bf56EriJuRA== +w3c-xmlserializer@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/w3c-xmlserializer/-/w3c-xmlserializer-3.0.0.tgz#06cdc3eefb7e4d0b20a560a5a3aeb0d2d9a65923" + integrity sha512-3WFqGEgSXIyGhOmAFtlicJNMjEps8b1MG31NCA0/vOF9+nKMUW1ckhi9cnNHmf88Rzw5V+dwIwsm2C7X8k9aQg== dependencies: - xml-name-validator "^3.0.0" + xml-name-validator "^4.0.0" -walker@^1.0.7: +walker@^1.0.8: version "1.0.8" resolved "https://registry.yarnpkg.com/walker/-/walker-1.0.8.tgz#bd498db477afe573dc04185f011d3ab8a8d7653f" integrity sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ== @@ -11764,16 +11717,16 @@ webidl-conversions@^4.0.2: resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-4.0.2.tgz#a855980b1f0b6b359ba1d5d9fb39ae941faa63ad" integrity sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg== -webidl-conversions@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-5.0.0.tgz#ae59c8a00b121543a2acc65c0434f57b0fc11aff" - integrity sha512-VlZwKPCkYKxQgeSbH5EyngOmRp7Ww7I9rQLERETtf5ofd9pGeswWiOtogpEO850jziPRarreGxn5QIiTqpb2wA== - webidl-conversions@^6.1.0: version "6.1.0" resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-6.1.0.tgz#9111b4d7ea80acd40f5270d666621afa78b69514" integrity sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w== +webidl-conversions@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-7.0.0.tgz#256b4e1882be7debbf01d05f0aa2039778ea080a" + integrity sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g== + webpack-assets-manifest@^5.1.0: version "5.1.0" resolved "https://registry.yarnpkg.com/webpack-assets-manifest/-/webpack-assets-manifest-5.1.0.tgz#5af328f6c8fa760cb9a62af631a83da2b478b791" @@ -11930,17 +11883,33 @@ websocket-extensions@>=0.1.1: resolved "https://registry.yarnpkg.com/websocket-extensions/-/websocket-extensions-0.1.4.tgz#7f8473bc839dfd87608adb95d7eb075211578a42" integrity sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg== -whatwg-encoding@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz#5abacf777c32166a51d085d6b4f3e7d27113ddb0" - integrity sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw== +whatwg-encoding@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/whatwg-encoding/-/whatwg-encoding-2.0.0.tgz#e7635f597fd87020858626805a2729fa7698ac53" + integrity sha512-p41ogyeMUrw3jWclHWTQg1k05DSVXPLcVxRTYsXUk+ZooOCZLcoYgPZ/HL/D/N+uQPOtcp1me1WhBEaX02mhWg== dependencies: - iconv-lite "0.4.24" + iconv-lite "0.6.3" -whatwg-mimetype@^2.3.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz#3d4b1e0312d2079879f826aff18dbeeca5960fbf" - integrity sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g== +whatwg-mimetype@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/whatwg-mimetype/-/whatwg-mimetype-3.0.0.tgz#5fa1a7623867ff1af6ca3dc72ad6b8a4208beba7" + integrity sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q== + +whatwg-url@^10.0.0: + version "10.0.0" + resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-10.0.0.tgz#37264f720b575b4a311bd4094ed8c760caaa05da" + integrity sha512-CLxxCmdUby142H5FZzn4D8ikO1cmypvXVQktsgosNy4a4BHrDHeciBBGZhb0bNoR5/MltoCatso+vFjjGx8t0w== + dependencies: + tr46 "^3.0.0" + webidl-conversions "^7.0.0" + +whatwg-url@^11.0.0: + version "11.0.0" + resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-11.0.0.tgz#0a849eebb5faf2119b901bb76fd795c2848d4018" + integrity sha512-RKT8HExMpoYx4igMiVMY83lN6UeITKJlBQ+vR/8ZJ8OCdSiN3RwCq+9gH0+Xzj0+5IrM6i4j/6LuvzbZIQgEcQ== + dependencies: + tr46 "^3.0.0" + webidl-conversions "^7.0.0" whatwg-url@^5.0.0: version "5.0.0" @@ -11959,7 +11928,7 @@ whatwg-url@^7.0.0: tr46 "^1.0.1" webidl-conversions "^4.0.2" -whatwg-url@^8.0.0, whatwg-url@^8.4.0, whatwg-url@^8.5.0: +whatwg-url@^8.4.0: version "8.7.0" resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-8.7.0.tgz#656a78e510ff8f3937bc0bcbe9f5c0ac35941b77" integrity sha512-gAojqb/m9Q8a5IV96E3fHJM70AzCkgt4uXYX2O7EmuyOnLrViCQlsEBmF9UQIu3/aeAIp2U17rtbpZWNntQqdg== @@ -12043,7 +12012,7 @@ wrappy@1: resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= -write-file-atomic@^3.0.0, write-file-atomic@^3.0.3: +write-file-atomic@^3.0.3: version "3.0.3" resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-3.0.3.tgz#56bd5c5a5c70481cd19c571bd39ab965a5de56e8" integrity sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q== @@ -12061,20 +12030,25 @@ write-file-atomic@^4.0.1: imurmurhash "^0.1.4" signal-exit "^3.0.7" -ws@^7.3.1, ws@^7.4.6: +ws@^7.3.1: version "7.5.5" resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.5.tgz#8b4bc4af518cfabd0473ae4f99144287b33eb881" integrity sha512-BAkMFcAzl8as1G/hArkxOxq3G7pjUqQ3gzYbLL0/5zNkph70e+lCoxBGnm6AW1+/aiNeV4fnKqZ8m4GZewmH2w== +ws@^8.2.3: + version "8.8.0" + resolved "https://registry.yarnpkg.com/ws/-/ws-8.8.0.tgz#8e71c75e2f6348dbf8d78005107297056cb77769" + integrity sha512-JDAgSYQ1ksuwqfChJusw1LSJ8BizJ2e/vVu5Lxjq3YvNJNlROv1ui4i+c/kUUrPheBvQl4c5UbERhTwKa6QBJQ== + ws@^8.4.2: version "8.7.0" resolved "https://registry.yarnpkg.com/ws/-/ws-8.7.0.tgz#eaf9d874b433aa00c0e0d8752532444875db3957" integrity sha512-c2gsP0PRwcLFzUiA8Mkr37/MI7ilIlHQxaEAtd0uNMbVMoy8puJyafRlm0bV9MbGSabUPeLrRRaqIBcFcA2Pqg== -xml-name-validator@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/xml-name-validator/-/xml-name-validator-3.0.0.tgz#6ae73e06de4d8c6e47f9fb181f78d648ad457c6a" - integrity sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw== +xml-name-validator@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/xml-name-validator/-/xml-name-validator-4.0.0.tgz#79a006e2e63149a8600f15430f0a4725d1524835" + integrity sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw== xml@^1.0.1: version "1.0.1" @@ -12111,12 +12085,17 @@ yaml@^1.10.0, yaml@^1.10.2: resolved "https://registry.yarnpkg.com/yaml/-/yaml-1.10.2.tgz#2301c5ffbf12b467de8da2333a459e29e7920e4b" integrity sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg== -yargs-parser@20.x, yargs-parser@^20.2.2, yargs-parser@^20.2.3: +yargs-parser@^20.2.2, yargs-parser@^20.2.3: version "20.2.9" resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.9.tgz#2eb7dc3b0289718fc295f362753845c41a0c94ee" integrity sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w== -yargs@^16.0.3, yargs@^16.2.0: +yargs-parser@^21.0.0, yargs-parser@^21.0.1: + version "21.0.1" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-21.0.1.tgz#0267f286c877a4f0f728fceb6f8a3e4cb95c6e35" + integrity sha512-9BK1jFpLzJROCI5TzwZL/TU4gqjK5xiHV/RfWLOahrjAko/e4DJkRDZQXfvqAsiZzzYhgAzbgz6lg48jcm4GLg== + +yargs@^16.0.3: version "16.2.0" resolved "https://registry.yarnpkg.com/yargs/-/yargs-16.2.0.tgz#1c82bf0f6b6a66eafce7ef30e376f49a12477f66" integrity sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw== @@ -12129,6 +12108,19 @@ yargs@^16.0.3, yargs@^16.2.0: y18n "^5.0.5" yargs-parser "^20.2.2" +yargs@^17.3.1: + version "17.5.1" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.5.1.tgz#e109900cab6fcb7fd44b1d8249166feb0b36e58e" + integrity sha512-t6YAJcxDkNX7NFYiVtKvWUz8l+PaKTLiL63mJYWR2GnHq2gjEWISzsLp9wg3aY36dY1j+gfIEL3pIF+XlJJfbA== + dependencies: + cliui "^7.0.2" + escalade "^3.1.1" + get-caller-file "^2.0.5" + require-directory "^2.1.1" + string-width "^4.2.3" + y18n "^5.0.5" + yargs-parser "^21.0.0" + yocto-queue@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b"