You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@dolphinscheduler.apache.org by so...@apache.org on 2022/03/24 05:58:02 UTC

[dolphinscheduler] branch dev updated: [Fix][UI Next][V1.0.0-Alpha]Fix the resources options incorrect in FLINK. (#9146)

This is an automated email from the ASF dual-hosted git repository.

songjian pushed a commit to branch dev
in repository https://gitbox.apache.org/repos/asf/dolphinscheduler.git


The following commit(s) were added to refs/heads/dev by this push:
     new 926fad8  [Fix][UI Next][V1.0.0-Alpha]Fix the resources options incorrect in FLINK. (#9146)
926fad8 is described below

commit 926fad861eadc008e9869822c1d72fef2b6e4e6a
Author: Amy0104 <97...@users.noreply.github.com>
AuthorDate: Thu Mar 24 13:57:56 2022 +0800

    [Fix][UI Next][V1.0.0-Alpha]Fix the resources options incorrect in FLINK. (#9146)
---
 .../src/components/form/types.ts                   |   4 +-
 .../src/store/project/task-node.ts                 |  25 +++-
 .../src/store/project/types.ts                     |  23 +++-
 .../projects/task/components/node/fields/index.ts  |   2 +
 .../task/components/node/fields/use-flink.ts       |  77 +----------
 .../task/components/node/fields/use-main-jar.ts    |  79 +++++++++++
 .../projects/task/components/node/fields/use-mr.ts |  73 +---------
 .../node/fields/{use-shell.ts => use-resources.ts} |  77 +++++------
 .../task/components/node/fields/use-sea-tunnel.ts  | 153 +--------------------
 .../task/components/node/fields/use-shell.ts       |  41 +-----
 .../task/components/node/fields/use-spark.ts       |  91 ++----------
 .../task/components/node/fields/use-sql.ts         | 145 +------------------
 .../views/projects/task/components/node/types.ts   |   3 +-
 13 files changed, 196 insertions(+), 597 deletions(-)

diff --git a/dolphinscheduler-ui-next/src/components/form/types.ts b/dolphinscheduler-ui-next/src/components/form/types.ts
index c1a7d8a..6be131b 100644
--- a/dolphinscheduler-ui-next/src/components/form/types.ts
+++ b/dolphinscheduler-ui-next/src/components/form/types.ts
@@ -38,9 +38,7 @@ type IType =
   | 'custom'
   | 'multi-condition'
 
-interface IOption extends SelectOption, TreeSelectOption {
-  label: string
-}
+type IOption = SelectOption | TreeSelectOption
 
 interface IFormItem {
   showLabel?: boolean
diff --git a/dolphinscheduler-ui-next/src/store/project/task-node.ts b/dolphinscheduler-ui-next/src/store/project/task-node.ts
index 9779594..8dca166 100644
--- a/dolphinscheduler-ui-next/src/store/project/task-node.ts
+++ b/dolphinscheduler-ui-next/src/store/project/task-node.ts
@@ -16,14 +16,23 @@
  */
 import { defineStore } from 'pinia'
 import { uniqBy } from 'lodash'
-import type { TaskNodeState, EditWorkflowDefinition, IOption } from './types'
+import type {
+  TaskNodeState,
+  EditWorkflowDefinition,
+  IOption,
+  IResource,
+  ProgramType,
+  IMainJar
+} from './types'
 
 export const useTaskNodeStore = defineStore({
   id: 'project-task',
   state: (): TaskNodeState => ({
     preTaskOptions: [],
     postTaskOptions: [],
-    preTasks: []
+    preTasks: [],
+    resources: [],
+    mainJars: {}
   }),
   persist: true,
   getters: {
@@ -35,6 +44,12 @@ export const useTaskNodeStore = defineStore({
     },
     getPreTasks(): number[] {
       return this.preTasks
+    },
+    getResources(): IResource[] {
+      return this.resources
+    },
+    getMainJar(state) {
+      return (type: ProgramType): IMainJar[] | undefined => state.mainJars[type]
     }
   },
   actions: {
@@ -94,6 +109,12 @@ export const useTaskNodeStore = defineStore({
       )
       this.preTasks = preTasks
       this.postTaskOptions = postTaskOptions
+    },
+    updateResource(resources: IResource[]) {
+      this.resources = resources
+    },
+    updateMainJar(type: ProgramType, mainJar: IMainJar[]) {
+      this.mainJars[type] = mainJar
     }
   }
 })
diff --git a/dolphinscheduler-ui-next/src/store/project/types.ts b/dolphinscheduler-ui-next/src/store/project/types.ts
index 38b8803..b9a5b17 100644
--- a/dolphinscheduler-ui-next/src/store/project/types.ts
+++ b/dolphinscheduler-ui-next/src/store/project/types.ts
@@ -18,9 +18,30 @@
 import type { EditWorkflowDefinition } from '@/views/projects/workflow/components/dag/types'
 import type { IOption } from '@/components/form/types'
 
+type ProgramType = 'JAVA' | 'SCALA' | 'PYTHON'
+
+interface IResource {
+  id: number
+  name: string
+  children?: IResource[]
+}
+interface IMainJar {
+  id: number
+  fullName: string
+  children: IMainJar[]
+}
 interface TaskNodeState {
   postTaskOptions: IOption[]
   preTaskOptions: IOption[]
   preTasks: number[]
+  resources: IResource[]
+  mainJars: { [key in ProgramType]?: IMainJar[] }
+}
+export {
+  TaskNodeState,
+  EditWorkflowDefinition,
+  IOption,
+  IResource,
+  ProgramType,
+  IMainJar
 }
-export { TaskNodeState, EditWorkflowDefinition, IOption }
diff --git a/dolphinscheduler-ui-next/src/views/projects/task/components/node/fields/index.ts b/dolphinscheduler-ui-next/src/views/projects/task/components/node/fields/index.ts
index 1ca0476..b69fb0a 100644
--- a/dolphinscheduler-ui-next/src/views/projects/task/components/node/fields/index.ts
+++ b/dolphinscheduler-ui-next/src/views/projects/task/components/node/fields/index.ts
@@ -46,6 +46,8 @@ export { useDriverMemory } from './use-driver-memory'
 export { useExecutorNumber } from './use-executor-number'
 export { useExecutorMemory } from './use-executor-memory'
 export { useExecutorCores } from './use-executor-cores'
+export { useMainJar } from './use-main-jar'
+export { useResources } from './use-resources'
 
 export { useShell } from './use-shell'
 export { useSpark } from './use-spark'
diff --git a/dolphinscheduler-ui-next/src/views/projects/task/components/node/fields/use-flink.ts b/dolphinscheduler-ui-next/src/views/projects/task/components/node/fields/use-flink.ts
index 23bb68b..d1e1382 100644
--- a/dolphinscheduler-ui-next/src/views/projects/task/components/node/fields/use-flink.ts
+++ b/dolphinscheduler-ui-next/src/views/projects/task/components/node/fields/use-flink.ts
@@ -14,16 +14,13 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-import { ref, onMounted, computed } from 'vue'
+import { computed } from 'vue'
 import { useI18n } from 'vue-i18n'
-import { queryResourceByProgramType } from '@/service/modules/resources'
-import { removeUselessChildren } from '@/utils/tree-format'
-import { useCustomParams, useDeployMode } from '.'
-import type { IJsonItem, ProgramType } from '../types'
+import { useCustomParams, useDeployMode, useMainJar, useResources } from '.'
+import type { IJsonItem } from '../types'
 
 export function useFlink(model: { [field: string]: any }): IJsonItem[] {
   const { t } = useI18n()
-
   const mainClassSpan = computed(() =>
     model.programType === 'PYTHON' ? 0 : 24
   )
@@ -38,27 +35,6 @@ export function useFlink(model: { [field: string]: any }): IJsonItem[] {
 
   const appNameSpan = computed(() => (model.deployMode === 'cluster' ? 24 : 0))
 
-  const mainJarOptions = ref([])
-  const resources: { [field: string]: any } = {}
-
-  const getResourceList = async (programType: ProgramType) => {
-    if (resources[programType] !== void 0) {
-      mainJarOptions.value = resources[programType]
-      return
-    }
-    const res = await queryResourceByProgramType({
-      type: 'FILE',
-      programType
-    })
-    removeUselessChildren(res)
-    mainJarOptions.value = res || []
-    resources[programType] = res
-  }
-
-  onMounted(() => {
-    getResourceList(model.programType)
-  })
-
   return [
     {
       type: 'select',
@@ -67,13 +43,11 @@ export function useFlink(model: { [field: string]: any }): IJsonItem[] {
       name: t('project.node.program_type'),
       options: PROGRAM_TYPES,
       props: {
-        'on-update:value': (value: ProgramType) => {
+        'on-update:value': () => {
           model.mainJar = null
           model.mainClass = ''
-          getResourceList(value)
         }
-      },
-      value: model.programType
+      }
     },
     {
       type: 'input',
@@ -93,29 +67,7 @@ export function useFlink(model: { [field: string]: any }): IJsonItem[] {
         }
       }
     },
-    {
-      type: 'tree-select',
-      field: 'mainJar',
-      name: t('project.node.main_package'),
-      props: {
-        cascade: true,
-        showPath: true,
-        checkStrategy: 'child',
-        placeholder: t('project.node.main_package_tips'),
-        keyField: 'id',
-        labelField: 'fullName'
-      },
-      validate: {
-        trigger: ['input', 'blur'],
-        required: model.programType !== 'PYTHON',
-        validator(validate: any, value: string) {
-          if (!value) {
-            return new Error(t('project.node.main_package_tips'))
-          }
-        }
-      },
-      options: mainJarOptions
-    },
+    useMainJar(model),
     useDeployMode(24, false),
     {
       type: 'select',
@@ -241,22 +193,7 @@ export function useFlink(model: { [field: string]: any }): IJsonItem[] {
         placeholder: t('project.node.option_parameters_tips')
       }
     },
-    {
-      type: 'tree-select',
-      field: 'resourceList',
-      name: t('project.node.resources'),
-      options: mainJarOptions,
-      props: {
-        multiple: true,
-        checkable: true,
-        cascade: true,
-        showPath: true,
-        checkStrategy: 'child',
-        placeholder: t('project.node.resources_tips'),
-        keyField: 'id',
-        labelField: 'name'
-      }
-    },
+    useResources(),
     ...useCustomParams({
       model,
       field: 'localParams',
diff --git a/dolphinscheduler-ui-next/src/views/projects/task/components/node/fields/use-main-jar.ts b/dolphinscheduler-ui-next/src/views/projects/task/components/node/fields/use-main-jar.ts
new file mode 100644
index 0000000..5c33c4e
--- /dev/null
+++ b/dolphinscheduler-ui-next/src/views/projects/task/components/node/fields/use-main-jar.ts
@@ -0,0 +1,79 @@
+/*
+ * 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 { ref, onMounted, watch } from 'vue'
+import { useI18n } from 'vue-i18n'
+import { queryResourceByProgramType } from '@/service/modules/resources'
+import { useTaskNodeStore } from '@/store/project/task-node'
+import { removeUselessChildren } from '@/utils/tree-format'
+import type { IJsonItem, ProgramType, IMainJar } from '../types'
+
+export function useMainJar(model: { [field: string]: any }): IJsonItem {
+  const { t } = useI18n()
+  const mainJarOptions = ref([] as IMainJar[])
+  const taskStore = useTaskNodeStore()
+
+  const getMainJars = async (programType: ProgramType) => {
+    const storeMainJar = taskStore.getMainJar(programType)
+    if (storeMainJar) {
+      mainJarOptions.value = storeMainJar
+      return
+    }
+    const res = await queryResourceByProgramType({
+      type: 'FILE',
+      programType
+    })
+    removeUselessChildren(res)
+    mainJarOptions.value = res || []
+    taskStore.updateMainJar(programType, res)
+  }
+
+  onMounted(() => {
+    getMainJars(model.programType)
+  })
+
+  watch(
+    () => model.programType,
+    (value) => {
+      getMainJars(value)
+    }
+  )
+
+  return {
+    type: 'tree-select',
+    field: 'mainJar',
+    name: t('project.node.main_package'),
+    props: {
+      cascade: true,
+      showPath: true,
+      checkStrategy: 'child',
+      placeholder: t('project.node.main_package_tips'),
+      keyField: 'id',
+      labelField: 'fullName'
+    },
+    validate: {
+      trigger: ['input', 'blur'],
+      required: true,
+      validator(validate: any, value: string) {
+        if (!value) {
+          return new Error(t('project.node.main_package_tips'))
+        }
+      }
+    },
+    options: mainJarOptions
+  }
+}
diff --git a/dolphinscheduler-ui-next/src/views/projects/task/components/node/fields/use-mr.ts b/dolphinscheduler-ui-next/src/views/projects/task/components/node/fields/use-mr.ts
index aa0b825..ea64355 100644
--- a/dolphinscheduler-ui-next/src/views/projects/task/components/node/fields/use-mr.ts
+++ b/dolphinscheduler-ui-next/src/views/projects/task/components/node/fields/use-mr.ts
@@ -14,13 +14,11 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-import { ref, onMounted, computed } from 'vue'
+import { computed } from 'vue'
 import { useI18n } from 'vue-i18n'
-import { queryResourceByProgramType } from '@/service/modules/resources'
-import { removeUselessChildren } from '@/utils/tree-format'
 import { PROGRAM_TYPES } from './use-spark'
-import { useCustomParams } from '.'
-import type { IJsonItem, ProgramType } from '../types'
+import { useCustomParams, useMainJar, useResources } from '.'
+import type { IJsonItem } from '../types'
 
 export function useMr(model: { [field: string]: any }): IJsonItem[] {
   const { t } = useI18n()
@@ -29,27 +27,6 @@ export function useMr(model: { [field: string]: any }): IJsonItem[] {
     model.programType === 'PYTHON' ? 0 : 24
   )
 
-  const mainJarOptions = ref([])
-  const resources: { [field: string]: any } = {}
-
-  const getResourceList = async (programType: ProgramType) => {
-    if (resources[programType] !== void 0) {
-      mainJarOptions.value = resources[programType]
-      return
-    }
-    const res = await queryResourceByProgramType({
-      type: 'FILE',
-      programType
-    })
-    removeUselessChildren(res)
-    mainJarOptions.value = res || []
-    resources[programType] = res
-  }
-
-  onMounted(() => {
-    getResourceList(model.programType)
-  })
-
   return [
     {
       type: 'select',
@@ -58,10 +35,9 @@ export function useMr(model: { [field: string]: any }): IJsonItem[] {
       name: t('project.node.program_type'),
       options: PROGRAM_TYPES,
       props: {
-        'on-update:value': (value: ProgramType) => {
+        'on-update:value': () => {
           model.mainJar = null
           model.mainClass = ''
-          getResourceList(value)
         }
       },
       value: model.programType
@@ -84,29 +60,7 @@ export function useMr(model: { [field: string]: any }): IJsonItem[] {
         }
       }
     },
-    {
-      type: 'tree-select',
-      field: 'mainJar',
-      name: t('project.node.main_package'),
-      props: {
-        cascade: true,
-        showPath: true,
-        checkStrategy: 'child',
-        placeholder: t('project.node.main_package_tips'),
-        keyField: 'id',
-        labelField: 'fullName'
-      },
-      validate: {
-        trigger: ['input', 'blur'],
-        required: model.programType !== 'PYTHON',
-        validator(validate: any, value: string) {
-          if (!value) {
-            return new Error(t('project.node.main_package_tips'))
-          }
-        }
-      },
-      options: mainJarOptions
-    },
+    useMainJar(model),
     {
       type: 'input',
       field: 'appName',
@@ -133,22 +87,7 @@ export function useMr(model: { [field: string]: any }): IJsonItem[] {
         placeholder: t('project.node.option_parameters_tips')
       }
     },
-    {
-      type: 'tree-select',
-      field: 'resourceList',
-      name: t('project.node.resources'),
-      options: mainJarOptions,
-      props: {
-        multiple: true,
-        checkable: true,
-        cascade: true,
-        showPath: true,
-        checkStrategy: 'child',
-        placeholder: t('project.node.resources_tips'),
-        keyField: 'id',
-        labelField: 'name'
-      }
-    },
+    useResources(),
     ...useCustomParams({ model, field: 'localParams', isSimple: true })
   ]
 }
diff --git a/dolphinscheduler-ui-next/src/views/projects/task/components/node/fields/use-shell.ts b/dolphinscheduler-ui-next/src/views/projects/task/components/node/fields/use-resources.ts
similarity index 50%
copy from dolphinscheduler-ui-next/src/views/projects/task/components/node/fields/use-shell.ts
copy to dolphinscheduler-ui-next/src/views/projects/task/components/node/fields/use-resources.ts
index 2d19508..93c3452 100644
--- a/dolphinscheduler-ui-next/src/views/projects/task/components/node/fields/use-shell.ts
+++ b/dolphinscheduler-ui-next/src/views/projects/task/components/node/fields/use-resources.ts
@@ -14,60 +14,55 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 import { ref, onMounted } from 'vue'
 import { useI18n } from 'vue-i18n'
 import { queryResourceList } from '@/service/modules/resources'
-import { useCustomParams } from './use-custom-params'
+import { useTaskNodeStore } from '@/store/project/task-node'
 import { removeUselessChildren } from '@/utils/tree-format'
-import type { IJsonItem } from '../types'
+import type { IJsonItem, IResource } from '../types'
 
-export function useShell(model: { [field: string]: any }): IJsonItem[] {
+export function useResources(): IJsonItem {
   const { t } = useI18n()
-  const options = ref([])
 
-  const loading = ref(false)
+  const resourcesOptions = ref([] as IResource[])
+  const resourcesLoading = ref(false)
+
+  const taskStore = useTaskNodeStore()
 
-  const getResourceList = async () => {
-    if (loading.value) return
-    loading.value = true
+  const getResources = async () => {
+    if (taskStore.resources.length) {
+      resourcesOptions.value = taskStore.resources
+      return
+    }
+    if (resourcesLoading.value) return
+    resourcesLoading.value = true
     const res = await queryResourceList({ type: 'FILE' })
     removeUselessChildren(res)
-    options.value = res || []
-    loading.value = false
+    resourcesOptions.value = res || []
+    resourcesLoading.value = false
+    taskStore.updateResource(res)
   }
 
   onMounted(() => {
-    getResourceList()
+    getResources()
   })
 
-  return [
-    {
-      type: 'editor',
-      field: 'rawScript',
-      name: t('project.node.script'),
-      validate: {
-        trigger: ['input', 'trigger'],
-        required: true,
-        message: t('project.node.script_tips')
-      }
-    },
-    {
-      type: 'tree-select',
-      field: 'resourceList',
-      name: t('project.node.resources'),
-      options,
-      props: {
-        multiple: true,
-        checkable: true,
-        cascade: true,
-        showPath: true,
-        checkStrategy: 'child',
-        placeholder: t('project.node.resources_tips'),
-        keyField: 'id',
-        labelField: 'name',
-        loading
-      }
-    },
-    ...useCustomParams({ model, field: 'localParams', isSimple: false })
-  ]
+  return {
+    type: 'tree-select',
+    field: 'resourceList',
+    name: t('project.node.resources'),
+    options: resourcesOptions,
+    props: {
+      multiple: true,
+      checkable: true,
+      cascade: true,
+      showPath: true,
+      checkStrategy: 'child',
+      placeholder: t('project.node.resources_tips'),
+      keyField: 'id',
+      labelField: 'name',
+      loading: resourcesLoading
+    }
+  }
 }
diff --git a/dolphinscheduler-ui-next/src/views/projects/task/components/node/fields/use-sea-tunnel.ts b/dolphinscheduler-ui-next/src/views/projects/task/components/node/fields/use-sea-tunnel.ts
index ee2d132..d0a0473 100644
--- a/dolphinscheduler-ui-next/src/views/projects/task/components/node/fields/use-sea-tunnel.ts
+++ b/dolphinscheduler-ui-next/src/views/projects/task/components/node/fields/use-sea-tunnel.ts
@@ -14,16 +14,13 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-import { ref, onMounted, watch, computed } from 'vue'
+import { watch, computed } from 'vue'
 import { useI18n } from 'vue-i18n'
-import { queryResourceList } from '@/service/modules/resources'
-import { useDeployMode } from '.'
-import { removeUselessChildren } from '@/utils/tree-format'
+import { useDeployMode, useResources, useCustomParams } from '.'
 import type { IJsonItem } from '../types'
 
 export function useSeaTunnel(model: { [field: string]: any }): IJsonItem[] {
   const { t } = useI18n()
-  const options = ref([])
 
   const masterTypeOptions = [
     {
@@ -51,22 +48,6 @@ export function useSeaTunnel(model: { [field: string]: any }): IJsonItem[] {
     }
   ]
 
-  const loading = ref(false)
-
-  const getResourceList = async () => {
-    if (loading.value) return
-    loading.value = true
-    model.resourceFiles = []
-    const res = await queryResourceList({ type: 'FILE' })
-    removeUselessChildren(res)
-    options.value = res || []
-    loading.value = false
-  }
-
-  onMounted(() => {
-    getResourceList()
-  })
-
   const masterSpan = computed(() => (model.deployMode === 'local' ? 0 : 12))
   const queueSpan = computed(() =>
     model.deployMode === 'local' || model.master != 'yarn' ? 0 : 12
@@ -141,133 +122,7 @@ export function useSeaTunnel(model: { [field: string]: any }): IJsonItem[] {
       value: model.queue,
       span: queueSpan
     },
-
-    {
-      type: 'tree-select',
-      field: 'resourceList',
-      name: t('project.node.resources'),
-      options,
-      props: {
-        multiple: true,
-        checkable: true,
-        cascade: true,
-        showPath: true,
-        checkStrategy: 'child',
-        placeholder: t('project.node.resources_tips'),
-        keyField: 'id',
-        labelField: 'name',
-        loading,
-        validate: {
-          trigger: ['input', 'blur'],
-          required: true
-        }
-      }
-    },
-    {
-      type: 'custom-parameters',
-      field: 'localParams',
-      name: t('project.node.custom_parameters'),
-      children: [
-        {
-          type: 'input',
-          field: 'prop',
-          span: 6,
-          props: {
-            placeholder: t('project.node.prop_tips'),
-            maxLength: 256
-          },
-          validate: {
-            trigger: ['input', 'blur'],
-            required: true,
-            validator(validate: any, value: string) {
-              if (!value) {
-                return new Error(t('project.node.prop_tips'))
-              }
-
-              const sameItems = model.localParams.filter(
-                (item: { prop: string }) => item.prop === value
-              )
-
-              if (sameItems.length > 1) {
-                return new Error(t('project.node.prop_repeat'))
-              }
-            }
-          }
-        },
-        {
-          type: 'select',
-          field: 'direct',
-          span: 4,
-          options: DIRECT_LIST,
-          value: 'IN'
-        },
-        {
-          type: 'select',
-          field: 'type',
-          span: 6,
-          options: TYPE_LIST,
-          value: 'VARCHAR'
-        },
-        {
-          type: 'input',
-          field: 'value',
-          span: 6,
-          props: {
-            placeholder: t('project.node.value_tips'),
-            maxLength: 256
-          }
-        }
-      ]
-    }
+    useResources(),
+    ...useCustomParams({ model, field: 'localParams', isSimple: true })
   ]
 }
-
-export const TYPE_LIST = [
-  {
-    value: 'VARCHAR',
-    label: 'VARCHAR'
-  },
-  {
-    value: 'INTEGER',
-    label: 'INTEGER'
-  },
-  {
-    value: 'LONG',
-    label: 'LONG'
-  },
-  {
-    value: 'FLOAT',
-    label: 'FLOAT'
-  },
-  {
-    value: 'DOUBLE',
-    label: 'DOUBLE'
-  },
-  {
-    value: 'DATE',
-    label: 'DATE'
-  },
-  {
-    value: 'TIME',
-    label: 'TIME'
-  },
-  {
-    value: 'TIMESTAMP',
-    label: 'TIMESTAMP'
-  },
-  {
-    value: 'BOOLEAN',
-    label: 'BOOLEAN'
-  }
-]
-
-export const DIRECT_LIST = [
-  {
-    value: 'IN',
-    label: 'IN'
-  },
-  {
-    value: 'OUT',
-    label: 'OUT'
-  }
-]
diff --git a/dolphinscheduler-ui-next/src/views/projects/task/components/node/fields/use-shell.ts b/dolphinscheduler-ui-next/src/views/projects/task/components/node/fields/use-shell.ts
index 2d19508..5b853a9 100644
--- a/dolphinscheduler-ui-next/src/views/projects/task/components/node/fields/use-shell.ts
+++ b/dolphinscheduler-ui-next/src/views/projects/task/components/node/fields/use-shell.ts
@@ -14,31 +14,12 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-import { ref, onMounted } from 'vue'
 import { useI18n } from 'vue-i18n'
-import { queryResourceList } from '@/service/modules/resources'
-import { useCustomParams } from './use-custom-params'
-import { removeUselessChildren } from '@/utils/tree-format'
+import { useCustomParams, useResources } from '.'
 import type { IJsonItem } from '../types'
 
 export function useShell(model: { [field: string]: any }): IJsonItem[] {
   const { t } = useI18n()
-  const options = ref([])
-
-  const loading = ref(false)
-
-  const getResourceList = async () => {
-    if (loading.value) return
-    loading.value = true
-    const res = await queryResourceList({ type: 'FILE' })
-    removeUselessChildren(res)
-    options.value = res || []
-    loading.value = false
-  }
-
-  onMounted(() => {
-    getResourceList()
-  })
 
   return [
     {
@@ -51,23 +32,7 @@ export function useShell(model: { [field: string]: any }): IJsonItem[] {
         message: t('project.node.script_tips')
       }
     },
-    {
-      type: 'tree-select',
-      field: 'resourceList',
-      name: t('project.node.resources'),
-      options,
-      props: {
-        multiple: true,
-        checkable: true,
-        cascade: true,
-        showPath: true,
-        checkStrategy: 'child',
-        placeholder: t('project.node.resources_tips'),
-        keyField: 'id',
-        labelField: 'name',
-        loading
-      }
-    },
-    ...useCustomParams({ model, field: 'localParams', isSimple: false })
+    useResources(),
+    ...useCustomParams({ model, field: 'localParams', isSimple: true })
   ]
 }
diff --git a/dolphinscheduler-ui-next/src/views/projects/task/components/node/fields/use-spark.ts b/dolphinscheduler-ui-next/src/views/projects/task/components/node/fields/use-spark.ts
index 076d6a8..fe33b1c 100644
--- a/dolphinscheduler-ui-next/src/views/projects/task/components/node/fields/use-spark.ts
+++ b/dolphinscheduler-ui-next/src/views/projects/task/components/node/fields/use-spark.ts
@@ -14,62 +14,26 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-import { ref, onMounted, computed } from 'vue'
+import { computed } from 'vue'
 import { useI18n } from 'vue-i18n'
 import {
-  queryResourceByProgramType,
-  queryResourceList
-} from '@/service/modules/resources'
-import { removeUselessChildren } from '@/utils/tree-format'
-import {
   useCustomParams,
   useDeployMode,
   useDriverCores,
   useDriverMemory,
   useExecutorNumber,
   useExecutorMemory,
-  useExecutorCores
+  useExecutorCores,
+  useMainJar,
+  useResources
 } from '.'
-import type { IJsonItem, ProgramType } from '../types'
+import type { IJsonItem } from '../types'
 
 export function useSpark(model: { [field: string]: any }): IJsonItem[] {
   const { t } = useI18n()
-
   const mainClassSpan = computed(() =>
     model.programType === 'PYTHON' ? 0 : 24
   )
-  const resourcesOptions = ref([])
-  const resourcesLoading = ref(false)
-  const mainJarOptions = ref([])
-  const mainJarOptionsStore: { [field: string]: any } = {}
-
-  const getMainJars = async (programType: ProgramType) => {
-    if (mainJarOptionsStore[programType] !== void 0) {
-      mainJarOptions.value = mainJarOptionsStore[programType]
-      return
-    }
-    const res = await queryResourceByProgramType({
-      type: 'FILE',
-      programType
-    })
-    removeUselessChildren(res)
-    mainJarOptions.value = res || []
-    mainJarOptionsStore[programType] = res
-  }
-
-  const getResources = async () => {
-    if (resourcesLoading.value) return
-    resourcesLoading.value = true
-    const res = await queryResourceList({ type: 'FILE' })
-    removeUselessChildren(res)
-    resourcesOptions.value = res || []
-    resourcesLoading.value = false
-  }
-
-  onMounted(() => {
-    getMainJars(model.programType)
-    getResources()
-  })
 
   return [
     {
@@ -79,10 +43,9 @@ export function useSpark(model: { [field: string]: any }): IJsonItem[] {
       name: t('project.node.program_type'),
       options: PROGRAM_TYPES,
       props: {
-        'on-update:value': (value: ProgramType) => {
+        'on-update:value': () => {
           model.mainJar = null
           model.mainClass = ''
-          getMainJars(value)
         }
       }
     },
@@ -111,29 +74,7 @@ export function useSpark(model: { [field: string]: any }): IJsonItem[] {
         }
       }
     },
-    {
-      type: 'tree-select',
-      field: 'mainJar',
-      name: t('project.node.main_package'),
-      props: {
-        cascade: true,
-        showPath: true,
-        checkStrategy: 'child',
-        placeholder: t('project.node.main_package_tips'),
-        keyField: 'id',
-        labelField: 'fullName'
-      },
-      validate: {
-        trigger: ['input', 'blur'],
-        required: model.programType !== 'PYTHON',
-        validator(validate: any, value: string) {
-          if (!value) {
-            return new Error(t('project.node.main_package_tips'))
-          }
-        }
-      },
-      options: mainJarOptions
-    },
+    useMainJar(model),
     useDeployMode(),
     {
       type: 'input',
@@ -166,23 +107,7 @@ export function useSpark(model: { [field: string]: any }): IJsonItem[] {
         placeholder: t('project.node.option_parameters_tips')
       }
     },
-    {
-      type: 'tree-select',
-      field: 'resourceList',
-      name: t('project.node.resources'),
-      options: resourcesOptions,
-      props: {
-        multiple: true,
-        checkable: true,
-        cascade: true,
-        showPath: true,
-        checkStrategy: 'child',
-        placeholder: t('project.node.resources_tips'),
-        keyField: 'id',
-        labelField: 'name',
-        loading: resourcesLoading
-      }
-    },
+    useResources(),
     ...useCustomParams({ model, field: 'localParams', isSimple: true })
   ]
 }
diff --git a/dolphinscheduler-ui-next/src/views/projects/task/components/node/fields/use-sql.ts b/dolphinscheduler-ui-next/src/views/projects/task/components/node/fields/use-sql.ts
index 48a92fc..e6a5a5e 100644
--- a/dolphinscheduler-ui-next/src/views/projects/task/components/node/fields/use-sql.ts
+++ b/dolphinscheduler-ui-next/src/views/projects/task/components/node/fields/use-sql.ts
@@ -14,32 +14,16 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-import { ref, onMounted, computed } from 'vue'
+import { computed } from 'vue'
 import { useI18n } from 'vue-i18n'
-import { queryResourceList } from '@/service/modules/resources'
-import { removeUselessChildren } from '@/utils/tree-format'
+import { useResources, useCustomParams } from '.'
 import { useUdfs } from './use-udfs'
 import type { IJsonItem } from '../types'
 
 export function useSql(model: { [field: string]: any }): IJsonItem[] {
   const { t } = useI18n()
-  const options = ref([])
-  const loading = ref(false)
   const hiveSpan = computed(() => (model.type === 'HIVE' ? 24 : 0))
 
-  const getResourceList = async () => {
-    if (loading.value) return
-    loading.value = true
-    const res = await queryResourceList({ type: 'FILE' })
-    removeUselessChildren(res)
-    options.value = res || []
-    loading.value = false
-  }
-
-  onMounted(() => {
-    getResourceList()
-  })
-
   return [
     {
       type: 'input',
@@ -62,79 +46,8 @@ export function useSql(model: { [field: string]: any }): IJsonItem[] {
       }
     },
     useUdfs(model),
-    {
-      type: 'tree-select',
-      field: 'resourceList',
-      name: t('project.node.resources'),
-      options,
-      props: {
-        multiple: true,
-        checkable: true,
-        cascade: true,
-        showPath: true,
-        checkStrategy: 'child',
-        placeholder: t('project.node.resources_tips'),
-        keyField: 'id',
-        labelField: 'name',
-        loading
-      }
-    },
-    {
-      type: 'custom-parameters',
-      field: 'localParams',
-      name: t('project.node.custom_parameters'),
-      children: [
-        {
-          type: 'input',
-          field: 'prop',
-          span: 6,
-          props: {
-            placeholder: t('project.node.prop_tips'),
-            maxLength: 256
-          },
-          validate: {
-            trigger: ['input', 'blur'],
-            required: true,
-            validator(validate: any, value: string) {
-              if (!value) {
-                return new Error(t('project.node.prop_tips'))
-              }
-
-              const sameItems = model.localParams.filter(
-                (item: { prop: string }) => item.prop === value
-              )
-
-              if (sameItems.length > 1) {
-                return new Error(t('project.node.prop_repeat'))
-              }
-            }
-          }
-        },
-        {
-          type: 'select',
-          field: 'direct',
-          span: 4,
-          options: DIRECT_LIST,
-          value: 'IN'
-        },
-        {
-          type: 'select',
-          field: 'type',
-          span: 6,
-          options: TYPE_LIST,
-          value: 'VARCHAR'
-        },
-        {
-          type: 'input',
-          field: 'value',
-          span: 6,
-          props: {
-            placeholder: t('project.node.value_tips'),
-            maxLength: 256
-          }
-        }
-      ]
-    },
+    useResources(),
+    ...useCustomParams({ model, field: 'localParams', isSimple: false }),
     {
       type: 'multi-input',
       field: 'preStatements',
@@ -159,53 +72,3 @@ export function useSql(model: { [field: string]: any }): IJsonItem[] {
     }
   ]
 }
-
-export const TYPE_LIST = [
-  {
-    value: 'VARCHAR',
-    label: 'VARCHAR'
-  },
-  {
-    value: 'INTEGER',
-    label: 'INTEGER'
-  },
-  {
-    value: 'LONG',
-    label: 'LONG'
-  },
-  {
-    value: 'FLOAT',
-    label: 'FLOAT'
-  },
-  {
-    value: 'DOUBLE',
-    label: 'DOUBLE'
-  },
-  {
-    value: 'DATE',
-    label: 'DATE'
-  },
-  {
-    value: 'TIME',
-    label: 'TIME'
-  },
-  {
-    value: 'TIMESTAMP',
-    label: 'TIMESTAMP'
-  },
-  {
-    value: 'BOOLEAN',
-    label: 'BOOLEAN'
-  }
-]
-
-export const DIRECT_LIST = [
-  {
-    value: 'IN',
-    label: 'IN'
-  },
-  {
-    value: 'OUT',
-    label: 'OUT'
-  }
-]
diff --git a/dolphinscheduler-ui-next/src/views/projects/task/components/node/types.ts b/dolphinscheduler-ui-next/src/views/projects/task/components/node/types.ts
index 52ffa87..e9047b7 100644
--- a/dolphinscheduler-ui-next/src/views/projects/task/components/node/types.ts
+++ b/dolphinscheduler-ui-next/src/views/projects/task/components/node/types.ts
@@ -30,8 +30,8 @@ export type {
   IWorkflowTaskInstance,
   WorkflowInstance
 } from '@/views/projects/workflow/components/dag/types'
+export type { IResource, ProgramType, IMainJar } from '@/store/project/types'
 
-type ProgramType = 'JAVA' | 'SCALA' | 'PYTHON'
 type SourceType = 'MYSQL' | 'HDFS' | 'HIVE'
 type ModelType = 'import' | 'export'
 type RelationType = 'AND' | 'OR'
@@ -360,7 +360,6 @@ export {
   ITaskParams,
   IOption,
   IDataBase,
-  ProgramType,
   ModelType,
   SourceType,
   ISqoopSourceParams,