diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index f2f769441..8443f91d1 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -3,12 +3,13 @@ image: node:18 variables: NODE_ENV: test -cache: +cache: &cache key: files: - yarn.lock paths: - node_modules/ + policy: pull stages: - deps @@ -21,6 +22,16 @@ deps: only: changes: - yarn.lock + cache: + <<: *cache + policy: push + +danger: + stage: test + script: + # https://github.com/danger/danger-js/issues/1029#issuecomment-998915436 + - export CI_MERGE_REQUEST_IID=${CI_OPEN_MERGE_REQUESTS#*!} + - npx danger ci lint-js: stage: test diff --git a/app/soapbox/actions/__tests__/accounts.test.ts b/app/soapbox/actions/__tests__/accounts.test.ts index b02469527..2ea60bd80 100644 --- a/app/soapbox/actions/__tests__/accounts.test.ts +++ b/app/soapbox/actions/__tests__/accounts.test.ts @@ -435,10 +435,14 @@ describe('followAccount()', () => { skipLoading: true, }, ]; - await store.dispatch(followAccount(id)); - const actions = store.getActions(); - expect(actions).toEqual(expectedActions); + try { + await store.dispatch(followAccount(id)); + } catch (e) { + const actions = store.getActions(); + expect(actions).toEqual(expectedActions); + expect(e).toEqual(new Error('Network Error')); + } }); }); }); diff --git a/app/soapbox/actions/accounts.js b/app/soapbox/actions/accounts.js index 5cc0008a4..63314a6b1 100644 --- a/app/soapbox/actions/accounts.js +++ b/app/soapbox/actions/accounts.js @@ -240,7 +240,10 @@ export function followAccount(id, options = { reblogs: true }) { return api(getState) .post(`/api/v1/accounts/${id}/follow`, options) .then(response => dispatch(followAccountSuccess(response.data, alreadyFollowing))) - .catch(error => dispatch(followAccountFail(error, locked))); + .catch(error => { + dispatch(followAccountFail(error, locked)); + throw error; + }); }; } diff --git a/app/soapbox/actions/compose.js b/app/soapbox/actions/compose.js index fe54c843e..c42176fa2 100644 --- a/app/soapbox/actions/compose.js +++ b/app/soapbox/actions/compose.js @@ -1,6 +1,6 @@ import { CancelToken, isCancel } from 'axios'; import { OrderedSet as ImmutableOrderedSet } from 'immutable'; -import { throttle } from 'lodash'; +import throttle from 'lodash/throttle'; import { defineMessages } from 'react-intl'; import snackbar from 'soapbox/actions/snackbar'; diff --git a/app/soapbox/actions/instance.ts b/app/soapbox/actions/instance.ts index cabccdd33..60a6b2e89 100644 --- a/app/soapbox/actions/instance.ts +++ b/app/soapbox/actions/instance.ts @@ -1,5 +1,5 @@ import { createAsyncThunk } from '@reduxjs/toolkit'; -import { get } from 'lodash'; +import get from 'lodash/get'; import KVStore from 'soapbox/storage/kv_store'; import { RootState } from 'soapbox/store'; diff --git a/app/soapbox/actions/preload.js b/app/soapbox/actions/preload.js index d14c6f9fe..abde36da6 100644 --- a/app/soapbox/actions/preload.js +++ b/app/soapbox/actions/preload.js @@ -1,4 +1,4 @@ -import { mapValues } from 'lodash'; +import mapValues from 'lodash/mapValues'; import { verifyCredentials } from './auth'; import { importFetchedAccounts } from './importer'; diff --git a/app/soapbox/build_config.js b/app/soapbox/build_config.js index 6ddb309cb..04b48bf78 100644 --- a/app/soapbox/build_config.js +++ b/app/soapbox/build_config.js @@ -4,7 +4,8 @@ * @module soapbox/build_config */ -const { trim, trimEnd } = require('lodash'); +const trim = require('lodash/trim'); +const trimEnd = require('lodash/trimEnd'); const { NODE_ENV, diff --git a/app/soapbox/components/autosuggest_account_input.tsx b/app/soapbox/components/autosuggest_account_input.tsx index e103d7722..79d247fd9 100644 --- a/app/soapbox/components/autosuggest_account_input.tsx +++ b/app/soapbox/components/autosuggest_account_input.tsx @@ -1,5 +1,5 @@ import { OrderedSet as ImmutableOrderedSet } from 'immutable'; -import { throttle } from 'lodash'; +import throttle from 'lodash/throttle'; import React, { useState, useRef, useCallback, useEffect } from 'react'; import { accountSearch } from 'soapbox/actions/accounts'; diff --git a/app/soapbox/components/filter_bar.js b/app/soapbox/components/filter_bar.js index 46a7dc748..7b0651d01 100644 --- a/app/soapbox/components/filter_bar.js +++ b/app/soapbox/components/filter_bar.js @@ -1,5 +1,5 @@ import classNames from 'classnames'; -import { debounce } from 'lodash'; +import debounce from 'lodash/debounce'; import PropTypes from 'prop-types'; import React from 'react'; import { withRouter } from 'react-router-dom'; diff --git a/app/soapbox/components/hover_ref_wrapper.tsx b/app/soapbox/components/hover_ref_wrapper.tsx index 2ef2d8372..bf4e253f2 100644 --- a/app/soapbox/components/hover_ref_wrapper.tsx +++ b/app/soapbox/components/hover_ref_wrapper.tsx @@ -1,5 +1,5 @@ import classNames from 'classnames'; -import { debounce } from 'lodash'; +import debounce from 'lodash/debounce'; import React, { useRef } from 'react'; import { useDispatch } from 'react-redux'; diff --git a/app/soapbox/components/scroll-top-button.tsx b/app/soapbox/components/scroll-top-button.tsx index 5de90abb6..f68a22d3f 100644 --- a/app/soapbox/components/scroll-top-button.tsx +++ b/app/soapbox/components/scroll-top-button.tsx @@ -1,5 +1,5 @@ import classNames from 'classnames'; -import { throttle } from 'lodash'; +import throttle from 'lodash/throttle'; import React, { useState, useEffect, useCallback } from 'react'; import { useIntl, MessageDescriptor } from 'react-intl'; diff --git a/app/soapbox/components/scrollable_list.tsx b/app/soapbox/components/scrollable_list.tsx index 8b803be66..31b892e6d 100644 --- a/app/soapbox/components/scrollable_list.tsx +++ b/app/soapbox/components/scrollable_list.tsx @@ -1,4 +1,4 @@ -import { debounce } from 'lodash'; +import debounce from 'lodash/debounce'; import React, { useEffect, useRef, useMemo, useCallback } from 'react'; import { useHistory } from 'react-router-dom'; import { Virtuoso, Components, VirtuosoProps, VirtuosoHandle, ListRange, IndexLocationWithAlign } from 'react-virtuoso'; diff --git a/app/soapbox/components/status_list.tsx b/app/soapbox/components/status_list.tsx index 37e37f59d..6eac9c7b2 100644 --- a/app/soapbox/components/status_list.tsx +++ b/app/soapbox/components/status_list.tsx @@ -1,5 +1,5 @@ import classNames from 'classnames'; -import { debounce } from 'lodash'; +import debounce from 'lodash/debounce'; import React, { useRef, useCallback } from 'react'; import { FormattedMessage } from 'react-intl'; diff --git a/app/soapbox/components/sub_navigation.js b/app/soapbox/components/sub_navigation.js index 0d24dfffb..f75ca802f 100644 --- a/app/soapbox/components/sub_navigation.js +++ b/app/soapbox/components/sub_navigation.js @@ -1,4 +1,4 @@ -import { throttle } from 'lodash'; +import throttle from 'lodash/throttle'; import PropTypes from 'prop-types'; import React from 'react'; import { injectIntl, defineMessages } from 'react-intl'; diff --git a/app/soapbox/features/account/components/header.js b/app/soapbox/features/account/components/header.js index b76a156a5..c7da47cf1 100644 --- a/app/soapbox/features/account/components/header.js +++ b/app/soapbox/features/account/components/header.js @@ -1,7 +1,7 @@ 'use strict'; import { List as ImmutableList, Map as ImmutableMap } from 'immutable'; -import { debounce } from 'lodash'; +import debounce from 'lodash/debounce'; import PropTypes from 'prop-types'; import React from 'react'; import ImmutablePropTypes from 'react-immutable-proptypes'; @@ -17,6 +17,7 @@ import StillImage from 'soapbox/components/still_image'; import { HStack, IconButton, Menu, MenuButton, MenuItem, MenuList, MenuLink, MenuDivider } from 'soapbox/components/ui'; import SvgIcon from 'soapbox/components/ui/icon/svg-icon'; import ActionButton from 'soapbox/features/ui/components/action-button'; +import SubscriptionButton from 'soapbox/features/ui/components/subscription-button'; import { isLocal, isRemote, @@ -61,8 +62,6 @@ const messages = defineMessages({ promoteToModerator: { id: 'admin.users.actions.promote_to_moderator', defaultMessage: 'Promote @{name} to a moderator' }, demoteToModerator: { id: 'admin.users.actions.demote_to_moderator', defaultMessage: 'Demote @{name} to a moderator' }, demoteToUser: { id: 'admin.users.actions.demote_to_user', defaultMessage: 'Demote @{name} to a regular user' }, - subscribe: { id: 'account.subscribe', defaultMessage: 'Subscribe to notifications from @{name}' }, - unsubscribe: { id: 'account.unsubscribe', defaultMessage: 'Unsubscribe to notifications from @{name}' }, suggestUser: { id: 'admin.users.actions.suggest_user', defaultMessage: 'Suggest @{name}' }, unsuggestUser: { id: 'admin.users.actions.unsuggest_user', defaultMessage: 'Unsuggest @{name}' }, }); @@ -250,22 +249,6 @@ class Header extends ImmutablePureComponent { }); } - if (features.accountSubscriptions) { - if (account.relationship?.subscribing) { - menu.push({ - text: intl.formatMessage(messages.unsubscribe, { name: account.get('username') }), - action: this.props.onSubscriptionToggle, - icon: require('@tabler/icons/icons/bell.svg'), - }); - } else { - menu.push({ - text: intl.formatMessage(messages.subscribe, { name: account.get('username') }), - action: this.props.onSubscriptionToggle, - icon: require('@tabler/icons/icons/bell-off.svg'), - }); - } - } - if (features.lists) { menu.push({ text: intl.formatMessage(messages.add_or_remove_from_list), @@ -476,7 +459,7 @@ class Header extends ImmutablePureComponent { } + title={} />, ); } @@ -578,11 +561,6 @@ class Header extends ImmutablePureComponent { const menu = this.makeMenu(); const header = account.get('header', ''); - // NOTE: Removing Subscription element - // {features.accountSubscriptions &&