@craftercms/studio-ui
Version:
Services, components, models & utils to build CrafterCMS authoring extensions.
175 lines (173 loc) • 6.08 kB
JavaScript
/*
* 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' })
)
)
);
}