You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@seatunnel.apache.org by so...@apache.org on 2023/05/05 11:20:18 UTC
[incubator-seatunnel-web] branch add_canvas_job_define updated: [Feat][UI] Add component of dynamic form in this project.
This is an automated email from the ASF dual-hosted git repository.
songjian pushed a commit to branch add_canvas_job_define
in repository https://gitbox.apache.org/repos/asf/incubator-seatunnel-web.git
The following commit(s) were added to refs/heads/add_canvas_job_define by this push:
new dfa56fde [Feat][UI] Add component of dynamic form in this project.
dfa56fde is described below
commit dfa56fde1e5040ab15465d58a0d7c42439c8fbf0
Author: songjianet <17...@qq.com>
AuthorDate: Fri May 5 20:20:05 2023 +0900
[Feat][UI] Add component of dynamic form in this project.
---
.../components/dynamic-form/dynamic-form-item.tsx | 165 +++++++++++++++++++++
.../src/components/dynamic-form/use-form-field.ts | 32 ++++
.../components/dynamic-form/use-form-locales.ts | 26 ++++
.../components/dynamic-form/use-form-request.ts | 39 +++++
.../components/dynamic-form/use-form-structure.ts | 25 ++++
.../components/dynamic-form/use-form-validate.ts | 69 +++++++++
6 files changed, 356 insertions(+)
diff --git a/seatunnel-ui/src/components/dynamic-form/dynamic-form-item.tsx b/seatunnel-ui/src/components/dynamic-form/dynamic-form-item.tsx
new file mode 100644
index 00000000..e29727fb
--- /dev/null
+++ b/seatunnel-ui/src/components/dynamic-form/dynamic-form-item.tsx
@@ -0,0 +1,165 @@
+/*
+ * 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 { defineComponent } from 'vue'
+import {
+ NFormItemGi,
+ NGrid,
+ NInput,
+ NSelect,
+ NCheckboxGroup,
+ NSpace,
+ NCheckbox
+} from 'naive-ui'
+import { useI18n } from 'vue-i18n'
+import type { PropType } from 'vue'
+import type { SelectOption } from 'naive-ui'
+
+const props = {
+ formStructure: {
+ type: Object as PropType<Array<object>>
+ },
+ model: {
+ type: Object as PropType<object>
+ },
+ name: {
+ type: String as PropType<string>,
+ default: ''
+ },
+ locales: {
+ type: Object as PropType<object>
+ }
+}
+
+const DynamicFormItem = defineComponent({
+ name: 'DynamicFormItem',
+ props,
+ setup(props) {
+ const { t } = useI18n()
+
+ if (props.locales) {
+ useI18n().mergeLocaleMessage('zh_CN', {
+ i18n: (props.locales as any).zh_CN
+ })
+ useI18n().mergeLocaleMessage('en_US', {
+ i18n: (props.locales as any).en_US
+ })
+ }
+
+ const formatClass = (name: string, modelField: string) => {
+ return name.indexOf('[') >= 0
+ ? name.split('[')[0].toLowerCase() + name.split('[')[1].split(']')[0]
+ : name.toLowerCase() + '-' + modelField.toLowerCase()
+ }
+
+ const formItemDisabled = (field: string, value: Array<any>) => {
+ return value.map((v) => field === v).indexOf(false) < 0
+ }
+
+ return {
+ t,
+ formatClass,
+ formItemDisabled
+ }
+ },
+ render() {
+ return (
+ <NGrid xGap={10}>
+ {(this.formStructure as Array<any>).map((f) => {
+ return (
+ (f.show
+ ? this.formItemDisabled(
+ (this.model as any)[f.show.field],
+ f.show.value
+ )
+ : true) && (
+ <NFormItemGi
+ label={this.t(f.label)}
+ path={f.field}
+ span={f.span || 24}
+ >
+ {f.type === 'input' && (
+ <NInput
+ class={`dynamic-form_${this.formatClass(
+ this.name,
+ f.field
+ )}`}
+ placeholder={f.placeholder ? this.t(f.placeholder) : ''}
+ v-model={[(this.model as any)[f.field], 'value']}
+ clearable={f.clearable}
+ type={f.inputType}
+ rows={f.row ? f.row : 4}
+ />
+ )}
+ {f.type === 'select' &&
+ (f.show
+ ? this.formItemDisabled(
+ (this.model as any)[f.show.field],
+ f.show.value
+ )
+ : true) && (
+ <NSelect
+ class={`dynamic-form_${this.formatClass(
+ this.name,
+ f.field
+ )}`}
+ placeholder={f.placeholder ? this.t(f.placeholder) : ''}
+ v-model={[(this.model as any)[f.field], 'value']}
+ options={
+ f.options.map((o: SelectOption) => {
+ return {
+ label: this.t(o.label as string),
+ value: o.value
+ }
+ })
+ }
+ />
+ )}
+ {f.type === 'checkbox' &&
+ (f.show
+ ? this.formItemDisabled(
+ (this.model as any)[f.show.field],
+ f.show.value
+ )
+ : true) && (
+ <NCheckboxGroup
+ class={`dynamic-form_${this.formatClass(
+ this.name,
+ f.field
+ )}`}
+ v-model={[(this.model as any)[f.field], 'value']}
+ >
+ <NSpace vertical={f.vertical}>
+ {f.options.map((o: any) => (
+ <NCheckbox
+ label={this.t(o.label as string)}
+ value={o.value}
+ />
+ ))}
+ </NSpace>
+ </NCheckboxGroup>
+ )}
+ </NFormItemGi>
+ )
+ )
+ })}
+ </NGrid>
+ )
+ }
+})
+
+export { DynamicFormItem }
diff --git a/seatunnel-ui/src/components/dynamic-form/use-form-field.ts b/seatunnel-ui/src/components/dynamic-form/use-form-field.ts
new file mode 100644
index 00000000..3d6a0e97
--- /dev/null
+++ b/seatunnel-ui/src/components/dynamic-form/use-form-field.ts
@@ -0,0 +1,32 @@
+/*
+ * 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.
+ */
+
+export function useFormField(forms: Array<any>) {
+ const model: any = {}
+
+ const setField = (value: string, type: string): null | string => {
+ return value ? value : type === 'select' ? null : ''
+ }
+
+ forms.forEach((f: any) => {
+ if (!f.field) return
+
+ model[f.field] = setField(f.defaultValue, f.type)
+ })
+
+ return model
+}
diff --git a/seatunnel-ui/src/components/dynamic-form/use-form-locales.ts b/seatunnel-ui/src/components/dynamic-form/use-form-locales.ts
new file mode 100644
index 00000000..90d8c7c0
--- /dev/null
+++ b/seatunnel-ui/src/components/dynamic-form/use-form-locales.ts
@@ -0,0 +1,26 @@
+/*
+ * 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 { useI18n } from 'vue-i18n'
+
+export function useFormLocales(locales: {
+ zh_CN: object
+ en_US: object
+}): void {
+ useI18n().mergeLocaleMessage('zh_CN', { i18n: locales.zh_CN })
+ useI18n().mergeLocaleMessage('en_US', { i18n: locales.en_US })
+}
diff --git a/seatunnel-ui/src/components/dynamic-form/use-form-request.ts b/seatunnel-ui/src/components/dynamic-form/use-form-request.ts
new file mode 100644
index 00000000..6ba882e9
--- /dev/null
+++ b/seatunnel-ui/src/components/dynamic-form/use-form-request.ts
@@ -0,0 +1,39 @@
+/*
+ * 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 { axios } from '@/service/service'
+
+const reqFunction = (url: string, method: string) => {
+ return axios({
+ url,
+ method
+ } as any)
+}
+
+export function useFormRequest(apis: any, forms: Array<any>): Array<any> {
+ forms.map(f => {
+ if (f.api) {
+ reqFunction(apis[f.api].url, apis[f.api].method).then((res: any) => {
+ f.options = res.map((r: any) => {
+ return { label: r.label, value: r.value }
+ })
+ })
+ }
+ })
+
+ return forms
+}
\ No newline at end of file
diff --git a/seatunnel-ui/src/components/dynamic-form/use-form-structure.ts b/seatunnel-ui/src/components/dynamic-form/use-form-structure.ts
new file mode 100644
index 00000000..34166ac6
--- /dev/null
+++ b/seatunnel-ui/src/components/dynamic-form/use-form-structure.ts
@@ -0,0 +1,25 @@
+/*
+ * 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.
+ */
+
+export function useFormStructure(forms: Array<any>) {
+ return forms.map((f: any) => {
+ delete f.validate
+ delete f.api
+
+ return f
+ })
+}
\ No newline at end of file
diff --git a/seatunnel-ui/src/components/dynamic-form/use-form-validate.ts b/seatunnel-ui/src/components/dynamic-form/use-form-validate.ts
new file mode 100644
index 00000000..86be15ae
--- /dev/null
+++ b/seatunnel-ui/src/components/dynamic-form/use-form-validate.ts
@@ -0,0 +1,69 @@
+/*
+ * 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 { FormItemRule } from 'naive-ui'
+
+export function useFormValidate(forms: Array<any>, model: any, t: any) {
+ const validate: any = {}
+
+ const setValidate = (validate: any, field: string): object => {
+ const data: any = {
+ required: validate.required,
+ trigger: validate.trigger
+ }
+
+ if (validate.type === 'non-empty') {
+ data['validator'] = (rule: FormItemRule, value: string) => {
+ if (!model[field]) {
+ return Error(t(validate.message))
+ }
+ }
+ } else if (validate.type === 'union-non-empty') {
+ const fields = validate.fields.splice(
+ validate.fields.findIndex((f: any) => f !== field),
+ 1
+ )
+ data['validator'] = (rule: FormItemRule, value: string) => {
+ const fieldsValidate = fields.map((f: string) => !!model[f])
+ if (!value && fieldsValidate.includes(true)) {
+ return Error(t(validate.message))
+ }
+ }
+ } else if (validate.type === 'mutually-exclusive') {
+ const fields = validate.fields.splice(
+ validate.fields.findIndex((f: any) => f !== field),
+ 1
+ )
+ data['validator'] = (rule: FormItemRule, value: string) => {
+ const fieldsValidate = fields.map((f: string) => !!model[f])
+ if (value && fieldsValidate.indexOf(false) < 0) {
+ return Error(t(validate.message))
+ }
+ }
+ }
+
+ return data
+ }
+
+ forms.forEach((f: any) => {
+ if (!f.validate || Object.keys(f.validate).length <= 0) return
+
+ validate[f.field] = setValidate(f.validate, f.field)
+ })
+
+ return validate
+}