All checks were successful
farmcontrol/farmcontrol-ui/pipeline/head This commit looks good
- Introduced MagicWandIcon component using SVG for enhanced visual representation in the TemplateEditor. - Updated TemplateEditor to include a button for formatting template content, utilizing the new fetchTemplateFormat function from ApiServerContext. - Enhanced DocumentTemplateDesign to pass necessary props to TemplateEditor for improved functionality. - Refactored CodeBlockEditor to support an additional value prop for better code handling.
253 lines
7.3 KiB
JavaScript
253 lines
7.3 KiB
JavaScript
import { useState, useCallback, useContext } from 'react'
|
|
import PropTypes from 'prop-types'
|
|
import {
|
|
Flex,
|
|
Alert,
|
|
Card,
|
|
Spin,
|
|
Splitter,
|
|
Button,
|
|
Modal,
|
|
Segmented,
|
|
Popover
|
|
} from 'antd'
|
|
import { LoadingOutlined, CaretDownOutlined } from '@ant-design/icons'
|
|
import ExclamationOctagonIcon from '../../Icons/ExclamationOctagonIcon.jsx'
|
|
import CheckCircleIcon from '../../Icons/CheckCircleIcon.jsx'
|
|
import MagicWandIcon from '../../Icons/MagicWandIcon.jsx'
|
|
import ObjectProperty from '../common/ObjectProperty.jsx'
|
|
import TemplatePreview from './TemplatePreview.jsx'
|
|
import DataTree from './DataTree.jsx'
|
|
import { ApiServerContext } from '../context/ApiServerContext.jsx'
|
|
//import { useMediaQuery } from 'react-responsive'
|
|
|
|
const TemplateEditor = ({
|
|
objectData,
|
|
loading,
|
|
collapseState,
|
|
isEditing,
|
|
style,
|
|
form,
|
|
setObjectData
|
|
}) => {
|
|
const { fetchTemplateFormat } = useContext(ApiServerContext)
|
|
const [testObjectOpen, setTestObjectOpen] = useState(false)
|
|
const [testObjectViewMode, setTestObjectViewMode] = useState('Tree')
|
|
const [previewMessage, setPreviewMessage] = useState('No issues found.')
|
|
const [previewError, setPreviewError] = useState(false)
|
|
const [formatLoading, setFormatLoading] = useState(false)
|
|
//const isMobile = useMediaQuery({ maxWidth: 768 })
|
|
|
|
const handlePreviewMessage = useCallback((message, isError) => {
|
|
if (isError) {
|
|
setPreviewMessage(
|
|
<Flex gap={'small'} align={'center'} justify={'space-between'}>
|
|
Compile error.
|
|
<Popover
|
|
content={message}
|
|
trigger={['hover', 'click']}
|
|
placement='bottomRight'
|
|
arrow={false}
|
|
overlayStyle={{ width: '560px' }}
|
|
>
|
|
<Button
|
|
type={'text'}
|
|
size={'small'}
|
|
icon={
|
|
<CaretDownOutlined
|
|
style={{
|
|
marginLeft: '0.5px',
|
|
marginBottom: '2.5px',
|
|
fontSize: '12.5px'
|
|
}}
|
|
/>
|
|
}
|
|
/>
|
|
</Popover>
|
|
</Flex>
|
|
)
|
|
} else {
|
|
setPreviewMessage(message)
|
|
}
|
|
|
|
setPreviewError(isError)
|
|
}, [])
|
|
|
|
const handleFormatCode = useCallback(async () => {
|
|
const content = form?.getFieldValue?.('content') ?? objectData?.content
|
|
if (content == null || typeof content !== 'string') {
|
|
return
|
|
}
|
|
|
|
setFormatLoading(true)
|
|
try {
|
|
const result = await fetchTemplateFormat(content)
|
|
if (result?.error) {
|
|
handlePreviewMessage(result.error, true)
|
|
return
|
|
}
|
|
|
|
if (result?.content == null) {
|
|
return
|
|
}
|
|
|
|
form?.setFieldValue?.('content', result.content)
|
|
setObjectData?.((prev) => ({
|
|
...prev,
|
|
content: result.content
|
|
}))
|
|
} finally {
|
|
setFormatLoading(false)
|
|
}
|
|
}, [
|
|
form,
|
|
objectData?.content,
|
|
fetchTemplateFormat,
|
|
handlePreviewMessage,
|
|
setObjectData
|
|
])
|
|
|
|
return (
|
|
<>
|
|
<Splitter className={'farmcontrol-splitter'} vertical={true}>
|
|
{collapseState.preview == true && (
|
|
<Splitter.Panel style={{ height: '100%' }}>
|
|
<Card
|
|
spinning={loading}
|
|
style={style}
|
|
styles={{ body: { height: '100%' } }}
|
|
>
|
|
<TemplatePreview
|
|
objectData={objectData?.testObject}
|
|
documentTemplate={objectData}
|
|
loading={loading}
|
|
isEditing={isEditing}
|
|
style={style}
|
|
onTestObjectOpen={() => setTestObjectOpen(true)}
|
|
onPreviewMessage={handlePreviewMessage}
|
|
showTestObject={true}
|
|
/>
|
|
</Card>
|
|
</Splitter.Panel>
|
|
)}
|
|
{collapseState.editor == true && (
|
|
<Splitter.Panel>
|
|
<Spin spinning={loading} indicator={<LoadingOutlined />}>
|
|
<Card style={style} styles={{ body: { height: '100%' } }}>
|
|
<Flex vertical gap={'middle'} style={{ height: '100%' }}>
|
|
<Flex gap={'small'} align={'stretch'}>
|
|
<Alert
|
|
message={previewMessage}
|
|
showIcon
|
|
style={{
|
|
padding: '4px 5px 4px 8px',
|
|
flex: '1 1 auto',
|
|
minWidth: 0
|
|
}}
|
|
icon={
|
|
previewError ? (
|
|
<ExclamationOctagonIcon />
|
|
) : (
|
|
<CheckCircleIcon />
|
|
)
|
|
}
|
|
type={previewError ? 'error' : 'success'}
|
|
/>
|
|
{isEditing && (
|
|
<Button
|
|
icon={<MagicWandIcon />}
|
|
loading={formatLoading}
|
|
disabled={loading || formatLoading}
|
|
onClick={handleFormatCode}
|
|
/>
|
|
)}
|
|
</Flex>
|
|
|
|
<div
|
|
style={{
|
|
overflowY: 'scroll',
|
|
height: '100%',
|
|
flex: '1 1 auto'
|
|
}}
|
|
>
|
|
<ObjectProperty
|
|
name={'content'}
|
|
height='100%'
|
|
type='codeBlock'
|
|
language={'fcTemplateLang'}
|
|
objectData={objectData}
|
|
isEditing={isEditing}
|
|
autoCompleteObject={objectData?.testObject}
|
|
/>
|
|
</div>
|
|
</Flex>
|
|
</Card>
|
|
</Spin>
|
|
</Splitter.Panel>
|
|
)}
|
|
</Splitter>
|
|
<Modal
|
|
open={testObjectOpen}
|
|
closeIcon={null}
|
|
width={800}
|
|
footer={
|
|
<Button
|
|
onClick={() => {
|
|
setTestObjectOpen(false)
|
|
}}
|
|
>
|
|
Close
|
|
</Button>
|
|
}
|
|
>
|
|
<Flex gap={'small'} vertical>
|
|
<div>
|
|
<Segmented
|
|
options={['Tree', 'Code']}
|
|
value={testObjectViewMode}
|
|
onChange={(value) => setTestObjectViewMode(value)}
|
|
size='small'
|
|
/>
|
|
</div>
|
|
<div
|
|
style={{
|
|
maxHeight: 'calc(var(--unit-100vh) - 280px)',
|
|
overflowY: 'scroll'
|
|
}}
|
|
>
|
|
{testObjectViewMode == 'Code' && (
|
|
<ObjectProperty
|
|
type={'codeBlock'}
|
|
name='testObject'
|
|
language='json'
|
|
objectData={objectData}
|
|
isEditing={true}
|
|
/>
|
|
)}
|
|
{testObjectViewMode == 'Tree' && (
|
|
<DataTree
|
|
data={objectData?.testObject}
|
|
defaultExpandAll={true}
|
|
showValueCopy={false}
|
|
showKeyCopy={true}
|
|
/>
|
|
)}
|
|
</div>
|
|
</Flex>
|
|
</Modal>
|
|
</>
|
|
)
|
|
}
|
|
|
|
TemplateEditor.propTypes = {
|
|
loading: PropTypes.bool,
|
|
objectData: PropTypes.object,
|
|
collapseState: PropTypes.object,
|
|
isEditing: PropTypes.bool,
|
|
style: PropTypes.object,
|
|
form: PropTypes.object,
|
|
setObjectData: PropTypes.func
|
|
}
|
|
|
|
export default TemplateEditor
|