[Feature][UI Next] Add monaco editor to form (#8241)

This commit is contained in:
Amy0104 2022-01-28 18:03:07 +08:00 committed by GitHub
parent a778146ec6
commit 832f7352c9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 95 additions and 32 deletions

View File

@ -17,6 +17,7 @@
import { h } from 'vue'
import { NInput, NRadio, NRadioGroup, NSpace } from 'naive-ui'
import Editor from '@/components/monaco-editor'
import type { IFieldParams } from './types'
// TODO Support other widgets later
@ -52,3 +53,13 @@ export function renderRadio(params: IFieldParams) {
)
)
}
// Editor
export function renderEditor(params: IFieldParams) {
const { props, fields, field } = params
return h(Editor, {
...props,
value: fields[field],
onUpdateValue: (value) => void (fields[field] = value)
})
}

View File

@ -22,9 +22,7 @@ import type { IJsonItem } from './types'
export default function getElementByJson(
json: IJsonItem[],
fields: { [field: string]: any },
t: Function,
prefix: string
fields: { [field: string]: any }
) {
const rules: FormRules = {}
const initialValues: { [field: string]: any } = {}
@ -41,6 +39,13 @@ export default function getElementByJson(
options
})
}
if (type === 'editor') {
return Field.renderEditor({
field,
fields,
props
})
}
return Field.renderInput({ field, fields, props })
}
@ -50,7 +55,7 @@ export default function getElementByJson(
initialValues[item.field] = item.value
if (item.validate) rules[item.field] = formatValidate(item.validate)
elements.push({
label: t(prefix + '.' + item.field),
label: item.name,
path: item.field,
widget: () => getElement(item)
})

View File

@ -24,7 +24,7 @@ import type {
SelectOption
} from 'naive-ui'
type IType = 'input' | 'radio'
type IType = 'input' | 'radio' | 'editor'
type IOption = SelectOption

View File

@ -27,7 +27,7 @@ export function formatValidate(
): FormItemRule {
if (!validate) return {}
if (Array.isArray(validate)) {
validate.map((item: FormItemRule) => {
validate.forEach((item: FormItemRule) => {
if (!item?.message) delete item.message
return item
})

View File

@ -24,18 +24,26 @@ import {
ref,
watch
} from 'vue'
import { useFormItem } from 'naive-ui/es/_mixins'
import { call } from 'naive-ui/es/_utils'
import * as monaco from 'monaco-editor'
import editorWorker from 'monaco-editor/esm/vs/editor/editor.worker?worker'
import jsonWorker from 'monaco-editor/esm/vs/language/json/json.worker?worker'
import cssWorker from 'monaco-editor/esm/vs/language/css/css.worker?worker'
import htmlWorker from 'monaco-editor/esm/vs/language/html/html.worker?worker'
import tsWorker from 'monaco-editor/esm/vs/language/typescript/ts.worker?worker'
import type { MaybeArray, OnUpdateValue, OnUpdateValueImpl } from './types'
const props = {
modelValue: {
value: {
type: String as PropType<string>,
default: ''
},
defaultValue: {
type: String as PropType<string>
},
'onUpdate:value': [Function, Array] as PropType<MaybeArray<OnUpdateValue>>,
onUpdateValue: [Function, Array] as PropType<MaybeArray<OnUpdateValue>>,
language: {
type: String as PropType<string>,
default: 'shell'
@ -72,13 +80,18 @@ window.MonacoEnvironment = {
export default defineComponent({
name: 'MonacoEditor',
props,
setup(props) {
emits: ['change', 'focus', 'blur'],
setup(props, ctx) {
let editor = null as monaco.editor.IStandaloneCodeEditor | null
const content = ref()
const editorRef = ref()
const getValue = () => editor?.getValue()
const formItem = useFormItem({})
watch(
() => props.modelValue,
() => props.value,
(val) => {
if (val !== getValue()) {
editor?.setValue(val)
@ -87,17 +100,34 @@ export default defineComponent({
)
onMounted(async () => {
content.value = props.modelValue
await nextTick()
const dom = document.getElementById('monaco-container')
const dom = editorRef.value
if (dom) {
editor = monaco.editor.create(dom, props.options, {
value: props.modelValue,
value: props.defaultValue ?? props.value,
language: props.language,
readOnly: props.readOnly,
automaticLayout: true
})
editor.onDidChangeModelContent(() => {
const { onUpdateValue, 'onUpdate:value': _onUpdateValue } = props
const value = editor?.getValue() || ''
if (onUpdateValue) call(onUpdateValue as OnUpdateValueImpl, value)
if (_onUpdateValue) call(_onUpdateValue as OnUpdateValueImpl, value)
ctx.emit('change', value)
formItem.nTriggerFormChange()
formItem.nTriggerFormInput()
})
editor.onDidBlurEditorWidget(() => {
ctx.emit('blur')
formItem.nTriggerFormBlur()
})
editor.onDidFocusEditorWidget(() => {
ctx.emit('focus')
formItem.nTriggerFormFocus()
})
}
})
@ -105,14 +135,17 @@ export default defineComponent({
editor?.dispose()
})
return { getValue }
ctx.expose({ getValue })
return { editorRef }
},
render() {
return (
<div
id='monaco-container'
ref='editorRef'
style={{
height: '300px',
width: '100%',
border: '1px solid #eee'
}}
></div>

View File

@ -0,0 +1,22 @@
/*
* 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 type { MaybeArray } from 'naive-ui/es/_utils'
type OnUpdateValue = <T extends string>(value: T) => void
type OnUpdateValueImpl = (value: string) => void
export { MaybeArray, OnUpdateValue, OnUpdateValueImpl }

View File

@ -91,7 +91,6 @@ export function useColumns(onCallback: Function) {
NButton,
{
circle: true,
class: styles['mr-10'],
type: 'info',
onClick: () => void onCallback(rowData.id, 'edit')
},

View File

@ -35,7 +35,6 @@ export default defineComponent({
setup() {
const router: Router = useRouter()
const codeEditorRef = ref()
const { state } = useForm()
const { handleCreateFile } = useCreate(state)
@ -46,7 +45,6 @@ export default defineComponent({
}))
const handleFile = () => {
state.fileForm.content = codeEditorRef.value?.getValue()
handleCreateFile()
}
@ -57,7 +55,6 @@ export default defineComponent({
}
return {
codeEditorRef,
fileSuffixOptions,
handleFile,
handleReturn,
@ -105,7 +102,7 @@ export default defineComponent({
width: '90%'
}}
>
<MonacoEditor ref='codeEditorRef' />
<MonacoEditor v-model={[this.fileForm.content, 'value']} />
</div>
</NFormItem>
<div class={styles['file-edit-content']}>

View File

@ -33,7 +33,6 @@ export default defineComponent({
const router: Router = useRouter()
const resourceViewRef = ref()
const codeEditorRef = ref()
const routeNameRef = ref(router.currentRoute.value.name)
const idRef = ref(Number(router.currentRoute.value.params.id))
@ -41,7 +40,7 @@ export default defineComponent({
const { getResourceView, handleUpdateContent } = useEdit(state)
const handleFileContent = () => {
state.fileForm.content = codeEditorRef.value?.getValue()
state.fileForm.content = resourceViewRef.value.content
handleUpdateContent(idRef.value)
}
@ -56,7 +55,6 @@ export default defineComponent({
return {
idRef,
routeNameRef,
codeEditorRef,
resourceViewRef,
handleReturn,
handleFileContent,
@ -84,8 +82,7 @@ export default defineComponent({
}}
>
<MonacoEditor
ref='codeEditorRef'
modelValue={this.resourceViewRef?.value.content}
v-model={[this.resourceViewRef?.value.content, 'value']}
/>
</div>
</NFormItem>

View File

@ -83,13 +83,12 @@ const DetailModal = defineComponent({
watch(
() => state.json,
() => {
if (state.json?.length) return
state.json.forEach((item) => {
item.name = t('security.alarm_instance' + '.' + item.field)
})
const { rules: fieldsRules, elements: fieldsElements } =
getElementByJson(
state.json,
state.detailForm,
t,
'security.alarm_instance'
)
getElementByJson(state.json, state.detailForm)
rules.value = fieldsRules
elements.value = fieldsElements
}