diff --git a/examples/getstarted/api/restaurant/models/Restaurant.settings.json b/examples/getstarted/api/restaurant/models/Restaurant.settings.json index 26ba49bf47..78eac44d6f 100755 --- a/examples/getstarted/api/restaurant/models/Restaurant.settings.json +++ b/examples/getstarted/api/restaurant/models/Restaurant.settings.json @@ -125,6 +125,7 @@ "component": "default.restaurantservice", "repeatable": true, "type": "component", + "max": 1, "pluginOptions": { "i18n": { "localized": true diff --git a/packages/core/admin/admin/src/StrapiApp.js b/packages/core/admin/admin/src/StrapiApp.js index 99f6a2e7e5..2e92a79eb6 100644 --- a/packages/core/admin/admin/src/StrapiApp.js +++ b/packages/core/admin/admin/src/StrapiApp.js @@ -152,14 +152,16 @@ class StrapiApp { - <> - - - - - - - + + <> + + + + + + + + diff --git a/packages/core/admin/admin/src/components/LeftMenu/useMenuSections.js b/packages/core/admin/admin/src/components/LeftMenu/useMenuSections.js index 69d679d491..583304332c 100644 --- a/packages/core/admin/admin/src/components/LeftMenu/useMenuSections.js +++ b/packages/core/admin/admin/src/components/LeftMenu/useMenuSections.js @@ -1,6 +1,7 @@ import { useEffect, useRef } from 'react'; -import { useUser } from '@strapi/helper-plugin'; +import { useUser, useNotification } from '@strapi/helper-plugin'; import { useSelector, useDispatch } from 'react-redux'; + import getCtOrStLinks from './utils/getCtOrStLinks'; import getPluginSectionLinks from './utils/getPluginSectionLinks'; import getGeneralLinks from './utils/getGeneralLinks'; @@ -10,6 +11,7 @@ import toPluginLinks from './utils/toPluginLinks'; import selectMenuLinks from './selectors'; const useMenuSections = (plugins, shouldUpdateStrapi) => { + const toggleNotification = useNotification(); const state = useSelector(selectMenuLinks); const dispatch = useDispatch(); const { userPermissions } = useUser(); @@ -30,7 +32,8 @@ const useMenuSections = (plugins, shouldUpdateStrapi) => { const resolvePermissions = async (permissions = userPermissions) => { const pluginsSectionLinks = toPluginLinks(pluginsRef.current); const { authorizedCtLinks, authorizedStLinks, contentTypes } = await getCtOrStLinks( - permissions + permissions, + toggleNotification ); const authorizedPluginSectionLinks = await getPluginSectionLinks( diff --git a/packages/core/admin/admin/src/components/LeftMenu/utils/getCtOrStLinks.js b/packages/core/admin/admin/src/components/LeftMenu/utils/getCtOrStLinks.js index 30dfa6b436..875471c89d 100644 --- a/packages/core/admin/admin/src/components/LeftMenu/utils/getCtOrStLinks.js +++ b/packages/core/admin/admin/src/components/LeftMenu/utils/getCtOrStLinks.js @@ -2,7 +2,7 @@ import { request } from '@strapi/helper-plugin'; import generateModelsLinks from './generateModelsLinks'; import checkPermissions from './checkPermissions'; -const getCtOrStLinks = async userPermissions => { +const getCtOrStLinks = async (userPermissions, toggleNotification) => { const requestURL = '/content-manager/content-types'; try { @@ -37,7 +37,7 @@ const getCtOrStLinks = async userPermissions => { } catch (err) { console.error(err); - strapi.notification.toggle({ + toggleNotification({ type: 'warning', message: { id: 'notification.error' }, }); diff --git a/packages/core/admin/admin/src/components/LeftMenu/utils/tests/getCtOrStLinks.test.js b/packages/core/admin/admin/src/components/LeftMenu/utils/tests/getCtOrStLinks.test.js index 24679ed151..e4ea836b2e 100644 --- a/packages/core/admin/admin/src/components/LeftMenu/utils/tests/getCtOrStLinks.test.js +++ b/packages/core/admin/admin/src/components/LeftMenu/utils/tests/getCtOrStLinks.test.js @@ -135,14 +135,14 @@ describe('checkPermissions', () => { it('creates an array of boolean corresponding to the permission state', async () => { console.error = () => undefined; - strapi.notification.toggle = jest.fn(); + const toggleNotification = jest.fn(); const userPermissions = []; request.mockImplementation(() => { throw new Error('Something went wrong'); }); - await getCtOrStLinks(userPermissions); - expect(strapi.notification.toggle).toBeCalled(); + await getCtOrStLinks(userPermissions, toggleNotification); + expect(toggleNotification).toBeCalled(); }); }); diff --git a/packages/core/admin/admin/src/components/Notifications/index.js b/packages/core/admin/admin/src/components/Notifications/index.js index b900ff9c65..ffc7e01ee3 100644 --- a/packages/core/admin/admin/src/components/Notifications/index.js +++ b/packages/core/admin/admin/src/components/Notifications/index.js @@ -1,11 +1,13 @@ -import React, { useEffect, useReducer } from 'react'; +import { NotificationsProvider } from '@strapi/helper-plugin'; +import React, { useReducer } from 'react'; +import PropTypes from 'prop-types'; import { CSSTransition } from 'react-transition-group'; import Notification from './Notification'; import reducer, { initialState } from './reducer'; import NotificationsWrapper from './Wrapper'; -const Notifications = () => { +const Notifications = ({ children }) => { const [{ notifications }, dispatch] = useReducer(reducer, initialState); const displayNotification = config => { @@ -15,32 +17,29 @@ const Notifications = () => { }); }; - useEffect(() => { - window.strapi = Object.assign(window.strapi || {}, { - notification: { - toggle: config => { - displayNotification(config); - }, - }, - }); - }, []); - return ( - - {notifications.map(notification => ( - - - - ))} - + + + {notifications.map(notification => ( + + + + ))} + + {children} + ); }; +Notifications.propTypes = { + children: PropTypes.element.isRequired, +}; + export default Notifications; diff --git a/packages/core/admin/admin/src/components/Users/LinkNotification/index.js b/packages/core/admin/admin/src/components/Users/LinkNotification/index.js index 9a3f5b8b65..91e6b60cc5 100644 --- a/packages/core/admin/admin/src/components/Users/LinkNotification/index.js +++ b/packages/core/admin/admin/src/components/Users/LinkNotification/index.js @@ -1,6 +1,7 @@ // This component is a work in progress // It's made to be used when the users API is ready import React from 'react'; +import { useNotification } from '@strapi/helper-plugin'; import { Flex, Text } from '@buffetjs/core'; import { Duplicate } from '@buffetjs/icons'; import PropTypes from 'prop-types'; @@ -10,8 +11,10 @@ import Envelope from './Envelope'; import Wrapper from './Wrapper'; const LinkNotification = ({ target, children }) => { + const toggleNotification = useNotification(); + const handleCopy = () => { - strapi.notification.toggle({ type: 'info', message: { id: 'notification.link-copied' } }); + toggleNotification({ type: 'info', message: { id: 'notification.link-copied' } }); }; return ( diff --git a/packages/core/admin/admin/src/components/Users/ModalCreateBody/index.js b/packages/core/admin/admin/src/components/Users/ModalCreateBody/index.js index 19807166bf..540c74840f 100644 --- a/packages/core/admin/admin/src/components/Users/ModalCreateBody/index.js +++ b/packages/core/admin/admin/src/components/Users/ModalCreateBody/index.js @@ -1,6 +1,6 @@ import React, { forwardRef, useReducer, useImperativeHandle, useRef } from 'react'; import PropTypes from 'prop-types'; -import { BaselineAlignment, ModalSection, request } from '@strapi/helper-plugin'; +import { BaselineAlignment, ModalSection, request, useNotification } from '@strapi/helper-plugin'; import { useIntl } from 'react-intl'; import { get } from 'lodash'; import { Padded, Text } from '@buffetjs/core'; @@ -19,6 +19,7 @@ import RoleSettingsModalSection from '../RoleSettingsModalSection'; // This component accepts a ref so we can have access to the submit handler. const ModalCreateBody = forwardRef( ({ isDisabled, onSubmit, registrationToken, setIsSubmiting, showMagicLink }, ref) => { + const toggleNotification = useNotification(); const [reducerState, dispatch] = useReducer(reducer, initialState, init); const { formErrors, modifiedData } = reducerState; const buttonSubmitRef = useRef(null); @@ -62,7 +63,7 @@ const ModalCreateBody = forwardRef( } catch (err) { const message = get(err, ['response', 'payload', 'message'], 'An error occured'); - strapi.notification.toggle({ type: 'warning', message }); + toggleNotification({ type: 'warning', message }); } finally { strapi.unlockApp(); setIsSubmiting(false); diff --git a/packages/core/admin/admin/src/hooks/useFetchRole/index.js b/packages/core/admin/admin/src/hooks/useFetchRole/index.js index 94715af5be..92bf62c08c 100644 --- a/packages/core/admin/admin/src/hooks/useFetchRole/index.js +++ b/packages/core/admin/admin/src/hooks/useFetchRole/index.js @@ -1,8 +1,9 @@ import { useCallback, useReducer, useEffect } from 'react'; -import { request } from '@strapi/helper-plugin'; +import { request, useNotification } from '@strapi/helper-plugin'; import reducer, { initialState } from './reducer'; const useFetchRole = id => { + const toggleNotification = useNotification(); const [state, dispatch] = useReducer(reducer, initialState); useEffect(() => { @@ -38,7 +39,7 @@ const useFetchRole = id => { dispatch({ type: 'GET_DATA_ERROR', }); - strapi.notification.toggle({ + toggleNotification({ type: 'warning', message: { id: 'notification.error' }, }); diff --git a/packages/core/admin/admin/src/hooks/useModels/index.js b/packages/core/admin/admin/src/hooks/useModels/index.js index 4d18b3f9ea..88dfb4f452 100644 --- a/packages/core/admin/admin/src/hooks/useModels/index.js +++ b/packages/core/admin/admin/src/hooks/useModels/index.js @@ -1,13 +1,14 @@ import { useReducer, useEffect } from 'react'; -import { request } from '@strapi/helper-plugin'; - +import { request, useNotification } from '@strapi/helper-plugin'; import reducer, { initialState } from './reducer'; const useModels = () => { + const toggleNotification = useNotification(); const [state, dispatch] = useReducer(reducer, initialState); useEffect(() => { fetchModels(); + // eslint-disable-next-line react-hooks/exhaustive-deps }, []); const fetchModels = async () => { @@ -31,7 +32,7 @@ const useModels = () => { dispatch({ type: 'GET_MODELS_ERROR', }); - strapi.notification.toggle({ + toggleNotification({ type: 'warning', message: { id: 'notification.error' }, }); diff --git a/packages/core/admin/admin/src/hooks/useRolesList/index.js b/packages/core/admin/admin/src/hooks/useRolesList/index.js index 88f64d92e5..d3bc0ce504 100644 --- a/packages/core/admin/admin/src/hooks/useRolesList/index.js +++ b/packages/core/admin/admin/src/hooks/useRolesList/index.js @@ -1,10 +1,11 @@ import { useEffect, useReducer } from 'react'; -import { request } from '@strapi/helper-plugin'; +import { request, useNotification } from '@strapi/helper-plugin'; import { get } from 'lodash'; import init from './init'; import reducer, { initialState } from './reducer'; const useRolesList = (shouldFetchData = true) => { + const toggleNotification = useNotification(); const [{ roles, isLoading }, dispatch] = useReducer(reducer, initialState, () => init(initialState, shouldFetchData) ); @@ -13,6 +14,7 @@ const useRolesList = (shouldFetchData = true) => { if (shouldFetchData) { fetchRolesList(); } + // eslint-disable-next-line react-hooks/exhaustive-deps }, [shouldFetchData]); const fetchRolesList = async () => { @@ -35,7 +37,7 @@ const useRolesList = (shouldFetchData = true) => { }); if (message !== 'Forbidden') { - strapi.notification.toggle({ + toggleNotification({ type: 'warning', message, }); diff --git a/packages/core/admin/admin/src/hooks/useSettingsForm/index.js b/packages/core/admin/admin/src/hooks/useSettingsForm/index.js index cf8f300511..3997135fdb 100644 --- a/packages/core/admin/admin/src/hooks/useSettingsForm/index.js +++ b/packages/core/admin/admin/src/hooks/useSettingsForm/index.js @@ -1,5 +1,5 @@ import { useEffect, useReducer } from 'react'; -import { request } from '@strapi/helper-plugin'; +import { request, useNotification } from '@strapi/helper-plugin'; import { get, has, omit } from 'lodash'; import { checkFormValidity, formatAPIErrors } from '../../utils'; import { initialState, reducer } from './reducer'; @@ -10,6 +10,7 @@ const useSettingsForm = (endPoint, schema, cbSuccess, fieldsToPick) => { { formErrors, initialData, isLoading, modifiedData, showHeaderButtonLoader, showHeaderLoader }, dispatch, ] = useReducer(reducer, initialState, () => init(initialState, fieldsToPick)); + const toggleNotification = useNotification(); useEffect(() => { const getData = async () => { @@ -23,7 +24,7 @@ const useSettingsForm = (endPoint, schema, cbSuccess, fieldsToPick) => { }); } catch (err) { console.error(err.response); - strapi.notification.toggle({ + toggleNotification({ type: 'warning', message: { id: 'notification.error' }, }); @@ -95,7 +96,7 @@ const useSettingsForm = (endPoint, schema, cbSuccess, fieldsToPick) => { data, }); - strapi.notification.toggle({ + toggleNotification({ type: 'success', message: { id: 'notification.success.saved' }, }); @@ -103,12 +104,12 @@ const useSettingsForm = (endPoint, schema, cbSuccess, fieldsToPick) => { const data = get(err, 'response.payload', { data: {} }); if (has(data, 'data') && typeof data.data === 'string') { - strapi.notification.toggle({ + toggleNotification({ type: 'warning', message: data.data, }); } else { - strapi.notification.toggle({ + toggleNotification({ type: 'warning', message: data.message, }); diff --git a/packages/core/admin/admin/src/pages/Admin/index.js b/packages/core/admin/admin/src/pages/Admin/index.js index c1bbb6061a..c4805c5cbd 100644 --- a/packages/core/admin/admin/src/pages/Admin/index.js +++ b/packages/core/admin/admin/src/pages/Admin/index.js @@ -19,6 +19,7 @@ import { GlobalContextProvider, CheckPagePermissions, request, + NotificationsContext, } from '@strapi/helper-plugin'; import { checkLatestStrapiVersion } from '../../utils'; @@ -36,7 +37,7 @@ import PluginDispatcher from '../PluginDispatcher'; import ProfilePage from '../ProfilePage'; import SettingsPage from '../SettingsPage'; import Logout from './Logout'; -import { getInfosDataSucceeded, updatePlugin } from '../App/actions'; +import { getInfosDataSucceeded } from '../App/actions'; import makeSelecApp from '../App/selectors'; import { getStrapiLatestReleaseSucceeded, setAppError } from './actions'; import makeSelectAdmin from './selectors'; @@ -45,13 +46,12 @@ import Content from './Content'; export class Admin extends React.Component { // eslint-disable-line react/prefer-stateless-function + static contextType = NotificationsContext; // This state is really temporary until we create a menu API state = { updateMenu: null }; - helpers = { - updatePlugin: this.props.updatePlugin, - }; + helpers = {}; componentDidMount() { this.emitEvent('didAccessAuthenticatedAdministration'); @@ -103,7 +103,10 @@ export class Admin extends React.Component { this.props.getInfosDataSucceeded(data); } catch (err) { console.error(err); - strapi.notification.error('notification.error'); + this.context.toggleNotification({ + type: 'warning', + message: { id: 'notification.error' }, + }); } }; @@ -129,7 +132,7 @@ export class Admin extends React.Component { } if (shouldUpdateStrapi) { - strapi.notification.toggle({ + this.context.toggleNotification({ type: 'info', message: { id: 'notification.version.update.message' }, link: { @@ -173,7 +176,6 @@ export class Admin extends React.Component { intl: { formatMessage, locale }, // FIXME plugins, - updatePlugin, } = this.props; return ( @@ -187,10 +189,9 @@ export class Admin extends React.Component { disableGlobalOverlayBlocker={() => console.log('todo')} enableGlobalOverlayBlocker={() => console.log('todo')} formatMessage={formatMessage} - shouldUpdateStrapi={shouldUpdateStrapi} plugins={plugins} + shouldUpdateStrapi={shouldUpdateStrapi} strapiVersion={strapiVersion} - updatePlugin={updatePlugin} updateMenu={this.state.updateMenu} > @@ -263,7 +264,6 @@ Admin.propTypes = { }), plugins: PropTypes.object.isRequired, setAppError: PropTypes.func.isRequired, - updatePlugin: PropTypes.func.isRequired, }; const mapStateToProps = createStructuredSelector({ @@ -277,7 +277,6 @@ export function mapDispatchToProps(dispatch) { getInfosDataSucceeded, getStrapiLatestReleaseSucceeded, setAppError, - updatePlugin, }, dispatch ); diff --git a/packages/core/admin/admin/src/pages/Admin/tests/index.test.js b/packages/core/admin/admin/src/pages/Admin/tests/index.test.js index 017a955083..f404c01508 100644 --- a/packages/core/admin/admin/src/pages/Admin/tests/index.test.js +++ b/packages/core/admin/admin/src/pages/Admin/tests/index.test.js @@ -1,8 +1,6 @@ import React from 'react'; import { shallow } from 'enzyme'; -import { updatePlugin } from '../../App/actions'; - import { Admin, mapDispatchToProps } from '../index'; import { setAppError } from '../actions'; @@ -28,7 +26,6 @@ describe('', () => { global: { autoReload: false, currentEnvironment: 'development', - hasAdminUser: false, isLoading: true, strapiVersion: '3', uuid: false, @@ -38,7 +35,6 @@ describe('', () => { }, location: {}, setAppError: jest.fn(), - updatePlugin: jest.fn(), }; }); @@ -141,21 +137,4 @@ describe(', mapDispatchToProps', () => { expect(dispatch).toHaveBeenCalledWith(setAppError()); }); }); - - describe('updatePlugin', () => { - it('should be injected', () => { - const dispatch = jest.fn(); - const result = mapDispatchToProps(dispatch); - - expect(result.updatePlugin).toBeDefined(); - }); - - it('should dispatch the updatePlugin action when called', () => { - const dispatch = jest.fn(); - const result = mapDispatchToProps(dispatch); - result.updatePlugin(); - - expect(dispatch).toHaveBeenCalledWith(updatePlugin()); - }); - }); }); diff --git a/packages/core/admin/admin/src/pages/App/actions.js b/packages/core/admin/admin/src/pages/App/actions.js index 17a21bdb14..6f2e1a654b 100644 --- a/packages/core/admin/admin/src/pages/App/actions.js +++ b/packages/core/admin/admin/src/pages/App/actions.js @@ -4,14 +4,7 @@ * */ -import { - GET_INFOS_DATA_SUCCEEDED, - GET_DATA_SUCCEEDED, - LOAD_PLUGIN, - PLUGIN_DELETED, - PLUGIN_LOADED, - UPDATE_PLUGIN, -} from './constants'; +import { GET_INFOS_DATA_SUCCEEDED, GET_DATA_SUCCEEDED } from './constants'; export function getInfosDataSucceeded(data) { return { @@ -26,33 +19,3 @@ export function getDataSucceeded(data) { data, }; } - -export function loadPlugin(newPlugin) { - return { - type: LOAD_PLUGIN, - plugin: newPlugin, - }; -} - -export function pluginDeleted(plugin) { - return { - type: PLUGIN_DELETED, - plugin, - }; -} - -export function pluginLoaded(newPlugin) { - return { - type: PLUGIN_LOADED, - plugin: newPlugin, - }; -} - -export function updatePlugin(pluginId, updatedKey, updatedValue) { - return { - type: UPDATE_PLUGIN, - pluginId, - updatedKey, - updatedValue, - }; -} diff --git a/packages/core/admin/admin/src/pages/App/constants.js b/packages/core/admin/admin/src/pages/App/constants.js index e016a05073..5cae31b411 100644 --- a/packages/core/admin/admin/src/pages/App/constants.js +++ b/packages/core/admin/admin/src/pages/App/constants.js @@ -4,9 +4,5 @@ * */ -export const LOAD_PLUGIN = 'app/App/LOAD_PLUGIN'; -export const PLUGIN_LOADED = 'app/App/PLUGIN_LOADED'; -export const PLUGIN_DELETED = 'app/App/PLUGIN_DELETED'; -export const UPDATE_PLUGIN = 'app/App/UPDATE_PLUGIN'; export const GET_DATA_SUCCEEDED = 'app/App/GET_DATA_SUCCEEDED'; export const GET_INFOS_DATA_SUCCEEDED = 'admin/App/GET_INFOS_DATA_SUCCEEDED'; diff --git a/packages/core/admin/admin/src/pages/App/index.js b/packages/core/admin/admin/src/pages/App/index.js index bf5dc95891..5a8b66a271 100644 --- a/packages/core/admin/admin/src/pages/App/index.js +++ b/packages/core/admin/admin/src/pages/App/index.js @@ -9,7 +9,7 @@ import PropTypes from 'prop-types'; import { Switch, Route } from 'react-router-dom'; import { connect } from 'react-redux'; import { bindActionCreators, compose } from 'redux'; -import { LoadingIndicatorPage, auth, request } from '@strapi/helper-plugin'; +import { LoadingIndicatorPage, auth, request, useNotification } from '@strapi/helper-plugin'; import PluginsInitializer from '../../components/PluginsInitializer'; import PrivateRoute from '../../components/PrivateRoute'; import AuthPage from '../AuthPage'; @@ -25,6 +25,7 @@ window.strapi = Object.assign(window.strapi || {}, { }); function App(props) { + const toggleNotification = useNotification(); const getDataRef = useRef(); const [{ isLoading, hasAdmin }, setState] = useState({ isLoading: true, hasAdmin: false }); getDataRef.current = props.getDataSucceeded; @@ -89,7 +90,7 @@ function App(props) { getDataRef.current(data); setState({ isLoading: false, hasAdmin: data.hasAdmin }); } catch (err) { - strapi.notification.toggle({ + toggleNotification({ type: 'warning', message: { id: 'app.containers.App.notification.error.init' }, }); @@ -97,7 +98,7 @@ function App(props) { }; getData(); - }, []); + }, [toggleNotification]); const setHasAdmin = hasAdmin => setState(prev => ({ ...prev, hasAdmin })); diff --git a/packages/core/admin/admin/src/pages/App/reducer.js b/packages/core/admin/admin/src/pages/App/reducer.js index 167db42c70..a0598da787 100644 --- a/packages/core/admin/admin/src/pages/App/reducer.js +++ b/packages/core/admin/admin/src/pages/App/reducer.js @@ -1,66 +1,44 @@ -// Shared constants -import { fromJS } from 'immutable'; +/* eslint-disable consistent-return */ +import produce from 'immer'; import packageJSON from '../../../../package.json'; - -import { - GET_INFOS_DATA_SUCCEEDED, - GET_DATA_SUCCEEDED, - PLUGIN_DELETED, - PLUGIN_LOADED, - UPDATE_PLUGIN, -} from './constants'; +import { GET_INFOS_DATA_SUCCEEDED, GET_DATA_SUCCEEDED } from './constants'; const packageVersion = packageJSON.version; -// TODO: remove immutable -const initialState = fromJS({ +const initialState = { appInfos: {}, autoReload: false, currentEnvironment: 'development', - hasAdminUser: false, isLoading: true, - plugins: {}, strapiVersion: packageVersion, uuid: false, -}); +}; -function appReducer(state = initialState, action) { - switch (action.type) { - case GET_INFOS_DATA_SUCCEEDED: { - if (action.data.strapiVersion !== state.get('strapiVersion')) { - console.error( - `It seems that the built version ${packageVersion} is different than your project's one (${action.data.strapiVersion})` - ); - console.error('Please delete your `.cache` and `build` folders and restart your app'); +const appReducer = (state = initialState, action) => + produce(state, draftState => { + switch (action.type) { + case GET_INFOS_DATA_SUCCEEDED: { + if (action.data.strapiVersion !== state.strapiVersion) { + console.error( + `It seems that the built version ${packageVersion} is different than your project's one (${action.data.strapiVersion})` + ); + console.error('Please delete your `.cache` and `build` folders and restart your app'); + } + + draftState.appInfos = action.data; + draftState.autoReload = action.data.autoReload; + draftState.currentEnvironment = action.data.currentEnvironment; + break; + } + case GET_DATA_SUCCEEDED: { + draftState.isLoading = false; + draftState.uuid = action.data.uuid; + break; } - return ( - state - .update('appInfos', () => action.data) - // Keep this for plugins legacy - .update('autoReload', () => action.data.autoReload) - .update('currentEnvironment', () => action.data.currentEnvironment) - ); + default: + return draftState; } - case GET_DATA_SUCCEEDED: { - return state - .update('isLoading', () => false) - .update('hasAdminUser', () => action.data.hasAdmin) - .update('uuid', () => action.data.uuid); - } - case PLUGIN_LOADED: - return state.setIn(['plugins', action.plugin.id], fromJS(action.plugin)); - case UPDATE_PLUGIN: - return state.setIn( - ['plugins', action.pluginId, action.updatedKey], - fromJS(action.updatedValue) - ); - case PLUGIN_DELETED: - return state.deleteIn(['plugins', action.plugin]); - - default: - return state; - } -} + }); export default appReducer; diff --git a/packages/core/admin/admin/src/pages/App/selectors.js b/packages/core/admin/admin/src/pages/App/selectors.js index 184c6721c2..e92ad4bca4 100644 --- a/packages/core/admin/admin/src/pages/App/selectors.js +++ b/packages/core/admin/admin/src/pages/App/selectors.js @@ -9,7 +9,7 @@ const selectApp = () => state => state.app; * Select the language locale */ -const makeSelectApp = () => createSelector(selectApp(), appState => appState.toJS()); +const makeSelectApp = () => createSelector(selectApp(), appState => appState); export default makeSelectApp; export { selectApp }; diff --git a/packages/core/admin/admin/src/pages/App/tests/actions.test.js b/packages/core/admin/admin/src/pages/App/tests/actions.test.js index 07207e441e..3d3d0c47d2 100644 --- a/packages/core/admin/admin/src/pages/App/tests/actions.test.js +++ b/packages/core/admin/admin/src/pages/App/tests/actions.test.js @@ -1,19 +1,5 @@ -import { - GET_DATA_SUCCEEDED, - GET_INFOS_DATA_SUCCEEDED, - LOAD_PLUGIN, - PLUGIN_DELETED, - PLUGIN_LOADED, - UPDATE_PLUGIN, -} from '../constants'; -import { - loadPlugin, - getInfosDataSucceeded, - getDataSucceeded, - pluginDeleted, - pluginLoaded, - updatePlugin, -} from '../actions'; +import { GET_DATA_SUCCEEDED, GET_INFOS_DATA_SUCCEEDED } from '../constants'; +import { getInfosDataSucceeded, getDataSucceeded } from '../actions'; describe(' actions', () => { describe('getDataSucceeded', () => { @@ -39,62 +25,4 @@ describe(' actions', () => { expect(getInfosDataSucceeded(data)).toEqual(expected); }); }); - - describe('loadPlugin', () => { - it('should return the correct type and the passed data', () => { - const plugin = { - id: 'content-manager', - description: 'Manage your content', - }; - const expected = { - type: LOAD_PLUGIN, - plugin, - }; - - expect(loadPlugin(plugin)).toEqual(expected); - }); - }); - - describe('pluginLoaded', () => { - it('should return the correct type and the passed data', () => { - const plugin = { - id: 'content-manager', - description: 'Manage your content', - }; - const expected = { - type: PLUGIN_LOADED, - plugin, - }; - - expect(pluginLoaded(plugin)).toEqual(expected); - }); - }); - - describe('pluginDeleted', () => { - it('should return the correct type and the passed data', () => { - const plugin = 'content-manager'; - const expected = { - type: PLUGIN_DELETED, - plugin, - }; - - expect(pluginDeleted(plugin)).toEqual(expected); - }); - }); - - describe('updatePlugin', () => { - it('should return the correct type and the passed data', () => { - const pluginId = 'content-manager'; - const updatedKey = 'isReady'; - const updatedValue = true; - const expected = { - type: UPDATE_PLUGIN, - pluginId, - updatedKey, - updatedValue, - }; - - expect(updatePlugin(pluginId, updatedKey, updatedValue)).toEqual(expected); - }); - }); }); diff --git a/packages/core/admin/admin/src/pages/App/tests/reducer.test.js b/packages/core/admin/admin/src/pages/App/tests/reducer.test.js index 88163bd0cb..9d3fdc21fe 100644 --- a/packages/core/admin/admin/src/pages/App/tests/reducer.test.js +++ b/packages/core/admin/admin/src/pages/App/tests/reducer.test.js @@ -1,62 +1,23 @@ -import { fromJS } from 'immutable'; import packageJSON from '../../../../../package.json'; -import { - getDataSucceeded, - getInfosDataSucceeded, - pluginDeleted, - pluginLoaded, - updatePlugin, -} from '../actions'; +import { getDataSucceeded, getInfosDataSucceeded } from '../actions'; import appReducer from '../reducer'; describe(' reducer', () => { let state; beforeEach(() => { - state = fromJS({ + state = { appInfos: {}, autoReload: false, currentEnvironment: 'development', - hasAdminUser: false, isLoading: true, - plugins: {}, strapiVersion: packageJSON.version, uuid: false, - }); + }; }); it('should return the initial state', () => { - const expectedResult = state.toJS(); - expect(appReducer(undefined, {}).toJS()).toEqual(expectedResult); - }); - - it('should handle the pluginLoaded action correclty', () => { - const plugin = { - id: 'content-manager', - description: 'Manage your content', - }; - const expectedResult = state.setIn(['plugins', 'content-manager'], fromJS(plugin)); - - expect(appReducer(state, pluginLoaded(plugin))).toEqual(expectedResult); - }); - - it('should handle the updatePlugin action correclty', () => { - const plugin = { id: 'content-manager', isReady: false }; - state = state.setIn(['plugins', 'content-manager'], fromJS(plugin)); - - const expectedResult = state.setIn(['plugins', 'content-manager', 'isReady'], true); - - expect(appReducer(state, updatePlugin('content-manager', 'isReady', true))).toEqual( - expectedResult - ); - }); - - it('should handle the pluginDeleted action correclty', () => { - const plugin = { id: 'content-manager', isReady: false }; - state = state.setIn(['plugins', 'content-manager'], fromJS(plugin)); - const expectedResult = state.deleteIn(['plugins', 'content-manager']); - - expect(appReducer(state, pluginDeleted('content-manager'))).toEqual(expectedResult); + expect(appReducer(undefined, {})).toEqual(state); }); describe('GET_INFOS_DATA_SUCCEEDED', () => { @@ -66,12 +27,10 @@ describe(' reducer', () => { communityEdition: false, currentEnvironment: 'test', nodeVersion: 'v12.14.1', - strapiVersion: '3.2.1', + strapiVersion: packageJSON.version, }; - const expected = state - .set('appInfos', data) - .set('autoReload', true) - .set('currentEnvironment', 'test'); + + const expected = { ...state, appInfos: data, autoReload: true, currentEnvironment: 'test' }; expect(appReducer(state, getInfosDataSucceeded(data))).toEqual(expected); }); @@ -79,10 +38,7 @@ describe(' reducer', () => { describe('GET_DATA_SUCCEEDED', () => { it('should handle the set the data correctly', () => { - const expected = state - .set('hasAdminUser', true) - .set('uuid', 'true') - .set('isLoading', false); + const expected = { ...state, uuid: 'true', isLoading: false }; expect(appReducer(state, getDataSucceeded({ hasAdmin: true, uuid: 'true' }))).toEqual( expected diff --git a/packages/core/admin/admin/src/pages/App/tests/selectors.test.js b/packages/core/admin/admin/src/pages/App/tests/selectors.test.js index aa90a0bf26..fdbdb6b898 100644 --- a/packages/core/admin/admin/src/pages/App/tests/selectors.test.js +++ b/packages/core/admin/admin/src/pages/App/tests/selectors.test.js @@ -1,11 +1,9 @@ -import { fromJS } from 'immutable'; - import makeSelectApp, { selectApp } from '../selectors'; describe(' selectors', () => { describe('selectApp', () => { it('should select the global state', () => { - const appState = fromJS({}); + const appState = {}; const mockedState = { app: appState, }; @@ -16,12 +14,12 @@ describe(' selectors', () => { describe('makeSelectApp', () => { it('should select the appState (.toJS())', () => { - const appState = fromJS({}); + const appState = {}; const mockedState = { app: appState, }; - expect(makeSelectApp()(mockedState)).toEqual(appState.toJS()); + expect(makeSelectApp()(mockedState)).toEqual(appState); }); }); }); diff --git a/packages/core/admin/admin/src/pages/AuthPage/index.js b/packages/core/admin/admin/src/pages/AuthPage/index.js index 7bea246267..7419964ded 100644 --- a/packages/core/admin/admin/src/pages/AuthPage/index.js +++ b/packages/core/admin/admin/src/pages/AuthPage/index.js @@ -2,7 +2,7 @@ import React, { useEffect, useReducer } from 'react'; import axios from 'axios'; import { camelCase, get, omit, upperFirst } from 'lodash'; import { Redirect, useRouteMatch, useHistory } from 'react-router-dom'; -import { BaselineAlignment, auth, useQuery } from '@strapi/helper-plugin'; +import { BaselineAlignment, auth, useNotification, useQuery } from '@strapi/helper-plugin'; import { Padded } from '@buffetjs/core'; import PropTypes from 'prop-types'; import forms from 'ee_else_ce/pages/AuthPage/utils/forms'; @@ -17,6 +17,7 @@ import { initialState, reducer } from './reducer'; import useChangeLanguage from '../../components/LanguageProvider/hooks/useChangeLanguage'; const AuthPage = ({ hasAdmin, setHasAdmin }) => { + const toggleNotification = useNotification(); const { push } = useHistory(); const changeLocale = useChangeLanguage(); const { @@ -71,7 +72,7 @@ const AuthPage = ({ hasAdmin, setHasAdmin }) => { } catch (err) { const errorMessage = get(err, ['response', 'data', 'message'], 'An error occurred'); - strapi.notification.toggle({ + toggleNotification({ type: 'warning', message: errorMessage, }); @@ -145,7 +146,7 @@ const AuthPage = ({ hasAdmin, setHasAdmin }) => { } catch (err) { console.error(err); - strapi.notification.toggle({ + toggleNotification({ type: 'warning', message: { id: 'notification.error' }, }); diff --git a/packages/core/admin/admin/src/pages/InstalledPluginsPage/index.js b/packages/core/admin/admin/src/pages/InstalledPluginsPage/index.js index d9a1dd69f2..e9dda50e99 100644 --- a/packages/core/admin/admin/src/pages/InstalledPluginsPage/index.js +++ b/packages/core/admin/admin/src/pages/InstalledPluginsPage/index.js @@ -1,5 +1,5 @@ import React from 'react'; -import { useGlobalContext, request } from '@strapi/helper-plugin'; +import { useGlobalContext, request, useNotification } from '@strapi/helper-plugin'; import { Header, List } from '@buffetjs/custom'; import PageTitle from '../../components/PageTitle'; import ContainerFluid from '../../components/ContainerFluid'; @@ -8,6 +8,7 @@ import Row from './Row'; import generateRows from './utils/generateRows'; const InstalledPluginsPage = () => { + const toggleNotification = useNotification(); const { formatMessage, plugins } = useGlobalContext(); const onConfirm = async id => { try { @@ -28,7 +29,7 @@ const InstalledPluginsPage = () => { } } catch (err) { strapi.unlockAppWithAutoreload(); - strapi.notification.toggle({ + toggleNotification({ type: 'warning', message: { id: 'app.components.listPluginsPage.deletePlugin.error' }, }); diff --git a/packages/core/admin/admin/src/pages/MarketplacePage/index.js b/packages/core/admin/admin/src/pages/MarketplacePage/index.js index 188edc7cc6..6237824f3a 100644 --- a/packages/core/admin/admin/src/pages/MarketplacePage/index.js +++ b/packages/core/admin/admin/src/pages/MarketplacePage/index.js @@ -1,14 +1,19 @@ import React from 'react'; -import { LoadingIndicatorPage, useGlobalContext, request } from '@strapi/helper-plugin'; +import { + LoadingIndicatorPage, + useGlobalContext, + request, + useNotification, +} from '@strapi/helper-plugin'; import { Header } from '@buffetjs/custom'; import { useHistory } from 'react-router-dom'; - import { useFetchPluginsFromMarketPlace } from '../../hooks'; import PageTitle from '../../components/PageTitle'; import PluginCard from './PluginCard'; import Wrapper from './Wrapper'; const MarketPlacePage = () => { + const toggleNotification = useNotification(); const history = useHistory(); const { autoReload, currentEnvironment, formatMessage, plugins } = useGlobalContext(); const { error, isLoading, data } = useFetchPluginsFromMarketPlace(); @@ -43,7 +48,7 @@ const MarketPlacePage = () => { } } catch (err) { strapi.unlockApp(); - strapi.notification.toggle({ + toggleNotification({ type: 'warning', message: { id: 'notification.error' }, }); diff --git a/packages/core/admin/admin/src/pages/Roles/EditPage/index.js b/packages/core/admin/admin/src/pages/Roles/EditPage/index.js index 34ec9eb3c6..4bf1827227 100644 --- a/packages/core/admin/admin/src/pages/Roles/EditPage/index.js +++ b/packages/core/admin/admin/src/pages/Roles/EditPage/index.js @@ -1,7 +1,12 @@ import React, { useState, useRef } from 'react'; import { useRouteMatch } from 'react-router-dom'; import get from 'lodash/get'; -import { BaselineAlignment, useGlobalContext, request } from '@strapi/helper-plugin'; +import { + BaselineAlignment, + useGlobalContext, + request, + useNotification, +} from '@strapi/helper-plugin'; import { Header } from '@buffetjs/custom'; import { Padded } from '@buffetjs/core'; import { Formik } from 'formik'; @@ -13,6 +18,7 @@ import { useFetchRole, useFetchPermissionsLayout } from '../../../hooks'; import schema from './utils/schema'; const EditPage = () => { + const toggleNotification = useNotification(); const { formatMessage } = useIntl(); const { emitEvent } = useGlobalContext(); const { @@ -89,7 +95,7 @@ const EditPage = () => { permissionsRef.current.setFormAfterSubmit(); onSubmitSucceeded({ name: data.name, description: data.description }); - strapi.notification.toggle({ + toggleNotification({ type: 'success', message: { id: 'notification.success.saved' }, }); @@ -99,7 +105,7 @@ const EditPage = () => { const errorMessage = get(err, 'response.payload.message', 'An error occured'); const message = get(err, 'response.payload.data.permissions[0]', errorMessage); - strapi.notification.toggle({ + toggleNotification({ type: 'warning', message, }); diff --git a/packages/core/admin/admin/src/pages/Users/ListPage/index.js b/packages/core/admin/admin/src/pages/Users/ListPage/index.js index f9615fc1cd..7f01a433f5 100644 --- a/packages/core/admin/admin/src/pages/Users/ListPage/index.js +++ b/packages/core/admin/admin/src/pages/Users/ListPage/index.js @@ -6,6 +6,7 @@ import { useUserPermissions, LoadingIndicatorPage, PopUpWarning, + useNotification, } from '@strapi/helper-plugin'; import { get } from 'lodash'; import { useHistory, useLocation } from 'react-router-dom'; @@ -25,6 +26,7 @@ const ListPage = () => { isLoading: isLoadingForPermissions, allowedActions: { canCreate, canDelete, canRead, canUpdate }, } = useUserPermissions(adminPermissions.settings.users); + const toggleNotification = useNotification(); const [isWarningDeleteAllOpened, setIsWarningDeleteAllOpened] = useState(false); const [isModalOpened, setIsModalOpened] = useState(false); const { toggleHeaderSearch } = useSettingsHeaderSearchContext(); @@ -78,7 +80,7 @@ const ListPage = () => { }); } catch (err) { console.error(err.response); - strapi.notification.toggle({ + toggleNotification({ type: 'warning', message: { id: 'notification.error' }, }); @@ -185,7 +187,7 @@ const ListPage = () => { } catch (err) { const errorMessage = get(err, 'response.payload.data', 'An error occured'); - strapi.notification.toggle({ + toggleNotification({ type: 'warning', message: errorMessage, }); @@ -199,7 +201,7 @@ const ListPage = () => { } handleToggleModal(); - }, [dataToDelete]); + }, [dataToDelete, toggleNotification]); const handleToggle = () => setIsModalOpened(prev => !prev); diff --git a/packages/core/admin/admin/src/pages/Users/ProtectedEditPage/index.js b/packages/core/admin/admin/src/pages/Users/ProtectedEditPage/index.js index 2855604b0f..5807d1a1be 100644 --- a/packages/core/admin/admin/src/pages/Users/ProtectedEditPage/index.js +++ b/packages/core/admin/admin/src/pages/Users/ProtectedEditPage/index.js @@ -1,11 +1,12 @@ import React, { useEffect, useMemo } from 'react'; -import { useUserPermissions, LoadingIndicatorPage } from '@strapi/helper-plugin'; +import { useUserPermissions, LoadingIndicatorPage, useNotification } from '@strapi/helper-plugin'; import { Redirect, useLocation } from 'react-router-dom'; import { get } from 'lodash'; import adminPermissions from '../../../permissions'; import EditPage from '../EditPage'; const ProtectedEditPage = () => { + const toggleNotification = useNotification(); const permissions = useMemo(() => { return { read: adminPermissions.settings.users.read, @@ -23,13 +24,13 @@ const ProtectedEditPage = () => { useEffect(() => { if (!isLoading) { if (!canRead && !canUpdate) { - strapi.notification.toggle({ + toggleNotification({ type: 'info', message: { id: 'notification.permission.not-allowed-read' }, }); } } - }, [isLoading, canRead, canUpdate]); + }, [isLoading, canRead, canUpdate, toggleNotification]); if (isLoading) { return ; diff --git a/packages/core/admin/admin/src/pages/Webhooks/EditView/index.js b/packages/core/admin/admin/src/pages/Webhooks/EditView/index.js index 9468d4e88a..512b03ba10 100644 --- a/packages/core/admin/admin/src/pages/Webhooks/EditView/index.js +++ b/packages/core/admin/admin/src/pages/Webhooks/EditView/index.js @@ -15,6 +15,7 @@ import { getYupInnerErrors, BackHeader, LoadingIndicatorPage, + useNotification, } from '@strapi/helper-plugin'; import { useModels } from '../../../hooks'; import PageTitle from '../../../components/SettingsPageTitle'; @@ -25,7 +26,7 @@ import Wrapper from './Wrapper'; function EditView() { const { isLoading: isLoadingForModels, collectionTypes } = useModels(); - + const toggleNotification = useNotification(); const isMounted = useRef(); const { formatMessage } = useGlobalContext(); const [submittedOnce, setSubmittedOnce] = useState(false); @@ -69,7 +70,7 @@ function EditView() { dispatch({ type: 'UNSET_LOADER' }); if (err.code !== 20) { - strapi.notification.toggle({ + toggleNotification({ type: 'warning', message: { id: 'notification.error' }, }); @@ -179,7 +180,7 @@ function EditView() { setErrors(getYupInnerErrors(err)); if (submit) { - strapi.notification.toggle({ + toggleNotification({ type: 'warning', message: { id: 'notification.form.error.fields' }, }); @@ -200,14 +201,14 @@ function EditView() { dispatch({ type: 'SUBMIT_SUCCEEDED', }); - strapi.notification.toggle({ + toggleNotification({ type: 'success', message: { id: 'Settings.webhooks.created' }, }); replace(`/settings/webhooks/${data.id}`); } catch (err) { setIsSubmitting(false); - strapi.notification.toggle({ + toggleNotification({ type: 'warning', message: { id: 'notification.error' }, }); @@ -272,7 +273,7 @@ function EditView() { } catch (err) { if (isMounted.current) { if (err.code !== 20) { - strapi.notification.toggle({ + toggleNotification({ type: 'warning', message: { id: 'notification.error' }, }); @@ -368,13 +369,13 @@ function EditView() { dispatch({ type: 'SUBMIT_SUCCEEDED', }); - strapi.notification.toggle({ + toggleNotification({ type: 'success', message: { id: 'notification.form.success.fields' }, }); } catch (err) { setIsSubmitting(false); - strapi.notification.toggle({ + toggleNotification({ type: 'warning', message: { id: 'notification.error' }, }); diff --git a/packages/core/admin/admin/src/pages/Webhooks/ListView/index.js b/packages/core/admin/admin/src/pages/Webhooks/ListView/index.js index fa507b7140..0f63d51983 100644 --- a/packages/core/admin/admin/src/pages/Webhooks/ListView/index.js +++ b/packages/core/admin/admin/src/pages/Webhooks/ListView/index.js @@ -18,6 +18,7 @@ import { useUserPermissions, LoadingIndicatorPage, EmptyState, + useNotification, } from '@strapi/helper-plugin'; import adminPermissions from '../../../permissions'; import PageTitle from '../../../components/SettingsPageTitle'; @@ -30,7 +31,7 @@ function ListView() { isLoading, allowedActions: { canCreate, canRead, canUpdate, canDelete }, } = useUserPermissions(adminPermissions.settings.webhooks); - + const toggleNotification = useNotification(); const isMounted = useRef(true); const { formatMessage } = useIntl(); const [showModal, setShowModal] = useState(false); @@ -52,6 +53,7 @@ function ListView() { if (canRead) { fetchData(); } + // eslint-disable-next-line react-hooks/exhaustive-deps }, [canRead]); const getWebhookIndex = id => webhooks.findIndex(webhook => webhook.id === id); @@ -138,7 +140,7 @@ function ListView() { } catch (err) { if (isMounted.current) { if (err.code !== 20) { - strapi.notification.toggle({ + toggleNotification({ type: 'warning', message: { id: 'notification.error' }, }); @@ -175,7 +177,7 @@ function ListView() { }); } catch (err) { if (err.code !== 20) { - strapi.notification.toggle({ + toggleNotification({ type: 'warning', message: { id: 'notification.error' }, }); @@ -203,7 +205,7 @@ function ListView() { } catch (err) { if (isMounted.current) { if (err.code !== 20) { - strapi.notification.toggle({ + toggleNotification({ type: 'warning', message: { id: 'notification.error' }, }); @@ -255,7 +257,7 @@ function ListView() { }); if (err.code !== 20) { - strapi.notification.toggle({ + toggleNotification({ type: 'warning', message: { id: 'notification.error' }, }); diff --git a/packages/core/admin/admin/src/pages/Webhooks/ListView/tests/index.test.js b/packages/core/admin/admin/src/pages/Webhooks/ListView/tests/index.test.js index 036e157e35..e7338f8329 100644 --- a/packages/core/admin/admin/src/pages/Webhooks/ListView/tests/index.test.js +++ b/packages/core/admin/admin/src/pages/Webhooks/ListView/tests/index.test.js @@ -1,10 +1,10 @@ import React from 'react'; import { Router, Route, Switch } from 'react-router-dom'; -// import { render, cleanup } from '@testing-library/react'; import { shallow } from 'enzyme'; import { createMemoryHistory } from 'history'; import { GlobalContextProvider, UserProvider } from '@strapi/helper-plugin'; import { IntlProvider } from 'react-intl'; +import Notifications from '../../../../components/Notifications'; import translationMessages from '../../../../translations/en.json'; @@ -14,15 +14,6 @@ const history = createMemoryHistory(); describe('Admin | containers | ListView', () => { it('should not crash', () => { - const intlProvider = new IntlProvider( - { - locale: 'en', - messages: translationMessages, - }, - {} - ); - const { intl: originalIntl } = intlProvider.state; - shallow( { messages={translationMessages} textComponent="span" > - - - - - - - - - - - + + + + + + + + + + + + + ); }); diff --git a/packages/core/admin/ee/admin/hooks/useAuthProviders/index.js b/packages/core/admin/ee/admin/hooks/useAuthProviders/index.js index dcbb187b19..6fad3a5974 100644 --- a/packages/core/admin/ee/admin/hooks/useAuthProviders/index.js +++ b/packages/core/admin/ee/admin/hooks/useAuthProviders/index.js @@ -1,11 +1,12 @@ import { useReducer, useEffect } from 'react'; -import { request } from '@strapi/helper-plugin'; +import { request, useNotification } from '@strapi/helper-plugin'; import { getRequestUrl } from '../../../../admin/src/utils'; import reducer, { initialState } from './reducer'; const useAuthProviders = ({ ssoEnabled }) => { const [state, dispatch] = useReducer(reducer, initialState); + const toggleNotification = useNotification(); useEffect(() => { fetchAuthProviders(); @@ -37,7 +38,7 @@ const useAuthProviders = ({ ssoEnabled }) => { type: 'GET_DATA_ERROR', }); - strapi.notification.toggle({ + toggleNotification({ type: 'warning', message: { id: 'notification.error' }, centered: true, diff --git a/packages/core/admin/ee/admin/pages/Roles/CreatePage/index.js b/packages/core/admin/ee/admin/pages/Roles/CreatePage/index.js index 4c4bc5abd5..27a9b8a767 100644 --- a/packages/core/admin/ee/admin/pages/Roles/CreatePage/index.js +++ b/packages/core/admin/ee/admin/pages/Roles/CreatePage/index.js @@ -10,6 +10,7 @@ import { CheckPagePermissions, request, useGlobalContext, + useNotification, } from '@strapi/helper-plugin'; import { useHistory, useRouteMatch } from 'react-router-dom'; import adminPermissions from '../../../../../admin/src/permissions'; @@ -24,6 +25,7 @@ import Permissions from '../../../../../admin/src/components/Roles/Permissions'; import schema from './utils/schema'; const CreatePage = () => { + const toggleNotification = useNotification(); const { formatMessage } = useIntl(); const [isSubmiting, setIsSubmiting] = useState(false); const { replace } = useHistory(); @@ -95,7 +97,7 @@ const CreatePage = () => { }) .then(res => { setIsSubmiting(false); - strapi.notification.toggle({ + toggleNotification({ type: 'success', message: { id: 'Settings.roles.created' }, }); @@ -104,7 +106,7 @@ const CreatePage = () => { .catch(err => { console.error(err); setIsSubmiting(false); - strapi.notification.toggle({ + toggleNotification({ type: 'warning', message: { id: 'notification.error' }, }); diff --git a/packages/core/admin/ee/admin/pages/Roles/ListPage/RoleRow.js b/packages/core/admin/ee/admin/pages/Roles/ListPage/RoleRow.js index b1162e3e8d..296ab8ea99 100644 --- a/packages/core/admin/ee/admin/pages/Roles/ListPage/RoleRow.js +++ b/packages/core/admin/ee/admin/pages/Roles/ListPage/RoleRow.js @@ -1,6 +1,7 @@ import React, { useCallback } from 'react'; import PropTypes from 'prop-types'; import { useHistory } from 'react-router-dom'; +import { useNotification } from '@strapi/helper-plugin'; import { Pencil, Duplicate } from '@buffetjs/icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { RoleRow as RoleRowBase } from '../../../../../admin/src/components/Roles'; @@ -17,6 +18,7 @@ const RoleRow = ({ selectedRoles, }) => { const { push } = useHistory(); + const toggleNotification = useNotification(); const handleRoleSelection = e => { e.stopPropagation(); @@ -29,7 +31,7 @@ const RoleRow = ({ e.stopPropagation(); if (role.usersCount) { - strapi.notification.toggle({ + toggleNotification({ type: 'info', message: { id: 'Roles.ListPage.notification.delete-not-allowed' }, }); diff --git a/packages/core/admin/ee/admin/pages/Roles/ListPage/index.js b/packages/core/admin/ee/admin/pages/Roles/ListPage/index.js index 1a86fe5179..6eb7a165da 100644 --- a/packages/core/admin/ee/admin/pages/Roles/ListPage/index.js +++ b/packages/core/admin/ee/admin/pages/Roles/ListPage/index.js @@ -11,6 +11,7 @@ import { PopUpWarning, request, useUserPermissions, + useNotification, LoadingIndicatorPage, } from '@strapi/helper-plugin'; import { useIntl } from 'react-intl'; @@ -24,6 +25,7 @@ import BaselineAlignment from './BaselineAlignment'; import reducer, { initialState } from './reducer'; const RoleListPage = () => { + const toggleNotification = useNotification(); const [isWarningDeleteAllOpened, setIsWarningDeleteAllOpenend] = useState(false); const { formatMessage } = useIntl(); const { push } = useHistory(); @@ -85,7 +87,7 @@ const RoleListPage = () => { }); if (selectedRoles.length !== filteredRoles.length) { - strapi.notification.toggle({ + toggleNotification({ type: 'info', message: { id: 'Roles.ListPage.notification.delete-all-not-allowed' }, }); @@ -111,12 +113,12 @@ const RoleListPage = () => { if (errorIds && Array.isArray(errorIds)) { const errorsMsg = errorIds.join('\n'); - strapi.notification.toggle({ + toggleNotification({ type: 'warning', message: errorsMsg, }); } else { - strapi.notification.toggle({ + toggleNotification({ type: 'warning', message: { id: 'notification.error' }, }); diff --git a/packages/core/content-manager/admin/src/components/DynamicZone/index.js b/packages/core/content-manager/admin/src/components/DynamicZone/index.js index f3274219cd..89deb47a0a 100644 --- a/packages/core/content-manager/admin/src/components/DynamicZone/index.js +++ b/packages/core/content-manager/admin/src/components/DynamicZone/index.js @@ -4,7 +4,7 @@ import isEqual from 'react-fast-compare'; import PropTypes from 'prop-types'; import { FormattedMessage, useIntl } from 'react-intl'; import { Flex } from '@buffetjs/core'; -import { LabelIconWrapper, NotAllowedInput } from '@strapi/helper-plugin'; +import { LabelIconWrapper, NotAllowedInput, useNotification } from '@strapi/helper-plugin'; import pluginId from '../../pluginId'; import connect from './utils/connect'; import select from './utils/select'; @@ -35,6 +35,7 @@ const DynamicZone = ({ fieldSchema, metadatas, }) => { + const toggleNotification = useNotification(); const [isOpen, setIsOpen] = useState(false); const { formatMessage } = useIntl(); // We cannot use the default props here @@ -71,7 +72,10 @@ const DynamicZone = ({ if (dynamicDisplayedComponentsLength < max) { setIsOpen(prev => !prev); } else { - strapi.notification.info(`${pluginId}.components.notification.info.maximum-requirement`); + toggleNotification({ + type: 'info', + message: { id: `${pluginId}.components.notification.info.maximum-requirement` }, + }); } }; diff --git a/packages/core/content-manager/admin/src/components/RepeatableComponent/index.js b/packages/core/content-manager/admin/src/components/RepeatableComponent/index.js index 3b397b64c7..6b001795ef 100644 --- a/packages/core/content-manager/admin/src/components/RepeatableComponent/index.js +++ b/packages/core/content-manager/admin/src/components/RepeatableComponent/index.js @@ -4,6 +4,7 @@ import { useDrop } from 'react-dnd'; import PropTypes from 'prop-types'; import { get, take } from 'lodash'; import { FormattedMessage } from 'react-intl'; +import { useNotification } from '@strapi/helper-plugin'; import { ErrorMessage } from '@buffetjs/styles'; import pluginId from '../../pluginId'; import { getMaxTempKey } from '../../utils'; @@ -27,6 +28,7 @@ const RepeatableComponent = ({ min, name, }) => { + const toggleNotification = useNotification(); const [collapseToOpen, setCollapseToOpen] = useState(''); const [, drop] = useDrop({ accept: ItemTypes.COMPONENT }); const { getComponentLayout } = useContentTypeLayout(); @@ -67,7 +69,10 @@ const RepeatableComponent = ({ setCollapseToOpen(nextTempKey); } else if (componentValueLength >= max) { - strapi.notification.info(`${pluginId}.components.notification.info.maximum-requirement`); + toggleNotification({ + type: 'info', + message: { id: `${pluginId}.components.notification.info.maximum-requirement` }, + }); } } }, [ @@ -79,6 +84,7 @@ const RepeatableComponent = ({ max, name, nextTempKey, + toggleNotification, ]); return ( diff --git a/packages/core/content-manager/admin/src/components/RepeatableComponent/reducer.js b/packages/core/content-manager/admin/src/components/RepeatableComponent/reducer.js index 5fb9a00b69..21942a2795 100644 --- a/packages/core/content-manager/admin/src/components/RepeatableComponent/reducer.js +++ b/packages/core/content-manager/admin/src/components/RepeatableComponent/reducer.js @@ -1,5 +1,4 @@ import { fromJS } from 'immutable'; -import getTrad from '../../utils/getTrad'; const initialState = fromJS({ collapses: [] }); @@ -33,11 +32,6 @@ const reducer = (state, action) => { // https://github.com/react-dnd/react-dnd/issues/1368 // https://github.com/frontend-collective/react-sortable-tree/issues/490 if (oldList.size !== newList.size) { - strapi.notification.toggle({ - type: 'warning', - message: getTrad('components.repeatable.reorder.error'), - }); - return oldList; } diff --git a/packages/core/content-manager/admin/src/containers/CollectionTypeFormWrapper/index.js b/packages/core/content-manager/admin/src/containers/CollectionTypeFormWrapper/index.js index 3c7a32bf40..d717a09ca2 100644 --- a/packages/core/content-manager/admin/src/containers/CollectionTypeFormWrapper/index.js +++ b/packages/core/content-manager/admin/src/containers/CollectionTypeFormWrapper/index.js @@ -4,6 +4,7 @@ import { get } from 'lodash'; import { request, useGlobalContext, + useNotification, useQueryParams, formatComponentData, contentManagementUtilRemoveFieldsFromData, @@ -28,6 +29,7 @@ import { getRequestUrl } from './utils'; // This container is used to handle the CRUD const CollectionTypeFormWrapper = ({ allLayoutData, children, slug, id, origin }) => { + const toggleNotification = useNotification(); const { emitEvent } = useGlobalContext(); const { push, replace } = useHistory(); const [{ rawQuery }] = useQueryParams(); @@ -152,7 +154,10 @@ const CollectionTypeFormWrapper = ({ allLayoutData, children, slug, id, origin } // Not allowed to read a document if (resStatus === 403) { - strapi.notification.info(getTrad('permissions.not-allowed.update')); + toggleNotification({ + type: 'info', + message: { id: getTrad('permissions.not-allowed.update') }, + }); push(redirectionLink); } @@ -178,23 +183,35 @@ const CollectionTypeFormWrapper = ({ allLayoutData, children, slug, id, origin } return () => { abortController.abort(); }; - }, [cleanClonedData, cleanReceivedData, push, requestURL, dispatch, rawQuery, redirectionLink]); + }, [ + cleanClonedData, + cleanReceivedData, + push, + requestURL, + dispatch, + rawQuery, + redirectionLink, + toggleNotification, + ]); - const displayErrors = useCallback(err => { - const errorPayload = err.response.payload; - console.error(errorPayload); + const displayErrors = useCallback( + err => { + const errorPayload = err.response.payload; + console.error(errorPayload); - let errorMessage = get(errorPayload, ['message'], 'Bad Request'); + let errorMessage = get(errorPayload, ['message'], 'Bad Request'); - // TODO handle errors correctly when back-end ready - if (Array.isArray(errorMessage)) { - errorMessage = get(errorMessage, ['0', 'messages', '0', 'id']); - } + // TODO handle errors correctly when back-end ready + if (Array.isArray(errorMessage)) { + errorMessage = get(errorMessage, ['0', 'messages', '0', 'id']); + } - if (typeof errorMessage === 'string') { - strapi.notification.error(errorMessage); - } - }, []); + if (typeof errorMessage === 'string') { + toggleNotification({ type: 'warning', message: errorMessage }); + } + }, + [toggleNotification] + ); const onDelete = useCallback( async trackerProperty => { @@ -205,7 +222,10 @@ const CollectionTypeFormWrapper = ({ allLayoutData, children, slug, id, origin } method: 'DELETE', }); - strapi.notification.success(getTrad('success.record.delete')); + toggleNotification({ + type: 'success', + message: { id: getTrad('success.record.delete') }, + }); emitEventRef.current('didDeleteEntry', trackerProperty); @@ -216,7 +236,7 @@ const CollectionTypeFormWrapper = ({ allLayoutData, children, slug, id, origin } return Promise.reject(err); } }, - [id, slug] + [id, slug, toggleNotification] ); const onDeleteSucceeded = useCallback(() => { @@ -234,7 +254,7 @@ const CollectionTypeFormWrapper = ({ allLayoutData, children, slug, id, origin } const response = await request(endPoint, { method: 'POST', body }); emitEventRef.current('didCreateEntry', trackerProperty); - strapi.notification.toggle({ + toggleNotification({ type: 'success', message: { id: getTrad('success.record.save') }, }); @@ -250,7 +270,7 @@ const CollectionTypeFormWrapper = ({ allLayoutData, children, slug, id, origin } dispatch(setStatus('resolved')); } }, - [cleanReceivedData, displayErrors, replace, slug, dispatch, rawQuery] + [cleanReceivedData, displayErrors, replace, slug, dispatch, rawQuery, toggleNotification] ); const onPublish = useCallback(async () => { @@ -267,7 +287,7 @@ const CollectionTypeFormWrapper = ({ allLayoutData, children, slug, id, origin } dispatch(submitSucceeded(cleanReceivedData(data))); dispatch(setStatus('resolved')); - strapi.notification.toggle({ + toggleNotification({ type: 'success', message: { id: getTrad('success.record.publish') }, }); @@ -275,7 +295,7 @@ const CollectionTypeFormWrapper = ({ allLayoutData, children, slug, id, origin } displayErrors(err); dispatch(setStatus('resolved')); } - }, [cleanReceivedData, displayErrors, id, slug, dispatch]); + }, [cleanReceivedData, displayErrors, id, slug, dispatch, toggleNotification]); const onPut = useCallback( async (body, trackerProperty) => { @@ -289,7 +309,7 @@ const CollectionTypeFormWrapper = ({ allLayoutData, children, slug, id, origin } const response = await request(endPoint, { method: 'PUT', body }); emitEventRef.current('didEditEntry', { trackerProperty }); - strapi.notification.toggle({ + toggleNotification({ type: 'success', message: { id: getTrad('success.record.save') }, }); @@ -304,7 +324,7 @@ const CollectionTypeFormWrapper = ({ allLayoutData, children, slug, id, origin } dispatch(setStatus('resolved')); } }, - [cleanReceivedData, displayErrors, slug, id, dispatch] + [cleanReceivedData, displayErrors, slug, id, dispatch, toggleNotification] ); const onUnpublish = useCallback(async () => { @@ -318,7 +338,10 @@ const CollectionTypeFormWrapper = ({ allLayoutData, children, slug, id, origin } const response = await request(endPoint, { method: 'POST' }); emitEventRef.current('didUnpublishEntry'); - strapi.notification.success(getTrad('success.record.unpublish')); + toggleNotification({ + type: 'success', + message: { id: getTrad('success.record.unpublish') }, + }); dispatch(submitSucceeded(cleanReceivedData(response))); dispatch(setStatus('resolved')); @@ -326,7 +349,7 @@ const CollectionTypeFormWrapper = ({ allLayoutData, children, slug, id, origin } dispatch(setStatus('resolved')); displayErrors(err); } - }, [cleanReceivedData, displayErrors, id, slug, dispatch]); + }, [cleanReceivedData, displayErrors, id, slug, dispatch, toggleNotification]); return children({ componentsDataStructure, diff --git a/packages/core/content-manager/admin/src/containers/EditSettingsView/index.js b/packages/core/content-manager/admin/src/containers/EditSettingsView/index.js index 5bff9beb6e..5e5b9192d8 100644 --- a/packages/core/content-manager/admin/src/containers/EditSettingsView/index.js +++ b/packages/core/content-manager/admin/src/containers/EditSettingsView/index.js @@ -3,7 +3,7 @@ import PropTypes from 'prop-types'; import { useHistory } from 'react-router-dom'; import { useSelector, shallowEqual } from 'react-redux'; import { cloneDeep, flatMap, get, set, pick } from 'lodash'; -import { request, useGlobalContext } from '@strapi/helper-plugin'; +import { request, useGlobalContext, useNotification } from '@strapi/helper-plugin'; import { Inputs as Input } from '@buffetjs/custom'; import { FormattedMessage } from 'react-intl'; import pluginId from '../../pluginId'; @@ -25,6 +25,7 @@ import LinkToCTB from './LinkToCTB'; const EditSettingsView = ({ components, mainLayout, isContentTypeView, slug, updateLayout }) => { const { push } = useHistory(); const { emitEvent } = useGlobalContext(); + const toggleNotification = useNotification(); const [reducerState, dispatch] = useReducer(reducer, initialState, () => init(initialState, mainLayout, components) @@ -134,7 +135,7 @@ const EditSettingsView = ({ components, mainLayout, isContentTypeView, slug, upd emitEvent('didEditEditSettings'); } catch (err) { - strapi.notification.error('notification.error'); + toggleNotification({ type: 'warning', message: { id: 'notification.error' } }); } }; diff --git a/packages/core/content-manager/admin/src/containers/EditView/DeleteLink/index.js b/packages/core/content-manager/admin/src/containers/EditView/DeleteLink/index.js index f60023bb2c..08e8b4192b 100644 --- a/packages/core/content-manager/admin/src/containers/EditView/DeleteLink/index.js +++ b/packages/core/content-manager/admin/src/containers/EditView/DeleteLink/index.js @@ -4,7 +4,7 @@ import { get } from 'lodash'; import isEqual from 'react-fast-compare'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { Text } from '@buffetjs/core'; -import { PopUpWarning } from '@strapi/helper-plugin'; +import { PopUpWarning, useNotification } from '@strapi/helper-plugin'; import PropTypes from 'prop-types'; import pluginId from '../../../pluginId'; import { getTrad } from '../../../utils'; @@ -16,6 +16,7 @@ const DeleteLink = ({ isCreatingEntry, onDelete, onDeleteSucceeded, trackerPrope const [didDeleteEntry, setDidDeleteEntry] = useState(false); const [isModalConfirmButtonLoading, setIsModalConfirmButtonLoading] = useState(false); const { formatMessage } = useIntl(); + const toggleNotification = useNotification(); const toggleWarningDelete = () => setWarningDelete(prevState => !prevState); @@ -36,7 +37,7 @@ const DeleteLink = ({ isCreatingEntry, onDelete, onDeleteSucceeded, trackerPrope 'response.payload.message', formatMessage({ id: `${pluginId}.error.record.delete` }) ); - strapi.notification.error(errorMessage); + toggleNotification({ type: 'warning', message: errorMessage }); } finally { setIsModalConfirmButtonLoading(false); toggleWarningDelete(); diff --git a/packages/core/content-manager/admin/src/containers/EditViewDataManagerProvider/index.js b/packages/core/content-manager/admin/src/containers/EditViewDataManagerProvider/index.js index c980a29a5a..d5e13aea37 100644 --- a/packages/core/content-manager/admin/src/containers/EditViewDataManagerProvider/index.js +++ b/packages/core/content-manager/admin/src/containers/EditViewDataManagerProvider/index.js @@ -7,6 +7,7 @@ import { useGlobalContext, OverlayBlocker, ContentManagerEditViewDataManagerContext, + useNotification, } from '@strapi/helper-plugin'; import { getTrad, removeKeyInObject } from '../../utils'; import reducer, { initialState } from './reducer'; @@ -43,6 +44,7 @@ const EditViewDataManagerProvider = ({ modifiedDZName, shouldCheckErrors, } = reducerState.toJS(); + const toggleNotification = useNotification(); const currentContentTypeLayout = get(allLayoutData, ['contentType'], {}); @@ -83,9 +85,12 @@ const EditViewDataManagerProvider = ({ useEffect(() => { if (shouldRedirectToHomepageWhenEditingEntry) { - strapi.notification.info(getTrad('permissions.not-allowed.update')); + toggleNotification({ + type: 'info', + message: { id: getTrad('permissions.not-allowed.update') }, + }); } - }, [shouldRedirectToHomepageWhenEditingEntry]); + }, [shouldRedirectToHomepageWhenEditingEntry, toggleNotification]); useEffect(() => { dispatch({ diff --git a/packages/core/content-manager/admin/src/containers/ListSettingsView/index.js b/packages/core/content-manager/admin/src/containers/ListSettingsView/index.js index f03f4a4c3b..bffe780379 100644 --- a/packages/core/content-manager/admin/src/containers/ListSettingsView/index.js +++ b/packages/core/content-manager/admin/src/containers/ListSettingsView/index.js @@ -1,7 +1,7 @@ import React, { memo, useMemo, useReducer, useState } from 'react'; import PropTypes from 'prop-types'; import { get, pick } from 'lodash'; -import { request, useGlobalContext } from '@strapi/helper-plugin'; +import { request, useGlobalContext, useNotification } from '@strapi/helper-plugin'; import { FormattedMessage, useIntl } from 'react-intl'; import { useDrop } from 'react-dnd'; import { DropdownItem } from 'reactstrap'; @@ -22,6 +22,7 @@ import reducer, { initialState } from './reducer'; import forms from './forms.json'; const ListSettingsView = ({ layout, slug, updateLayout }) => { + const toggleNotification = useNotification(); const [reducerState, dispatch] = useReducer(reducer, initialState, () => init(initialState, layout) ); @@ -103,7 +104,7 @@ const ListSettingsView = ({ layout, slug, updateLayout }) => { }); emitEvent('didEditListSettings'); } catch (err) { - strapi.notification.toggle({ + toggleNotification({ type: 'warning', message: { id: 'notification.error' }, }); @@ -211,7 +212,7 @@ const ListSettingsView = ({ layout, slug, updateLayout }) => { e.stopPropagation(); if (displayedFields.length === 1) { - strapi.notification.toggle({ + toggleNotification({ type: 'info', message: { id: `${pluginId}.notification.info.minimumFields` }, }); diff --git a/packages/core/content-manager/admin/src/containers/ListView/index.js b/packages/core/content-manager/admin/src/containers/ListView/index.js index 02b77d19ab..1f369586f4 100644 --- a/packages/core/content-manager/admin/src/containers/ListView/index.js +++ b/packages/core/content-manager/admin/src/containers/ListView/index.js @@ -15,6 +15,7 @@ import { InjectionZoneList, PopUpWarning, useGlobalContext, + useNotification, useQueryParams, useUser, request, @@ -86,7 +87,7 @@ function ListView({ settings: { bulkable: isBulkable, filterable: isFilterable, searchable: isSearchable }, }, } = layout; - + const toggleNotification = useNotification(); const { emitEvent } = useGlobalContext(); const { fetchUserPermissions } = useUser(); const emitEventRef = useRef(emitEvent); @@ -142,7 +143,10 @@ function ListView({ if (resStatus === 403) { await fetchPermissionsRef.current(); - strapi.notification.info(getTrad('permissions.not-allowed.update')); + toggleNotification({ + type: 'info', + message: { id: getTrad('permissions.not-allowed.update') }, + }); push('/'); @@ -151,11 +155,14 @@ function ListView({ if (err.name !== 'AbortError') { console.error(err); - strapi.notification.error(getTrad('error.model.fetch')); + toggleNotification({ + type: 'warning', + message: { id: getTrad('error.model.fetch') }, + }); } } }, - [getData, getDataSucceeded, push] + [getData, getDataSucceeded, push, toggleNotification] ); const handleChangeListLabels = useCallback( @@ -163,7 +170,7 @@ function ListView({ // Display a notification if trying to remove the last displayed field if (value && displayedHeaders.length === 1) { - strapi.notification.toggle({ + toggleNotification({ type: 'warning', message: { id: 'content-manager.notification.error.displayedFields' }, }); @@ -173,7 +180,7 @@ function ListView({ onChangeListHeaders({ name, value }); } }, - [displayedHeaders, onChangeListHeaders] + [displayedHeaders, onChangeListHeaders, toggleNotification] ); const handleConfirmDeleteAllData = useCallback(async () => { @@ -188,9 +195,18 @@ function ListView({ onDeleteSeveralDataSucceeded(); emitEventRef.current('didBulkDeleteEntries'); } catch (err) { - strapi.notification.error(`${pluginId}.error.record.delete`); + toggleNotification({ + type: 'warning', + message: { id: getTrad('error.record.delete') }, + }); } - }, [entriesToDelete, onDeleteSeveralDataSucceeded, slug, setModalLoadingState]); + }, [ + entriesToDelete, + onDeleteSeveralDataSucceeded, + slug, + setModalLoadingState, + toggleNotification, + ]); const handleConfirmDeleteData = useCallback(async () => { try { @@ -211,9 +227,9 @@ function ListView({ method: 'DELETE', }); - strapi.notification.toggle({ + toggleNotification({ type: 'success', - message: { id: `${pluginId}.success.record.delete` }, + message: { id: getTrad('success.record.delete') }, }); // Close the modal and refetch data @@ -223,10 +239,10 @@ function ListView({ const errorMessage = get( err, 'response.payload.message', - formatMessage({ id: `${pluginId}.error.record.delete` }) + formatMessage({ id: getTrad('error.record.delete') }) ); - strapi.notification.toggle({ + toggleNotification({ type: 'warning', message: errorMessage, }); @@ -234,6 +250,7 @@ function ListView({ onDeleteDataError(); } }, [ + toggleNotification, hasDraftAndPublish, setModalLoadingState, slug, diff --git a/packages/core/content-manager/admin/src/containers/Main/index.js b/packages/core/content-manager/admin/src/containers/Main/index.js index 89644abd58..df1b5f7290 100644 --- a/packages/core/content-manager/admin/src/containers/Main/index.js +++ b/packages/core/content-manager/admin/src/containers/Main/index.js @@ -8,6 +8,7 @@ import { LoadingIndicatorPage, NotFound, request, + useNotification, } from '@strapi/helper-plugin'; import { DndProvider } from 'react-dnd'; import HTML5Backend from 'react-dnd-html5-backend'; @@ -22,6 +23,8 @@ import { getData, getDataSucceeded, resetProps } from './actions'; import makeSelectMain from './selectors'; function Main({ getData, getDataSucceeded, isLoading, resetProps }) { + const toggleNotification = useNotification(); + useEffect(() => { const abortController = new AbortController(); const { signal } = abortController; @@ -39,7 +42,7 @@ function Main({ getData, getDataSucceeded, isLoading, resetProps }) { getDataSucceeded(models, components); } catch (err) { console.error(err); - strapi.notification.error('notification.error'); + toggleNotification({ type: 'warning', message: { id: 'notification.error' } }); } }; @@ -49,7 +52,7 @@ function Main({ getData, getDataSucceeded, isLoading, resetProps }) { abortController.abort(); resetProps(); }; - }, [getData, getDataSucceeded, resetProps]); + }, [getData, getDataSucceeded, resetProps, toggleNotification]); if (isLoading) { return ; diff --git a/packages/core/content-manager/admin/src/containers/SingleTypeFormWrapper/index.js b/packages/core/content-manager/admin/src/containers/SingleTypeFormWrapper/index.js index b24dcb3268..6a38672d14 100644 --- a/packages/core/content-manager/admin/src/containers/SingleTypeFormWrapper/index.js +++ b/packages/core/content-manager/admin/src/containers/SingleTypeFormWrapper/index.js @@ -6,6 +6,7 @@ import { useGlobalContext, formatComponentData, useQueryParams, + useNotification, } from '@strapi/helper-plugin'; import { useSelector, useDispatch } from 'react-redux'; import PropTypes from 'prop-types'; @@ -31,8 +32,9 @@ const SingleTypeFormWrapper = ({ allLayoutData, children, slug }) => { const [isCreatingEntry, setIsCreatingEntry] = useState(true); const [{ query, rawQuery }] = useQueryParams(); const searchToSend = buildQueryString(query); - + const toggleNotification = useNotification(); const dispatch = useDispatch(); + const { componentsDataStructure, contentTypeDataStructure, @@ -122,7 +124,10 @@ const SingleTypeFormWrapper = ({ allLayoutData, children, slug }) => { } if (responseStatus === 403) { - strapi.notification.info(getTrad('permissions.not-allowed.update')); + toggleNotification({ + type: 'info', + message: { id: getTrad('permissions.not-allowed.update') }, + }); push('/'); } @@ -132,23 +137,26 @@ const SingleTypeFormWrapper = ({ allLayoutData, children, slug }) => { fetchData(signal); return () => abortController.abort(); - }, [cleanReceivedData, push, slug, dispatch, searchToSend, rawQuery]); + }, [cleanReceivedData, push, slug, dispatch, searchToSend, rawQuery, toggleNotification]); - const displayErrors = useCallback(err => { - const errorPayload = err.response.payload; - console.error(errorPayload); + const displayErrors = useCallback( + err => { + const errorPayload = err.response.payload; + console.error(errorPayload); - let errorMessage = get(errorPayload, ['message'], 'Bad Request'); + let errorMessage = get(errorPayload, ['message'], 'Bad Request'); - // TODO handle errors correctly when back-end ready - if (Array.isArray(errorMessage)) { - errorMessage = get(errorMessage, ['0', 'messages', '0', 'id']); - } + // TODO handle errors correctly when back-end ready + if (Array.isArray(errorMessage)) { + errorMessage = get(errorMessage, ['0', 'messages', '0', 'id']); + } - if (typeof errorMessage === 'string') { - strapi.notification.error(errorMessage); - } - }, []); + if (typeof errorMessage === 'string') { + toggleNotification({ type: 'warning', message: errorMessage }); + } + }, + [toggleNotification] + ); const onDelete = useCallback( async trackerProperty => { @@ -159,7 +167,10 @@ const SingleTypeFormWrapper = ({ allLayoutData, children, slug }) => { method: 'DELETE', }); - strapi.notification.success(getTrad('success.record.delete')); + toggleNotification({ + type: 'success', + message: { id: getTrad('success.record.delete') }, + }); emitEventRef.current('didDeleteEntry', trackerProperty); @@ -170,7 +181,7 @@ const SingleTypeFormWrapper = ({ allLayoutData, children, slug }) => { return Promise.reject(err); } }, - [slug] + [slug, toggleNotification] ); const onDeleteSucceeded = useCallback(() => { @@ -189,7 +200,7 @@ const SingleTypeFormWrapper = ({ allLayoutData, children, slug }) => { const response = await request(endPoint, { method: 'PUT', body }); emitEventRef.current('didCreateEntry', trackerProperty); - strapi.notification.toggle({ + toggleNotification({ type: 'success', message: { id: getTrad('success.record.save') }, }); @@ -206,7 +217,7 @@ const SingleTypeFormWrapper = ({ allLayoutData, children, slug }) => { dispatch(setStatus('resolved')); } }, - [cleanReceivedData, displayErrors, slug, dispatch, rawQuery] + [cleanReceivedData, displayErrors, slug, dispatch, rawQuery, toggleNotification] ); const onPublish = useCallback(async () => { try { @@ -218,7 +229,7 @@ const SingleTypeFormWrapper = ({ allLayoutData, children, slug }) => { const data = await request(endPoint, { method: 'POST' }); emitEventRef.current('didPublishEntry'); - strapi.notification.toggle({ + toggleNotification({ type: 'success', message: { id: getTrad('success.record.publish') }, }); @@ -231,7 +242,7 @@ const SingleTypeFormWrapper = ({ allLayoutData, children, slug }) => { dispatch(setStatus('resolved')); } - }, [cleanReceivedData, displayErrors, slug, searchToSend, dispatch]); + }, [cleanReceivedData, displayErrors, slug, searchToSend, dispatch, toggleNotification]); const onPut = useCallback( async (body, trackerProperty) => { @@ -244,7 +255,7 @@ const SingleTypeFormWrapper = ({ allLayoutData, children, slug }) => { const response = await request(endPoint, { method: 'PUT', body }); - strapi.notification.toggle({ + toggleNotification({ type: 'success', message: { id: getTrad('success.record.save') }, }); @@ -262,7 +273,7 @@ const SingleTypeFormWrapper = ({ allLayoutData, children, slug }) => { dispatch(setStatus('resolved')); } }, - [cleanReceivedData, displayErrors, slug, dispatch, rawQuery] + [cleanReceivedData, displayErrors, slug, dispatch, rawQuery, toggleNotification] ); // The publish and unpublish method could be refactored but let's leave the duplication for now @@ -277,7 +288,10 @@ const SingleTypeFormWrapper = ({ allLayoutData, children, slug }) => { const response = await request(endPoint, { method: 'POST' }); emitEventRef.current('didUnpublishEntry'); - strapi.notification.success(getTrad('success.record.unpublish')); + toggleNotification({ + type: 'success', + message: { id: getTrad('success.record.unpublish') }, + }); dispatch(submitSucceeded(cleanReceivedData(response))); @@ -286,7 +300,7 @@ const SingleTypeFormWrapper = ({ allLayoutData, children, slug }) => { dispatch(setStatus('resolved')); displayErrors(err); } - }, [cleanReceivedData, displayErrors, slug, dispatch, searchToSend]); + }, [cleanReceivedData, toggleNotification, displayErrors, slug, dispatch, searchToSend]); return children({ componentsDataStructure, diff --git a/packages/core/content-type-builder/admin/src/components/BooleanBox/index.js b/packages/core/content-type-builder/admin/src/components/BooleanBox/index.js index d2fed6252d..25cf5e521d 100644 --- a/packages/core/content-type-builder/admin/src/components/BooleanBox/index.js +++ b/packages/core/content-type-builder/admin/src/components/BooleanBox/index.js @@ -1,6 +1,7 @@ import React from 'react'; import PropTypes from 'prop-types'; -import { useGlobalContext } from '@strapi/helper-plugin'; +import { useIntl } from 'react-intl'; +import { useNotification } from '@strapi/helper-plugin'; import { Flex } from '@buffetjs/core'; import styled from 'styled-components'; import CTIcon from './CT'; @@ -25,11 +26,13 @@ const STHackSpan = styled.span` `; const BooleanBox = ({ label, name, onChange, onChangeCallback, options, value }) => { - const { formatMessage } = useGlobalContext(); + const { formatMessage } = useIntl(); + + const toggleNotification = useNotification(); const handleChange = e => { onChange(e); - onChangeCallback(); + onChangeCallback({ toggleNotification }); }; return ( diff --git a/packages/core/content-type-builder/admin/src/components/BooleanBox/tests/BooleanBox.test.js b/packages/core/content-type-builder/admin/src/components/BooleanBox/tests/BooleanBox.test.js index 54e21f228e..4c722e1583 100644 --- a/packages/core/content-type-builder/admin/src/components/BooleanBox/tests/BooleanBox.test.js +++ b/packages/core/content-type-builder/admin/src/components/BooleanBox/tests/BooleanBox.test.js @@ -1,11 +1,16 @@ import React from 'react'; import { render, screen } from '@testing-library/react'; import { ThemeProvider } from 'styled-components'; + import defaultThemes from '../../../../../../admin/admin/src/themes'; import BooleanBox from '..'; +jest.mock('react-intl', () => ({ + useIntl: () => ({ formatMessage: ({ id }) => id }), +})); + jest.mock('@strapi/helper-plugin', () => ({ - useGlobalContext: () => ({ formatMessage: ({ id }) => id }), + useNotification: () => jest.fn(), })); describe('BooleanBox', () => { diff --git a/packages/core/content-type-builder/admin/src/containers/DataManagerProvider/index.js b/packages/core/content-type-builder/admin/src/containers/DataManagerProvider/index.js index 0ec8ce9fe8..4f779b4985 100644 --- a/packages/core/content-type-builder/admin/src/containers/DataManagerProvider/index.js +++ b/packages/core/content-type-builder/admin/src/containers/DataManagerProvider/index.js @@ -6,6 +6,7 @@ import { LoadingIndicatorPage, useGlobalContext, PopUpWarning, + useNotification, useStrapiApp, useUser, } from '@strapi/helper-plugin'; @@ -63,6 +64,7 @@ const DataManagerProvider = ({ reservedNames, }) => { const dispatch = useDispatch(); + const toggleNotification = useNotification(); const { getPlugin } = useStrapiApp(); @@ -124,7 +126,7 @@ const DataManagerProvider = ({ }); } catch (err) { console.error({ err }); - strapi.notification.toggle({ + toggleNotification({ type: 'warning', message: { id: 'notification.error' }, }); @@ -146,12 +148,12 @@ const DataManagerProvider = ({ useEffect(() => { if (!autoReload) { - strapi.notification.toggle({ + toggleNotification({ type: 'info', message: { id: getTrad('notification.info.autoreaload-disable') }, }); } - }, [autoReload]); + }, [autoReload, toggleNotification]); const didModifiedComponents = getCreatedAndModifiedComponents(modifiedData.components || {}, components).length > 0; @@ -258,7 +260,7 @@ const DataManagerProvider = ({ } } catch (err) { console.error({ err }); - strapi.notification.toggle({ + toggleNotification({ type: 'warning', message: { id: 'notification.error' }, }); @@ -309,7 +311,7 @@ const DataManagerProvider = ({ } } catch (err) { console.error({ err }); - strapi.notification.toggle({ + toggleNotification({ type: 'warning', message: { id: 'notification.error' }, }); @@ -339,7 +341,7 @@ const DataManagerProvider = ({ getDataRef.current(); } catch (err) { console.error({ err }); - strapi.notification.toggle({ + toggleNotification({ type: 'warning', message: { id: 'notification.error' }, }); @@ -495,7 +497,7 @@ const DataManagerProvider = ({ } console.error({ err: err.response }); - strapi.notification.toggle({ + toggleNotification({ type: 'warning', message: { id: 'notification.error' }, }); diff --git a/packages/core/content-type-builder/admin/src/containers/FormModal/contentType/form.js b/packages/core/content-type-builder/admin/src/containers/FormModal/contentType/form.js index 4509cac87c..5b8b55363a 100644 --- a/packages/core/content-type-builder/admin/src/containers/FormModal/contentType/form.js +++ b/packages/core/content-type-builder/admin/src/containers/FormModal/contentType/form.js @@ -87,8 +87,8 @@ const forms = { name: 'kind', type: 'booleanBox', size: 12, - onChangeCallback: () => - strapi.notification.toggle({ + onChangeCallback: ({ toggleNotification }) => + toggleNotification({ type: 'info', message: { id: getTrad('contentType.kind.change.warning') }, }), diff --git a/packages/core/content-type-builder/admin/src/containers/FormModal/index.js b/packages/core/content-type-builder/admin/src/containers/FormModal/index.js index 0de6725a0e..8d74c70e95 100644 --- a/packages/core/content-type-builder/admin/src/containers/FormModal/index.js +++ b/packages/core/content-type-builder/admin/src/containers/FormModal/index.js @@ -9,6 +9,7 @@ import { PopUpWarning, getYupInnerErrors, useGlobalContext, + useNotification, useQuery, useStrapiApp, InputsIndex, @@ -68,6 +69,7 @@ const FormModal = () => { const [showConfirmModal, setShowConfirmModal] = useState(false); const formModalSelector = useMemo(makeSelectFormModal, []); const dispatch = useDispatch(); + const toggleNotification = useNotification(); const reducerState = useSelector(state => formModalSelector(state), shallowEqual); const { push } = useHistory(); const { search } = useLocation(); @@ -704,7 +706,7 @@ const FormModal = () => { push({ search: '' }); submitData(modifiedData); } else { - strapi.notification.toggle({ + toggleNotification({ type: 'warning', message: { id: 'notification.contentType.relations.conflict' }, }); diff --git a/packages/core/content-type-builder/admin/src/containers/LeftMenu/index.js b/packages/core/content-type-builder/admin/src/containers/LeftMenu/index.js index 7eb4addeaa..469980a374 100644 --- a/packages/core/content-type-builder/admin/src/containers/LeftMenu/index.js +++ b/packages/core/content-type-builder/admin/src/containers/LeftMenu/index.js @@ -8,7 +8,7 @@ import React, { useMemo } from 'react'; import PropTypes from 'prop-types'; import { sortBy, camelCase, upperFirst } from 'lodash'; import { useHistory } from 'react-router-dom'; -import { LeftMenuList, useGlobalContext } from '@strapi/helper-plugin'; +import { LeftMenuList, useGlobalContext, useNotification } from '@strapi/helper-plugin'; import { Text } from '@buffetjs/core'; import pluginId from '../../pluginId'; import getTrad from '../../utils/getTrad'; @@ -19,13 +19,6 @@ import Wrapper from './Wrapper'; /* eslint-disable indent */ -const displayNotificationCTNotSaved = () => { - strapi.notification.toggle({ - type: 'info', - message: { id: `${pluginId}.notification.info.creating.notSaved` }, - }); -}; - function LeftMenu({ wait }) { const { components, @@ -34,8 +27,10 @@ function LeftMenu({ wait }) { isInDevelopmentMode, sortedContentTypesList, } = useDataManager(); + const toggleNotification = useNotification(); const { emitEvent, formatMessage } = useGlobalContext(); const { push } = useHistory(); + const componentsData = sortBy( Object.keys(componentsGroupedByCategory).map(category => ({ name: category, @@ -107,7 +102,10 @@ function LeftMenu({ wait }) { search, }); } else { - displayNotificationCTNotSaved(); + toggleNotification({ + type: 'info', + message: { id: `${pluginId}.notification.info.creating.notSaved` }, + }); } }; diff --git a/packages/core/email/admin/src/containers/Settings/index.js b/packages/core/email/admin/src/containers/Settings/index.js index 977388fbde..baedd23eae 100644 --- a/packages/core/email/admin/src/containers/Settings/index.js +++ b/packages/core/email/admin/src/containers/Settings/index.js @@ -1,3 +1,4 @@ +/* eslint-disable react/jsx-wrap-multilines */ import React, { useState, useEffect, useRef } from 'react'; import { useIntl, FormattedMessage } from 'react-intl'; import { get } from 'lodash'; @@ -12,6 +13,7 @@ import { getYupInnerErrors, BaselineAlignment, CheckPagePermissions, + useNotification, } from '@strapi/helper-plugin'; import getTrad from '../../utils/getTrad'; import { AlignedButton, Text } from './components'; @@ -19,6 +21,7 @@ import schema from '../../utils/schema'; import pluginPermissions from '../../permissions'; const SettingsPage = () => { + const toggleNotification = useNotification(); const { formatMessage } = useIntl(); const [formErrors, setFormErrors] = useState({}); const [isTestButtonLoading, setIsTestButtonLoading] = useState(false); @@ -50,14 +53,17 @@ const SettingsPage = () => { }); setTestSuccess(true); - - strapi.notification.success( - formatMessage({ id: getTrad('Settings.notification.test.success') }, { to: testAddress }) + const message = formatMessage( + { id: getTrad('Settings.notification.test.success') }, + { to: testAddress } ); + toggleNotification({ type: 'success', message }); } catch (err) { - strapi.notification.error( - formatMessage({ id: getTrad('Settings.notification.test.error') }, { to: testAddress }) + const message = formatMessage( + { id: getTrad('Settings.notification.test.error') }, + { to: testAddress } ); + toggleNotification({ type: 'warning', message }); } finally { if (isMounted.current) { setIsTestButtonLoading(false); @@ -83,15 +89,16 @@ const SettingsPage = () => { setTestAddress(get(data, 'config.settings.testAddress')); }) .catch(() => - strapi.notification.error( - formatMessage({ id: getTrad('Settings.notification.config.error') }) - ) + toggleNotification({ + type: 'warning', + message: { id: getTrad('Settings.notification.config.error') }, + }) ) .finally(() => setShowLoader(false)); }; fetchEmailSettings(); - }, [formatMessage]); + }, [formatMessage, toggleNotification]); useEffect(() => { return () => { @@ -178,12 +185,12 @@ const SettingsPage = () => { - )} + } isLoading={isTestButtonLoading} style={{ fontWeight: 600 }} type="submit" diff --git a/packages/core/helper-plugin/lib/src/components/CheckPagePermissions/index.js b/packages/core/helper-plugin/lib/src/components/CheckPagePermissions/index.js index 84b6e969c5..d46e326d41 100644 --- a/packages/core/helper-plugin/lib/src/components/CheckPagePermissions/index.js +++ b/packages/core/helper-plugin/lib/src/components/CheckPagePermissions/index.js @@ -1,6 +1,7 @@ import React, { useEffect, useRef, useState } from 'react'; import { Redirect } from 'react-router-dom'; import PropTypes from 'prop-types'; +import useNotification from '../../hooks/useNotification'; import useUser from '../../hooks/useUser'; import hasPermissions from '../../utils/hasPermissions'; import LoadingIndicatorPage from '../LoadingIndicatorPage'; @@ -9,6 +10,7 @@ const CheckPagePermissions = ({ permissions, children }) => { const abortController = new AbortController(); const { signal } = abortController; const { userPermissions } = useUser(); + const toggleNotification = useNotification(); const [state, setState] = useState({ isLoading: true, canAccess: false }); const isMounted = useRef(true); @@ -27,7 +29,7 @@ const CheckPagePermissions = ({ permissions, children }) => { if (isMounted.current) { console.error(err); - strapi.notification.toggle({ + toggleNotification({ type: 'warning', message: { id: 'notification.error' }, }); diff --git a/packages/core/helper-plugin/lib/src/components/CheckPermissions/index.js b/packages/core/helper-plugin/lib/src/components/CheckPermissions/index.js index 48145923ca..91162c8e86 100644 --- a/packages/core/helper-plugin/lib/src/components/CheckPermissions/index.js +++ b/packages/core/helper-plugin/lib/src/components/CheckPermissions/index.js @@ -1,6 +1,6 @@ import { useEffect, useRef, useState } from 'react'; - import PropTypes from 'prop-types'; +import useNotification from '../../hooks/useNotification'; import useUser from '../../hooks/useUser'; import hasPermissions from '../../utils/hasPermissions'; @@ -9,6 +9,7 @@ import hasPermissions from '../../utils/hasPermissions'; const CheckPermissions = ({ permissions, children }) => { const { userPermissions } = useUser(); + const toggleNotification = useNotification(); const [state, setState] = useState({ isLoading: true, canAccess: false }); const isMounted = useRef(true); const abortController = new AbortController(); @@ -27,7 +28,7 @@ const CheckPermissions = ({ permissions, children }) => { } catch (err) { if (isMounted.current) { console.error(err); - strapi.notification.toggle({ + toggleNotification({ type: 'warning', message: { id: 'notification.error' }, }); diff --git a/packages/core/helper-plugin/lib/src/contexts/NotificationsContext.js b/packages/core/helper-plugin/lib/src/contexts/NotificationsContext.js new file mode 100644 index 0000000000..b9918c225b --- /dev/null +++ b/packages/core/helper-plugin/lib/src/contexts/NotificationsContext.js @@ -0,0 +1,11 @@ +/** + * + * NotificationsContext + * + */ + +import { createContext } from 'react'; + +const NotificationsContext = createContext(); + +export default NotificationsContext; diff --git a/packages/core/helper-plugin/lib/src/hooks/useNotification/index.js b/packages/core/helper-plugin/lib/src/hooks/useNotification/index.js new file mode 100644 index 0000000000..824ff1206f --- /dev/null +++ b/packages/core/helper-plugin/lib/src/hooks/useNotification/index.js @@ -0,0 +1,19 @@ +/** + * + * useNotification + * + */ + +import { useContext, useRef } from 'react'; +import NotificationsContext from '../../contexts/NotificationsContext'; + +const useNotification = () => { + const { toggleNotification } = useContext(NotificationsContext); + // Use a ref so we can safely add the toggleNotification + // to a hook dependencies array + const toggleNotificationRef = useRef(toggleNotification); + + return toggleNotificationRef.current; +}; + +export default useNotification; diff --git a/packages/core/helper-plugin/lib/src/index.js b/packages/core/helper-plugin/lib/src/index.js index 47d1fa44cd..52e916eec8 100644 --- a/packages/core/helper-plugin/lib/src/index.js +++ b/packages/core/helper-plugin/lib/src/index.js @@ -105,6 +105,7 @@ export { default as PopUpWarningIcon } from './components/PopUpWarning/Icon'; export { default as PopUpWarningModal } from './components/PopUpWarning/StyledModal'; // Contexts +export { default as NotificationsContext } from './contexts/NotificationsContext'; export { GlobalContext, GlobalContextProvider, useGlobalContext } from './contexts/GlobalContext'; export { default as UserContext } from './contexts/UserContext'; export { default as ContentManagerEditViewDataManagerContext } from './contexts/ContentManagerEditViewDataManagerContext'; @@ -113,6 +114,7 @@ export { default as ContentManagerEditViewDataManagerContext } from './contexts/ export { default as useContentManagerEditViewDataManager } from './hooks/useContentManagerEditViewDataManager'; export { default as useQuery } from './hooks/useQuery'; export { default as useLibrary } from './hooks/useLibrary'; +export { default as useNotification } from './hooks/useNotification'; export { default as useStrapiApp } from './hooks/useStrapiApp'; export { default as useUser } from './hooks/useUser'; export { default as useUserPermissions } from './hooks/useUserPermissions'; @@ -120,6 +122,7 @@ export { default as useQueryParams } from './hooks/useQueryParams'; // Providers export { default as LibraryProvider } from './providers/LibraryProvider'; +export { default as NotificationsProvider } from './providers/NotificationsProvider'; export { default as StrapiAppProvider } from './providers/StrapiAppProvider'; // Utils diff --git a/packages/core/helper-plugin/lib/src/providers/NotificationsProvider/index.js b/packages/core/helper-plugin/lib/src/providers/NotificationsProvider/index.js new file mode 100644 index 0000000000..cb11b50ca2 --- /dev/null +++ b/packages/core/helper-plugin/lib/src/providers/NotificationsProvider/index.js @@ -0,0 +1,23 @@ +/** + * + * NotificationsProvider + * + */ +import React from 'react'; +import PropTypes from 'prop-types'; +import NotificationsContext from '../../contexts/NotificationsContext'; + +const NotificationsProvider = ({ children, toggleNotification }) => { + return ( + + {children} + + ); +}; + +NotificationsProvider.propTypes = { + children: PropTypes.node.isRequired, + toggleNotification: PropTypes.func.isRequired, +}; + +export default NotificationsProvider; diff --git a/packages/core/upload/admin/src/components/EditForm/index.js b/packages/core/upload/admin/src/components/EditForm/index.js index 1b5dfda549..3c558452aa 100644 --- a/packages/core/upload/admin/src/components/EditForm/index.js +++ b/packages/core/upload/admin/src/components/EditForm/index.js @@ -14,7 +14,11 @@ import { get } from 'lodash'; import PropTypes from 'prop-types'; import { Row } from 'reactstrap'; import { Inputs } from '@buffetjs/custom'; -import { useGlobalContext, prefixFileUrlWithBackendUrl } from '@strapi/helper-plugin'; +import { + useGlobalContext, + useNotification, + prefixFileUrlWithBackendUrl, +} from '@strapi/helper-plugin'; import Cropper from 'cropperjs'; import 'cropperjs/dist/cropper.css'; import { createFileToDownloadName } from '../../utils'; @@ -53,6 +57,7 @@ const EditForm = forwardRef( }, ref ) => { + const toggleNotification = useNotification(); const { formatMessage } = useGlobalContext(); const [isCropping, setIsCropping] = useState(false); const [infos, setInfos] = useState({ width: null, height: null }); @@ -193,7 +198,7 @@ const EditForm = forwardRef( }; const handleCopy = () => { - strapi.notification.toggle({ + toggleNotification({ type: 'info', message: { id: 'notification.link-copied' }, }); diff --git a/packages/core/upload/admin/src/components/InputMedia/index.js b/packages/core/upload/admin/src/components/InputMedia/index.js index 036c170bef..dac898cf34 100644 --- a/packages/core/upload/admin/src/components/InputMedia/index.js +++ b/packages/core/upload/admin/src/components/InputMedia/index.js @@ -6,6 +6,7 @@ import { CheckPermissions, LabelIconWrapper, prefixFileUrlWithBackendUrl, + useNotification, } from '@strapi/helper-plugin'; import pluginPermissions from '../../permissions'; import { getTrad, formatFileForEditing } from '../../utils'; @@ -33,6 +34,7 @@ const InputMedia = ({ error, labelIcon, }) => { + const toggleNotification = useNotification(); const [modal, setModal] = useState({ isOpen: false, step: 'list', @@ -108,7 +110,7 @@ const InputMedia = ({ }; const handleCopy = () => { - strapi.notification.toggle({ + toggleNotification({ type: 'info', message: { id: 'notification.link-copied' }, }); diff --git a/packages/core/upload/admin/src/containers/HomePage/index.js b/packages/core/upload/admin/src/containers/HomePage/index.js index 3864a9da24..a14c877924 100644 --- a/packages/core/upload/admin/src/containers/HomePage/index.js +++ b/packages/core/upload/admin/src/containers/HomePage/index.js @@ -10,6 +10,7 @@ import { generateSearchFromFilters, request, useQuery, + useNotification, } from '@strapi/helper-plugin'; import { formatFileForEditing, getRequestUrl, getTrad } from '../../utils'; import { useAppContext, useSelectTimestamps } from '../../hooks'; @@ -21,6 +22,7 @@ import init from './init'; import reducer, { initialState } from './reducer'; const HomePage = () => { + const toggleNotification = useNotification(); const { allowedActions } = useAppContext(); const { canRead } = allowedActions; const { formatMessage } = useGlobalContext(); @@ -91,7 +93,7 @@ const HomePage = () => { } catch (err) { if (isMounted.current) { dispatch({ type: 'GET_DATA_ERROR' }); - strapi.notification.toggle({ + toggleNotification({ type: 'warning', message: { id: 'notification.error' }, }); @@ -114,7 +116,7 @@ const HomePage = () => { } catch (err) { if (isMounted.current) { dispatch({ type: 'GET_DATA_ERROR' }); - strapi.notification.toggle({ + toggleNotification({ type: 'warning', message: { id: 'notification.error' }, }); @@ -232,7 +234,7 @@ const HomePage = () => { type: 'ON_DELETE_MEDIAS_SUCCEEDED', }); } catch (err) { - strapi.notification.toggle({ + toggleNotification({ type: 'warning', message: err, }); @@ -243,7 +245,7 @@ const HomePage = () => { } finally { setIsPopupOpen(false); } - }, [dataToDelete]); + }, [dataToDelete, toggleNotification]); const handleClosedModalDeleteAll = useCallback(() => { if (shouldRefetchData) { diff --git a/packages/core/upload/admin/src/containers/Initializer/index.js b/packages/core/upload/admin/src/containers/Initializer/index.js index c5db3b1935..bf8bc7d052 100644 --- a/packages/core/upload/admin/src/containers/Initializer/index.js +++ b/packages/core/upload/admin/src/containers/Initializer/index.js @@ -8,7 +8,7 @@ import { useEffect, useRef } from 'react'; import PropTypes from 'prop-types'; import { useDispatch } from 'react-redux'; import get from 'lodash/get'; -import { request } from '@strapi/helper-plugin'; +import { request, useNotification } from '@strapi/helper-plugin'; import pluginId from '../../pluginId'; import { setFileModelTimestamps } from './actions'; @@ -16,6 +16,7 @@ const Initializer = ({ setPlugin }) => { const ref = useRef(); const dispatch = useDispatch(); ref.current = setPlugin; + const toggleNotification = useNotification(); useEffect(() => { const getData = async () => { @@ -35,7 +36,7 @@ const Initializer = ({ setPlugin }) => { ref.current(pluginId); } catch (err) { - strapi.notification.toggle({ + toggleNotification({ type: 'warning', message: { id: 'content-manager.error.model.fetch' }, }); @@ -43,7 +44,7 @@ const Initializer = ({ setPlugin }) => { }; getData(); - }, [dispatch]); + }, [dispatch, toggleNotification]); return null; }; diff --git a/packages/core/upload/admin/src/containers/InputModalStepper/InputModalStepper.js b/packages/core/upload/admin/src/containers/InputModalStepper/InputModalStepper.js index 36cf08851c..6787292974 100644 --- a/packages/core/upload/admin/src/containers/InputModalStepper/InputModalStepper.js +++ b/packages/core/upload/admin/src/containers/InputModalStepper/InputModalStepper.js @@ -1,6 +1,13 @@ import React, { useEffect, useState, useRef, memo } from 'react'; import PropTypes from 'prop-types'; -import { Modal, ModalFooter, PopUpWarning, useGlobalContext, request } from '@strapi/helper-plugin'; +import { + Modal, + ModalFooter, + PopUpWarning, + useGlobalContext, + useNotification, + request, +} from '@strapi/helper-plugin'; import { Button } from '@buffetjs/core'; import { get, isEmpty, isEqual } from 'lodash'; import { getRequestUrl, getTrad } from '../../utils'; @@ -19,6 +26,7 @@ const InputModalStepper = ({ const { emitEvent, formatMessage } = useGlobalContext(); const [shouldDeleteFile, setShouldDeleteFile] = useState(false); const [displayNextButton, setDisplayNextButton] = useState(false); + const toggleNotification = useNotification(); const { addFilesToUpload, currentStep, @@ -210,7 +218,7 @@ const InputModalStepper = ({ ['response', 'payload', 'message', '0', 'messages', '0', 'message'], get(err, ['response', 'payload', 'message'], statusText) ); - strapi.notification.toggle({ + toggleNotification({ type: 'warning', message: errorMessage, }); diff --git a/packages/core/upload/admin/src/containers/InputModalStepperProvider/index.js b/packages/core/upload/admin/src/containers/InputModalStepperProvider/index.js index 2a7bdead45..647b1b9fd9 100644 --- a/packages/core/upload/admin/src/containers/InputModalStepperProvider/index.js +++ b/packages/core/upload/admin/src/containers/InputModalStepperProvider/index.js @@ -1,6 +1,11 @@ import React, { useReducer, useEffect, useState } from 'react'; import PropTypes from 'prop-types'; -import { request, generateSearchFromFilters, useGlobalContext } from '@strapi/helper-plugin'; +import { + request, + generateSearchFromFilters, + useGlobalContext, + useNotification, +} from '@strapi/helper-plugin'; import { clone, get, isEmpty, set } from 'lodash'; import { useIntl } from 'react-intl'; import axios from 'axios'; @@ -37,6 +42,7 @@ const InputModalStepperProvider = ({ step, }) => { const [formErrors, setFormErrors] = useState(null); + const toggleNotification = useNotification(); const { formatMessage } = useIntl(); const { emitEvent } = useGlobalContext(); @@ -338,7 +344,7 @@ const InputModalStepperProvider = ({ }); } catch (err) { console.error(err); - strapi.notification.toggle({ + toggleNotification({ type: 'warning', message: { id: 'notification.error' }, }); @@ -368,7 +374,7 @@ const InputModalStepperProvider = ({ }); } catch (err) { console.error(err); - strapi.notification.toggle({ + toggleNotification({ type: 'warning', message: { id: 'notification.error' }, }); diff --git a/packages/core/upload/admin/src/containers/ModalStepper/index.js b/packages/core/upload/admin/src/containers/ModalStepper/index.js index 3e358f92aa..6eef4ae172 100644 --- a/packages/core/upload/admin/src/containers/ModalStepper/index.js +++ b/packages/core/upload/admin/src/containers/ModalStepper/index.js @@ -2,7 +2,14 @@ import React, { useCallback, useEffect, useState, useReducer, useRef } from 'rea import axios from 'axios'; import PropTypes from 'prop-types'; import { isEqual, isEmpty, get, set } from 'lodash'; -import { Modal, ModalFooter, PopUpWarning, useGlobalContext, request } from '@strapi/helper-plugin'; +import { + Modal, + ModalFooter, + PopUpWarning, + useGlobalContext, + request, + useNotification, +} from '@strapi/helper-plugin'; import { Button } from '@buffetjs/core'; import pluginId from '../../pluginId'; import { getFilesToDownload, getTrad, getYupError, urlSchema } from '../../utils'; @@ -20,6 +27,7 @@ const ModalStepper = ({ onRemoveFileFromDataToDelete, onToggle, }) => { + const toggleNotification = useNotification(); const { allowedActions } = useAppContext(); const { emitEvent, formatMessage } = useGlobalContext(); const [isWarningDeleteOpen, setIsWarningDeleteOpen] = useState(false); @@ -191,7 +199,7 @@ const ModalStepper = ({ } catch (err) { const errorMessage = get(err, 'response.payload.message', 'An error occured'); - strapi.notification.toggle({ + toggleNotification({ type: 'warning', message: errorMessage, }); diff --git a/packages/core/upload/admin/src/containers/SettingsPage/index.js b/packages/core/upload/admin/src/containers/SettingsPage/index.js index 9d2f01081d..fc6639b735 100644 --- a/packages/core/upload/admin/src/containers/SettingsPage/index.js +++ b/packages/core/upload/admin/src/containers/SettingsPage/index.js @@ -3,7 +3,12 @@ import { Header, Inputs } from '@buffetjs/custom'; import { Helmet } from 'react-helmet'; import { Text } from '@buffetjs/core'; import { isEqual } from 'lodash'; -import { LoadingIndicatorPage, useGlobalContext, request } from '@strapi/helper-plugin'; +import { + LoadingIndicatorPage, + useGlobalContext, + useNotification, + request, +} from '@strapi/helper-plugin'; import { getRequestUrl, getTrad } from '../../utils'; import SectionTitleWrapper from './SectionTitleWrapper'; @@ -17,6 +22,8 @@ const SettingsPage = () => { const { initialData, isLoading, modifiedData } = reducerState.toJS(); const isMounted = useRef(true); const getDataRef = useRef(); + const toggleNotification = useNotification(); + const abortController = new AbortController(); getDataRef.current = async () => { @@ -58,7 +65,7 @@ const SettingsPage = () => { }); } - strapi.notification.toggle({ + toggleNotification({ type: 'success', message: { id: 'notification.form.success.fields' }, }); diff --git a/packages/plugins/documentation/admin/src/components/Copy/index.js b/packages/plugins/documentation/admin/src/components/Copy/index.js index 6c150945a1..d8924d2974 100644 --- a/packages/plugins/documentation/admin/src/components/Copy/index.js +++ b/packages/plugins/documentation/admin/src/components/Copy/index.js @@ -1,11 +1,13 @@ import React from 'react'; -import { auth, InputsIndex as Input } from '@strapi/helper-plugin'; +import { auth, InputsIndex as Input, useNotification } from '@strapi/helper-plugin'; import { CopyToClipboard } from 'react-copy-to-clipboard'; import getTrad from '../../utils/getTrad'; const Copy = () => { + const toggleNotification = useNotification(); + const handleCopy = () => { - strapi.notification.toggle({ + toggleNotification({ type: 'info', message: { id: getTrad('containers.HomePage.copied') }, }); diff --git a/packages/plugins/documentation/admin/src/containers/HomePage/useHomePage.js b/packages/plugins/documentation/admin/src/containers/HomePage/useHomePage.js index e45b68f5c9..5d4147b3b2 100644 --- a/packages/plugins/documentation/admin/src/containers/HomePage/useHomePage.js +++ b/packages/plugins/documentation/admin/src/containers/HomePage/useHomePage.js @@ -1,13 +1,15 @@ import { useQuery, useMutation, useQueryClient } from 'react-query'; +import { useNotification } from '@strapi/helper-plugin'; import { fetchData, deleteDoc, regenerateDoc, submit } from './utils/api'; import getTrad from '../../utils/getTrad'; const useHomePage = () => { const queryClient = useQueryClient(); - const { isLoading, data } = useQuery('get-documentation', fetchData); + const toggleNotification = useNotification(); + const { isLoading, data } = useQuery('get-documentation', () => fetchData(toggleNotification)); const handleError = err => { - strapi.notification.toggle({ + toggleNotification({ type: 'warning', message: err.response.payload.message, }); @@ -16,7 +18,7 @@ const useHomePage = () => { const deleteMutation = useMutation(deleteDoc, { onSuccess: () => { queryClient.invalidateQueries('get-documentation'); - strapi.notification.toggle({ + toggleNotification({ type: 'info', message: { id: getTrad('notification.delete.success') }, }); @@ -28,7 +30,7 @@ const useHomePage = () => { onSuccess: () => { queryClient.invalidateQueries('get-documentation'); - strapi.notification.toggle({ + toggleNotification({ type: 'success', message: { id: getTrad('notification.update.success') }, }); @@ -40,7 +42,7 @@ const useHomePage = () => { onSuccess: () => { queryClient.invalidateQueries('get-documentation'); - strapi.notification.toggle({ + toggleNotification({ type: 'info', message: { id: getTrad('notification.generate.success') }, }); diff --git a/packages/plugins/documentation/admin/src/containers/HomePage/utils/api.js b/packages/plugins/documentation/admin/src/containers/HomePage/utils/api.js index b535c662c4..765957c9c5 100644 --- a/packages/plugins/documentation/admin/src/containers/HomePage/utils/api.js +++ b/packages/plugins/documentation/admin/src/containers/HomePage/utils/api.js @@ -5,17 +5,18 @@ const deleteDoc = ({ prefix, version }) => { return request(`${prefix}/deleteDoc/${version}`, { method: 'DELETE' }); }; -const fetchData = async () => { +const fetchData = async toggleNotification => { try { const data = await request(`/${pluginId}/getInfos`, { method: 'GET' }); return data; } catch (err) { - strapi.notification.toggle({ + toggleNotification({ type: 'warning', message: { id: 'notification.error' }, }); + // FIXME return null; } }; diff --git a/packages/plugins/i18n/admin/src/components/CMEditViewCopyLocale/index.js b/packages/plugins/i18n/admin/src/components/CMEditViewCopyLocale/index.js index 7eded7431f..38ced8a829 100644 --- a/packages/plugins/i18n/admin/src/components/CMEditViewCopyLocale/index.js +++ b/packages/plugins/i18n/admin/src/components/CMEditViewCopyLocale/index.js @@ -12,6 +12,7 @@ import { ModalConfirm, selectStyles, useContentManagerEditViewDataManager, + useNotification, request, } from '@strapi/helper-plugin'; import { getTrad } from '../../utils'; @@ -28,6 +29,7 @@ const CMEditViewCopyLocale = props => { const Content = ({ appLocales, currentLocale, localizations, readPermissions }) => { const options = generateOptions(appLocales, currentLocale, localizations, readPermissions); + const toggleNotification = useNotification(); const { formatMessage } = useIntl(); const dispatch = useDispatch(); const { allLayoutData, slug } = useContentManagerEditViewDataManager(); @@ -52,7 +54,7 @@ const Content = ({ appLocales, currentLocale, localizations, readPermissions }) dispatch({ type: 'ContentManager/CrudReducer/GET_DATA_SUCCEEDED', data: cleanedData }); - strapi.notification.toggle({ + toggleNotification({ type: 'success', message: { id: getTrad('CMEditViewCopyLocale.copy-success'), @@ -62,7 +64,7 @@ const Content = ({ appLocales, currentLocale, localizations, readPermissions }) } catch (err) { console.error(err); - strapi.notification.toggle({ + toggleNotification({ type: 'warning', message: { id: getTrad('CMEditViewCopyLocale.copy-failure'), diff --git a/packages/plugins/i18n/admin/src/containers/SettingsPage/tests/SettingsPage.test.js b/packages/plugins/i18n/admin/src/containers/SettingsPage/tests/SettingsPage.test.js index f635c8bb84..01b903ddc7 100644 --- a/packages/plugins/i18n/admin/src/containers/SettingsPage/tests/SettingsPage.test.js +++ b/packages/plugins/i18n/admin/src/containers/SettingsPage/tests/SettingsPage.test.js @@ -8,6 +8,8 @@ import { fireEvent, render, screen, within, waitFor } from '@testing-library/rea import { ThemeProvider } from 'styled-components'; import { QueryClient, QueryClientProvider } from 'react-query'; import LocaleSettingsPage from '..'; +// eslint-disable-next-line import/extensions +import '@fortawesome/fontawesome-free/js/all.min.js'; // TODO: move to @strapi/helper-plugin import themes from '../../../../../../../core/admin/admin/src/themes'; import i18nReducers, { initialState } from '../../../hooks/reducers'; @@ -28,6 +30,8 @@ const TestWrapper = ({ children }) => { ); }; +const toggleNotificationMock = jest.fn(); + // TODO: we should not be forced to mock this module // but it bugs somehow when run with jest jest.mock('@strapi/helper-plugin', () => ({ @@ -65,6 +69,7 @@ jest.mock('@strapi/helper-plugin', () => ({ selectStyles: () => ({ control: () => ({}), indicatorsContainer: () => ({}) }), useGlobalContext: () => ({ updateMenu: jest.fn() }), useUser: () => ({ fetchUserPermissions: jest.fn() }), + useNotification: () => toggleNotificationMock, })); jest.mock('../../../utils', () => ({ @@ -100,8 +105,6 @@ describe('i18n settings page', () => { isLoading: false, allowedActions: { canRead: true, canUpdate: true, canCreate: true, canDelete: true }, })); - - strapi.notification.toggle = jest.fn(); }); afterEach(() => { @@ -175,7 +178,7 @@ describe('i18n settings page', () => { fireEvent.click(screen.getByText('Confirm')); await waitFor(() => - expect(strapi.notification.toggle).toBeCalledWith({ + expect(toggleNotificationMock).toBeCalledWith({ type: 'success', message: { id: 'Settings.locales.modal.delete.success' }, }) @@ -215,7 +218,7 @@ describe('i18n settings page', () => { fireEvent.click(screen.getByText('Confirm')); await waitFor(() => - expect(strapi.notification.toggle).toBeCalledWith({ + expect(toggleNotificationMock).toBeCalledWith({ type: 'warning', message: { id: 'notification.error' }, }) @@ -316,7 +319,7 @@ describe('i18n settings page', () => { fireEvent.click(screen.getByText('Settings.locales.modal.edit.confirmation')); await waitFor(() => - expect(strapi.notification.toggle).toBeCalledWith({ + expect(toggleNotificationMock).toBeCalledWith({ type: 'warning', message: { id: 'notification.error' }, }) @@ -363,7 +366,7 @@ describe('i18n settings page', () => { fireEvent.click(screen.getByText('Settings.locales.modal.edit.confirmation')); await waitFor(() => - expect(strapi.notification.toggle).toBeCalledWith({ + expect(toggleNotificationMock).toBeCalledWith({ type: 'success', message: { id: 'Settings.locales.modal.edit.success' }, }) @@ -422,7 +425,7 @@ describe('i18n settings page', () => { fireEvent.click(screen.getByText('Settings.locales.modal.edit.confirmation')); await waitFor(() => - expect(strapi.notification.toggle).toBeCalledWith({ + expect(toggleNotificationMock).toBeCalledWith({ type: 'success', message: { id: 'Settings.locales.modal.edit.success' }, }) @@ -448,7 +451,7 @@ describe('i18n settings page', () => { ); await waitFor(() => - expect(strapi.notification.toggle).toBeCalledWith({ + expect(toggleNotificationMock).toBeCalledWith({ type: 'warning', message: { id: 'notification.error' }, }) @@ -697,7 +700,7 @@ describe('i18n settings page', () => { fireEvent.click(confirmationButton); await waitFor(() => - expect(strapi.notification.toggle).toBeCalledWith({ + expect(toggleNotificationMock).toBeCalledWith({ type: 'warning', message: { id: 'notification.error' }, }) @@ -732,7 +735,7 @@ describe('i18n settings page', () => { fireEvent.click(confirmationButton); await waitFor(() => - expect(strapi.notification.toggle).toBeCalledWith({ + expect(toggleNotificationMock).toBeCalledWith({ type: 'success', message: { id: 'Settings.locales.modal.create.success' }, }) diff --git a/packages/plugins/i18n/admin/src/hooks/useAddLocale/index.js b/packages/plugins/i18n/admin/src/hooks/useAddLocale/index.js index 218b6445d0..efc1c7e10e 100644 --- a/packages/plugins/i18n/admin/src/hooks/useAddLocale/index.js +++ b/packages/plugins/i18n/admin/src/hooks/useAddLocale/index.js @@ -1,11 +1,11 @@ import { useState } from 'react'; -import { request } from '@strapi/helper-plugin'; +import { request, useNotification } from '@strapi/helper-plugin'; import { useDispatch } from 'react-redux'; import get from 'lodash/get'; import { getTrad } from '../../utils'; import { ADD_LOCALE } from '../constants'; -const addLocale = async ({ code, name, isDefault }) => { +const addLocale = async ({ code, name, isDefault }, toggleNotification) => { const data = await request(`/i18n/locales`, { method: 'POST', body: { @@ -15,7 +15,7 @@ const addLocale = async ({ code, name, isDefault }) => { }, }); - strapi.notification.toggle({ + toggleNotification({ type: 'success', message: { id: getTrad('Settings.locales.modal.create.success') }, }); @@ -26,23 +26,24 @@ const addLocale = async ({ code, name, isDefault }) => { const useAddLocale = () => { const [isLoading, setLoading] = useState(false); const dispatch = useDispatch(); + const toggleNotification = useNotification(); const persistLocale = async locale => { setLoading(true); try { - const newLocale = await addLocale(locale); + const newLocale = await addLocale(locale, toggleNotification); dispatch({ type: ADD_LOCALE, newLocale }); } catch (e) { const message = get(e, 'response.payload.message', null); if (message && message.includes('already exists')) { - strapi.notification.toggle({ + toggleNotification({ type: 'warning', message: { id: getTrad('Settings.locales.modal.create.alreadyExist') }, }); } else { - strapi.notification.toggle({ + toggleNotification({ type: 'warning', message: { id: 'notification.error' }, }); diff --git a/packages/plugins/i18n/admin/src/hooks/useDefaultLocales/index.js b/packages/plugins/i18n/admin/src/hooks/useDefaultLocales/index.js index 30f867e4e7..79bd60cdfb 100644 --- a/packages/plugins/i18n/admin/src/hooks/useDefaultLocales/index.js +++ b/packages/plugins/i18n/admin/src/hooks/useDefaultLocales/index.js @@ -1,7 +1,7 @@ import { useQuery } from 'react-query'; -import { request } from '@strapi/helper-plugin'; +import { request, useNotification } from '@strapi/helper-plugin'; -const fetchDefaultLocalesList = async () => { +const fetchDefaultLocalesList = async toggleNotification => { try { const data = await request('/i18n/iso-locales', { method: 'GET', @@ -9,7 +9,7 @@ const fetchDefaultLocalesList = async () => { return data; } catch (e) { - strapi.notification.toggle({ + toggleNotification({ type: 'warning', message: { id: 'notification.error' }, }); @@ -19,7 +19,10 @@ const fetchDefaultLocalesList = async () => { }; const useDefaultLocales = () => { - const { isLoading, data } = useQuery('default-locales', fetchDefaultLocalesList); + const toggleNotification = useNotification(); + const { isLoading, data } = useQuery('default-locales', () => + fetchDefaultLocalesList(toggleNotification) + ); return { defaultLocales: data, isLoading }; }; diff --git a/packages/plugins/i18n/admin/src/hooks/useDeleteLocale/index.js b/packages/plugins/i18n/admin/src/hooks/useDeleteLocale/index.js index 2d012990fc..707d81817f 100644 --- a/packages/plugins/i18n/admin/src/hooks/useDeleteLocale/index.js +++ b/packages/plugins/i18n/admin/src/hooks/useDeleteLocale/index.js @@ -1,23 +1,23 @@ import { useState } from 'react'; -import { request } from '@strapi/helper-plugin'; +import { request, useNotification } from '@strapi/helper-plugin'; import { useDispatch } from 'react-redux'; import { getTrad } from '../../utils'; import { DELETE_LOCALE } from '../constants'; -const deleteLocale = async id => { +const deleteLocale = async (id, toggleNotification) => { try { const data = await request(`/i18n/locales/${id}`, { method: 'DELETE', }); - strapi.notification.toggle({ + toggleNotification({ type: 'success', message: { id: getTrad('Settings.locales.modal.delete.success') }, }); return data; } catch (e) { - strapi.notification.toggle({ + toggleNotification({ type: 'warning', message: { id: 'notification.error' }, }); @@ -29,11 +29,12 @@ const deleteLocale = async id => { const useDeleteLocale = () => { const [isLoading, setLoading] = useState(false); const dispatch = useDispatch(); + const toggleNotification = useNotification(); const removeLocale = async id => { setLoading(true); - await deleteLocale(id); + await deleteLocale(id, toggleNotification); dispatch({ type: DELETE_LOCALE, id }); setLoading(false); diff --git a/packages/plugins/i18n/admin/src/hooks/useEditLocale/index.js b/packages/plugins/i18n/admin/src/hooks/useEditLocale/index.js index 4088611f46..112dd0e666 100644 --- a/packages/plugins/i18n/admin/src/hooks/useEditLocale/index.js +++ b/packages/plugins/i18n/admin/src/hooks/useEditLocale/index.js @@ -1,24 +1,24 @@ import { useState } from 'react'; -import { request } from '@strapi/helper-plugin'; +import { request, useNotification } from '@strapi/helper-plugin'; import { useDispatch } from 'react-redux'; import { getTrad } from '../../utils'; import { UPDATE_LOCALE } from '../constants'; -const editLocale = async (id, payload) => { +const editLocale = async (id, payload, toggleNotification) => { try { const data = await request(`/i18n/locales/${id}`, { method: 'PUT', body: payload, }); - strapi.notification.toggle({ + toggleNotification({ type: 'success', message: { id: getTrad('Settings.locales.modal.edit.success') }, }); return data; } catch { - strapi.notification.toggle({ + toggleNotification({ type: 'warning', message: { id: 'notification.error' }, }); @@ -30,11 +30,12 @@ const editLocale = async (id, payload) => { const useEditLocale = () => { const [isLoading, setLoading] = useState(false); const dispatch = useDispatch(); + const toggleNotification = useNotification(); const modifyLocale = async (id, payload) => { setLoading(true); - const editedLocale = await editLocale(id, payload); + const editedLocale = await editLocale(id, payload, toggleNotification); dispatch({ type: UPDATE_LOCALE, editedLocale }); setLoading(false); diff --git a/packages/plugins/i18n/admin/src/hooks/useLocales/index.js b/packages/plugins/i18n/admin/src/hooks/useLocales/index.js index 45711ac4a4..e5cd29ea85 100644 --- a/packages/plugins/i18n/admin/src/hooks/useLocales/index.js +++ b/packages/plugins/i18n/admin/src/hooks/useLocales/index.js @@ -1,9 +1,9 @@ import { useEffect } from 'react'; -import { request } from '@strapi/helper-plugin'; +import { request, useNotification } from '@strapi/helper-plugin'; import { useSelector, useDispatch } from 'react-redux'; import { RESOLVE_LOCALES } from '../constants'; -const fetchLocalesList = async () => { +const fetchLocalesList = async toggleNotification => { try { const data = await request('/i18n/locales', { method: 'GET', @@ -11,7 +11,7 @@ const fetchLocalesList = async () => { return data; } catch (e) { - strapi.notification.toggle({ + toggleNotification({ type: 'warning', message: { id: 'notification.error' }, }); @@ -22,12 +22,15 @@ const fetchLocalesList = async () => { const useLocales = () => { const dispatch = useDispatch(); + const toggleNotification = useNotification(); const locales = useSelector(state => state.i18n_locales.locales); const isLoading = useSelector(state => state.i18n_locales.isLoading); useEffect(() => { - fetchLocalesList().then(locales => dispatch({ type: RESOLVE_LOCALES, locales })); - }, [dispatch]); + fetchLocalesList(toggleNotification).then(locales => + dispatch({ type: RESOLVE_LOCALES, locales }) + ); + }, [dispatch, toggleNotification]); return { locales, isLoading }; }; diff --git a/packages/plugins/users-permissions/admin/src/containers/AdvancedSettings/index.js b/packages/plugins/users-permissions/admin/src/containers/AdvancedSettings/index.js index e6d588a417..0616128b6d 100644 --- a/packages/plugins/users-permissions/admin/src/containers/AdvancedSettings/index.js +++ b/packages/plugins/users-permissions/admin/src/containers/AdvancedSettings/index.js @@ -9,6 +9,7 @@ import { SizedInput, useUserPermissions, request, + useNotification, } from '@strapi/helper-plugin'; import pluginPermissions from '../../permissions'; import { getTrad, getRequestURL } from '../../utils'; @@ -18,6 +19,7 @@ import reducer, { initialState } from './reducer'; const AdvancedSettingsPage = () => { const { formatMessage } = useIntl(); + const toggleNotification = useNotification(); const [showModalWarning, setShowModalWarning] = useState(false); const pageTitle = formatMessage({ id: getTrad('HeaderNav.link.advancedSettings') }); const updatePermissions = useMemo(() => { @@ -54,7 +56,7 @@ const AdvancedSettingsPage = () => { type: 'GET_DATA_ERROR', }); console.error(err); - strapi.notification.toggle({ + toggleNotification({ type: 'warning', message: { id: 'notification.error' }, }); @@ -98,7 +100,7 @@ const AdvancedSettingsPage = () => { type: 'ON_SUBMIT_SUCCEEDED', }); - strapi.notification.toggle({ + toggleNotification({ type: 'success', message: { id: getTrad('notification.success.submit') }, }); @@ -107,7 +109,7 @@ const AdvancedSettingsPage = () => { type: 'ON_SUBMIT_ERROR', }); console.error(err); - strapi.notification.toggle({ + toggleNotification({ type: 'warning', message: { id: 'notification.error' }, }); @@ -115,7 +117,7 @@ const AdvancedSettingsPage = () => { strapi.unlockApp(); }, - [modifiedData] + [modifiedData, toggleNotification] ); const handleConfirmReset = useCallback(() => { diff --git a/packages/plugins/users-permissions/admin/src/containers/EmailTemplates/index.js b/packages/plugins/users-permissions/admin/src/containers/EmailTemplates/index.js index c5e6cccb48..e9e85d6fc6 100644 --- a/packages/plugins/users-permissions/admin/src/containers/EmailTemplates/index.js +++ b/packages/plugins/users-permissions/admin/src/containers/EmailTemplates/index.js @@ -9,6 +9,7 @@ import { useGlobalContext, request, getYupInnerErrors, + useNotification, } from '@strapi/helper-plugin'; import { Row } from 'reactstrap'; import pluginPermissions from '../../permissions'; @@ -23,6 +24,7 @@ import schema from './utils/schema'; const EmailTemplatesPage = () => { const { formatMessage } = useIntl(); const { emitEvent } = useGlobalContext(); + const toggleNotification = useNotification(); const emitEventRef = useRef(emitEvent); const buttonSubmitRef = useRef(null); const pageTitle = formatMessage({ id: getTrad('HeaderNav.link.emailTemplates') }); @@ -111,7 +113,7 @@ const EmailTemplatesPage = () => { emitEventRef.current('didEditEmailTemplates'); - strapi.notification.toggle({ + toggleNotification({ type: 'success', message: { id: getTrad('notification.success.submit') }, }); @@ -122,7 +124,7 @@ const EmailTemplatesPage = () => { } catch (err) { console.error(err); - strapi.notification.toggle({ + toggleNotification({ type: 'warning', message: { id: 'notification.error' }, }); @@ -136,7 +138,14 @@ const EmailTemplatesPage = () => { dispatchSetFormErrors(errors); }, - [dispatchSetFormErrors, dispatchSubmitSucceeded, modifiedData, templateToEdit, handleToggle] + [ + dispatchSetFormErrors, + dispatchSubmitSucceeded, + modifiedData, + templateToEdit, + handleToggle, + toggleNotification, + ] ); const handleClick = useCallback(() => { diff --git a/packages/plugins/users-permissions/admin/src/containers/Providers/index.js b/packages/plugins/users-permissions/admin/src/containers/Providers/index.js index 47ba0365c5..0db46d42ba 100644 --- a/packages/plugins/users-permissions/admin/src/containers/Providers/index.js +++ b/packages/plugins/users-permissions/admin/src/containers/Providers/index.js @@ -9,6 +9,7 @@ import { useGlobalContext, getYupInnerErrors, request, + useNotification, } from '@strapi/helper-plugin'; import { get, upperFirst, has } from 'lodash'; import { Row } from 'reactstrap'; @@ -30,6 +31,7 @@ const ProvidersPage = () => { const buttonSubmitRef = useRef(null); const [showForm, setShowForm] = useState(false); const [providerToEditName, setProviderToEditName] = useState(null); + const toggleNotification = useNotification(); const updatePermissions = useMemo(() => { return { update: pluginPermissions.updateProviders }; @@ -150,7 +152,7 @@ const ProvidersPage = () => { emitEventRef.current('didEditAuthenticationProvider'); - strapi.notification.toggle({ + toggleNotification({ type: 'success', message: { id: getTrad('notification.success.submit') }, }); @@ -160,7 +162,7 @@ const ProvidersPage = () => { handleToggle(); } catch (err) { console.error(err); - strapi.notification.toggle({ + toggleNotification({ type: 'warning', message: { id: 'notification.error' }, }); @@ -183,6 +185,7 @@ const ProvidersPage = () => { handleToggle, modifiedData, providerToEditName, + toggleNotification, ] ); diff --git a/packages/plugins/users-permissions/admin/src/containers/Roles/CreatePage/index.js b/packages/plugins/users-permissions/admin/src/containers/Roles/CreatePage/index.js index 99fa17c8df..1f4bf4f878 100644 --- a/packages/plugins/users-permissions/admin/src/containers/Roles/CreatePage/index.js +++ b/packages/plugins/users-permissions/admin/src/containers/Roles/CreatePage/index.js @@ -4,7 +4,7 @@ import { Header } from '@buffetjs/custom'; import { Padded } from '@buffetjs/core'; import { Formik } from 'formik'; import { useIntl } from 'react-intl'; -import { request, useGlobalContext } from '@strapi/helper-plugin'; +import { request, useGlobalContext, useNotification } from '@strapi/helper-plugin'; import BaselineAlignement from '../../../components/BaselineAlignement'; import ContainerFluid from '../../../components/ContainerFluid'; import FormCard from '../../../components/FormBloc'; @@ -18,6 +18,7 @@ import schema from './utils/schema'; const CreatePage = () => { const { formatMessage } = useIntl(); const { emitEvent } = useGlobalContext(); + const toggleNotification = useNotification(); const { goBack } = useHistory(); const [isSubmiting, setIsSubmiting] = useState(false); const { permissions, routes, policies, isLoading } = usePlugins(); @@ -68,7 +69,7 @@ const CreatePage = () => { ) .then(() => { emitEvent('didCreateRole'); - strapi.notification.toggle({ + toggleNotification({ type: 'success', message: { id: 'Settings.roles.created' }, }); @@ -78,7 +79,7 @@ const CreatePage = () => { }) .catch(err => { console.error(err); - strapi.notification.toggle({ + toggleNotification({ type: 'warning', message: { id: 'notification.error' }, }); diff --git a/packages/plugins/users-permissions/admin/src/containers/Roles/EditPage/index.js b/packages/plugins/users-permissions/admin/src/containers/Roles/EditPage/index.js index 8634818bf9..4e16ed7b54 100644 --- a/packages/plugins/users-permissions/admin/src/containers/Roles/EditPage/index.js +++ b/packages/plugins/users-permissions/admin/src/containers/Roles/EditPage/index.js @@ -4,7 +4,7 @@ import { Padded } from '@buffetjs/core'; import { Formik } from 'formik'; import { useIntl } from 'react-intl'; import { useRouteMatch } from 'react-router-dom'; -import { request } from '@strapi/helper-plugin'; +import { request, useNotification } from '@strapi/helper-plugin'; import BaselineAlignement from '../../../components/BaselineAlignement'; import ContainerFluid from '../../../components/ContainerFluid'; @@ -20,6 +20,7 @@ import schema from './utils/schema'; const EditPage = () => { const { formatMessage } = useIntl(); const [isSubmiting, setIsSubmiting] = useState(false); + const toggleNotification = useNotification(); const { params: { id }, } = useRouteMatch(`/settings/${pluginId}/roles/:id`); @@ -73,14 +74,14 @@ const EditPage = () => { .then(() => { onSubmitSucceeded({ name: data.name, description: data.description }); permissionsRef.current.setFormAfterSubmit(); - strapi.notification.toggle({ + toggleNotification({ type: 'success', message: { id: getTrad('Settings.roles.edited') }, }); }) .catch(err => { console.error(err); - strapi.notification.toggle({ + toggleNotification({ type: 'warning', message: { id: 'notification.error' }, }); diff --git a/packages/plugins/users-permissions/admin/src/containers/Roles/ListPage/index.js b/packages/plugins/users-permissions/admin/src/containers/Roles/ListPage/index.js index cb68e2c5bb..77a7743210 100644 --- a/packages/plugins/users-permissions/admin/src/containers/Roles/ListPage/index.js +++ b/packages/plugins/users-permissions/admin/src/containers/Roles/ListPage/index.js @@ -4,7 +4,13 @@ import { Helmet } from 'react-helmet'; import { useIntl } from 'react-intl'; import { useHistory } from 'react-router-dom'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import { useUserPermissions, PopUpWarning, request, useGlobalContext } from '@strapi/helper-plugin'; +import { + useUserPermissions, + PopUpWarning, + request, + useGlobalContext, + useNotification, +} from '@strapi/helper-plugin'; import permissions from '../../../permissions'; import { EmptyRole, RoleListWrapper, RoleRow } from '../../../components/Roles'; @@ -17,6 +23,7 @@ const RoleListPage = () => { const { formatMessage } = useIntl(); const { emitEvent } = useGlobalContext(); const { push } = useHistory(); + const toggleNotification = useNotification(); const [modalToDelete, setModalDelete] = useState(); const [shouldRefetchData, setShouldRefetchData] = useState(false); @@ -56,14 +63,14 @@ const RoleListPage = () => { ) .then(() => { setShouldRefetchData(true); - strapi.notification.toggle({ + toggleNotification({ type: 'success', message: { id: getTrad('Settings.roles.deleted') }, }); }) .catch(err => { console.error(err); - strapi.notification.toggle({ + toggleNotification({ type: 'warning', message: { id: 'notification.error' }, }); diff --git a/packages/plugins/users-permissions/admin/src/hooks/useFetchRole/index.js b/packages/plugins/users-permissions/admin/src/hooks/useFetchRole/index.js index 4c25e7d5fb..6e9f2fb7d6 100644 --- a/packages/plugins/users-permissions/admin/src/hooks/useFetchRole/index.js +++ b/packages/plugins/users-permissions/admin/src/hooks/useFetchRole/index.js @@ -1,12 +1,11 @@ import { useCallback, useReducer, useEffect } from 'react'; -import { request } from '@strapi/helper-plugin'; - +import { request, useNotification } from '@strapi/helper-plugin'; import reducer, { initialState } from './reducer'; - import pluginId from '../../pluginId'; const useFetchRole = id => { const [state, dispatch] = useReducer(reducer, initialState); + const toggleNotification = useNotification(); useEffect(() => { if (id) { @@ -35,7 +34,7 @@ const useFetchRole = id => { dispatch({ type: 'GET_DATA_ERROR', }); - strapi.notification.toggle({ + toggleNotification({ type: 'warning', message: { id: 'notification.error' }, }); diff --git a/packages/plugins/users-permissions/admin/src/hooks/useForm/index.js b/packages/plugins/users-permissions/admin/src/hooks/useForm/index.js index 8faf7fe8fb..b5d77e184b 100644 --- a/packages/plugins/users-permissions/admin/src/hooks/useForm/index.js +++ b/packages/plugins/users-permissions/admin/src/hooks/useForm/index.js @@ -1,5 +1,5 @@ import { useCallback, useEffect, useReducer, useRef } from 'react'; -import { useUserPermissions, request } from '@strapi/helper-plugin'; +import { useUserPermissions, request, useNotification } from '@strapi/helper-plugin'; import { getRequestURL } from '../../utils'; import reducer, { initialState } from './reducer'; @@ -9,7 +9,7 @@ const useUserForm = (endPoint, permissions) => { reducer, initialState ); - + const toggleNotification = useNotification(); const isMounted = useRef(true); const abortController = new AbortController(); @@ -35,7 +35,7 @@ const useUserForm = (endPoint, permissions) => { type: 'GET_DATA_ERROR', }); console.error(err); - strapi.notification.toggle({ + toggleNotification({ type: 'warning', message: { id: 'notification.error' }, }); diff --git a/packages/plugins/users-permissions/admin/src/hooks/usePlugins/index.js b/packages/plugins/users-permissions/admin/src/hooks/usePlugins/index.js index 6b8d97b390..c5b03d89dd 100644 --- a/packages/plugins/users-permissions/admin/src/hooks/usePlugins/index.js +++ b/packages/plugins/users-permissions/admin/src/hooks/usePlugins/index.js @@ -1,5 +1,5 @@ import { useCallback, useEffect, useReducer } from 'react'; -import { request } from '@strapi/helper-plugin'; +import { request, useNotification } from '@strapi/helper-plugin'; import { useIntl } from 'react-intl'; import { get } from 'lodash'; import init from './init'; @@ -9,6 +9,7 @@ import reducer, { initialState } from './reducer'; const usePlugins = (shouldFetchData = true) => { const { formatMessage } = useIntl(); + const toggleNotification = useNotification(); const [{ permissions, routes, policies, isLoading }, dispatch] = useReducer( reducer, initialState, @@ -47,13 +48,13 @@ const usePlugins = (shouldFetchData = true) => { }); if (message !== 'Forbidden') { - strapi.notification.toggle({ + toggleNotification({ type: 'warning', message, }); } } - }, [formatMessage]); + }, [formatMessage, toggleNotification]); useEffect(() => { if (shouldFetchData) { diff --git a/packages/plugins/users-permissions/admin/src/hooks/useRolesList/index.js b/packages/plugins/users-permissions/admin/src/hooks/useRolesList/index.js index b1056be9d3..ec07d750c7 100644 --- a/packages/plugins/users-permissions/admin/src/hooks/useRolesList/index.js +++ b/packages/plugins/users-permissions/admin/src/hooks/useRolesList/index.js @@ -1,5 +1,5 @@ import { useEffect, useReducer, useRef } from 'react'; -import { request } from '@strapi/helper-plugin'; +import { request, useNotification } from '@strapi/helper-plugin'; import { get } from 'lodash'; import init from './init'; import pluginId from '../../pluginId'; @@ -9,6 +9,7 @@ const useRolesList = (shouldFetchData = true) => { const [{ roles, isLoading }, dispatch] = useReducer(reducer, initialState, () => init(initialState, shouldFetchData) ); + const toggleNotification = useNotification(); const isMounted = useRef(true); const abortController = new AbortController(); @@ -47,7 +48,7 @@ const useRolesList = (shouldFetchData = true) => { }); if (message !== 'Forbidden') { - strapi.notification.toggle({ + toggleNotification({ type: 'warning', message, });