diff --git a/admin/src/hooks/useConfig.js b/admin/src/hooks/useConfig.js index 626f17d..4731bbf 100644 --- a/admin/src/hooks/useConfig.js +++ b/admin/src/hooks/useConfig.js @@ -1,7 +1,6 @@ import { useQuery, useMutation, useQueryClient } from 'react-query'; -import { fetchConfig, restoreConfig, updateConfig } from '../pages/Settings/utils/api'; +import { fetchConfig, restartStrapi, restoreConfig, updateConfig } from '../pages/Settings/utils/api'; import pluginId from '../pluginId'; -import { getMessage } from '../utils'; const useConfig = (toggleNotification) => { const queryClient = useQueryClient(); @@ -18,8 +17,10 @@ const useConfig = (toggleNotification) => { callback(); }; - const handleSuccess = (type, callback = () => {}) => { - queryClient.invalidateQueries('get-config'); + const handleSuccess = (type, callback = () => {}, invalidateQueries = true) => { + if (invalidateQueries) { + queryClient.invalidateQueries('get-config'); + }; toggleNotification({ type: 'success', message: `${pluginId}.page.settings.notification.${type}.success`, @@ -37,7 +38,12 @@ const useConfig = (toggleNotification) => { onError: () => handleError('restore'), }); - return { fetch, submitMutation, restoreMutation }; + const restartMutation = useMutation(restartStrapi, { + onSuccess: () => handleSuccess('restart', () => {}, false), + onError: () => handleError('restart'), + }); + + return { fetch, restartMutation, submitMutation, restoreMutation }; }; export default useConfig; diff --git a/admin/src/pages/Settings/components/RestartAlert/styles.js b/admin/src/pages/Settings/components/RestartAlert/styles.js new file mode 100644 index 0000000..3ef8890 --- /dev/null +++ b/admin/src/pages/Settings/components/RestartAlert/styles.js @@ -0,0 +1,8 @@ +import styled from 'styled-components'; +import { Alert } from '@strapi/design-system/Alert'; + +export const RestartAlert = styled(Alert)` + [role="status"] { + flex-direction: column; + } +` diff --git a/admin/src/pages/Settings/index.js b/admin/src/pages/Settings/index.js index 156742a..0a1f0ee 100644 --- a/admin/src/pages/Settings/index.js +++ b/admin/src/pages/Settings/index.js @@ -1,7 +1,7 @@ import React, { useRef, useMemo, useState } from 'react'; import { useQuery } from 'react-query'; import { Formik } from 'formik'; -import { capitalize, first, orderBy, isEmpty } from 'lodash'; +import { capitalize, first, orderBy, isEmpty, isEqual } from 'lodash'; import { CheckPermissions, LoadingIndicatorPage, @@ -27,13 +27,14 @@ import { CardBody, CardContent, } from '@strapi/design-system/Card'; -import { Check, Refresh } from '@strapi/icons'; +import { Check, Refresh, Play } from '@strapi/icons'; import pluginPermissions from '../../permissions'; import useConfig from '../../hooks/useConfig'; import { fetchAllContentTypes, fetchRoles } from './utils/api'; import { getMessage, parseRegExp } from '../../utils'; import ConfirmationDialog from '../../components/ConfirmationDialog'; +import { RestartAlert } from './components/RestartAlert/styles'; const Settings = () => { @@ -56,8 +57,9 @@ const Settings = () => { } = useRBAC(viewPermissions); const [restoreConfigmationVisible, setRestoreConfigmationVisible] = useState(false); + const [restartRequired, setRestartRequired] = useState(false); - const { fetch, submitMutation, restoreMutation } = useConfig(toggleNotification); + const { fetch, restartMutation, submitMutation, restoreMutation } = useConfig(toggleNotification); const { data: configData, isLoading: isConfigLoading, err: configErr } = fetch; const { data: allCollectionsData, isLoading: areCollectionsLoading, err: collectionsErr } = useQuery( @@ -131,7 +133,13 @@ const Settings = () => { const handleUpdateConfiguration = async (form) => { if (canChange) { lockApp(); - await submitMutation.mutateAsync(preparePayload(form)); + const payload = preparePayload(form); + await submitMutation.mutateAsync(payload); + const enabledCollectionsChanged = !isEqual(payload.enabledCollections, configData?.enabledCollections); + const gqlAuthChanged = !isEqual(payload.gql?.auth, configData?.gql?.auth); + if (enabledCollectionsChanged || gqlAuthChanged) { + setRestartRequired(true); + } unlockApp(); } }; @@ -142,11 +150,22 @@ const Settings = () => { lockApp(); await restoreMutation.mutateAsync(); unlockApp(); + setRestartRequired(true); setRestoreConfigmationVisible(false); } }; const handleRestoreCancel = () => setRestoreConfigmationVisible(false); + const handleRestart = async () => { + if (canChange) { + lockApp(); + await restartMutation.mutateAsync(); + setRestartRequired(false); + unlockApp(); + } + }; + const handleRestartDiscard = () => setRestartRequired(false); + const boxDefaultProps = { background: "neutral0", hasRadius: true, @@ -175,7 +194,7 @@ const Settings = () => { subtitle={getMessage('page.settings.header.description')} primaryAction={ - @@ -183,6 +202,15 @@ const Settings = () => { /> + { restartRequired && ( + } + onClose={handleRestartDiscard}> + { getMessage('page.settings.actions.restart.alert.description')} + )} + @@ -198,6 +226,7 @@ const Settings = () => { onClear={() => setFieldValue('enabledCollections', [], false)} value={values.enabledCollections} onChange={(value) => setFieldValue('enabledCollections', value, false)} + disabled={restartRequired} multi withTags > @@ -214,6 +243,7 @@ const Settings = () => { onClear={() => setFieldValue('moderatorRoles', [], false)} value={values.moderatorRoles} onChange={(value) => setFieldValue('moderatorRoles', value, false)} + disabled={restartRequired} multi withTags > @@ -230,6 +260,7 @@ const Settings = () => { onChange={({ target: { checked } }) => setFieldValue('badWords', checked, false)} onLabel={getMessage('compontents.toogle.enabled')} offLabel={getMessage('compontents.toogle.disabled')} + disabled={restartRequired} /> { isGQLPluginEnabled && ( @@ -241,6 +272,7 @@ const Settings = () => { onChange={({ target: { checked } }) => setFieldValue('gqlAuthEnabled', checked, false)} onLabel={getMessage('compontents.toogle.enabled')} offLabel={getMessage('compontents.toogle.disabled')} + disabled={restartRequired} /> ) } @@ -272,6 +304,7 @@ const Settings = () => { onChange={({ target: { checked } }) => setFieldValue('approvalFlow', changeApprovalFlowFor(uid, values.approvalFlow, checked), [])} onLabel={getMessage('compontents.toogle.enabled')} offLabel={getMessage('compontents.toogle.disabled')} + disabled={restartRequired} /> { !isEmpty(stringAttributes) && (