diff --git a/packages/core/admin/admin/src/StrapiApp.js b/packages/core/admin/admin/src/StrapiApp.js
index 2e92a79eb6..4e811881de 100644
--- a/packages/core/admin/admin/src/StrapiApp.js
+++ b/packages/core/admin/admin/src/StrapiApp.js
@@ -10,8 +10,9 @@ import basename from './utils/basename';
import App from './pages/App';
import LanguageProvider from './components/LanguageProvider';
import AutoReloadOverlayBlocker from './components/AutoReloadOverlayBlocker';
-import Fonts from './components/Fonts';
import OverlayBlocker from './components/OverlayBlocker';
+import Fonts from './components/Fonts';
+
import GlobalStyle from './components/GlobalStyle';
import Notifications from './components/Notifications';
import themes from './themes';
@@ -152,16 +153,15 @@ class StrapiApp {
-
- <>
-
-
-
-
-
-
- >
-
+
+
+
+
+
+
+
+
+
diff --git a/packages/core/admin/admin/src/components/AutoReloadOverlayBlocker/Portal.js b/packages/core/admin/admin/src/components/AutoReloadOverlayBlocker/Portal.js
new file mode 100644
index 0000000000..b6b3a50395
--- /dev/null
+++ b/packages/core/admin/admin/src/components/AutoReloadOverlayBlocker/Portal.js
@@ -0,0 +1,62 @@
+import React, { useEffect } from 'react';
+import ReactDOM from 'react-dom';
+import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
+import PropTypes from 'prop-types';
+import Content from './Content';
+import Overlay from './Overlay';
+import Wrapper from './Wrapper';
+
+const overlayContainer = document.createElement('div');
+const ID = 'autoReloadOverlayBlocker';
+overlayContainer.setAttribute('id', ID);
+
+const Portal = ({ className, displayedIcon, description, title, elapsed, isOpen }) => {
+ useEffect(() => {
+ document.body.appendChild(overlayContainer);
+
+ return () => {
+ document.body.removeChild(overlayContainer);
+ };
+ }, []);
+
+ if (isOpen) {
+ return ReactDOM.createPortal(
+
+
+
+
+
+
+
+ {elapsed < 15 && (
+
+ )}
+
+
+ ,
+ overlayContainer
+ );
+ }
+
+ return null;
+};
+
+Portal.propTypes = {
+ className: PropTypes.string.isRequired,
+ displayedIcon: PropTypes.oneOfType([PropTypes.string, PropTypes.array]).isRequired,
+ description: PropTypes.object.isRequired,
+ elapsed: PropTypes.number.isRequired,
+ isOpen: PropTypes.bool.isRequired,
+ title: PropTypes.object.isRequired,
+};
+
+export default Portal;
diff --git a/packages/core/admin/admin/src/components/AutoReloadOverlayBlocker/index.js b/packages/core/admin/admin/src/components/AutoReloadOverlayBlocker/index.js
index d844c000a5..b831be6bcc 100644
--- a/packages/core/admin/admin/src/components/AutoReloadOverlayBlocker/index.js
+++ b/packages/core/admin/admin/src/components/AutoReloadOverlayBlocker/index.js
@@ -1,22 +1,14 @@
-import React, { useEffect, useState } from 'react';
-import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
-import ReactDOM from 'react-dom';
-import Content from './Content';
-import Overlay from './Overlay';
-import Wrapper from './Wrapper';
+import React, { useEffect, useRef, useState } from 'react';
+import { AutoReloadOverlayBockerContext } from '@strapi/helper-plugin';
+import PropTypes from 'prop-types';
+import Portal from './Portal';
-const overlayContainer = document.createElement('div');
-const ID = 'autoReloadOverlayBlocker';
-overlayContainer.setAttribute('id', ID);
-
-const AutoReloadOverlayBlocker = () => {
+const AutoReloadOverlayBlocker = ({ children }) => {
const [isOpen, setIsOpen] = useState(false);
const [{ elapsed }, setState] = useState({ elapsed: 0, start: 0 });
const [config, setConfig] = useState(undefined);
const lockAppWithAutoreload = (config = undefined) => {
- document.body.appendChild(overlayContainer);
-
setIsOpen(true);
setConfig(config);
setState(prev => ({ ...prev, start: Date.now() }));
@@ -26,18 +18,10 @@ const AutoReloadOverlayBlocker = () => {
setIsOpen(false);
setState({ start: 0, elapsed: 0 });
setConfig(undefined);
-
- if (document.getElementById(ID)) {
- document.body.removeChild(overlayContainer);
- }
};
- useEffect(() => {
- window.strapi = Object.assign(window.strapi || {}, {
- lockAppWithAutoreload,
- unlockAppWithAutoreload,
- });
- }, []);
+ const lockApp = useRef(lockAppWithAutoreload);
+ const unlockApp = useRef(unlockAppWithAutoreload);
useEffect(() => {
let timer = null;
@@ -89,35 +73,25 @@ const AutoReloadOverlayBlocker = () => {
};
}
- if (isOpen) {
- return ReactDOM.createPortal(
-
-
-
-
-
-
-
- {elapsed < 15 && (
-
- )}
-
-
- ,
- overlayContainer
- );
- }
+ return (
+
+
+ {children}
+
+ );
+};
- return null;
+AutoReloadOverlayBlocker.propTypes = {
+ children: PropTypes.element.isRequired,
};
export default AutoReloadOverlayBlocker;
diff --git a/packages/core/admin/admin/src/components/LanguageProvider/reducer.js b/packages/core/admin/admin/src/components/LanguageProvider/reducer.js
index a2f71a09d8..960ad7edf6 100644
--- a/packages/core/admin/admin/src/components/LanguageProvider/reducer.js
+++ b/packages/core/admin/admin/src/components/LanguageProvider/reducer.js
@@ -41,7 +41,6 @@ function languageProviderReducer(state = initialState, action) {
case CHANGE_LOCALE:
// Set user language in local storage.
window.localStorage.setItem(localStorageKey, action.locale);
- strapi.currentLanguage = action.locale;
return state.set('locale', action.locale);
default:
diff --git a/packages/core/admin/admin/src/components/OverlayBlocker/Overlay.js b/packages/core/admin/admin/src/components/OverlayBlocker/Overlay.js
deleted file mode 100644
index 0fbb04c3b1..0000000000
--- a/packages/core/admin/admin/src/components/OverlayBlocker/Overlay.js
+++ /dev/null
@@ -1,14 +0,0 @@
-import styled from 'styled-components';
-
-const Overlay = styled.div`
- position: fixed;
- top: 0;
- right: 0;
- bottom: 0;
- left: 0;
- z-index: 1140;
-`;
-
-Overlay.defaultProps = {};
-
-export default Overlay;
diff --git a/packages/core/admin/admin/src/components/OverlayBlocker/index.js b/packages/core/admin/admin/src/components/OverlayBlocker/index.js
index 2c35433b63..39864e19f0 100644
--- a/packages/core/admin/admin/src/components/OverlayBlocker/index.js
+++ b/packages/core/admin/admin/src/components/OverlayBlocker/index.js
@@ -1,39 +1,33 @@
/**
*
- * OverlayBlocker
- * This component is used to prevent user interactions
+ * OverlayBlockerProvider
*
*/
-
import React, { useEffect, useState } from 'react';
import ReactDOM from 'react-dom';
-import Overlay from './Overlay';
+import PropTypes from 'prop-types';
+import styled from 'styled-components';
+import { OverlayBlockerContext } from '@strapi/helper-plugin';
const overlayContainer = document.createElement('div');
overlayContainer.setAttribute('id', 'overlayBlocker');
-const OverlayBlocker = () => {
- const [isOpen, setIsOpen] = useState(false);
+const Overlay = styled.div`
+ position: fixed;
+ top: 0;
+ right: 0;
+ bottom: 0;
+ left: 0;
+ z-index: 1140;
+`;
- const lockApp = () => {
+const Portal = ({ isOpen }) => {
+ useEffect(() => {
document.body.appendChild(overlayContainer);
- setIsOpen(true);
- };
-
- const unlockApp = () => {
- setIsOpen(false);
-
- if (document.getElementById('overlayBlocker')) {
+ return () => {
document.body.removeChild(overlayContainer);
- }
- };
-
- useEffect(() => {
- window.strapi = Object.assign(window.strapi || {}, {
- lockApp,
- unlockApp,
- });
+ };
}, []);
if (isOpen) {
@@ -43,4 +37,27 @@ const OverlayBlocker = () => {
return null;
};
-export default OverlayBlocker;
+const OverlayBlockerProvider = ({ children }) => {
+ const [isOpen, setIsOpen] = useState(false);
+
+ const lockApp = () => {
+ setIsOpen(true);
+ };
+
+ const unlockApp = () => {
+ setIsOpen(false);
+ };
+
+ return (
+
+ {children}
+
+
+ );
+};
+
+OverlayBlockerProvider.propTypes = {
+ children: PropTypes.node.isRequired,
+};
+
+export default OverlayBlockerProvider;
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 540c74840f..46f3753524 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,12 @@
import React, { forwardRef, useReducer, useImperativeHandle, useRef } from 'react';
import PropTypes from 'prop-types';
-import { BaselineAlignment, ModalSection, request, useNotification } from '@strapi/helper-plugin';
+import {
+ BaselineAlignment,
+ ModalSection,
+ request,
+ useNotification,
+ useOverlayBlocker,
+} from '@strapi/helper-plugin';
import { useIntl } from 'react-intl';
import { get } from 'lodash';
import { Padded, Text } from '@buffetjs/core';
@@ -19,6 +25,8 @@ 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 { lockApp, unlockApp } = useOverlayBlocker();
+
const toggleNotification = useNotification();
const [reducerState, dispatch] = useReducer(reducer, initialState, init);
const { formErrors, modifiedData } = reducerState;
@@ -47,7 +55,7 @@ const ModalCreateBody = forwardRef(
if (!errors) {
try {
// Prevent user interactions until the request is completed
- strapi.lockApp();
+ lockApp();
setIsSubmiting(true);
@@ -65,7 +73,7 @@ const ModalCreateBody = forwardRef(
toggleNotification({ type: 'warning', message });
} finally {
- strapi.unlockApp();
+ unlockApp();
setIsSubmiting(false);
}
}
diff --git a/packages/core/admin/admin/src/hooks/useSettingsForm/index.js b/packages/core/admin/admin/src/hooks/useSettingsForm/index.js
index 3997135fdb..04c29bb18a 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, useNotification } from '@strapi/helper-plugin';
+import { request, useNotification, useOverlayBlocker } from '@strapi/helper-plugin';
import { get, has, omit } from 'lodash';
import { checkFormValidity, formatAPIErrors } from '../../utils';
import { initialState, reducer } from './reducer';
@@ -11,6 +11,7 @@ const useSettingsForm = (endPoint, schema, cbSuccess, fieldsToPick) => {
dispatch,
] = useReducer(reducer, initialState, () => init(initialState, fieldsToPick));
const toggleNotification = useNotification();
+ const { lockApp, unlockApp } = useOverlayBlocker();
useEffect(() => {
const getData = async () => {
@@ -72,7 +73,7 @@ const useSettingsForm = (endPoint, schema, cbSuccess, fieldsToPick) => {
if (!errors) {
try {
- strapi.lockApp();
+ lockApp();
dispatch({
type: 'ON_SUBMIT',
@@ -122,7 +123,7 @@ const useSettingsForm = (endPoint, schema, cbSuccess, fieldsToPick) => {
errors: apiErrors,
});
} finally {
- strapi.unlockApp();
+ unlockApp();
}
}
};
diff --git a/packages/core/admin/admin/src/pages/Admin/index.js b/packages/core/admin/admin/src/pages/Admin/index.js
index c4805c5cbd..768c8a55a7 100644
--- a/packages/core/admin/admin/src/pages/Admin/index.js
+++ b/packages/core/admin/admin/src/pages/Admin/index.js
@@ -185,9 +185,6 @@ export class Admin extends React.Component {
emitEvent={this.emitEvent}
currentEnvironment={currentEnvironment}
currentLocale={locale}
- // FIXME
- disableGlobalOverlayBlocker={() => console.log('todo')}
- enableGlobalOverlayBlocker={() => console.log('todo')}
formatMessage={formatMessage}
plugins={plugins}
shouldUpdateStrapi={shouldUpdateStrapi}
diff --git a/packages/core/admin/admin/src/pages/InstalledPluginsPage/index.js b/packages/core/admin/admin/src/pages/InstalledPluginsPage/index.js
index e9dda50e99..0ce8e94fcb 100644
--- a/packages/core/admin/admin/src/pages/InstalledPluginsPage/index.js
+++ b/packages/core/admin/admin/src/pages/InstalledPluginsPage/index.js
@@ -1,5 +1,10 @@
import React from 'react';
-import { useGlobalContext, request, useNotification } from '@strapi/helper-plugin';
+import {
+ useGlobalContext,
+ request,
+ useNotification,
+ useAutoReloadOverlayBlocker,
+} from '@strapi/helper-plugin';
import { Header, List } from '@buffetjs/custom';
import PageTitle from '../../components/PageTitle';
import ContainerFluid from '../../components/ContainerFluid';
@@ -9,6 +14,7 @@ import generateRows from './utils/generateRows';
const InstalledPluginsPage = () => {
const toggleNotification = useNotification();
+ const { lockAppWithAutoreload, unlockAppWithAutoreload } = useAutoReloadOverlayBlocker();
const { formatMessage, plugins } = useGlobalContext();
const onConfirm = async id => {
try {
@@ -20,7 +26,7 @@ const InstalledPluginsPage = () => {
description: 'app.components.ListPluginsPage.deletePlugin.description',
};
// Lock the app
- strapi.lockAppWithAutoreload(overlayblockerParams);
+ lockAppWithAutoreload(overlayblockerParams);
const response = await request(requestUrl, { method: 'DELETE' }, overlayblockerParams);
if (response.ok) {
@@ -28,7 +34,7 @@ const InstalledPluginsPage = () => {
window.location.reload();
}
} catch (err) {
- strapi.unlockAppWithAutoreload();
+ unlockAppWithAutoreload();
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 6237824f3a..0872d6a096 100644
--- a/packages/core/admin/admin/src/pages/MarketplacePage/index.js
+++ b/packages/core/admin/admin/src/pages/MarketplacePage/index.js
@@ -4,6 +4,7 @@ import {
useGlobalContext,
request,
useNotification,
+ useAutoReloadOverlayBlocker,
} from '@strapi/helper-plugin';
import { Header } from '@buffetjs/custom';
import { useHistory } from 'react-router-dom';
@@ -14,6 +15,7 @@ import Wrapper from './Wrapper';
const MarketPlacePage = () => {
const toggleNotification = useNotification();
+ const { lockAppWithAutoreload, unlockAppWithAutoreload } = useAutoReloadOverlayBlocker();
const history = useHistory();
const { autoReload, currentEnvironment, formatMessage, plugins } = useGlobalContext();
const { error, isLoading, data } = useFetchPluginsFromMarketPlace();
@@ -30,7 +32,7 @@ const MarketPlacePage = () => {
description: 'app.components.InstallPluginPage.Download.description',
};
// Lock the app
- strapi.lockAppWithAutoreload(overlayblockerParams);
+ lockAppWithAutoreload(overlayblockerParams);
try {
const opts = {
@@ -47,7 +49,7 @@ const MarketPlacePage = () => {
window.location.reload();
}
} catch (err) {
- strapi.unlockApp();
+ unlockAppWithAutoreload();
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 4bf1827227..ea61199fe5 100644
--- a/packages/core/admin/admin/src/pages/Roles/EditPage/index.js
+++ b/packages/core/admin/admin/src/pages/Roles/EditPage/index.js
@@ -6,6 +6,7 @@ import {
useGlobalContext,
request,
useNotification,
+ useOverlayBlocker,
} from '@strapi/helper-plugin';
import { Header } from '@buffetjs/custom';
import { Padded } from '@buffetjs/core';
@@ -26,6 +27,7 @@ const EditPage = () => {
} = useRouteMatch('/settings/roles/:id');
const [isSubmiting, setIsSubmiting] = useState(false);
const permissionsRef = useRef();
+ const { lockApp, unlockApp } = useOverlayBlocker();
const { isLoading: isLayoutLoading, data: permissionsLayout } = useFetchPermissionsLayout(id);
const {
@@ -69,7 +71,7 @@ const EditPage = () => {
const handleEditRoleSubmit = async data => {
try {
- strapi.lockApp();
+ lockApp();
setIsSubmiting(true);
const { permissionsToSend, didUpdateConditions } = permissionsRef.current.getPermissions();
@@ -111,7 +113,7 @@ const EditPage = () => {
});
} finally {
setIsSubmiting(false);
- strapi.unlockApp();
+ unlockApp();
}
};
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 512b03ba10..93bbf72d40 100644
--- a/packages/core/admin/admin/src/pages/Webhooks/EditView/index.js
+++ b/packages/core/admin/admin/src/pages/Webhooks/EditView/index.js
@@ -16,6 +16,7 @@ import {
BackHeader,
LoadingIndicatorPage,
useNotification,
+ useOverlayBlocker,
} from '@strapi/helper-plugin';
import { useModels } from '../../../hooks';
import PageTitle from '../../../components/SettingsPageTitle';
@@ -27,6 +28,7 @@ import Wrapper from './Wrapper';
function EditView() {
const { isLoading: isLoadingForModels, collectionTypes } = useModels();
const toggleNotification = useNotification();
+ const { lockApp, unlockApp } = useOverlayBlocker();
const isMounted = useRef();
const { formatMessage } = useGlobalContext();
const [submittedOnce, setSubmittedOnce] = useState(false);
@@ -191,7 +193,7 @@ function EditView() {
const createWebhooks = async () => {
try {
- strapi.lockApp();
+ lockApp();
setIsSubmitting(true);
const { data } = await request('/admin/webhooks', {
method: 'POST',
@@ -213,7 +215,7 @@ function EditView() {
message: { id: 'notification.error' },
});
} finally {
- strapi.unlockApp();
+ unlockApp();
}
};
@@ -355,7 +357,7 @@ function EditView() {
const updateWebhook = async () => {
try {
- strapi.lockApp();
+ lockApp();
setIsSubmitting(true);
const body = cleanData(modifiedData);
@@ -380,7 +382,7 @@ function EditView() {
message: { id: 'notification.error' },
});
} finally {
- strapi.unlockApp();
+ unlockApp();
}
};
diff --git a/packages/core/admin/admin/src/tests/StrapiApp.test.js b/packages/core/admin/admin/src/tests/StrapiApp.test.js
index a0d280f7c1..0bc2c8870e 100644
--- a/packages/core/admin/admin/src/tests/StrapiApp.test.js
+++ b/packages/core/admin/admin/src/tests/StrapiApp.test.js
@@ -73,6 +73,12 @@ describe('ADMIN | StrapiApp', () => {
+
+