| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| import { LinkOutlined } from '@ant-design/icons'; |
| import type { Monaco } from '@monaco-editor/react'; |
| import Editor from '@monaco-editor/react'; |
| import { Button, Drawer, notification, PageHeader, Select, Space } from 'antd'; |
| import { js_beautify } from 'js-beautify'; |
| import type { languages } from 'monaco-editor'; |
| import React, { useEffect, useState } from 'react'; |
| import { CopyToClipboard } from 'react-copy-to-clipboard'; |
| import { useIntl } from 'umi'; |
| |
| import { json2yaml, yaml2json } from '../../helpers'; |
| |
| type Props = { |
| visible: boolean; |
| readonly: boolean; |
| type: 'route' | 'service' | 'consumer' | 'upstream'; |
| data: Record<string, any>; |
| onClose?: () => void; |
| onSubmit?: (data: Record<string, any>) => void; |
| }; |
| |
| enum monacoLanguageList { |
| JSON = 'JSON', |
| YAML = 'YAML', |
| } |
| |
| const RawDataEditor: React.FC<Props> = ({ |
| visible, |
| readonly = true, |
| type, |
| data = {}, |
| onClose = () => {}, |
| onSubmit = () => {}, |
| }) => { |
| const { formatMessage } = useIntl(); |
| const [monacoLanguage, setMonacoLanguage] = useState<PluginComponent.MonacoLanguage>( |
| monacoLanguageList.JSON, |
| ); |
| const [content, setContent] = useState(''); |
| |
| useEffect(() => { |
| switch (monacoLanguage) { |
| case monacoLanguageList.JSON: |
| setContent(JSON.stringify(data, null, 2)); |
| break; |
| case monacoLanguageList.YAML: { |
| const { data: yamlData } = json2yaml(JSON.stringify(data, null, 2)); |
| setContent(yamlData); |
| break; |
| } |
| default: |
| } |
| }, [data]); |
| |
| useEffect(() => { |
| setMonacoLanguage(monacoLanguageList.JSON); |
| }, [visible]); |
| |
| const modeOptions = [ |
| { label: monacoLanguageList.JSON, value: monacoLanguageList.JSON }, |
| { label: monacoLanguageList.YAML, value: monacoLanguageList.YAML }, |
| ]; |
| |
| const handleModeChange = (value: PluginComponent.MonacoLanguage) => { |
| switch (value) { |
| case monacoLanguageList.JSON: |
| setContent((c) => { |
| const { data: jsonData, error } = yaml2json(c, true); |
| if (error) { |
| notification.error({ message: formatMessage({ id: 'component.global.invalidYaml' }) }); |
| return c; |
| } |
| return js_beautify(jsonData, { indent_size: 2 }); |
| }); |
| break; |
| case monacoLanguageList.YAML: |
| setContent((c) => { |
| const { data: yamlData, error } = json2yaml(c); |
| if (error) { |
| notification.error({ message: formatMessage({ id: 'component.global.invalidJson' }) }); |
| return c; |
| } |
| return yamlData; |
| }); |
| break; |
| default: |
| break; |
| } |
| setMonacoLanguage(value); |
| }; |
| |
| const formatYaml = (yaml: string): string => { |
| const json = yaml2json(yaml, true); |
| if (json.error) { |
| return yaml; |
| } |
| return json2yaml(json.data).data; |
| }; |
| |
| const editorWillMount = (monaco: Monaco) => { |
| const yamlFormatProvider: languages.DocumentFormattingEditProvider = { |
| provideDocumentFormattingEdits(model) { |
| return [ |
| { |
| text: formatYaml(model.getValue()), |
| range: model.getFullModelRange(), |
| }, |
| ]; |
| }, |
| }; |
| monaco.languages.registerDocumentFormattingEditProvider('yaml', yamlFormatProvider); |
| monaco.languages.json.jsonDefaults.setDiagnosticsOptions({ |
| validate: true, |
| trailingCommas: 'error', |
| }); |
| }; |
| |
| return ( |
| <> |
| <Drawer |
| title={formatMessage({ id: 'component.global.data.editor' })} |
| placement="right" |
| width={700} |
| visible={visible} |
| onClose={onClose} |
| footer={ |
| <div style={{ display: 'flex', justifyContent: 'space-between' }}> |
| <Button onClick={onClose} key={1}> |
| {formatMessage({ id: 'component.global.cancel' })} |
| </Button> |
| <Space> |
| <Button |
| key={2} |
| type="primary" |
| onClick={() => { |
| try { |
| const editorData = |
| monacoLanguage === monacoLanguageList.JSON |
| ? JSON.parse(content) |
| : yaml2json(content, false).data; |
| onSubmit(editorData); |
| } catch (error) { |
| notification.error({ |
| message: formatMessage({ id: 'component.global.invalidJson' }), |
| }); |
| } |
| }} |
| > |
| {formatMessage({ id: 'component.global.submit' })} |
| </Button> |
| </Space> |
| </div> |
| } |
| > |
| <PageHeader |
| title="" |
| extra={[ |
| <Select |
| key={'monaco-language'} |
| defaultValue={monacoLanguageList.JSON} |
| value={monacoLanguage} |
| options={modeOptions} |
| onChange={(value: PluginComponent.MonacoLanguage) => { |
| handleModeChange(value); |
| }} |
| data-cy="monaco-language" |
| />, |
| <CopyToClipboard |
| key={'copy'} |
| text={content} |
| onCopy={(_: string, result: boolean) => { |
| if (!result) { |
| notification.error({ |
| message: formatMessage({ id: 'component.global.copyFail' }), |
| }); |
| return; |
| } |
| notification.success({ |
| message: formatMessage({ id: 'component.global.copySuccess' }), |
| }); |
| }} |
| > |
| <Button type="primary" key={2}> |
| {formatMessage({ id: 'component.global.copy' })} |
| </Button> |
| </CopyToClipboard>, |
| <Button |
| type="default" |
| icon={<LinkOutlined />} |
| onClick={() => { |
| window.open(`https://apisix.apache.org/docs/apisix/admin-api#${type}`); |
| }} |
| key={'document'} |
| > |
| {formatMessage({ id: 'component.global.document' })} |
| </Button>, |
| ]} |
| /> |
| <Editor |
| value={content} |
| onChange={(text) => { |
| if (text) { |
| setContent(text); |
| } else { |
| setContent(''); |
| } |
| }} |
| onMount={(editor) => { |
| // NOTE: for debug & test |
| // @ts-ignore |
| window.monacoEditor = editor; |
| }} |
| beforeMount={editorWillMount} |
| language={monacoLanguage.toLocaleLowerCase()} |
| options={{ |
| scrollbar: { |
| vertical: 'hidden', |
| horizontal: 'hidden', |
| }, |
| wordWrap: 'on', |
| minimap: { enabled: false }, |
| readOnly: readonly, |
| }} |
| /> |
| </Drawer> |
| </> |
| ); |
| }; |
| |
| export default RawDataEditor; |