UNPKG

@craftercms/studio-ui

Version:

Services, components, models & utils to build CrafterCMS authoring extensions.

175 lines (173 loc) 6.08 kB
/* * Copyright (C) 2007-2022 Crafter Software Corporation. All Rights Reserved. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License version 3 as published by * the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ /* * Copyright (C) 2007-2022 Crafter Software Corporation. All Rights Reserved. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 3 as published by * the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ import DialogBody from '../DialogBody'; import DialogFooter from '../DialogFooter'; import React, { useEffect, useRef, useState } from 'react'; import { ConditionalLoadingState } from '../LoadingState'; import AceEditor from '../AceEditor/AceEditor'; import SecondaryButton from '../SecondaryButton'; import { FormattedMessage, useIntl } from 'react-intl'; import PrimaryButton from '../PrimaryButton'; import { getPluginConfiguration, setPluginConfiguration } from '../../services/marketplace'; import useActiveSiteId from '../../hooks/useActiveSiteId'; import useUpdateRefs from '../../hooks/useUpdateRefs'; import { useDispatch } from 'react-redux'; import { showErrorDialog } from '../../state/reducers/dialogs/error'; import { showSystemNotification } from '../../state/actions/system'; import { translations } from '../SiteConfigurationManagement/translations'; import { parseValidateDocument } from '../../utils/xml'; export function PluginConfigDialogContainer(props) { const siteId = useActiveSiteId(); const { pluginId, onSaved, isSubmitting, onClose, onSubmittingAndOrPendingChange } = props; const [loading, setLoading] = useState(false); const [content, setContent] = useState(''); const editorRef = useRef(); const dispatch = useDispatch(); const [disabledSaveButton, setDisabledSaveButton] = useState(true); const { formatMessage } = useIntl(); const functionRefs = useUpdateRefs({ onSubmittingAndOrPendingChange }); useEffect(() => { setLoading(true); getPluginConfiguration(siteId, pluginId).subscribe({ next: (content) => { setContent(content); setLoading(false); }, error: ({ response }) => { dispatch( showErrorDialog({ error: response }) ); } }); }, [dispatch, pluginId, siteId]); const onEditorChanges = () => { if (content !== editorRef.current.getValue()) { setDisabledSaveButton(false); onSubmittingAndOrPendingChange?.({ hasPendingChanges: true }); } else { setDisabledSaveButton(true); onSubmittingAndOrPendingChange?.({ hasPendingChanges: false }); } }; const onSave = () => { const content = editorRef.current.getValue(); const doc = parseValidateDocument(content); if (typeof doc === 'string') { dispatch( showSystemNotification({ message: formatMessage(translations.xmlContainsErrors, { errors: doc }), options: { variant: 'error' } }) ); return; } const errors = editorRef.current .getSession() .getAnnotations() .filter((annotation) => { return annotation.type === 'error'; }); if (errors.length) { dispatch( showSystemNotification({ message: formatMessage(translations.documentError), options: { variant: 'error' } }) ); } else { functionRefs.current.onSubmittingAndOrPendingChange({ isSubmitting: true }); setPluginConfiguration(siteId, pluginId, content).subscribe({ next: () => { functionRefs.current.onSubmittingAndOrPendingChange({ isSubmitting: false, hasPendingChanges: false }); onSaved(); }, error: ({ response }) => { functionRefs.current.onSubmittingAndOrPendingChange({ isSubmitting: false }); dispatch( showErrorDialog({ error: response.response }) ); } }); } }; const onCloseButtonClick = (e) => onClose(e, null); return React.createElement( React.Fragment, null, React.createElement( DialogBody, { sx: { height: '60vh', padding: 0 } }, React.createElement( ConditionalLoadingState, { isLoading: loading, styles: { root: { flexGrow: 1 } } }, React.createElement(AceEditor, { ref: editorRef, mode: 'ace/mode/xml', theme: 'ace/theme/textmate', autoFocus: true, onChange: onEditorChanges, value: content }) ) ), React.createElement( DialogFooter, null, React.createElement( SecondaryButton, { onClick: onCloseButtonClick, sx: { mr: '8px' } }, React.createElement(FormattedMessage, { id: 'words.cancel', defaultMessage: 'Cancel' }) ), React.createElement( PrimaryButton, { disabled: disabledSaveButton || isSubmitting, onClick: onSave, loading: isSubmitting }, React.createElement(FormattedMessage, { id: 'words.save', defaultMessage: 'Save' }) ) ) ); }