You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@dolphinscheduler.apache.org by li...@apache.org on 2020/03/28 01:26:46 UTC

[incubator-dolphinscheduler] branch dev updated: Resource tree code merge (#2322)

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

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


The following commit(s) were added to refs/heads/dev by this push:
     new c52c92e  Resource tree code merge (#2322)
c52c92e is described below

commit c52c92e0152fda1fe8835628717fc8da9b59a9ec
Author: break60 <79...@qq.com>
AuthorDate: Sat Mar 28 09:26:36 2020 +0800

    Resource tree code merge (#2322)
    
    * Change DOM label
    
    * Change name to lowercase
    
    * Limit customization file content to no more than 3000 lines
    
    * dd branch flow node verification
    
    * datax
    
    * datax add custom
    
    * Change normalize.scss import method and animation.scss license modification
    
    * Resource tree code merge
---
 dolphinscheduler-ui/package.json                   |   1 +
 .../pages/dag/_source/formModel/tasks/flink.vue    |  90 +++++++---------
 .../home/pages/dag/_source/formModel/tasks/mr.vue  |  93 +++++++---------
 .../pages/dag/_source/formModel/tasks/python.vue   |  50 +++------
 .../pages/dag/_source/formModel/tasks/shell.vue    |  80 +++++++-------
 .../pages/dag/_source/formModel/tasks/spark.vue    |  97 +++++++++--------
 .../home/pages/dag/_source/plugIn/jsPlumbHandle.js |  38 +++----
 .../js/conf/home/pages/dag/_source/plugIn/util.js  |   2 +-
 .../js/conf/home/pages/dag/definitionDetails.vue   |   4 +-
 .../src/js/conf/home/pages/dag/index.vue           |   6 +-
 .../pages/definition/pages/list/_source/start.vue  |   1 +
 .../resource/pages/file/pages/create/index.vue     |   5 +
 .../file/pages/{create => createFolder}/index.vue  |  98 +++++------------
 .../pages/{create => createUdfFolder}/index.vue    | 101 ++++-------------
 .../resource/pages/file/pages/details/index.vue    |   2 +-
 .../pages/resource/pages/file/pages/edit/index.vue |   8 +-
 .../pages/file/pages/list/_source/list.vue         |  14 ++-
 .../pages/resource/pages/file/pages/list/index.vue |   2 +
 .../pages/file/pages/{create => subFile}/index.vue |   8 +-
 .../file/pages/{create => subFileFolder}/index.vue |  98 +++++------------
 .../pages/{list => subdirectory}/_source/list.vue  |  26 ++++-
 .../file/pages/subdirectory/_source/rename.vue     | 120 +++++++++++++++++++++
 .../file/pages/{list => subdirectory}/index.vue    |  73 ++++++++++---
 .../create => udf/pages/createUdfFolder}/index.vue | 100 ++++-------------
 .../pages/udf/pages/function/_source/createUdf.vue |  90 ++++++++++++----
 .../pages/udf/pages/function/_source/list.vue      |   5 +-
 .../resource/pages/udf/pages/function/index.vue    |   5 +-
 .../pages/udf/pages/resource/_source/list.vue      |  17 ++-
 .../resource/pages/udf/pages/resource/index.vue    |   6 +-
 .../{resource => subUdfDirectory}/_source/list.vue |  17 ++-
 .../udf/pages/subUdfDirectory/_source/rename.vue   | 120 +++++++++++++++++++++
 .../pages/{resource => subUdfDirectory}/index.vue  |  70 ++++++++++--
 .../create => udf/pages/subUdfFolder}/index.vue    |  98 ++++-------------
 .../pages/security/pages/users/_source/list.vue    |  37 ++++---
 .../src/js/conf/home/router/index.js               |  64 ++++++++++-
 .../src/js/conf/home/store/dag/actions.js          |  19 ++++
 .../src/js/conf/home/store/dag/mutations.js        |   1 +
 .../src/js/conf/home/store/dag/state.js            |   2 +
 .../src/js/conf/home/store/resource/actions.js     |  21 ++++
 .../src/js/conf/home/store/security/actions.js     |  39 +++++++
 .../{fileUpdate.vue => fileChildUpdate.vue}        |  10 +-
 .../js/module/components/fileUpdate/fileUpdate.vue |   6 +-
 .../{fileUpdate.vue => resourceChildUpdate.vue}    |  10 +-
 .../js/module/components/fileUpdate/udfUpdate.vue  |  18 +++-
 .../src/js/module/components/nav/nav.vue           |  82 ++++++++++++++
 .../components/secondaryMenu/_source/menu.js       |   4 +-
 .../src/js/module/components/transfer/resource.vue |  72 ++++++++-----
 .../src/js/module/i18n/locale/en_US.js             |  13 +++
 .../src/js/module/i18n/locale/zh_CN.js             |  13 +++
 .../src/js/module/util/routerUtil.js               |   6 +-
 dolphinscheduler-ui/src/sass/common/_mixin.scss    |  16 ---
 dolphinscheduler-ui/src/sass/common/index.scss     |   2 -
 52 files changed, 1208 insertions(+), 772 deletions(-)

diff --git a/dolphinscheduler-ui/package.json b/dolphinscheduler-ui/package.json
index b8a288e..6b139fa 100644
--- a/dolphinscheduler-ui/package.json
+++ b/dolphinscheduler-ui/package.json
@@ -11,6 +11,7 @@
     "build:release": "npm run clean && cross-env NODE_ENV=production PUBLIC_PATH=/dolphinscheduler/ui webpack --config ./build/webpack.config.release.js"
   },
   "dependencies": {
+    "@riophae/vue-treeselect": "^0.4.0",
     "ans-ui": "1.1.7",
     "axios": "^0.16.2",
     "bootstrap": "3.3.7",
diff --git a/dolphinscheduler-ui/src/js/conf/home/pages/dag/_source/formModel/tasks/flink.vue b/dolphinscheduler-ui/src/js/conf/home/pages/dag/_source/formModel/tasks/flink.vue
index 03e53fe..ac04e21 100644
--- a/dolphinscheduler-ui/src/js/conf/home/pages/dag/_source/formModel/tasks/flink.vue
+++ b/dolphinscheduler-ui/src/js/conf/home/pages/dag/_source/formModel/tasks/flink.vue
@@ -48,19 +48,9 @@
     <m-list-box>
       <div slot="text">{{$t('Main jar package')}}</div>
       <div slot="content">
-        <x-select
-                style="width: 100%;"
-                :placeholder="$t('Please enter main jar package')"
-                v-model="mainJar"
-                filterable
-                :disabled="isDetails">
-          <x-option
-                  v-for="city in mainJarList"
-                  :key="city.code"
-                  :value="city.code"
-                  :label="city.code">
-          </x-option>
-        </x-select>
+        <treeselect v-model="mainJar" :options="mainJarLists" :disable-branch-nodes="true" :normalizer="normalizer" :placeholder="$t('Please enter main jar package')">
+          <div slot="value-label" slot-scope="{ node }">{{ node.raw.fullName }}</div>
+        </treeselect>
       </div>
     </m-list-box>
     <m-list-box>
@@ -151,12 +141,9 @@
     <m-list-box>
       <div slot="text">{{$t('Resources')}}</div>
       <div slot="content">
-        <m-resources
-                ref="refResources"
-                @on-resourcesData="_onResourcesData"
-                @on-cache-resourcesData="_onCacheResourcesData"
-                :resource-list="resourceList">
-        </m-resources>
+        <treeselect v-model="resourceList" :multiple="true" :options="mainJarList" :normalizer="normalizer" :placeholder="$t('Please select resources')">
+          <div slot="value-label" slot-scope="{ node }">{{ node.raw.fullName }}</div>
+        </treeselect>
       </div>
     </m-list-box>
     <m-list-box>
@@ -178,6 +165,8 @@
   import mLocalParams from './_source/localParams'
   import mListBox from './_source/listBox'
   import mResources from './_source/resources'
+  import Treeselect from '@riophae/vue-treeselect'
+  import '@riophae/vue-treeselect/dist/vue-treeselect.css'
   import disabledState from '@/module/mixin/disabledState'
 
   export default {
@@ -189,6 +178,7 @@
         // Master jar package
         mainJar: null,
         // Master jar package(List)
+        mainJarLists: [],
         mainJarList: [],
         // Deployment method
         deployMode: 'cluster',
@@ -215,7 +205,12 @@
         // Program type
         programType: 'SCALA',
         // Program type(List)
-        programTypeList: [{ code: 'JAVA' }, { code: 'SCALA' }, { code: 'PYTHON' }]
+        programTypeList: [{ code: 'JAVA' }, { code: 'SCALA' }, { code: 'PYTHON' }],
+        normalizer(node) {
+          return {
+            label: node.name
+          }
+        }
       }
     },
     props: {
@@ -291,10 +286,6 @@
           return false
         }
 
-        if (!this.$refs.refResources._verifResources()) {
-          return false
-        }
-
         // localParams Subcomponent verification
         if (!this.$refs.refLocalParams._verifProp()) {
           return false
@@ -304,10 +295,12 @@
         this.$emit('on-params', {
           mainClass: this.mainClass,
           mainJar: {
-            res: this.mainJar
+            id: this.mainJar
           },
           deployMode: this.deployMode,
-          resourceList: this.resourceList,
+          resourceList: _.map(this.resourceList, v => {
+            return {id: v}
+          }),
           localParams: this.localParams,
           slot: this.slot,
           taskManager: this.taskManager,
@@ -320,24 +313,12 @@
         })
         return true
       },
-      /**
-       * get resources list
-       */
-      _getResourcesList () {
-        return new Promise((resolve, reject) => {
-          let isJar = (alias) => {
-            return alias.substring(alias.lastIndexOf('.') + 1, alias.length) !== 'jar'
-          }
-          this.mainJarList = _.map(_.cloneDeep(this.store.state.dag.resourcesListS), v => {
-            return {
-              id: v.id,
-              code: v.alias,
-              disabled: isJar(v.alias)
-            }
-          })
-          resolve()
+      diGuiTree(item) {  // Recursive convenience tree structure
+        item.forEach(item => {
+          item.children === '' || item.children === undefined || item.children === null || item.children.length === 0?        
+            delete item.children : this.diGuiTree(item.children);
         })
-      }
+      },
     },
     watch: {
       // Listening type
@@ -356,10 +337,12 @@
         return {
           mainClass: this.mainClass,
           mainJar: {
-            res: this.mainJar
+            id: this.mainJar
           },
           deployMode: this.deployMode,
-          resourceList: this.cacheResourceList,
+          resourceList: _.map(this.resourceList, v => {
+            return {id: v}
+          }),
           localParams: this.localParams,
           slot: this.slot,
           taskManager: this.taskManager,
@@ -373,13 +356,17 @@
       }
     },
     created () {
-      this._getResourcesList().then(() => {
+        let item = this.store.state.dag.resourcesListS
+        let items = this.store.state.dag.resourcesListJar
+        this.diGuiTree(item)
+        this.diGuiTree(items)
+        this.mainJarList = item
+        this.mainJarLists = items
         let o = this.backfillItem
-
         // Non-null objects represent backfill
         if (!_.isEmpty(o)) {
           this.mainClass = o.params.mainClass || ''
-          this.mainJar = o.params.mainJar && o.params.mainJar.res ? o.params.mainJar.res : ''
+          this.mainJar = o.params.mainJar && o.params.mainJar.id ? o.params.mainJar.id : ''
           this.deployMode = o.params.deployMode || ''
           this.slot = o.params.slot || 1
           this.taskManager = o.params.taskManager || '2'
@@ -393,7 +380,9 @@
           // backfill resourceList
           let resourceList = o.params.resourceList || []
           if (resourceList.length) {
-            this.resourceList = resourceList
+            this.resourceList = _.map(resourceList, v => {
+              return v.id
+            })
             this.cacheResourceList = resourceList
           }
 
@@ -403,12 +392,11 @@
             this.localParams = localParams
           }
         }
-      })
     },
     mounted () {
 
     },
-    components: { mLocalParams, mListBox, mResources }
+    components: { mLocalParams, mListBox, mResources, Treeselect }
   }
 </script>
 
diff --git a/dolphinscheduler-ui/src/js/conf/home/pages/dag/_source/formModel/tasks/mr.vue b/dolphinscheduler-ui/src/js/conf/home/pages/dag/_source/formModel/tasks/mr.vue
index 706a35f..3691985 100644
--- a/dolphinscheduler-ui/src/js/conf/home/pages/dag/_source/formModel/tasks/mr.vue
+++ b/dolphinscheduler-ui/src/js/conf/home/pages/dag/_source/formModel/tasks/mr.vue
@@ -44,19 +44,9 @@
     <m-list-box>
       <div slot="text">{{$t('Main jar package')}}</div>
       <div slot="content">
-        <x-select
-                style="width: 100%;"
-                :placeholder="$t('Please enter main jar package')"
-                v-model="mainJar"
-                filterable
-                :disabled="isDetails">
-          <x-option
-                  v-for="city in mainJarList"
-                  :key="city.code"
-                  :value="city.code"
-                  :label="city.code">
-          </x-option>
-        </x-select>
+        <treeselect v-model="mainJar" :options="mainJarLists" :disable-branch-nodes="true" :normalizer="normalizer" :placeholder="$t('Please enter main jar package')">
+          <div slot="value-label" slot-scope="{ node }">{{ node.raw.fullName }}</div>
+        </treeselect>
       </div>
     </m-list-box>
     <m-list-box>
@@ -88,12 +78,9 @@
     <m-list-box>
       <div slot="text">{{$t('Resources')}}</div>
       <div slot="content">
-        <m-resources
-                ref="refResources"
-                @on-resourcesData="_onResourcesData"
-                @on-cache-resourcesData="_onCacheResourcesData"
-                :resource-list="resourceList">
-        </m-resources>
+        <treeselect v-model="resourceList" :multiple="true" :options="mainJarList" :normalizer="normalizer" :placeholder="$t('Please select resources')">
+          <div slot="value-label" slot-scope="{ node }">{{ node.raw.fullName }}</div>
+        </treeselect>
       </div>
     </m-list-box>
     <m-list-box>
@@ -115,6 +102,8 @@
   import mListBox from './_source/listBox'
   import mResources from './_source/resources'
   import mLocalParams from './_source/localParams'
+  import Treeselect from '@riophae/vue-treeselect'
+  import '@riophae/vue-treeselect/dist/vue-treeselect.css'
   import disabledState from '@/module/mixin/disabledState'
   export default {
     name: 'mr',
@@ -125,6 +114,7 @@
         // Master jar package
         mainJar: null,
         // Main jar package (List)
+        mainJarLists: [],
         mainJarList: [],
         // Resource(list)
         resourceList: [],
@@ -139,7 +129,12 @@
         // Program type
         programType: 'JAVA',
         // Program type(List)
-        programTypeList: [{ code: 'JAVA' }, { code: 'PYTHON' }]
+        programTypeList: [{ code: 'JAVA' }, { code: 'PYTHON' }],
+        normalizer(node) {
+          return {
+            label: node.name
+          }
+        }
       }
     },
     props: {
@@ -165,6 +160,12 @@
       _onCacheResourcesData (a) {
         this.cacheResourceList = a
       },
+      diGuiTree(item) {  // Recursive convenience tree structure
+        item.forEach(item => {
+          item.children === '' || item.children === undefined || item.children === null || item.children.length === 0?        
+            delete item.children : this.diGuiTree(item.children);
+        })
+      },
       /**
        * verification
        */
@@ -179,22 +180,19 @@
           return false
         }
 
-        if (!this.$refs.refResources._verifResources()) {
-          return false
-        }
-
         // localParams Subcomponent verification
         if (!this.$refs.refLocalParams._verifProp()) {
           return false
         }
-
         // storage
         this.$emit('on-params', {
           mainClass: this.mainClass,
           mainJar: {
-            res: this.mainJar
+            id: this.mainJar
           },
-          resourceList: this.resourceList,
+          resourceList: _.map(this.resourceList, v => {
+            return {id: v}
+          }),
           localParams: this.localParams,
           mainArgs: this.mainArgs,
           others: this.others,
@@ -202,24 +200,7 @@
         })
         return true
       },
-      /**
-       * Get resource data
-       */
-      _getResourcesList () {
-        return new Promise((resolve, reject) => {
-          let isJar = (alias) => {
-            return alias.substring(alias.lastIndexOf('.') + 1, alias.length) !== 'jar'
-          }
-          this.mainJarList = _.map(_.cloneDeep(this.store.state.dag.resourcesListS), v => {
-            return {
-              id: v.id,
-              code: v.alias,
-              disabled: isJar(v.alias)
-            }
-          })
-          resolve()
-        })
-      }
+    
     },
     watch: {
       /**
@@ -240,9 +221,11 @@
         return {
           mainClass: this.mainClass,
           mainJar: {
-            res: this.mainJar
+            id: this.mainJar
           },
-          resourceList: this.cacheResourceList,
+          resourceList: _.map(this.resourceList, v => {
+            return {id: v}
+          }),
           localParams: this.localParams,
           mainArgs: this.mainArgs,
           others: this.others,
@@ -251,13 +234,18 @@
       }
     },
     created () {
-      this._getResourcesList().then(() => {
+        let item = this.store.state.dag.resourcesListS
+        let items = this.store.state.dag.resourcesListJar
+        this.diGuiTree(item)
+        this.diGuiTree(items)
+        this.mainJarList = item
+        this.mainJarLists = items
         let o = this.backfillItem
 
         // Non-null objects represent backfill
         if (!_.isEmpty(o)) {
           this.mainClass = o.params.mainClass || ''
-          this.mainJar = o.params.mainJar.res || ''
+          this.mainJar = o.params.mainJar.id || ''
           this.mainArgs = o.params.mainArgs || ''
           this.others = o.params.others
           this.programType = o.params.programType || 'JAVA'
@@ -265,7 +253,9 @@
           // backfill resourceList
           let resourceList = o.params.resourceList || []
           if (resourceList.length) {
-            this.resourceList = resourceList
+            this.resourceList = _.map(resourceList, v => {
+              return v.id
+            })
             this.cacheResourceList = resourceList
           }
 
@@ -275,12 +265,11 @@
             this.localParams = localParams
           }
         }
-      })
     },
     mounted () {
 
     },
-    components: { mLocalParams, mListBox, mResources }
+    components: { mLocalParams, mListBox, mResources, Treeselect }
   }
 </script>
 
diff --git a/dolphinscheduler-ui/src/js/conf/home/pages/dag/_source/formModel/tasks/python.vue b/dolphinscheduler-ui/src/js/conf/home/pages/dag/_source/formModel/tasks/python.vue
index 6f495d2..e8e7e58 100644
--- a/dolphinscheduler-ui/src/js/conf/home/pages/dag/_source/formModel/tasks/python.vue
+++ b/dolphinscheduler-ui/src/js/conf/home/pages/dag/_source/formModel/tasks/python.vue
@@ -108,10 +108,6 @@
           return false
         }
 
-        if (!this.$refs.refResources._verifResources()) {
-          return false
-        }
-
         // localParams Subcomponent verification
         if (!this.$refs.refLocalParams._verifProp()) {
           return false
@@ -119,7 +115,9 @@
 
         // storage
         this.$emit('on-params', {
-          resourceList: this.resourceList,
+          resourceList: _.map(this.resourceList, v => {
+            return {id: v}
+          }),
           localParams: this.localParams,
           rawScript: editor.getValue()
         })
@@ -129,8 +127,6 @@
        * Processing code highlighting
        */
       _handlerEditor () {
-        this._destroyEditor()
-
         // editor
         editor = codemirror('code-python-mirror', {
           mode: 'python',
@@ -145,45 +141,28 @@
           }
         }
 
-        this.changes = () => {
-          this._cacheParams()
-        }
-
         // Monitor keyboard
         editor.on('keypress', this.keypress)
 
-        editor.on('changes', this.changes)
-
         editor.setValue(this.rawScript)
 
         return editor
-      },
-      _cacheParams () {
-        this.$emit('on-cache-params', {
-          resourceList: this.cacheResourceList,
-          localParams: this.localParams,
-          rawScript: editor ? editor.getValue() : ''
-        });
-      },
-      _destroyEditor () {
-         if (editor) {
-          editor.toTextArea() // Uninstall
-          editor.off($('.code-python-mirror'), 'keypress', this.keypress)
-          editor.off($('.code-python-mirror'), 'changes', this.changes)
-        }
       }
     },
     watch: {
       //Watch the cacheParams
       cacheParams (val) {
-        this._cacheParams()
+        this.$emit('on-cache-params', val);
       }
     },
     computed: {
       cacheParams () {
         return {
-          resourceList: this.cacheResourceList,
-          localParams: this.localParams
+          resourceList: _.map(this.resourceList, v => {
+            return {id: v}
+          }),
+          localParams: this.localParams,
+          rawScript: editor ? editor.getValue() : ''
         }
       }
     },
@@ -197,7 +176,9 @@
         // backfill resourceList
         let resourceList = o.params.resourceList || []
         if (resourceList.length) {
-          this.resourceList = resourceList
+          this.resourceList = _.map(resourceList, v => {
+            return v.id
+          })
           this.cacheResourceList = resourceList
         }
 
@@ -214,11 +195,8 @@
       }, 200)
     },
     destroyed () {
-      if (editor) {
-        editor.toTextArea() // Uninstall
-        editor.off($('.code-python-mirror'), 'keypress', this.keypress)
-        editor.off($('.code-python-mirror'), 'changes', this.changes)
-      }
+      editor.toTextArea() // Uninstall
+      editor.off($('.code-python-mirror'), 'keypress', this.keypress)
     },
     components: { mLocalParams, mListBox, mResources }
   }
diff --git a/dolphinscheduler-ui/src/js/conf/home/pages/dag/_source/formModel/tasks/shell.vue b/dolphinscheduler-ui/src/js/conf/home/pages/dag/_source/formModel/tasks/shell.vue
index a4b20f3..952fd3a 100644
--- a/dolphinscheduler-ui/src/js/conf/home/pages/dag/_source/formModel/tasks/shell.vue
+++ b/dolphinscheduler-ui/src/js/conf/home/pages/dag/_source/formModel/tasks/shell.vue
@@ -34,6 +34,14 @@
     <m-list-box>
       <div slot="text">{{$t('Resources')}}</div>
       <div slot="content">
+        <treeselect v-model="resourceList" :multiple="true" :options="options" :normalizer="normalizer" :placeholder="$t('Please select resources')">
+          <div slot="value-label" slot-scope="{ node }">{{ node.raw.fullName }}</div>
+        </treeselect>
+      </div>
+    </m-list-box>
+    <!-- <m-list-box>
+      <div slot="text">{{$t('Resources')}}</div>
+      <div slot="content">
         <m-resources
                 ref="refResources"
                 @on-resourcesData="_onResourcesData"
@@ -41,7 +49,7 @@
                 :resource-list="resourceList">
         </m-resources>
       </div>
-    </m-list-box>
+    </m-list-box> -->
     <m-list-box>
       <div slot="text">{{$t('Custom Parameters')}}</div>
       <div slot="content">
@@ -63,6 +71,8 @@
   import mResources from './_source/resources'
   import mLocalParams from './_source/localParams'
   import disabledState from '@/module/mixin/disabledState'
+  import Treeselect from '@riophae/vue-treeselect'
+  import '@riophae/vue-treeselect/dist/vue-treeselect.css'
   import codemirror from '@/conf/home/pages/resource/pages/file/pages/_source/codemirror'
 
   let editor
@@ -78,7 +88,14 @@
         // resource(list)
         resourceList: [],
         // Cache ResourceList
-        cacheResourceList: []
+        cacheResourceList: [],
+        // define options
+        options: [],
+        normalizer(node) {
+          return {
+            label: node.name
+          }
+        },
       }
     },
     mixins: [disabledState],
@@ -143,17 +160,19 @@
           return false
         }
 
-        if (!this.$refs.refResources._verifResources()) {
-          return false
-        }
-
         // localParams Subcomponent verification
         if (!this.$refs.refLocalParams._verifProp()) {
           return false
         }
+        // Process resourcelist
+        let dataProcessing= _.map(this.resourceList, v => {
+          return {
+            id: v
+          }
+        })
         // storage
         this.$emit('on-params', {
-          resourceList: this.resourceList,
+          resourceList: dataProcessing,
           localParams: this.localParams,
           rawScript: editor.getValue()
         })
@@ -163,8 +182,6 @@
        * Processing code highlighting
        */
       _handlerEditor () {
-        this._destroyEditor()
-
         // editor
         editor = codemirror('code-shell-mirror', {
           mode: 'shell',
@@ -179,51 +196,41 @@
           }
         }
 
-        this.changes = () => {
-          this._cacheParams()
-        }
-
         // Monitor keyboard
         editor.on('keypress', this.keypress)
-
-        editor.on('changes', this.changes)
-
         editor.setValue(this.rawScript)
 
         return editor
       },
-      _cacheParams () {
-        this.$emit('on-cache-params', {
-          resourceList: this.cacheResourceList,
-          localParams: this.localParams,
-          rawScript: editor ? editor.getValue() : ''
-        });
-      },
-      _destroyEditor () {
-         if (editor) {
-          editor.toTextArea() // Uninstall
-          editor.off($('.code-sql-mirror'), 'keypress', this.keypress)
-          editor.off($('.code-sql-mirror'), 'changes', this.changes)
-        }
+      diGuiTree(item) {  // Recursive convenience tree structure
+        item.forEach(item => {
+          item.children === '' || item.children === undefined || item.children === null || item.children.length === 0?        
+            delete item.children : this.diGuiTree(item.children);
+        })
       }
     },
     watch: {
       //Watch the cacheParams
       cacheParams (val) {
-        this._cacheParams()
+        this.$emit('on-cache-params', val);
       }
     },
     computed: {
       cacheParams () {
         return {
-          resourceList: this.cacheResourceList,
-          localParams: this.localParams
+          resourceList: _.map(this.resourceList, v => {
+            return {id: v}
+          }),
+          localParams: this.localParams,
+          rawScript: editor ? editor.getValue() : ''
         }
       }
     },
     created () {
+      let item = this.store.state.dag.resourcesListS
+      this.diGuiTree(item)
+      this.options = item
       let o = this.backfillItem
-
       // Non-null objects represent backfill
       if (!_.isEmpty(o)) {
         this.rawScript = o.params.rawScript || ''
@@ -231,7 +238,9 @@
         // backfill resourceList
         let resourceList = o.params.resourceList || []
         if (resourceList.length) {
-          this.resourceList = resourceList
+          this.resourceList = _.map(resourceList, v => {
+            return v.id
+          })
           this.cacheResourceList = resourceList
         }
 
@@ -251,10 +260,9 @@
       if (editor) {
         editor.toTextArea() // Uninstall
         editor.off($('.code-shell-mirror'), 'keypress', this.keypress)
-        editor.off($('.code-shell-mirror'), 'changes', this.changes)
       }
     },
-    components: { mLocalParams, mListBox, mResources, mScriptBox }
+    components: { mLocalParams, mListBox, mResources, mScriptBox, Treeselect }
   }
 </script>
 <style lang="scss" rel="stylesheet/scss" scope>
diff --git a/dolphinscheduler-ui/src/js/conf/home/pages/dag/_source/formModel/tasks/spark.vue b/dolphinscheduler-ui/src/js/conf/home/pages/dag/_source/formModel/tasks/spark.vue
index feef198..de7a21d 100644
--- a/dolphinscheduler-ui/src/js/conf/home/pages/dag/_source/formModel/tasks/spark.vue
+++ b/dolphinscheduler-ui/src/js/conf/home/pages/dag/_source/formModel/tasks/spark.vue
@@ -63,19 +63,9 @@
     <m-list-box>
       <div slot="text">{{$t('Main jar package')}}</div>
       <div slot="content">
-        <x-select
-                style="width: 100%;"
-                :placeholder="$t('Please enter main jar package')"
-                v-model="mainJar"
-                filterable
-                :disabled="isDetails">
-          <x-option
-                  v-for="city in mainJarList"
-                  :key="city.code"
-                  :value="city.code"
-                  :label="city.code">
-          </x-option>
-        </x-select>
+        <treeselect v-model="mainJar" :options="mainJarLists" :disable-branch-nodes="true" :normalizer="normalizer" :placeholder="$t('Please enter main jar package')">
+          <div slot="value-label" slot-scope="{ node }">{{ node.raw.fullName }}</div>
+        </treeselect>
       </div>
     </m-list-box>
     <m-list-box>
@@ -179,6 +169,14 @@
     <m-list-box>
       <div slot="text">{{$t('Resources')}}</div>
       <div slot="content">
+        <treeselect v-model="resourceList" :multiple="true" :options="mainJarList" :normalizer="normalizer" :placeholder="$t('Please select resources')">
+          <div slot="value-label" slot-scope="{ node }">{{ node.raw.fullName }}</div>
+        </treeselect>
+      </div>
+    </m-list-box>
+    <!-- <m-list-box>
+      <div slot="text">{{$t('Resources')}}</div>
+      <div slot="content">
         <m-resources
                 ref="refResources"
                 @on-resourcesData="_onResourcesData"
@@ -186,7 +184,7 @@
                 :resource-list="resourceList">
         </m-resources>
       </div>
-    </m-list-box>
+    </m-list-box> -->
     <m-list-box>
       <div slot="text">{{$t('Custom Parameters')}}</div>
       <div slot="content">
@@ -206,6 +204,8 @@
   import mLocalParams from './_source/localParams'
   import mListBox from './_source/listBox'
   import mResources from './_source/resources'
+  import Treeselect from '@riophae/vue-treeselect'
+  import '@riophae/vue-treeselect/dist/vue-treeselect.css'
   import disabledState from '@/module/mixin/disabledState'
 
   export default {
@@ -217,6 +217,7 @@
         // Master jar package
         mainJar: null,
         // Master jar package(List)
+        mainJarLists: [],
         mainJarList: [],
         // Deployment method
         deployMode: 'cluster',
@@ -247,7 +248,12 @@
         // Spark version
         sparkVersion: 'SPARK2',
         // Spark version(LIst)
-        sparkVersionList: [{ code: 'SPARK2' }, { code: 'SPARK1' }]
+        sparkVersionList: [{ code: 'SPARK2' }, { code: 'SPARK1' }],
+        normalizer(node) {
+          return {
+            label: node.name
+          }
+        }
       }
     },
     props: {
@@ -273,6 +279,12 @@
       _onCacheResourcesData (a) {
         this.cacheResourceList = a
       },
+      diGuiTree(item) {  // Recursive convenience tree structure
+        item.forEach(item => {
+          item.children === '' || item.children === undefined || item.children === null || item.children.length === 0?        
+            delete item.children : this.diGuiTree(item.children);
+        })
+      },
       /**
        * verification
        */
@@ -321,24 +333,25 @@
           this.$message.warning(`${i18n.$t('Core number should be positive integer')}`)
           return false
         }
-
-        if (!this.$refs.refResources._verifResources()) {
-          return false
-        }
-
         // localParams Subcomponent verification
         if (!this.$refs.refLocalParams._verifProp()) {
           return false
         }
+        // Process resourcelist
+        let dataProcessing= _.map(this.resourceList, v => {
+          return {
+            id: v
+          }
+        })
 
         // storage
         this.$emit('on-params', {
           mainClass: this.mainClass,
           mainJar: {
-            res: this.mainJar
+            id: this.mainJar
           },
           deployMode: this.deployMode,
-          resourceList: this.resourceList,
+          resourceList: dataProcessing,
           localParams: this.localParams,
           driverCores: this.driverCores,
           driverMemory: this.driverMemory,
@@ -351,24 +364,6 @@
           sparkVersion: this.sparkVersion
         })
         return true
-      },
-      /**
-       * get resources list
-       */
-      _getResourcesList () {
-        return new Promise((resolve, reject) => {
-          let isJar = (alias) => {
-            return alias.substring(alias.lastIndexOf('.') + 1, alias.length) !== 'jar'
-          }
-          this.mainJarList = _.map(_.cloneDeep(this.store.state.dag.resourcesListS), v => {
-            return {
-              id: v.id,
-              code: v.alias,
-              disabled: isJar(v.alias)
-            }
-          })
-          resolve()
-        })
       }
     },
     watch: {
@@ -388,10 +383,12 @@
         return {
           mainClass: this.mainClass,
           mainJar: {
-            res: this.mainJar
+            id: this.mainJar
           },
           deployMode: this.deployMode,
-          resourceList: this.cacheResourceList,
+          resourceList: _.map(this.resourceList, v => {
+            return {id: v}
+          }),
           localParams: this.localParams,
           driverCores: this.driverCores,
           driverMemory: this.driverMemory,
@@ -406,13 +403,18 @@
       }
     },
     created () {
-      this._getResourcesList().then(() => {
+        let item = this.store.state.dag.resourcesListS
+        let items = this.store.state.dag.resourcesListJar
+        this.diGuiTree(item)
+        this.diGuiTree(items)
+        this.mainJarList = item
+        this.mainJarLists = items
         let o = this.backfillItem
 
         // Non-null objects represent backfill
         if (!_.isEmpty(o)) {
           this.mainClass = o.params.mainClass || ''
-          this.mainJar = o.params.mainJar && o.params.mainJar.res ? o.params.mainJar.res : ''
+          this.mainJar = o.params.mainJar && o.params.mainJar.id ? o.params.mainJar.id : ''
           this.deployMode = o.params.deployMode || ''
           this.driverCores = o.params.driverCores || 1
           this.driverMemory = o.params.driverMemory || '512M'
@@ -427,7 +429,9 @@
           // backfill resourceList
           let resourceList = o.params.resourceList || []
           if (resourceList.length) {
-            this.resourceList = resourceList
+            this.resourceList = _.map(resourceList, v => {
+            return v.id
+          })
             this.cacheResourceList = resourceList
           }
 
@@ -437,12 +441,11 @@
             this.localParams = localParams
           }
         }
-      })
     },
     mounted () {
 
     },
-    components: { mLocalParams, mListBox, mResources }
+    components: { mLocalParams, mListBox, mResources, Treeselect }
   }
 </script>
 
diff --git a/dolphinscheduler-ui/src/js/conf/home/pages/dag/_source/plugIn/jsPlumbHandle.js b/dolphinscheduler-ui/src/js/conf/home/pages/dag/_source/plugIn/jsPlumbHandle.js
index 598c942..9412a8c 100755
--- a/dolphinscheduler-ui/src/js/conf/home/pages/dag/_source/plugIn/jsPlumbHandle.js
+++ b/dolphinscheduler-ui/src/js/conf/home/pages/dag/_source/plugIn/jsPlumbHandle.js
@@ -68,7 +68,7 @@ JSP.prototype.init = function ({ dag, instance, options }) {
   // Register jsplumb connection type and configuration
   this.JspInstance.registerConnectionType('basic', {
     anchor: 'Continuous',
-    connector: 'Straight' // Line type
+    connector: 'Bezier' // Line type
   })
 
   // Initial configuration
@@ -236,7 +236,7 @@ JSP.prototype.initNode = function (el) {
     filter: '.ep',
     anchor: 'Continuous',
     connectorStyle: {
-      stroke: '#555',
+      stroke: '#2d8cf0',
       strokeWidth: 2,
       outlineStroke: 'transparent',
       outlineWidth: 4
@@ -297,6 +297,7 @@ JSP.prototype.tasksContextmenu = function (event) {
     if (isOne) {
       // start run
       $('#startRunning').on('click', () => {
+        let name = store.state.dag.name
         let id = router.history.current.params.id
         store.dispatch('dag/getStartCheck', { processDefinitionId: id }).then(res => {
           let modal = Vue.$modal.dialog({
@@ -317,7 +318,8 @@ JSP.prototype.tasksContextmenu = function (event) {
                 },
                 props: {
                   item: {
-                    id: id
+                    id: id,
+                    name: name
                   },
                   startNodeList: $name,
                   sourceType: 'contextmenu'
@@ -378,7 +380,7 @@ JSP.prototype.tasksClick = function (e) {
     $('.w').removeClass('jtk-tasks-active')
     $(e.currentTarget).addClass('jtk-tasks-active')
     if ($connect) {
-      setSvgColor($connect, '#555')
+      setSvgColor($connect, '#2d8cf0')
       this.selectedElement.connect = null
     }
     this.selectedElement.id = $(e.currentTarget).attr('id')
@@ -437,19 +439,19 @@ JSP.prototype.handleEventPointer = function (is) {
     isClick: is,
     isAttachment: false
   })
-  wDom.removeClass('jtk-ep')
-  if (!is) {
-    wDom.removeClass('jtk-tasks-active')
-    this.selectedElement = {}
-    _.map($('#canvas svg'), v => {
-      if ($(v).attr('class')) {
-        _.map($(v).find('path'), v1 => {
-          $(v1).attr('fill', '#555')
-          $(v1).attr('stroke', '#555')
-        })
-      }
-    })
-  }
+  // wDom.removeClass('jtk-ep')
+  // if (!is) {
+  //   wDom.removeClass('jtk-tasks-active')
+  //   this.selectedElement = {}
+  //   _.map($('#canvas svg'), v => {
+  //     if ($(v).attr('class')) {
+  //       _.map($(v).find('path'), v1 => {
+  //         $(v1).attr('fill', '#555')
+  //         $(v1).attr('stroke', '#555')
+  //       })
+  //     }
+  //   })
+  // }
 }
 
 /**
@@ -764,7 +766,7 @@ JSP.prototype.jspBackfill = function ({ connects, locations, largeJson }) {
         source: sourceId,
         target: targetId,
         type: 'basic',
-        paintStyle: { strokeWidth: 2, stroke: '#555' }
+        paintStyle: { strokeWidth: 2, stroke: '#2d8cf0' }
       })
     })
   })
diff --git a/dolphinscheduler-ui/src/js/conf/home/pages/dag/_source/plugIn/util.js b/dolphinscheduler-ui/src/js/conf/home/pages/dag/_source/plugIn/util.js
index 4b485fe..17e7faf 100755
--- a/dolphinscheduler-ui/src/js/conf/home/pages/dag/_source/plugIn/util.js
+++ b/dolphinscheduler-ui/src/js/conf/home/pages/dag/_source/plugIn/util.js
@@ -100,7 +100,7 @@ const setSvgColor = (e, color) => {
   // Traverse clear all colors
   $('.jtk-connector').each((i, o) => {
     _.map($(o)[0].childNodes, v => {
-      $(v).attr('fill', '#555').attr('stroke', '#555').attr('stroke-width', 2)
+      $(v).attr('fill', '#2d8cf0').attr('stroke', '#2d8cf0').attr('stroke-width', 2)
     })
   })
 
diff --git a/dolphinscheduler-ui/src/js/conf/home/pages/dag/definitionDetails.vue b/dolphinscheduler-ui/src/js/conf/home/pages/dag/definitionDetails.vue
index bfe971c..b1d7a7b 100644
--- a/dolphinscheduler-ui/src/js/conf/home/pages/dag/definitionDetails.vue
+++ b/dolphinscheduler-ui/src/js/conf/home/pages/dag/definitionDetails.vue
@@ -41,7 +41,7 @@
     props: {},
     methods: {
       ...mapMutations('dag', ['resetParams', 'setIsDetails']),
-      ...mapActions('dag', ['getProcessList','getProjectList', 'getResourcesList', 'getProcessDetails']),
+      ...mapActions('dag', ['getProcessList','getProjectList', 'getResourcesList', 'getProcessDetails','getResourcesListJar']),
       ...mapActions('security', ['getTenantList','getWorkerGroupsAll']),
       /**
        * init
@@ -60,6 +60,8 @@
           this.getProjectList(),
           // get resource
           this.getResourcesList(),
+          // get jar
+          this.getResourcesListJar(),
           // get worker group list
           this.getWorkerGroupsAll(),
           this.getTenantList()
diff --git a/dolphinscheduler-ui/src/js/conf/home/pages/dag/index.vue b/dolphinscheduler-ui/src/js/conf/home/pages/dag/index.vue
index 3fd4eed..eedf741 100644
--- a/dolphinscheduler-ui/src/js/conf/home/pages/dag/index.vue
+++ b/dolphinscheduler-ui/src/js/conf/home/pages/dag/index.vue
@@ -40,7 +40,7 @@
     props: {},
     methods: {
       ...mapMutations('dag', ['resetParams']),
-      ...mapActions('dag', ['getProcessList','getProjectList', 'getResourcesList']),
+      ...mapActions('dag', ['getProcessList','getProjectList', 'getResourcesList','getResourcesListJar','getResourcesListJar']),
       ...mapActions('security', ['getTenantList','getWorkerGroupsAll']),
       /**
        * init
@@ -55,8 +55,12 @@
           this.getProcessList(),
           // get project
           this.getProjectList(),
+          // get jar
+          this.getResourcesListJar(),
           // get resource
           this.getResourcesList(),
+          // get jar
+          this.getResourcesListJar(),
           // get worker group list
           this.getWorkerGroupsAll(),
           this.getTenantList()
diff --git a/dolphinscheduler-ui/src/js/conf/home/pages/projects/pages/definition/pages/list/_source/start.vue b/dolphinscheduler-ui/src/js/conf/home/pages/projects/pages/definition/pages/list/_source/start.vue
index 0a22e22..5202185 100644
--- a/dolphinscheduler-ui/src/js/conf/home/pages/projects/pages/definition/pages/list/_source/start.vue
+++ b/dolphinscheduler-ui/src/js/conf/home/pages/projects/pages/definition/pages/list/_source/start.vue
@@ -274,6 +274,7 @@
     },
     created () {
       this.warningType = this.warningTypeList[0].id
+      this.workflowName = this.item.name
 
       this._getReceiver()
     },
diff --git a/dolphinscheduler-ui/src/js/conf/home/pages/resource/pages/file/pages/create/index.vue b/dolphinscheduler-ui/src/js/conf/home/pages/resource/pages/file/pages/create/index.vue
index df84f0f..fac37a4 100644
--- a/dolphinscheduler-ui/src/js/conf/home/pages/resource/pages/file/pages/create/index.vue
+++ b/dolphinscheduler-ui/src/js/conf/home/pages/resource/pages/file/pages/create/index.vue
@@ -96,6 +96,8 @@
         description: '',
         fileTypeList: filtTypeArr,
         content: '',
+        pid: -1,
+        currentDir: '/',
         spinnerLoading: false
       }
     },
@@ -107,6 +109,8 @@
           this.spinnerLoading = true
           this.createResourceFile({
             type: 'FILE',
+            pid: this.pid,
+            currentDir: this.currentDir,
             fileName: this.fileName,
             suffix: this.suffix,
             description: this.description,
@@ -136,6 +140,7 @@
           this.$message.warning(`${i18n.$t('Resource content cannot exceed 3000 lines')}`)
           return false
         }
+
         return true
       },
       /**
diff --git a/dolphinscheduler-ui/src/js/conf/home/pages/resource/pages/file/pages/create/index.vue b/dolphinscheduler-ui/src/js/conf/home/pages/resource/pages/file/pages/createFolder/index.vue
similarity index 60%
copy from dolphinscheduler-ui/src/js/conf/home/pages/resource/pages/file/pages/create/index.vue
copy to dolphinscheduler-ui/src/js/conf/home/pages/resource/pages/file/pages/createFolder/index.vue
index df84f0f..be53033 100644
--- a/dolphinscheduler-ui/src/js/conf/home/pages/resource/pages/file/pages/create/index.vue
+++ b/dolphinscheduler-ui/src/js/conf/home/pages/resource/pages/file/pages/createFolder/index.vue
@@ -15,15 +15,15 @@
  * limitations under the License.
  */
 <template>
-  <m-list-construction :title="$t('Create File')">
+  <m-list-construction :title="$t('Create folder')">
     <template slot="content">
       <div class="resource-create-model">
         <m-list-box-f>
-          <template slot="name"><strong>*</strong>{{$t('File Name')}}</template>
+          <template slot="name"><strong>*</strong>{{$t('Folder Name')}}</template>
           <template slot="content">
             <x-input
                     type="input"
-                    v-model="fileName"
+                    v-model="name"
                     maxlength="60"
                     style="width: 300px;"
                     :placeholder="$t('Please enter name')"
@@ -31,19 +31,19 @@
             </x-input>
           </template>
         </m-list-box-f>
-        <m-list-box-f>
-          <template slot="name"><strong>*</strong>{{$t('File Format')}}</template>
+        <!-- <m-list-box-f>
+          <template slot="name"><strong>*</strong>{{$t('Folder Format')}}</template>
           <template slot="content">
-            <x-select v-model="suffix" style="width: 100px;" @on-change="_onChange">
+            <x-select v-model="type" style="width: 100px;">
               <x-option
-                      v-for="city in fileTypeList"
-                      :key="city"
-                      :value="city"
-                      :label="city">
+                      v-for="item in folderList"
+                      :key="item.value"
+                      :value="item.value"
+                      :label="item.label">
               </x-option>
             </x-select>
           </template>
-        </m-list-box-f>
+        </m-list-box-f> -->
         <m-list-box-f>
           <template slot="name">{{$t('Description')}}</template>
           <template slot="content">
@@ -57,12 +57,6 @@
           </template>
         </m-list-box-f>
         <m-list-box-f>
-          <template slot="name"><strong>*</strong>{{$t('File Content')}}</template>
-          <template slot="content">
-            <textarea id="code-create-mirror" name="code-create-mirror"></textarea>
-          </template>
-        </m-list-box-f>
-        <m-list-box-f>
           <template slot="name">&nbsp;</template>
           <template slot="content">
             <div class="submit">
@@ -78,44 +72,42 @@
 <script>
   import i18n from '@/module/i18n'
   import { mapActions } from 'vuex'
-  import { filtTypeArr } from '../_source/common'
+  import { folderList } from '../_source/common'
   import { handlerSuffix } from '../details/_source/utils'
-  import codemirror from '../_source/codemirror'
   import mListBoxF from '@/module/components/listBoxF/listBoxF'
   import mSpin from '@/module/components/spin/spin'
   import mConditions from '@/module/components/conditions/conditions'
+  import localStore from '@/module/util/localStorage'
   import mListConstruction from '@/module/components/listConstruction/listConstruction'
 
-  let editor
   export default {
     name: 'resource-list-create-FILE',
     data () {
       return {
-        suffix: 'sh',
-        fileName: '',
+        type: '',
+        name: '',
         description: '',
-        fileTypeList: filtTypeArr,
-        content: '',
+        folderList: folderList,
         spinnerLoading: false
       }
     },
     props: {},
     methods: {
-      ...mapActions('resource', ['createResourceFile']),
+      ...mapActions('resource', ['createResourceFolder']),
       ok () {
         if (this._validation()) {
           this.spinnerLoading = true
-          this.createResourceFile({
+          this.createResourceFolder({
             type: 'FILE',
-            fileName: this.fileName,
-            suffix: this.suffix,
-            description: this.description,
-            content: editor.getValue()
+            name: this.name,
+            currentDir: '/',
+            pid: -1,
+            description: this.description
           }).then(res => {
             this.$message.success(res.msg)
             setTimeout(() => {
               this.spinnerLoading = false
-              this.$router.push({ name: 'file' })
+              this.$router.push({ path: `/resource/file`})
             }, 800)
           }).catch(e => {
             this.$message.error(e.msg || '')
@@ -124,55 +116,21 @@
         }
       },
       _validation () {
-        if (!this.fileName) {
-          this.$message.warning(`${i18n.$t('Please enter resource name')}`)
-          return false
-        }
-        if (!editor.getValue()) {
-          this.$message.warning(`${i18n.$t('Please enter the resource content')}`)
+        if (!this.name) {
+          this.$message.warning(`${i18n.$t('Please enter resource folder name')}`)
           return false
         }
-        if (editor.doc.size>3000) {
-          this.$message.warning(`${i18n.$t('Resource content cannot exceed 3000 lines')}`)
-          return false
-        }
-        return true
-      },
-      /**
-       * Processing code highlighting
-       */
-      _handlerEditor () {
-        // editor
-        editor = codemirror('code-create-mirror', {
-          mode: 'shell',
-          readOnly: false
-        })
-
-        this.keypress = () => {
-          if (!editor.getOption('readOnly')) {
-            editor.showHint({
-              completeSingle: false
-            })
-          }
-        }
 
-        // Monitor keyboard
-        editor.on('keypress', this.keypress)
+        return true
       },
-      _onChange (val) {
-        editor.setOption('mode', handlerSuffix['.' + val.label])
-      }
     },
     watch: {},
     created () {
     },
     mounted () {
       this.$modal.destroy()
-      this._handlerEditor()
     },
     destroyed () {
-      editor.toTextArea() // uninstall
-      editor.off($('.code-create-mirror'), 'keypress', this.keypress)
     },
     computed: {},
     components: { mListConstruction, mConditions, mSpin, mListBoxF }
@@ -183,8 +141,4 @@
   .resource-create-model {
     padding: 30px;
   }
-  .CodeMirror {
-    border:1px solid #DDDEDD;
-    border-radius: 3px;
-  }
 </style>
diff --git a/dolphinscheduler-ui/src/js/conf/home/pages/resource/pages/file/pages/create/index.vue b/dolphinscheduler-ui/src/js/conf/home/pages/resource/pages/file/pages/createUdfFolder/index.vue
old mode 100644
new mode 100755
similarity index 57%
copy from dolphinscheduler-ui/src/js/conf/home/pages/resource/pages/file/pages/create/index.vue
copy to dolphinscheduler-ui/src/js/conf/home/pages/resource/pages/file/pages/createUdfFolder/index.vue
index df84f0f..2511452
--- a/dolphinscheduler-ui/src/js/conf/home/pages/resource/pages/file/pages/create/index.vue
+++ b/dolphinscheduler-ui/src/js/conf/home/pages/resource/pages/file/pages/createUdfFolder/index.vue
@@ -15,15 +15,15 @@
  * limitations under the License.
  */
 <template>
-  <m-list-construction :title="$t('Create File')">
+  <m-list-construction :title="$t('Create folder')">
     <template slot="content">
       <div class="resource-create-model">
         <m-list-box-f>
-          <template slot="name"><strong>*</strong>{{$t('File Name')}}</template>
+          <template slot="name"><strong>*</strong>{{$t('Folder Name')}}</template>
           <template slot="content">
             <x-input
                     type="input"
-                    v-model="fileName"
+                    v-model="name"
                     maxlength="60"
                     style="width: 300px;"
                     :placeholder="$t('Please enter name')"
@@ -32,19 +32,6 @@
           </template>
         </m-list-box-f>
         <m-list-box-f>
-          <template slot="name"><strong>*</strong>{{$t('File Format')}}</template>
-          <template slot="content">
-            <x-select v-model="suffix" style="width: 100px;" @on-change="_onChange">
-              <x-option
-                      v-for="city in fileTypeList"
-                      :key="city"
-                      :value="city"
-                      :label="city">
-              </x-option>
-            </x-select>
-          </template>
-        </m-list-box-f>
-        <m-list-box-f>
           <template slot="name">{{$t('Description')}}</template>
           <template slot="content">
             <x-input
@@ -57,17 +44,11 @@
           </template>
         </m-list-box-f>
         <m-list-box-f>
-          <template slot="name"><strong>*</strong>{{$t('File Content')}}</template>
-          <template slot="content">
-            <textarea id="code-create-mirror" name="code-create-mirror"></textarea>
-          </template>
-        </m-list-box-f>
-        <m-list-box-f>
           <template slot="name">&nbsp;</template>
           <template slot="content">
             <div class="submit">
               <x-button type="primary" shape="circle" :loading="spinnerLoading" @click="ok()">{{spinnerLoading ? 'Loading...' : $t('Create')}} </x-button>
-              <x-button type="text" @click="() => $router.push({name: 'file'})"> {{$t('Cancel')}} </x-button>
+              <x-button type="text" @click="() => $router.push({name: 'resource-udf'})"> {{$t('Cancel')}} </x-button>
             </div>
           </template>
         </m-list-box-f>
@@ -78,44 +59,42 @@
 <script>
   import i18n from '@/module/i18n'
   import { mapActions } from 'vuex'
-  import { filtTypeArr } from '../_source/common'
+  import { folderList } from '../_source/common'
   import { handlerSuffix } from '../details/_source/utils'
-  import codemirror from '../_source/codemirror'
   import mListBoxF from '@/module/components/listBoxF/listBoxF'
   import mSpin from '@/module/components/spin/spin'
   import mConditions from '@/module/components/conditions/conditions'
+  import localStore from '@/module/util/localStorage'
   import mListConstruction from '@/module/components/listConstruction/listConstruction'
 
-  let editor
   export default {
-    name: 'resource-list-create-FILE',
+    name: 'resource-list-create-udf',
     data () {
       return {
-        suffix: 'sh',
-        fileName: '',
+        type: '',
+        name: '',
         description: '',
-        fileTypeList: filtTypeArr,
-        content: '',
+        folderList: folderList,
         spinnerLoading: false
       }
     },
     props: {},
     methods: {
-      ...mapActions('resource', ['createResourceFile']),
+      ...mapActions('resource', ['createResourceFolder']),
       ok () {
         if (this._validation()) {
           this.spinnerLoading = true
-          this.createResourceFile({
-            type: 'FILE',
-            fileName: this.fileName,
-            suffix: this.suffix,
-            description: this.description,
-            content: editor.getValue()
+          this.createResourceFolder({
+            type: 'UDF',
+            name: this.name,
+            currentDir: '/',
+            pid: -1,
+            description: this.description
           }).then(res => {
             this.$message.success(res.msg)
             setTimeout(() => {
               this.spinnerLoading = false
-              this.$router.push({ name: 'file' })
+              this.$router.push({ path: `/resource/udf/resource`})
             }, 800)
           }).catch(e => {
             this.$message.error(e.msg || '')
@@ -124,55 +103,21 @@
         }
       },
       _validation () {
-        if (!this.fileName) {
-          this.$message.warning(`${i18n.$t('Please enter resource name')}`)
-          return false
-        }
-        if (!editor.getValue()) {
-          this.$message.warning(`${i18n.$t('Please enter the resource content')}`)
+        if (!this.name) {
+          this.$message.warning(`${i18n.$t('Please enter resource folder name')}`)
           return false
         }
-        if (editor.doc.size>3000) {
-          this.$message.warning(`${i18n.$t('Resource content cannot exceed 3000 lines')}`)
-          return false
-        }
-        return true
-      },
-      /**
-       * Processing code highlighting
-       */
-      _handlerEditor () {
-        // editor
-        editor = codemirror('code-create-mirror', {
-          mode: 'shell',
-          readOnly: false
-        })
 
-        this.keypress = () => {
-          if (!editor.getOption('readOnly')) {
-            editor.showHint({
-              completeSingle: false
-            })
-          }
-        }
-
-        // Monitor keyboard
-        editor.on('keypress', this.keypress)
+        return true
       },
-      _onChange (val) {
-        editor.setOption('mode', handlerSuffix['.' + val.label])
-      }
     },
     watch: {},
     created () {
     },
     mounted () {
       this.$modal.destroy()
-      this._handlerEditor()
     },
     destroyed () {
-      editor.toTextArea() // uninstall
-      editor.off($('.code-create-mirror'), 'keypress', this.keypress)
     },
     computed: {},
     components: { mListConstruction, mConditions, mSpin, mListBoxF }
@@ -183,8 +128,4 @@
   .resource-create-model {
     padding: 30px;
   }
-  .CodeMirror {
-    border:1px solid #DDDEDD;
-    border-radius: 3px;
-  }
 </style>
diff --git a/dolphinscheduler-ui/src/js/conf/home/pages/resource/pages/file/pages/details/index.vue b/dolphinscheduler-ui/src/js/conf/home/pages/resource/pages/file/pages/details/index.vue
index e961d8b..6875cd4 100644
--- a/dolphinscheduler-ui/src/js/conf/home/pages/resource/pages/file/pages/details/index.vue
+++ b/dolphinscheduler-ui/src/js/conf/home/pages/resource/pages/file/pages/details/index.vue
@@ -21,7 +21,7 @@
         <h2>
           <span>{{name}}</span>
           <div class="down">
-            <em class="ans-icon-download" data-container="body" data-toggle="tooltip" :title="$t('Download Details')" @click="_downloadFile"></em>
+            <em class="ans-icon-download" style="font-size:20px" data-container="body" data-toggle="tooltip" :title="$t('Download Details')" @click="_downloadFile"></em>
             <em>{{size}}</em>
           </div>
         </h2>
diff --git a/dolphinscheduler-ui/src/js/conf/home/pages/resource/pages/file/pages/edit/index.vue b/dolphinscheduler-ui/src/js/conf/home/pages/resource/pages/file/pages/edit/index.vue
index a0d1d7d..0290af0 100644
--- a/dolphinscheduler-ui/src/js/conf/home/pages/resource/pages/file/pages/edit/index.vue
+++ b/dolphinscheduler-ui/src/js/conf/home/pages/resource/pages/file/pages/edit/index.vue
@@ -44,8 +44,8 @@
   </m-list-construction>
 </template>
 <script>
-  import _ from 'lodash'
   import i18n from '@/module/i18n'
+  import _ from 'lodash'
   import { mapActions } from 'vuex'
   import { filtTypeArr } from '../_source/common'
   import mNoType from '../details/_source/noType'
@@ -80,8 +80,8 @@
       ...mapActions('resource', ['getViewResources', 'updateContent']),
       ok () {
         if (this._validation()) {
-          this.spinnerLoading = true
-          this.updateContent({
+            this.spinnerLoading = true
+            this.updateContent({
             id: this.$route.params.id,
             content: editor.getValue()
           }).then(res => {
@@ -104,7 +104,7 @@
         return true
       },
       close () {
-        this.$router.push({ name: 'file' })
+        this.$router.go(-1)
       },
       _getViewResources () {
         this.isLoading = true
diff --git a/dolphinscheduler-ui/src/js/conf/home/pages/resource/pages/file/pages/list/_source/list.vue b/dolphinscheduler-ui/src/js/conf/home/pages/resource/pages/file/pages/list/_source/list.vue
index 783eead..3bc1bfa 100644
--- a/dolphinscheduler-ui/src/js/conf/home/pages/resource/pages/file/pages/list/_source/list.vue
+++ b/dolphinscheduler-ui/src/js/conf/home/pages/resource/pages/file/pages/list/_source/list.vue
@@ -26,6 +26,9 @@
             <span>{{$t('Name')}}</span>
           </th>
           <th scope="col">
+            <span>{{$t('Whether directory')}}</span>
+          </th>
+          <th scope="col">
             <span>{{$t('File Name')}}</span>
           </th>
           <th scope="col">
@@ -50,6 +53,9 @@
               <a href="javascript:" class="links" @click="_go(item)">{{item.alias}}</a>
             </span>
           </td>
+          <td>
+            <span>{{item.directory? $t('Yes') : $t('No')}}</span>
+          </td>
           <td><span class="ellipsis" v-tooltip.large.top.start.light="{text: item.fileName, maxWidth: '500px'}">{{item.fileName}}</span></td>
           <td>
             <span v-if="item.description" class="ellipsis" v-tooltip.large.top.start.light="{text: item.description, maxWidth: '500px'}">{{item.description}}</span>
@@ -89,6 +95,7 @@
                     size="xsmall"
                     data-toggle="tooltip"
                     :title="$t('Download')"
+                    :disabled="item.directory? true: false"
                     @click="_downloadFile(item)"
                     icon="ans-icon-download">
             </x-button>
@@ -148,7 +155,12 @@
       },
       _go (item) {
         localStore.setItem('file', `${item.alias}|${item.size}`)
-        this.$router.push({ path: `/resource/file/list/${item.id}` })
+        if(item.directory) {
+          localStore.setItem('currentDir', `${item.fullName}`)
+          this.$router.push({ path: `/resource/file/subdirectory/${item.id}` })
+        } else {
+          this.$router.push({ path: `/resource/file/list/${item.id}` })
+        }
       },
       _downloadFile (item) {
         downloadFile('/dolphinscheduler/resources/download', {
diff --git a/dolphinscheduler-ui/src/js/conf/home/pages/resource/pages/file/pages/list/index.vue b/dolphinscheduler-ui/src/js/conf/home/pages/resource/pages/file/pages/list/index.vue
index 8f1f939..73ce023 100644
--- a/dolphinscheduler-ui/src/js/conf/home/pages/resource/pages/file/pages/list/index.vue
+++ b/dolphinscheduler-ui/src/js/conf/home/pages/resource/pages/file/pages/list/index.vue
@@ -20,6 +20,7 @@
       <m-conditions @on-conditions="_onConditions">
         <template slot="button-group">
           <x-button-group size="small" >
+            <x-button type="ghost" @click="() => $router.push({name: 'resource-file-createFolder'})">{{$t('Create folder')}}</x-button>
             <x-button type="ghost" @click="() => $router.push({name: 'resource-file-create'})">{{$t('Create File')}}</x-button>
             <x-button type="ghost" @click="_uploading">{{$t('Upload Files')}}</x-button>
           </x-button-group>
@@ -61,6 +62,7 @@
         isLoading: false,
         fileResourcesList: [],
         searchParams: {
+          id: -1,
           pageSize: 10,
           pageNo: 1,
           searchVal: '',
diff --git a/dolphinscheduler-ui/src/js/conf/home/pages/resource/pages/file/pages/create/index.vue b/dolphinscheduler-ui/src/js/conf/home/pages/resource/pages/file/pages/subFile/index.vue
similarity index 95%
copy from dolphinscheduler-ui/src/js/conf/home/pages/resource/pages/file/pages/create/index.vue
copy to dolphinscheduler-ui/src/js/conf/home/pages/resource/pages/file/pages/subFile/index.vue
index df84f0f..9894ff9 100644
--- a/dolphinscheduler-ui/src/js/conf/home/pages/resource/pages/file/pages/create/index.vue
+++ b/dolphinscheduler-ui/src/js/conf/home/pages/resource/pages/file/pages/subFile/index.vue
@@ -84,6 +84,7 @@
   import mListBoxF from '@/module/components/listBoxF/listBoxF'
   import mSpin from '@/module/components/spin/spin'
   import mConditions from '@/module/components/conditions/conditions'
+  import localStore from '@/module/util/localStorage'
   import mListConstruction from '@/module/components/listConstruction/listConstruction'
 
   let editor
@@ -96,6 +97,8 @@
         description: '',
         fileTypeList: filtTypeArr,
         content: '',
+        pid: -1,
+        currentDir: '/',
         spinnerLoading: false
       }
     },
@@ -107,6 +110,8 @@
           this.spinnerLoading = true
           this.createResourceFile({
             type: 'FILE',
+            pid: this.$route.params.id,
+            currentDir: localStore.getItem('currentDir'),
             fileName: this.fileName,
             suffix: this.suffix,
             description: this.description,
@@ -115,7 +120,7 @@
             this.$message.success(res.msg)
             setTimeout(() => {
               this.spinnerLoading = false
-              this.$router.push({ name: 'file' })
+              this.$router.push({ path: `/resource/file/subdirectory/${this.$route.params.id}`})
             }, 800)
           }).catch(e => {
             this.$message.error(e.msg || '')
@@ -136,6 +141,7 @@
           this.$message.warning(`${i18n.$t('Resource content cannot exceed 3000 lines')}`)
           return false
         }
+
         return true
       },
       /**
diff --git a/dolphinscheduler-ui/src/js/conf/home/pages/resource/pages/file/pages/create/index.vue b/dolphinscheduler-ui/src/js/conf/home/pages/resource/pages/file/pages/subFileFolder/index.vue
old mode 100644
new mode 100755
similarity index 60%
copy from dolphinscheduler-ui/src/js/conf/home/pages/resource/pages/file/pages/create/index.vue
copy to dolphinscheduler-ui/src/js/conf/home/pages/resource/pages/file/pages/subFileFolder/index.vue
index df84f0f..9f903a1
--- a/dolphinscheduler-ui/src/js/conf/home/pages/resource/pages/file/pages/create/index.vue
+++ b/dolphinscheduler-ui/src/js/conf/home/pages/resource/pages/file/pages/subFileFolder/index.vue
@@ -15,15 +15,15 @@
  * limitations under the License.
  */
 <template>
-  <m-list-construction :title="$t('Create File')">
+  <m-list-construction :title="$t('Create folder')">
     <template slot="content">
       <div class="resource-create-model">
         <m-list-box-f>
-          <template slot="name"><strong>*</strong>{{$t('File Name')}}</template>
+          <template slot="name"><strong>*</strong>{{$t('Folder Name')}}</template>
           <template slot="content">
             <x-input
                     type="input"
-                    v-model="fileName"
+                    v-model="name"
                     maxlength="60"
                     style="width: 300px;"
                     :placeholder="$t('Please enter name')"
@@ -31,19 +31,19 @@
             </x-input>
           </template>
         </m-list-box-f>
-        <m-list-box-f>
-          <template slot="name"><strong>*</strong>{{$t('File Format')}}</template>
+        <!-- <m-list-box-f>
+          <template slot="name"><strong>*</strong>{{$t('Folder Format')}}</template>
           <template slot="content">
-            <x-select v-model="suffix" style="width: 100px;" @on-change="_onChange">
+            <x-select v-model="type" style="width: 100px;">
               <x-option
-                      v-for="city in fileTypeList"
-                      :key="city"
-                      :value="city"
-                      :label="city">
+                      v-for="item in folderList"
+                      :key="item.value"
+                      :value="item.value"
+                      :label="item.label">
               </x-option>
             </x-select>
           </template>
-        </m-list-box-f>
+        </m-list-box-f> -->
         <m-list-box-f>
           <template slot="name">{{$t('Description')}}</template>
           <template slot="content">
@@ -57,12 +57,6 @@
           </template>
         </m-list-box-f>
         <m-list-box-f>
-          <template slot="name"><strong>*</strong>{{$t('File Content')}}</template>
-          <template slot="content">
-            <textarea id="code-create-mirror" name="code-create-mirror"></textarea>
-          </template>
-        </m-list-box-f>
-        <m-list-box-f>
           <template slot="name">&nbsp;</template>
           <template slot="content">
             <div class="submit">
@@ -78,44 +72,42 @@
 <script>
   import i18n from '@/module/i18n'
   import { mapActions } from 'vuex'
-  import { filtTypeArr } from '../_source/common'
+  import { folderList } from '../_source/common'
   import { handlerSuffix } from '../details/_source/utils'
-  import codemirror from '../_source/codemirror'
   import mListBoxF from '@/module/components/listBoxF/listBoxF'
   import mSpin from '@/module/components/spin/spin'
   import mConditions from '@/module/components/conditions/conditions'
+  import localStore from '@/module/util/localStorage'
   import mListConstruction from '@/module/components/listConstruction/listConstruction'
 
-  let editor
   export default {
     name: 'resource-list-create-FILE',
     data () {
       return {
-        suffix: 'sh',
-        fileName: '',
+        type: '',
+        name: '',
         description: '',
-        fileTypeList: filtTypeArr,
-        content: '',
+        folderList: folderList,
         spinnerLoading: false
       }
     },
     props: {},
     methods: {
-      ...mapActions('resource', ['createResourceFile']),
+      ...mapActions('resource', ['createResourceFolder']),
       ok () {
         if (this._validation()) {
           this.spinnerLoading = true
-          this.createResourceFile({
+          this.createResourceFolder({
             type: 'FILE',
-            fileName: this.fileName,
-            suffix: this.suffix,
-            description: this.description,
-            content: editor.getValue()
+            name: this.name,
+            currentDir: localStore.getItem('currentDir'),
+            pid: this.$route.params.id,
+            description: this.description
           }).then(res => {
             this.$message.success(res.msg)
             setTimeout(() => {
               this.spinnerLoading = false
-              this.$router.push({ name: 'file' })
+              this.$router.push({ path: `/resource/file/subdirectory/${this.$route.params.id}`})
             }, 800)
           }).catch(e => {
             this.$message.error(e.msg || '')
@@ -124,55 +116,21 @@
         }
       },
       _validation () {
-        if (!this.fileName) {
-          this.$message.warning(`${i18n.$t('Please enter resource name')}`)
-          return false
-        }
-        if (!editor.getValue()) {
-          this.$message.warning(`${i18n.$t('Please enter the resource content')}`)
+        if (!this.name) {
+          this.$message.warning(`${i18n.$t('Please enter resource folder name')}`)
           return false
         }
-        if (editor.doc.size>3000) {
-          this.$message.warning(`${i18n.$t('Resource content cannot exceed 3000 lines')}`)
-          return false
-        }
-        return true
-      },
-      /**
-       * Processing code highlighting
-       */
-      _handlerEditor () {
-        // editor
-        editor = codemirror('code-create-mirror', {
-          mode: 'shell',
-          readOnly: false
-        })
-
-        this.keypress = () => {
-          if (!editor.getOption('readOnly')) {
-            editor.showHint({
-              completeSingle: false
-            })
-          }
-        }
 
-        // Monitor keyboard
-        editor.on('keypress', this.keypress)
+        return true
       },
-      _onChange (val) {
-        editor.setOption('mode', handlerSuffix['.' + val.label])
-      }
     },
     watch: {},
     created () {
     },
     mounted () {
       this.$modal.destroy()
-      this._handlerEditor()
     },
     destroyed () {
-      editor.toTextArea() // uninstall
-      editor.off($('.code-create-mirror'), 'keypress', this.keypress)
     },
     computed: {},
     components: { mListConstruction, mConditions, mSpin, mListBoxF }
@@ -183,8 +141,4 @@
   .resource-create-model {
     padding: 30px;
   }
-  .CodeMirror {
-    border:1px solid #DDDEDD;
-    border-radius: 3px;
-  }
 </style>
diff --git a/dolphinscheduler-ui/src/js/conf/home/pages/resource/pages/file/pages/list/_source/list.vue b/dolphinscheduler-ui/src/js/conf/home/pages/resource/pages/file/pages/subdirectory/_source/list.vue
old mode 100644
new mode 100755
similarity index 90%
copy from dolphinscheduler-ui/src/js/conf/home/pages/resource/pages/file/pages/list/_source/list.vue
copy to dolphinscheduler-ui/src/js/conf/home/pages/resource/pages/file/pages/subdirectory/_source/list.vue
index 783eead..f5e801a
--- a/dolphinscheduler-ui/src/js/conf/home/pages/resource/pages/file/pages/list/_source/list.vue
+++ b/dolphinscheduler-ui/src/js/conf/home/pages/resource/pages/file/pages/subdirectory/_source/list.vue
@@ -26,6 +26,9 @@
             <span>{{$t('Name')}}</span>
           </th>
           <th scope="col">
+            <span>{{$t('Whether directory')}}</span>
+          </th>
+          <th scope="col">
             <span>{{$t('File Name')}}</span>
           </th>
           <th scope="col">
@@ -50,6 +53,9 @@
               <a href="javascript:" class="links" @click="_go(item)">{{item.alias}}</a>
             </span>
           </td>
+          <td>
+            <span>{{item.directory? $t('Yes') : $t('No')}}</span>
+          </td>
           <td><span class="ellipsis" v-tooltip.large.top.start.light="{text: item.fileName, maxWidth: '500px'}">{{item.fileName}}</span></td>
           <td>
             <span v-if="item.description" class="ellipsis" v-tooltip.large.top.start.light="{text: item.description, maxWidth: '500px'}">{{item.description}}</span>
@@ -89,6 +95,7 @@
                     size="xsmall"
                     data-toggle="tooltip"
                     :title="$t('Download')"
+                    :disabled="item.directory? true: false"
                     @click="_downloadFile(item)"
                     icon="ans-icon-download">
             </x-button>
@@ -148,7 +155,12 @@
       },
       _go (item) {
         localStore.setItem('file', `${item.alias}|${item.size}`)
-        this.$router.push({ path: `/resource/file/list/${item.id}` })
+        if(item.directory) {
+          localStore.setItem('currentDir', `${item.fullName}`)
+          this.$router.push({ path: `/resource/file/subdirectory/${item.id}` })
+        } else {
+          this.$router.push({ path: `/resource/file/list/${item.id}` })
+        }
       },
       _downloadFile (item) {
         downloadFile('/dolphinscheduler/resources/download', {
@@ -217,7 +229,17 @@
         setTimeout(() => {
           this.list = a
         })
-      }
+      },
+      // Listening for routing changes
+      // '$route': {
+      //   deep: false,
+      //   handler () {
+      //     this.$emit('on-update',this.$route.params.id)
+      //   }
+      // }
+    },
+    beforeRouteUpdate (to, from, next) {
+      next() // 一定要有next
     },
     created () {
     },
diff --git a/dolphinscheduler-ui/src/js/conf/home/pages/resource/pages/file/pages/subdirectory/_source/rename.vue b/dolphinscheduler-ui/src/js/conf/home/pages/resource/pages/file/pages/subdirectory/_source/rename.vue
new file mode 100755
index 0000000..6f7daca
--- /dev/null
+++ b/dolphinscheduler-ui/src/js/conf/home/pages/resource/pages/file/pages/subdirectory/_source/rename.vue
@@ -0,0 +1,120 @@
+/*
+ * 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.
+ */
+<template>
+  <m-popup :ok-text="$t('Rename')" :nameText="$t('Rename')" @ok="_ok" :asyn-loading="true">
+    <template slot="content">
+      <div class="resource-rename-model">
+        <m-list-box-f>
+          <template slot="name"><strong>*</strong>{{$t('Name')}}</template>
+          <template slot="content">
+            <x-input
+                    type="input"
+                    v-model="name"
+                    :placeholder="$t('Please enter name')"
+                    autocomplete="off">
+            </x-input>
+          </template>
+        </m-list-box-f>
+        <m-list-box-f>
+          <template slot="name">{{$t('Description')}}</template>
+          <template slot="content">
+            <x-input
+                    type="textarea"
+                    v-model="description"
+                    :placeholder="$t('Please enter description')"
+                    autocomplete="off">
+            </x-input>
+          </template>
+        </m-list-box-f>
+      </div>
+    </template>
+  </m-popup>
+</template>
+<script>
+  import i18n from '@/module/i18n'
+  import store from '@/conf/home/store'
+  import localStore from '@/module/util/localStorage'
+  import mPopup from '@/module/components/popup/popup'
+  import mListBoxF from '@/module/components/listBoxF/listBoxF'
+
+  export default {
+    name: 'resource-file-rename',
+    data () {
+      return {
+        store,
+        description: '',
+        name: ''
+      }
+    },
+    props: {
+      item: Object
+    },
+    methods: {
+      _ok (fn) {
+        this._verification().then(res => {
+          if (this.name === this.item.alias) {
+            return new Promise((resolve,reject) => {
+              this.description === this.item.description ? reject({msg:'内容未修改'}) : resolve()
+            })
+          }else{
+            return this.store.dispatch('resource/resourceVerifyName', {
+              fullName: localStore.getItem('currentDir')+'/'+this.name,
+              type: 'FILE'
+            })
+          }
+        }).then(res => {
+          return this.store.dispatch('resource/resourceRename', {
+            name: this.name,
+            description: this.description,
+            id: this.item.id,
+            type: 'FILE'
+          })
+        }).then(res => {
+          this.$message.success(res.msg)
+          this.$emit('onUpDate', res.data)
+          fn()
+        }).catch(e => {
+          fn()
+          this.$message.error(e.msg || '')
+        })
+      },
+      _verification () {
+        return new Promise((resolve, reject) => {
+          if (!this.name) {
+            reject({ // eslint-disable-line
+              msg: `${i18n.$t('Please enter resource name')}`
+            })
+          } else {
+            resolve()
+          }
+
+        })
+      }
+    },
+    watch: {},
+    created () {
+      let item = this.item || {}
+      if (item) {
+        this.name = item.alias
+        this.description = item.description
+      }
+    },
+    mounted () {
+    },
+    components: { mPopup, mListBoxF }
+  }
+</script>
\ No newline at end of file
diff --git a/dolphinscheduler-ui/src/js/conf/home/pages/resource/pages/file/pages/list/index.vue b/dolphinscheduler-ui/src/js/conf/home/pages/resource/pages/file/pages/subdirectory/index.vue
old mode 100644
new mode 100755
similarity index 61%
copy from dolphinscheduler-ui/src/js/conf/home/pages/resource/pages/file/pages/list/index.vue
copy to dolphinscheduler-ui/src/js/conf/home/pages/resource/pages/file/pages/subdirectory/index.vue
index 8f1f939..12be6b0
--- a/dolphinscheduler-ui/src/js/conf/home/pages/resource/pages/file/pages/list/index.vue
+++ b/dolphinscheduler-ui/src/js/conf/home/pages/resource/pages/file/pages/subdirectory/index.vue
@@ -15,20 +15,25 @@
  * limitations under the License.
  */
 <template>
-  <m-list-construction :title="$t('File Manage')">
-    <template slot="conditions">
+  <div class="home-main list-construction-model">
+    <div class="content-title">
+      <a class="bread" style="padding-left: 15px;" @click="() => $router.push({path: `/resource/file`})">{{$t('File Manage')}}</a>
+      <a class="bread" v-for="(item,$index) in breadList" :key="$index" @click="_ckOperation($index)">{{'>'+item}}</a>
+    </div>
+    <div class="conditions-box">
       <m-conditions @on-conditions="_onConditions">
         <template slot="button-group">
           <x-button-group size="small" >
-            <x-button type="ghost" @click="() => $router.push({name: 'resource-file-create'})">{{$t('Create File')}}</x-button>
+            <x-button type="ghost" @click="() => $router.push({path: `/resource/file/subFileFolder/${searchParams.id}`})">{{$t('Create folder')}}</x-button>
+            <x-button type="ghost" @click="() => $router.push({path: `/resource/file/subFile/${searchParams.id}`})">{{$t('Create File')}}</x-button>
             <x-button type="ghost" @click="_uploading">{{$t('Upload Files')}}</x-button>
           </x-button-group>
         </template>
       </m-conditions>
-    </template>
-    <template slot="content">
+    </div>
+    <div class="list-box">
       <template v-if="fileResourcesList.length || total>0">
-        <m-list @on-update="_onUpdate" :file-resources-list="fileResourcesList" :page-no="searchParams.pageNo" :page-size="searchParams.pageSize">
+        <m-list @on-update="_onUpdate" @on-updateList="_updateList" :file-resources-list="fileResourcesList" :page-no="searchParams.pageNo" :page-size="searchParams.pageSize">
         </m-list>
         <div class="page-box">
           <x-page :current="parseInt(searchParams.pageNo)" :total="total" :page-size="searchParams.pageSize" show-elevator @on-change="_page" show-sizer :page-size-options="[10,30,50]" @on-size-change="_pageSize"></x-page>
@@ -39,13 +44,14 @@
       </template>
       <m-spin :is-spin="isLoading">
       </m-spin>
-    </template>
-  </m-list-construction>
+   </div>
+   </div>
 </template>
 <script>
   import _ from 'lodash'
   import { mapActions } from 'vuex'
   import mList from './_source/list'
+  import localStore from '@/module/util/localStorage'
   import mSpin from '@/module/components/spin/spin'
   import { findComponentDownward } from '@/module/util/'
   import mNoData from '@/module/components/noData/noData'
@@ -61,22 +67,24 @@
         isLoading: false,
         fileResourcesList: [],
         searchParams: {
+          id: this.$route.params.id,
           pageSize: 10,
           pageNo: 1,
           searchVal: '',
           type: 'FILE'
-        }
+        },
+        breadList: []
       }
     },
     mixins: [listUrlParamHandle],
     props: {},
     methods: {
-      ...mapActions('resource', ['getResourcesListP']),
+      ...mapActions('resource', ['getResourcesListP','getResourceId']),
       /**
        * File Upload
        */
       _uploading () {
-        findComponentDownward(this.$root, 'roof-nav')._fileUpdate('FILE')
+        findComponentDownward(this.$root, 'roof-nav')._fileChildUpdate('FILE',this.searchParams.id)
       },
       _onConditions (o) {
         this.searchParams = _.assign(this.searchParams, o)
@@ -102,13 +110,35 @@
           this.isLoading = false
         })
       },
-      _updateList () {
+      _updateList (data) {
+        this.searchParams.id = data
         this.searchParams.pageNo = 1
         this.searchParams.searchVal = ''
         this._debounceGET()
       },
        _onUpdate () {
+        this.searchParams.id = this.$route.params.id
         this._debounceGET()
+      },
+      _ckOperation(index) {
+        let breadName =''
+        this.breadList.forEach((item, i) => {
+          if(i<=index) {
+            breadName = breadName+'/'+item
+          }
+        })
+        this.transferApi(breadName)
+      },
+      transferApi(api) {
+        this.getResourceId({
+          type: 'FILE',
+          fullName: api
+        }).then(res => {
+          localStore.setItem('currentDir', `${res.fullName}`)
+          this.$router.push({ path: `/resource/file/subdirectory/${res.id}` })
+        }).catch(e => {
+          this.$message.error(e.msg || '')
+        })
       }
     },
     watch: {
@@ -116,13 +146,28 @@
       '$route' (a) {
         // url no params get instance list
         this.searchParams.pageNo = _.isEmpty(a.query) ? 1 : a.query.pageNo
+        this.searchParams.id = a.params.id
+        let dir = localStore.getItem('currentDir').split('/')
+        dir.shift()
+        this.breadList = dir
       }
     },
-    created () {
-    },
+    created () {},
     mounted () {
+      let dir = localStore.getItem('currentDir').split('/')
+      dir.shift()
+      this.breadList = dir
       this.$modal.destroy()
     },
     components: { mListConstruction, mConditions, mList, mSpin, mNoData }
   }
 </script>
+<style lang="scss" rel="stylesheet/scss">
+  .bread {
+    font-size: 22px;
+    padding-top: 10px;
+    color: #2a455b;
+    display: inline-block;
+    cursor: pointer;
+  }
+</style>
diff --git a/dolphinscheduler-ui/src/js/conf/home/pages/resource/pages/file/pages/create/index.vue b/dolphinscheduler-ui/src/js/conf/home/pages/resource/pages/udf/pages/createUdfFolder/index.vue
old mode 100644
new mode 100755
similarity index 56%
copy from dolphinscheduler-ui/src/js/conf/home/pages/resource/pages/file/pages/create/index.vue
copy to dolphinscheduler-ui/src/js/conf/home/pages/resource/pages/udf/pages/createUdfFolder/index.vue
index df84f0f..c707ce8
--- a/dolphinscheduler-ui/src/js/conf/home/pages/resource/pages/file/pages/create/index.vue
+++ b/dolphinscheduler-ui/src/js/conf/home/pages/resource/pages/udf/pages/createUdfFolder/index.vue
@@ -15,15 +15,15 @@
  * limitations under the License.
  */
 <template>
-  <m-list-construction :title="$t('Create File')">
+  <m-list-construction :title="$t('Create folder')">
     <template slot="content">
       <div class="resource-create-model">
         <m-list-box-f>
-          <template slot="name"><strong>*</strong>{{$t('File Name')}}</template>
+          <template slot="name"><strong>*</strong>{{$t('Folder Name')}}</template>
           <template slot="content">
             <x-input
                     type="input"
-                    v-model="fileName"
+                    v-model="name"
                     maxlength="60"
                     style="width: 300px;"
                     :placeholder="$t('Please enter name')"
@@ -32,19 +32,6 @@
           </template>
         </m-list-box-f>
         <m-list-box-f>
-          <template slot="name"><strong>*</strong>{{$t('File Format')}}</template>
-          <template slot="content">
-            <x-select v-model="suffix" style="width: 100px;" @on-change="_onChange">
-              <x-option
-                      v-for="city in fileTypeList"
-                      :key="city"
-                      :value="city"
-                      :label="city">
-              </x-option>
-            </x-select>
-          </template>
-        </m-list-box-f>
-        <m-list-box-f>
           <template slot="name">{{$t('Description')}}</template>
           <template slot="content">
             <x-input
@@ -57,17 +44,11 @@
           </template>
         </m-list-box-f>
         <m-list-box-f>
-          <template slot="name"><strong>*</strong>{{$t('File Content')}}</template>
-          <template slot="content">
-            <textarea id="code-create-mirror" name="code-create-mirror"></textarea>
-          </template>
-        </m-list-box-f>
-        <m-list-box-f>
           <template slot="name">&nbsp;</template>
           <template slot="content">
             <div class="submit">
               <x-button type="primary" shape="circle" :loading="spinnerLoading" @click="ok()">{{spinnerLoading ? 'Loading...' : $t('Create')}} </x-button>
-              <x-button type="text" @click="() => $router.push({name: 'file'})"> {{$t('Cancel')}} </x-button>
+              <x-button type="text" @click="() => $router.push({name: 'resource-udf'})"> {{$t('Cancel')}} </x-button>
             </div>
           </template>
         </m-list-box-f>
@@ -78,44 +59,39 @@
 <script>
   import i18n from '@/module/i18n'
   import { mapActions } from 'vuex'
-  import { filtTypeArr } from '../_source/common'
-  import { handlerSuffix } from '../details/_source/utils'
-  import codemirror from '../_source/codemirror'
   import mListBoxF from '@/module/components/listBoxF/listBoxF'
   import mSpin from '@/module/components/spin/spin'
   import mConditions from '@/module/components/conditions/conditions'
+  import localStore from '@/module/util/localStorage'
   import mListConstruction from '@/module/components/listConstruction/listConstruction'
 
-  let editor
   export default {
-    name: 'resource-list-create-FILE',
+    name: 'resource-list-create-udf',
     data () {
       return {
-        suffix: 'sh',
-        fileName: '',
+        type: '',
+        name: '',
         description: '',
-        fileTypeList: filtTypeArr,
-        content: '',
         spinnerLoading: false
       }
     },
     props: {},
     methods: {
-      ...mapActions('resource', ['createResourceFile']),
+      ...mapActions('resource', ['createResourceFolder']),
       ok () {
         if (this._validation()) {
           this.spinnerLoading = true
-          this.createResourceFile({
-            type: 'FILE',
-            fileName: this.fileName,
-            suffix: this.suffix,
-            description: this.description,
-            content: editor.getValue()
+          this.createResourceFolder({
+            type: 'UDF',
+            name: this.name,
+            currentDir: '/',
+            pid: -1,
+            description: this.description
           }).then(res => {
             this.$message.success(res.msg)
             setTimeout(() => {
               this.spinnerLoading = false
-              this.$router.push({ name: 'file' })
+              this.$router.push({ path: `/resource/udf`})
             }, 800)
           }).catch(e => {
             this.$message.error(e.msg || '')
@@ -124,55 +100,21 @@
         }
       },
       _validation () {
-        if (!this.fileName) {
-          this.$message.warning(`${i18n.$t('Please enter resource name')}`)
-          return false
-        }
-        if (!editor.getValue()) {
-          this.$message.warning(`${i18n.$t('Please enter the resource content')}`)
+        if (!this.name) {
+          this.$message.warning(`${i18n.$t('Please enter resource folder name')}`)
           return false
         }
-        if (editor.doc.size>3000) {
-          this.$message.warning(`${i18n.$t('Resource content cannot exceed 3000 lines')}`)
-          return false
-        }
-        return true
-      },
-      /**
-       * Processing code highlighting
-       */
-      _handlerEditor () {
-        // editor
-        editor = codemirror('code-create-mirror', {
-          mode: 'shell',
-          readOnly: false
-        })
 
-        this.keypress = () => {
-          if (!editor.getOption('readOnly')) {
-            editor.showHint({
-              completeSingle: false
-            })
-          }
-        }
-
-        // Monitor keyboard
-        editor.on('keypress', this.keypress)
+        return true
       },
-      _onChange (val) {
-        editor.setOption('mode', handlerSuffix['.' + val.label])
-      }
     },
     watch: {},
     created () {
     },
     mounted () {
       this.$modal.destroy()
-      this._handlerEditor()
     },
     destroyed () {
-      editor.toTextArea() // uninstall
-      editor.off($('.code-create-mirror'), 'keypress', this.keypress)
     },
     computed: {},
     components: { mListConstruction, mConditions, mSpin, mListBoxF }
@@ -183,8 +125,4 @@
   .resource-create-model {
     padding: 30px;
   }
-  .CodeMirror {
-    border:1px solid #DDDEDD;
-    border-radius: 3px;
-  }
 </style>
diff --git a/dolphinscheduler-ui/src/js/conf/home/pages/resource/pages/udf/pages/function/_source/createUdf.vue b/dolphinscheduler-ui/src/js/conf/home/pages/resource/pages/udf/pages/function/_source/createUdf.vue
index 01d8d22..1408c55 100644
--- a/dolphinscheduler-ui/src/js/conf/home/pages/resource/pages/udf/pages/function/_source/createUdf.vue
+++ b/dolphinscheduler-ui/src/js/conf/home/pages/resource/pages/udf/pages/function/_source/createUdf.vue
@@ -15,7 +15,7 @@
  * limitations under the License.
  */
 <template>
-  <m-popup :ok-text="item ? $t('Edit') : $t('Submit')" :nameText="item ? $t('Edit UDF Function') : $t('Create UDF Function')" @ok="_ok" ref="popup">
+  <m-popup style="width:800px" :ok-text="item ? $t('Edit') : $t('Submit')" :nameText="item ? $t('Edit UDF Function') : $t('Create UDF Function')" @ok="_ok" ref="popup">
     <template slot="content">
       <div class="udf-create-model">
         <m-list-box-f>
@@ -72,26 +72,25 @@
         <m-list-box-f>
           <template slot="name"><strong>*</strong>{{$t('UDF Resources')}}</template>
           <template slot="content">
-            <x-select
-                    filterable
-                    v-model="resourceId"
-                    :disabled="isUpdate"
-                    :add-title="true"
-                    style="width: 261px">
-              <x-option
-                      v-for="city in udfResourceList"
-                      :key="city.id"
-                      :value="city.id"
-                      :label="city.alias">
-              </x-option>
-            </x-select>
+            <treeselect style="width:535px;float:left;" v-model="resourceId" :disable-branch-nodes="true" :options="udfResourceList" :disabled="isUpdate" :normalizer="normalizer" :placeholder="$t('Please select UDF resources directory')">
+              <div slot="value-label" slot-scope="{ node }">{{ node.raw.fullName }}</div>
+            </treeselect>
             <x-button type="primary" @click="_toggleUpdate" :disabled="upDisabled">{{$t('Upload Resources')}}</x-button>
           </template>
         </m-list-box-f>
         <m-list-box-f v-if="isUpdate">
+          <template slot="name"><strong>*</strong>{{$t('UDF resources directory')}}</template>
+          <template slot="content">
+            <treeselect style="width:535px;float:left;" v-model="pid" @select="selTree" :options="udfResourceDirList" :normalizer="normalizer" :placeholder="$t('Please select UDF resources directory')">
+              <div slot="value-label" slot-scope="{ node }">{{ node.raw.fullName }}</div>
+            </treeselect>
+          </template>
+        </m-list-box-f>
+        <m-list-box-f v-if="isUpdate">
           <template slot="name">&nbsp;</template>
           <template slot="content">
             <m-udf-update
+                    ref="assignment"
                     @on-update-present="_onUpdatePresent"
                     @on-update="_onUpdate">
             </m-udf-update>
@@ -115,6 +114,8 @@
   import _ from 'lodash'
   import i18n from '@/module/i18n'
   import store from '@/conf/home/store'
+  import Treeselect from '@riophae/vue-treeselect'
+  import '@riophae/vue-treeselect/dist/vue-treeselect.css'
   import mPopup from '@/module/components/popup/popup'
   import mListBoxF from '@/module/components/listBoxF/listBoxF'
   import mUdfUpdate from '@/module/components/fileUpdate/udfUpdate'
@@ -130,10 +131,16 @@
         argTypes: '',
         database: '',
         description: '',
-        resourceId: '',
+        resourceId: null,
+        pid: null,
         udfResourceList: [],
         isUpdate: false,
-        upDisabled: false
+        upDisabled: false,
+        normalizer(node) {
+          return {
+            label: node.name
+          }
+        },
       }
     },
     props: {
@@ -192,17 +199,54 @@
         // disabled update
         this.upDisabled = true
       },
+      // selTree
+      selTree(node) {
+        this.$refs.assignment.receivedValue(node.id,node.fullName)
+      },
       /**
        * get udf resources
        */
       _getUdfList () {
         return new Promise((resolve, reject) => {
           this.store.dispatch('resource/getResourcesList', { type: 'UDF' }).then(res => {
-            this.udfResourceList = res.data
+            let item = res.data
+            this.filterEmptyDirectory(item)
+            item = this.filterEmptyDirectory(item)
+            let item1 = _.cloneDeep(res.data)
+            this.diGuiTree(item)
+            
+            this.diGuiTree(this.filterJarFile(item1))
+            this.udfResourceList = item
+            this.udfResourceDirList = item1
             resolve()
           })
         })
       },
+      // filterEmptyDirectory
+      filterEmptyDirectory(array) {
+        for (const item of array) {
+          if (item.children) {
+            this.filterEmptyDirectory(item.children)
+          }
+        }
+        return array.filter(n => ((/\.jar$/.test(n.name) && n.children.length==0) || (!/\.jar$/.test(n.name) && n.children.length>0)))
+      },
+      // filterJarFile
+      filterJarFile (array) {
+        for (const item of array) {
+          if (item.children) {
+            item.children = this.filterJarFile(item.children)
+          }
+        }
+        return array.filter(n => !/\.jar$/.test(n.name))
+      },
+      // diGuiTree
+      diGuiTree(item) {  // Recursive convenience tree structure
+        item.forEach(item => {
+          item.children === '' || item.children === undefined || item.children === null || item.children.length === 0?        
+            delete item.children : this.diGuiTree(item.children);
+        })
+      },
       /**
        * Upload udf resources
        */
@@ -257,8 +301,7 @@
         })
       }
     },
-    watch: {
-    },
+    watch: {},
     created () {
       this._getUdfList().then(res => {
         // edit
@@ -271,13 +314,18 @@
           this.description = this.item.description || ''
           this.resourceId = this.item.resourceId
         } else {
-          this.resourceId = this.udfResourceList.length && this.udfResourceList[0].id || ''
+          this.resourceId = null
         }
       })
     },
     mounted () {
 
     },
-    components: { mPopup, mListBoxF, mUdfUpdate }
+    components: { mPopup, mListBoxF, mUdfUpdate, Treeselect }
   }
 </script>
+<style lang="scss" rel="stylesheet/scss">
+  .vue-treeselect__control {
+    height: 32px;
+  }
+</style>
diff --git a/dolphinscheduler-ui/src/js/conf/home/pages/resource/pages/udf/pages/function/_source/list.vue b/dolphinscheduler-ui/src/js/conf/home/pages/resource/pages/udf/pages/function/_source/list.vue
index ed441ba..d77f557 100644
--- a/dolphinscheduler-ui/src/js/conf/home/pages/resource/pages/udf/pages/function/_source/list.vue
+++ b/dolphinscheduler-ui/src/js/conf/home/pages/resource/pages/udf/pages/function/_source/list.vue
@@ -43,7 +43,7 @@ v-ps<template>
           <!-- <th scope="col">
             <span>{{$t('Library Name')}}</span>
           </th> -->
-          <th scope="col" width="140">
+          <th scope="col" width="150">
             <span>{{$t('Update Time')}}</span>
           </th>
           <th scope="col" width="80">
@@ -71,7 +71,8 @@ v-ps<template>
             <span v-else>-</span>
           </td>
           <td>
-            <span>{{item.resourceName}}</span>
+            <span v-if="item.resourceName" class="ellipsis" v-tooltip.large.top.start.light="{text: item.resourceName, maxWidth: '500px'}">{{item.resourceName}}</span>
+            <span v-else>-</span>
           </td>
           <!-- <td>
             <span>{{item.database || '-'}}</span>
diff --git a/dolphinscheduler-ui/src/js/conf/home/pages/resource/pages/udf/pages/function/index.vue b/dolphinscheduler-ui/src/js/conf/home/pages/resource/pages/udf/pages/function/index.vue
index df46d7f..d6c79bd 100644
--- a/dolphinscheduler-ui/src/js/conf/home/pages/resource/pages/udf/pages/function/index.vue
+++ b/dolphinscheduler-ui/src/js/conf/home/pages/resource/pages/udf/pages/function/index.vue
@@ -19,7 +19,9 @@
     <template slot="conditions">
       <m-conditions @on-conditions="_onConditions">
         <template slot="button-group">
-          <x-button type="ghost" @click="_create"  size="small" >{{$t('Create UDF Function')}}</x-button>
+          <x-button-group size="small">
+            <x-button type="ghost" @click="_create">{{$t('Create UDF Function')}}</x-button>
+          </x-button-group>
         </template>
       </m-conditions>
     </template>
@@ -58,6 +60,7 @@
         isLoading: false,
         udfFuncList: [],
         searchParams: {
+          id: -1,
           pageSize: 10,
           pageNo: 1,
           searchVal: ''
diff --git a/dolphinscheduler-ui/src/js/conf/home/pages/resource/pages/udf/pages/resource/_source/list.vue b/dolphinscheduler-ui/src/js/conf/home/pages/resource/pages/udf/pages/resource/_source/list.vue
index 1f72e51..ddb097e 100644
--- a/dolphinscheduler-ui/src/js/conf/home/pages/resource/pages/udf/pages/resource/_source/list.vue
+++ b/dolphinscheduler-ui/src/js/conf/home/pages/resource/pages/udf/pages/resource/_source/list.vue
@@ -26,6 +26,9 @@
             <span>{{$t('UDF Resource Name')}}</span>
           </th>
           <th scope="col">
+            <span>{{$t('Whether directory')}}</span>
+          </th>
+          <th scope="col">
             <span>{{$t('File Name')}}</span>
           </th>
           <th scope="col" width="80">
@@ -50,9 +53,12 @@
           </td>
           <td>
             <span class="ellipsis" v-tooltip.large.top.start.light="{text: item.alias, maxWidth: '500px'}">
-              <a href="javascript:" class="links" >{{item.alias}}</a>
+              <a href="javascript:" class="links" @click="_go(item)">{{item.alias}}</a>
             </span>
           </td>
+          <td>
+            <span>{{item.directory? $t('Yes') : $t('No')}}</span>
+          </td>
           <td><span class="ellipsis" v-tooltip.large.top.start.light="{text: item.fileName, maxWidth: '500px'}">{{item.fileName}}</span></td>
           <td>
             <span>{{_rtSize(item.size)}}</span>
@@ -85,6 +91,7 @@
                     size="xsmall"
                     data-toggle="tooltip"
                     :title="$t('Download')"
+                    :disabled="item.directory? true: false"
                     icon="ans-icon-download"
                     @click="_downloadFile(item)">
             </x-button>
@@ -120,6 +127,7 @@
   import mRename from './rename'
   import { downloadFile } from '@/module/download'
   import { bytesToSize } from '@/module/util/util'
+  import localStore from '@/module/util/localStorage'
 
   export default {
     name: 'udf-manage-list',
@@ -140,6 +148,13 @@
           id: item.id
         })
       },
+      _go (item) {
+        localStore.setItem('file', `${item.alias}|${item.size}`)
+        if(item.directory) {
+          localStore.setItem('currentDir', `${item.fullName}`)
+          this.$router.push({ path: `/resource/udf/subUdfDirectory/${item.id}` })
+        }
+      },
       _rtSize (val) {
         return bytesToSize(parseInt(val))
       },
diff --git a/dolphinscheduler-ui/src/js/conf/home/pages/resource/pages/udf/pages/resource/index.vue b/dolphinscheduler-ui/src/js/conf/home/pages/resource/pages/udf/pages/resource/index.vue
index 732c5a2..b87b178 100644
--- a/dolphinscheduler-ui/src/js/conf/home/pages/resource/pages/udf/pages/resource/index.vue
+++ b/dolphinscheduler-ui/src/js/conf/home/pages/resource/pages/udf/pages/resource/index.vue
@@ -19,7 +19,10 @@
     <template slot="conditions">
       <m-conditions @on-conditions="_onConditions">
         <template slot="button-group">
-          <x-button type="ghost" size="small"  @click="_uploading">{{$t('Upload UDF Resources')}}</x-button>
+          <x-button-group size="small">
+            <x-button type="ghost"  @click="() => this.$router.push({name: 'resource-udf-createUdfFolder'})">{{$t('Create folder')}}</x-button>
+            <x-button type="ghost" size="small"  @click="_uploading">{{$t('Upload UDF Resources')}}</x-button>
+          </x-button-group>
         </template>
       </m-conditions>
     </template>
@@ -58,6 +61,7 @@
         isLoading: false,
         udfResourcesList: [],
         searchParams: {
+          id: -1,
           pageSize: 10,
           pageNo: 1,
           searchVal: '',
diff --git a/dolphinscheduler-ui/src/js/conf/home/pages/resource/pages/udf/pages/resource/_source/list.vue b/dolphinscheduler-ui/src/js/conf/home/pages/resource/pages/udf/pages/subUdfDirectory/_source/list.vue
old mode 100644
new mode 100755
similarity index 90%
copy from dolphinscheduler-ui/src/js/conf/home/pages/resource/pages/udf/pages/resource/_source/list.vue
copy to dolphinscheduler-ui/src/js/conf/home/pages/resource/pages/udf/pages/subUdfDirectory/_source/list.vue
index 1f72e51..ddb097e
--- a/dolphinscheduler-ui/src/js/conf/home/pages/resource/pages/udf/pages/resource/_source/list.vue
+++ b/dolphinscheduler-ui/src/js/conf/home/pages/resource/pages/udf/pages/subUdfDirectory/_source/list.vue
@@ -26,6 +26,9 @@
             <span>{{$t('UDF Resource Name')}}</span>
           </th>
           <th scope="col">
+            <span>{{$t('Whether directory')}}</span>
+          </th>
+          <th scope="col">
             <span>{{$t('File Name')}}</span>
           </th>
           <th scope="col" width="80">
@@ -50,9 +53,12 @@
           </td>
           <td>
             <span class="ellipsis" v-tooltip.large.top.start.light="{text: item.alias, maxWidth: '500px'}">
-              <a href="javascript:" class="links" >{{item.alias}}</a>
+              <a href="javascript:" class="links" @click="_go(item)">{{item.alias}}</a>
             </span>
           </td>
+          <td>
+            <span>{{item.directory? $t('Yes') : $t('No')}}</span>
+          </td>
           <td><span class="ellipsis" v-tooltip.large.top.start.light="{text: item.fileName, maxWidth: '500px'}">{{item.fileName}}</span></td>
           <td>
             <span>{{_rtSize(item.size)}}</span>
@@ -85,6 +91,7 @@
                     size="xsmall"
                     data-toggle="tooltip"
                     :title="$t('Download')"
+                    :disabled="item.directory? true: false"
                     icon="ans-icon-download"
                     @click="_downloadFile(item)">
             </x-button>
@@ -120,6 +127,7 @@
   import mRename from './rename'
   import { downloadFile } from '@/module/download'
   import { bytesToSize } from '@/module/util/util'
+  import localStore from '@/module/util/localStorage'
 
   export default {
     name: 'udf-manage-list',
@@ -140,6 +148,13 @@
           id: item.id
         })
       },
+      _go (item) {
+        localStore.setItem('file', `${item.alias}|${item.size}`)
+        if(item.directory) {
+          localStore.setItem('currentDir', `${item.fullName}`)
+          this.$router.push({ path: `/resource/udf/subUdfDirectory/${item.id}` })
+        }
+      },
       _rtSize (val) {
         return bytesToSize(parseInt(val))
       },
diff --git a/dolphinscheduler-ui/src/js/conf/home/pages/resource/pages/udf/pages/subUdfDirectory/_source/rename.vue b/dolphinscheduler-ui/src/js/conf/home/pages/resource/pages/udf/pages/subUdfDirectory/_source/rename.vue
new file mode 100755
index 0000000..0c3b2f0
--- /dev/null
+++ b/dolphinscheduler-ui/src/js/conf/home/pages/resource/pages/udf/pages/subUdfDirectory/_source/rename.vue
@@ -0,0 +1,120 @@
+/*
+ * 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.
+ */
+<template>
+  <m-popup :ok-text="$t('Rename')" :nameText="$t('Rename')" @ok="_ok" :asyn-loading="true">
+    <template slot="content">
+      <div class="resource-rename-model">
+        <m-list-box-f>
+          <template slot="name"><strong>*</strong>{{$t('Name')}}</template>
+          <template slot="content">
+            <x-input
+                    type="input"
+                    v-model="name"
+                    maxlength="60"
+                    :placeholder="$t('Please enter name')"
+                    autocomplete="off">
+            </x-input>
+          </template>
+        </m-list-box-f>
+        <m-list-box-f>
+          <template slot="name">{{$t('Description')}}</template>
+          <template slot="content">
+            <x-input
+                    type="textarea"
+                    v-model="description"
+                    :placeholder="$t('Please enter description')"
+                    autocomplete="off">
+            </x-input>
+          </template>
+        </m-list-box-f>
+      </div>
+    </template>
+  </m-popup>
+</template>
+<script>
+  import i18n from '@/module/i18n'
+  import store from '@/conf/home/store'
+  import localStore from '@/module/util/localStorage'
+  import mPopup from '@/module/components/popup/popup'
+  import mListBoxF from '@/module/components/listBoxF/listBoxF'
+
+  export default {
+    name: 'resource-udf-rename',
+    data () {
+      return {
+        store,
+        description: '',
+        name: ''
+      }
+    },
+    props: {
+      item: Object
+    },
+    methods: {
+      _ok (fn) {
+        this._verification().then(res => {
+          if (this.name === this.item.alias) {
+            return new Promise((resolve,reject) => {
+              this.description === this.item.description ? reject({msg:'内容未修改'}) : resolve()
+            })
+          }else{
+            return this.store.dispatch('resource/resourceVerifyName', {
+              fullName: localStore.getItem('currentDir')+'/'+this.name,
+              type: 'UDF'
+            })
+          }
+        }).then(res => {
+          return this.store.dispatch('resource/resourceRename', {
+            name: this.name,
+            description: this.description,
+            id: this.item.id,
+            type: 'UDF'
+          })
+        }).then(res => {
+          this.$message.success(res.msg)
+          this.$emit('onUpDate', res.data)
+          fn()
+        }).catch(e => {
+          fn()
+          this.$message.error(e.msg || '')
+        })
+      },
+      _verification () {
+        return new Promise((resolve, reject) => {
+          if (!this.name) {
+            reject({ // eslint-disable-line
+              msg: `${i18n.$t('Please enter resource name')}`
+            })
+          } else {
+            resolve()
+          }
+        })
+      }
+    },
+    watch: {},
+    created () {
+      let item = this.item || {}
+      if (item) {
+        this.name = item.alias
+        this.description = item.description
+      }
+    },
+    mounted () {
+    },
+    components: { mPopup, mListBoxF }
+  }
+</script>
diff --git a/dolphinscheduler-ui/src/js/conf/home/pages/resource/pages/udf/pages/resource/index.vue b/dolphinscheduler-ui/src/js/conf/home/pages/resource/pages/udf/pages/subUdfDirectory/index.vue
old mode 100644
new mode 100755
similarity index 63%
copy from dolphinscheduler-ui/src/js/conf/home/pages/resource/pages/udf/pages/resource/index.vue
copy to dolphinscheduler-ui/src/js/conf/home/pages/resource/pages/udf/pages/subUdfDirectory/index.vue
index 732c5a2..dd39716
--- a/dolphinscheduler-ui/src/js/conf/home/pages/resource/pages/udf/pages/resource/index.vue
+++ b/dolphinscheduler-ui/src/js/conf/home/pages/resource/pages/udf/pages/subUdfDirectory/index.vue
@@ -15,15 +15,22 @@
  * limitations under the License.
  */
 <template>
-  <m-list-construction :title="$t('UDF Resources')">
-    <template slot="conditions">
+  <div class="home-main list-construction-model">
+    <div class="content-title">
+      <a class="bread" style="padding-left: 15px;" @click="() => $router.push({path: `/resource/udf`})">{{$t('UDF Resources')}}</a>
+      <a class="bread" v-for="(item,$index) in breadList" :key="$index" @click="_ckOperation($index)">{{'>'+item}}</a>
+    </div>
+    <div class="conditions-box">
       <m-conditions @on-conditions="_onConditions">
         <template slot="button-group">
-          <x-button type="ghost" size="small"  @click="_uploading">{{$t('Upload UDF Resources')}}</x-button>
+          <x-button-group size="small" >
+            <x-button type="ghost" @click="() => $router.push({name: 'resource-udf-subCreateUdfFolder'})">{{$t('Create folder')}}</x-button>
+            <x-button type="ghost" size="small"  @click="_uploading">{{$t('Upload UDF Resources')}}</x-button>
+          </x-button-group>
         </template>
       </m-conditions>
-    </template>
-    <template slot="content">
+      </div>
+      <div class="list-box">
       <template v-if="udfResourcesList.length || total>0">
         <m-list @on-update="_onUpdate" :udf-resources-list="udfResourcesList" :page-no="searchParams.pageNo" :page-size="searchParams.pageSize">
         </m-list>
@@ -36,13 +43,14 @@
       </template>
       <m-spin :is-spin="isLoading">
       </m-spin>
-    </template>
-  </m-list-construction>
+    </div>
+  </div>
 </template>
 <script>
   import _ from 'lodash'
   import { mapActions } from 'vuex'
   import mList from './_source/list'
+  import localStore from '@/module/util/localStorage'
   import mSpin from '@/module/components/spin/spin'
   import { findComponentDownward } from '@/module/util/'
   import mNoData from '@/module/components/noData/noData'
@@ -58,22 +66,24 @@
         isLoading: false,
         udfResourcesList: [],
         searchParams: {
+          id: this.$route.params.id,
           pageSize: 10,
           pageNo: 1,
           searchVal: '',
           type: 'UDF'
-        }
+        },
+        breadList: []
       }
     },
     mixins: [listUrlParamHandle],
     props: {},
     methods: {
-      ...mapActions('resource', ['getResourcesListP']),
+      ...mapActions('resource', ['getResourcesListP','getResourceId']),
       /**
        * File Upload
        */
       _uploading () {
-        findComponentDownward(this.$root, 'roof-nav')._fileUpdate('UDF')
+        findComponentDownward(this.$root, 'roof-nav')._resourceChildUpdate('UDF',this.searchParams.id)
       },
       _onConditions (o) {
         this.searchParams = _.assign(this.searchParams, o)
@@ -86,9 +96,11 @@
         this.searchParams.pageSize = val
       },
       _onUpdate () {
+        this.searchParams.id = this.$route.params.id
         this._debounceGET()
       },
-      _updateList () {
+      _updateList (data) {
+        this.searchParams.id = data
         this.searchParams.pageNo = 1
         this.searchParams.searchVal = ''
         this._debounceGET()
@@ -107,6 +119,26 @@
         }).catch(e => {
           this.isLoading = false
         })
+      },
+       _ckOperation(index) {
+        let breadName =''
+        this.breadList.forEach((item, i) => {
+          if(i<=index) {
+            breadName = breadName+'/'+item
+          }
+        })
+        this.transferApi(breadName)
+      },
+      transferApi(api) {
+        this.getResourceId({
+          type: 'UDF',
+          fullName: api
+        }).then(res => {
+          localStore.setItem('currentDir', `${res.fullName}`)
+          this.$router.push({ path: `/resource/udf/subUdfDirectory/${res.id}` })
+        }).catch(e => {
+          this.$message.error(e.msg || '')
+        })
       }
     },
     watch: {
@@ -114,13 +146,29 @@
       '$route' (a) {
         // url no params get instance list
         this.searchParams.pageNo = _.isEmpty(a.query) ? 1 : a.query.pageNo
+        this.searchParams.id = a.params.id
+        let dir = localStore.getItem('currentDir').split('/')
+        dir.shift()
+        this.breadList = dir
       }
     },
     created () {
     },
     mounted () {
+      let dir = localStore.getItem('currentDir').split('/')
+      dir.shift()
+      this.breadList = dir
       this.$modal.destroy()
     },
     components: { mListConstruction, mConditions, mList, mSpin, mNoData }
   }
 </script>
+<style lang="scss" rel="stylesheet/scss">
+  .bread {
+    font-size: 22px;
+    padding-top: 10px;
+    color: #2a455b;
+    display: inline-block;
+    cursor: pointer;
+  }
+</style>
diff --git a/dolphinscheduler-ui/src/js/conf/home/pages/resource/pages/file/pages/create/index.vue b/dolphinscheduler-ui/src/js/conf/home/pages/resource/pages/udf/pages/subUdfFolder/index.vue
old mode 100644
new mode 100755
similarity index 56%
copy from dolphinscheduler-ui/src/js/conf/home/pages/resource/pages/file/pages/create/index.vue
copy to dolphinscheduler-ui/src/js/conf/home/pages/resource/pages/udf/pages/subUdfFolder/index.vue
index df84f0f..c3cddc3
--- a/dolphinscheduler-ui/src/js/conf/home/pages/resource/pages/file/pages/create/index.vue
+++ b/dolphinscheduler-ui/src/js/conf/home/pages/resource/pages/udf/pages/subUdfFolder/index.vue
@@ -15,15 +15,15 @@
  * limitations under the License.
  */
 <template>
-  <m-list-construction :title="$t('Create File')">
+  <m-list-construction :title="$t('Create folder')">
     <template slot="content">
       <div class="resource-create-model">
         <m-list-box-f>
-          <template slot="name"><strong>*</strong>{{$t('File Name')}}</template>
+          <template slot="name"><strong>*</strong>{{$t('Folder Name')}}</template>
           <template slot="content">
             <x-input
                     type="input"
-                    v-model="fileName"
+                    v-model="name"
                     maxlength="60"
                     style="width: 300px;"
                     :placeholder="$t('Please enter name')"
@@ -32,19 +32,6 @@
           </template>
         </m-list-box-f>
         <m-list-box-f>
-          <template slot="name"><strong>*</strong>{{$t('File Format')}}</template>
-          <template slot="content">
-            <x-select v-model="suffix" style="width: 100px;" @on-change="_onChange">
-              <x-option
-                      v-for="city in fileTypeList"
-                      :key="city"
-                      :value="city"
-                      :label="city">
-              </x-option>
-            </x-select>
-          </template>
-        </m-list-box-f>
-        <m-list-box-f>
           <template slot="name">{{$t('Description')}}</template>
           <template slot="content">
             <x-input
@@ -57,17 +44,11 @@
           </template>
         </m-list-box-f>
         <m-list-box-f>
-          <template slot="name"><strong>*</strong>{{$t('File Content')}}</template>
-          <template slot="content">
-            <textarea id="code-create-mirror" name="code-create-mirror"></textarea>
-          </template>
-        </m-list-box-f>
-        <m-list-box-f>
           <template slot="name">&nbsp;</template>
           <template slot="content">
             <div class="submit">
               <x-button type="primary" shape="circle" :loading="spinnerLoading" @click="ok()">{{spinnerLoading ? 'Loading...' : $t('Create')}} </x-button>
-              <x-button type="text" @click="() => $router.push({name: 'file'})"> {{$t('Cancel')}} </x-button>
+              <x-button type="text" @click="() => $router.push({name: 'resource-udf-subUdfDirectory'})"> {{$t('Cancel')}} </x-button>
             </div>
           </template>
         </m-list-box-f>
@@ -78,44 +59,39 @@
 <script>
   import i18n from '@/module/i18n'
   import { mapActions } from 'vuex'
-  import { filtTypeArr } from '../_source/common'
-  import { handlerSuffix } from '../details/_source/utils'
-  import codemirror from '../_source/codemirror'
   import mListBoxF from '@/module/components/listBoxF/listBoxF'
   import mSpin from '@/module/components/spin/spin'
   import mConditions from '@/module/components/conditions/conditions'
+  import localStore from '@/module/util/localStorage'
   import mListConstruction from '@/module/components/listConstruction/listConstruction'
 
-  let editor
   export default {
     name: 'resource-list-create-FILE',
     data () {
       return {
-        suffix: 'sh',
-        fileName: '',
+        type: '',
+        name: '',
         description: '',
-        fileTypeList: filtTypeArr,
-        content: '',
         spinnerLoading: false
       }
     },
     props: {},
     methods: {
-      ...mapActions('resource', ['createResourceFile']),
+      ...mapActions('resource', ['createResourceFolder']),
       ok () {
         if (this._validation()) {
           this.spinnerLoading = true
-          this.createResourceFile({
-            type: 'FILE',
-            fileName: this.fileName,
-            suffix: this.suffix,
-            description: this.description,
-            content: editor.getValue()
+          this.createResourceFolder({
+            type: 'UDF',
+            name: this.name,
+            currentDir: localStore.getItem('currentDir'),
+            pid: this.$route.params.id,
+            description: this.description
           }).then(res => {
             this.$message.success(res.msg)
             setTimeout(() => {
               this.spinnerLoading = false
-              this.$router.push({ name: 'file' })
+              this.$router.push({ path: `/resource/udf/subUdfDirectory/${this.$route.params.id}`})
             }, 800)
           }).catch(e => {
             this.$message.error(e.msg || '')
@@ -124,55 +100,21 @@
         }
       },
       _validation () {
-        if (!this.fileName) {
-          this.$message.warning(`${i18n.$t('Please enter resource name')}`)
-          return false
-        }
-        if (!editor.getValue()) {
-          this.$message.warning(`${i18n.$t('Please enter the resource content')}`)
+        if (!this.name) {
+          this.$message.warning(`${i18n.$t('Please enter resource folder name')}`)
           return false
         }
-        if (editor.doc.size>3000) {
-          this.$message.warning(`${i18n.$t('Resource content cannot exceed 3000 lines')}`)
-          return false
-        }
-        return true
-      },
-      /**
-       * Processing code highlighting
-       */
-      _handlerEditor () {
-        // editor
-        editor = codemirror('code-create-mirror', {
-          mode: 'shell',
-          readOnly: false
-        })
 
-        this.keypress = () => {
-          if (!editor.getOption('readOnly')) {
-            editor.showHint({
-              completeSingle: false
-            })
-          }
-        }
-
-        // Monitor keyboard
-        editor.on('keypress', this.keypress)
+        return true
       },
-      _onChange (val) {
-        editor.setOption('mode', handlerSuffix['.' + val.label])
-      }
     },
     watch: {},
     created () {
     },
     mounted () {
       this.$modal.destroy()
-      this._handlerEditor()
     },
     destroyed () {
-      editor.toTextArea() // uninstall
-      editor.off($('.code-create-mirror'), 'keypress', this.keypress)
     },
     computed: {},
     components: { mListConstruction, mConditions, mSpin, mListBoxF }
@@ -183,8 +125,4 @@
   .resource-create-model {
     padding: 30px;
   }
-  .CodeMirror {
-    border:1px solid #DDDEDD;
-    border-radius: 3px;
-  }
 </style>
diff --git a/dolphinscheduler-ui/src/js/conf/home/pages/security/pages/users/_source/list.vue b/dolphinscheduler-ui/src/js/conf/home/pages/security/pages/users/_source/list.vue
index 6e8887b..d88d6e8 100644
--- a/dolphinscheduler-ui/src/js/conf/home/pages/security/pages/users/_source/list.vue
+++ b/dolphinscheduler-ui/src/js/conf/home/pages/security/pages/users/_source/list.vue
@@ -144,7 +144,7 @@
       pageSize: Number
     },
     methods: {
-      ...mapActions('security', ['deleteUser', 'getAuthList', 'grantAuthorization']),
+      ...mapActions('security', ['deleteUser', 'getAuthList', 'grantAuthorization','getResourceList']),
       _closeDelete (i) {
         this.$refs[`poptip-delete-${i}`][0].doClose()
       },
@@ -215,45 +215,44 @@
           })
         })
       },
-      _authFile (item, i) {
+      _authFile (item, i) { 
         this.$refs[`poptip-auth-${i}`][0].doClose()
-        this.getAuthList({
+        this.getResourceList({
           id: item.id,
           type: 'file',
           category: 'resources'
         }).then(data => {
-          let sourceListPrs = _.map(data[0], v => {
-            return {
-              id: v.id,
-              name: v.alias,
-              type: v.type
-            }
-          })
+          // let sourceListPrs = _.map(data[0], v => {
+          //   return {
+          //     id: v.id,
+          //     name: v.alias,
+          //     type: v.type
+          //   }
+          // })
           let fileSourceList = []
           let udfSourceList = []
-          sourceListPrs.forEach((value,index,array)=>{
+          data[0].forEach((value,index,array)=>{
             if(value.type =='FILE'){
               fileSourceList.push(value)
             } else{
               udfSourceList.push(value)
             }
           })
-          let targetListPrs = _.map(data[1], v => {
-            return {
-              id: v.id,
-              name: v.alias,
-              type: v.type
-            }
-          })
           let fileTargetList = []
           let udfTargetList = []
-          targetListPrs.forEach((value,index,array)=>{
+          data[1].forEach((value,index,array)=>{
             if(value.type =='FILE'){
               fileTargetList.push(value)
             } else{
               udfTargetList.push(value)
             }
           })
+          fileTargetList = _.map(fileTargetList, v => {
+            return v.id
+          })
+          udfTargetList = _.map(udfTargetList, v => {
+            return v.id
+          })
           let self = this
           let modal = this.$modal.dialog({
             closable: false,
diff --git a/dolphinscheduler-ui/src/js/conf/home/router/index.js b/dolphinscheduler-ui/src/js/conf/home/router/index.js
index 21e211d..8a18965 100644
--- a/dolphinscheduler-ui/src/js/conf/home/router/index.js
+++ b/dolphinscheduler-ui/src/js/conf/home/router/index.js
@@ -211,6 +211,30 @@ const router = new Router({
           }
         },
         {
+          path: '/resource/file/createFolder',
+          name: 'resource-file-createFolder',
+          component: resolve => require(['../pages/resource/pages/file/pages/createFolder/index'], resolve),
+          meta: {
+            title: `${i18n.$t('Create Resource')}`
+          }
+        },
+        {
+          path: '/resource/file/subFileFolder/:id',
+          name: 'resource-file-subFileFolder',
+          component: resolve => require(['../pages/resource/pages/file/pages/subFileFolder/index'], resolve),
+          meta: {
+            title: `${i18n.$t('Create Resource')}`
+          }
+        },
+        {
+          path: '/resource/file/subFile/:id',
+          name: 'resource-file-subFile',
+          component: resolve => require(['../pages/resource/pages/file/pages/subFile/index'], resolve),
+          meta: {
+            title: `${i18n.$t('Create Resource')}`
+          }
+        },
+        {
           path: '/resource/file/list/:id',
           name: 'resource-file-details',
           component: resolve => require(['../pages/resource/pages/file/pages/details/index'], resolve),
@@ -219,6 +243,14 @@ const router = new Router({
           }
         },
         {
+          path: '/resource/file/subdirectory/:id',
+          name: 'resource-file-subdirectory',
+          component: resolve => require(['../pages/resource/pages/file/pages/subdirectory/index'], resolve),
+          meta: {
+            title: `${i18n.$t('File Manage')}`
+          }
+        },
+        {
           path: '/resource/file/edit/:id',
           name: 'resource-file-edit',
           component: resolve => require(['../pages/resource/pages/file/pages/edit/index'], resolve),
@@ -235,16 +267,40 @@ const router = new Router({
           },
           children: [
             {
-              path: '/resource/udf/resource',
-              name: 'resource-udf-resource',
+              path: '/resource/udf',
+              name: 'resource-udf',
               component: resolve => require(['../pages/resource/pages/udf/pages/resource/index'], resolve),
               meta: {
                 title: `${i18n.$t('UDF Resources')}`
               }
             },
             {
-              path: '/resource/udf/function',
-              name: 'resource-udf-function',
+              path: '/resource/udf/subUdfDirectory/:id',
+              name: 'resource-udf-subUdfDirectory',
+              component: resolve => require(['../pages/resource/pages/udf/pages/subUdfDirectory/index'], resolve),
+              meta: {
+                title: `${i18n.$t('UDF Resources')}`
+              }
+            },
+            {
+              path: '/resource/udf/createUdfFolder',
+              name: 'resource-udf-createUdfFolder',
+              component: resolve => require(['../pages/resource/pages/udf/pages/createUdfFolder/index'], resolve),
+              meta: {
+                title: `${i18n.$t('Create Resource')}`
+              }
+            },
+            {
+              path: '/resource/udf/subCreateUdfFolder/:id',
+              name: 'resource-udf-subCreateUdfFolder',
+              component: resolve => require(['../pages/resource/pages/udf/pages/subUdfFolder/index'], resolve),
+              meta: {
+                title: `${i18n.$t('Create Resource')}`
+              }
+            },
+            {
+              path: '/resource/func',
+              name: 'resource-func',
               component: resolve => require(['../pages/resource/pages/udf/pages/function/index'], resolve),
               meta: {
                 title: `${i18n.$t('UDF Function')}`
diff --git a/dolphinscheduler-ui/src/js/conf/home/store/dag/actions.js b/dolphinscheduler-ui/src/js/conf/home/store/dag/actions.js
index 20bc113..50295ad 100644
--- a/dolphinscheduler-ui/src/js/conf/home/store/dag/actions.js
+++ b/dolphinscheduler-ui/src/js/conf/home/store/dag/actions.js
@@ -334,6 +334,25 @@ export default {
     })
   },
   /**
+   * get jar
+   */
+  getResourcesListJar ({ state }) {
+    return new Promise((resolve, reject) => {
+      if (state.resourcesListJar.length) {
+        resolve()
+        return
+      }
+      io.get(`resources/list/jar`, {
+        type: 'FILE'
+      }, res => {
+        state.resourcesListJar = res.data
+        resolve(res.data)
+      }).catch(res => {
+        reject(res)
+      })
+    })
+  },
+  /**
    * Get process instance
    */
   getProcessInstance ({ state }, payload) {
diff --git a/dolphinscheduler-ui/src/js/conf/home/store/dag/mutations.js b/dolphinscheduler-ui/src/js/conf/home/store/dag/mutations.js
index b914b86..b6142bb 100755
--- a/dolphinscheduler-ui/src/js/conf/home/store/dag/mutations.js
+++ b/dolphinscheduler-ui/src/js/conf/home/store/dag/mutations.js
@@ -108,6 +108,7 @@ export default {
     state.tenantId = payload && payload.tenantId || -1
     state.processListS = payload && payload.processListS || []
     state.resourcesListS = payload && payload.resourcesListS || []
+    state.resourcesListJar = payload && payload.resourcesListJar || []
     state.projectListS = payload && payload.projectListS || []
     state.isDetails = payload && payload.isDetails || false
     state.runFlag = payload && payload.runFlag || ''
diff --git a/dolphinscheduler-ui/src/js/conf/home/store/dag/state.js b/dolphinscheduler-ui/src/js/conf/home/store/dag/state.js
index b7d592a..0605a26 100644
--- a/dolphinscheduler-ui/src/js/conf/home/store/dag/state.js
+++ b/dolphinscheduler-ui/src/js/conf/home/store/dag/state.js
@@ -53,6 +53,8 @@ export default {
   projectListS: [],
   // tasks resourcesList
   resourcesListS: [],
+  // tasks resourcesListJar
+  resourcesListJar: [],
   // tasks datasource Type
   dsTypeListS: [
     {
diff --git a/dolphinscheduler-ui/src/js/conf/home/store/resource/actions.js b/dolphinscheduler-ui/src/js/conf/home/store/resource/actions.js
index 2537062..c27c6d0 100644
--- a/dolphinscheduler-ui/src/js/conf/home/store/resource/actions.js
+++ b/dolphinscheduler-ui/src/js/conf/home/store/resource/actions.js
@@ -30,6 +30,15 @@ export default {
       })
     })
   },
+  getResourceId ({ state }, payload) {
+    return new Promise((resolve, reject) => {
+      io.get(`resources/queryResource`, payload, res => {
+        resolve(res.data)
+      }).catch(e => {
+        reject(e)
+      })
+    })
+  },
   getResourcesList ({ state }, payload) {
     return new Promise((resolve, reject) => {
       io.get(`resources/list`, payload, res => {
@@ -161,6 +170,18 @@ export default {
     })
   },
   /**
+   * Resource online create folder
+   */
+  createResourceFolder ({ state }, payload) {
+    return new Promise((resolve, reject) => {
+      io.post(`resources/directory/create`, payload, res => {
+        resolve(res)
+      }).catch(e => {
+        reject(e)
+      })
+    })
+  },
+  /**
    * Resource rename
    */
   resourceRename ({ state }, payload) {
diff --git a/dolphinscheduler-ui/src/js/conf/home/store/security/actions.js b/dolphinscheduler-ui/src/js/conf/home/store/security/actions.js
index ff96adc..10a2bf1 100644
--- a/dolphinscheduler-ui/src/js/conf/home/store/security/actions.js
+++ b/dolphinscheduler-ui/src/js/conf/home/store/security/actions.js
@@ -195,6 +195,45 @@ export default {
       })
     })
   },
+
+  getResourceList ({ state }, payload) {
+    let o = {
+      type: payload.type,
+      category: payload.category
+    }
+
+    let param = {}
+    // Manage user
+    if (o.type === 'user') {
+      param.alertgroupId = payload.id
+    } else {
+      param.userId = payload.id
+    }
+
+    // Authorized project
+    const p1 = new Promise((resolve, reject) => {
+      io.get(`${o.category}/authorize-resource-tree`, param, res => {
+        resolve(res.data)
+      }).catch(e => {
+        reject(e)
+      })
+    })
+    // Unauthorized project
+    const p2 = new Promise((resolve, reject) => {
+      io.get(`${o.category}/authed-${o.type}`, param, res => {
+        resolve(res.data)
+      }).catch(e => {
+        reject(e)
+      })
+    })
+    return new Promise((resolve, reject) => {
+      Promise.all([p1, p2]).then(a => {
+        resolve(a)
+      }).catch(e => {
+        reject(e)
+      })
+    })
+  },
   /**
    * Authorization [project, resource, data source]
    * @param Project,Resources,Datasource
diff --git a/dolphinscheduler-ui/src/js/module/components/fileUpdate/fileUpdate.vue b/dolphinscheduler-ui/src/js/module/components/fileUpdate/fileChildUpdate.vue
similarity index 96%
copy from dolphinscheduler-ui/src/js/module/components/fileUpdate/fileUpdate.vue
copy to dolphinscheduler-ui/src/js/module/components/fileUpdate/fileChildUpdate.vue
index b7cef4e..05d12b1 100644
--- a/dolphinscheduler-ui/src/js/module/components/fileUpdate/fileUpdate.vue
+++ b/dolphinscheduler-ui/src/js/module/components/fileUpdate/fileChildUpdate.vue
@@ -90,6 +90,7 @@
   import io from '@/module/io'
   import i18n from '@/module/i18n'
   import store from '@/conf/home/store'
+  import localStore from '@/module/util/localStorage'
   import mPopup from '@/module/components/popup/popup'
   import mListBoxF from '@/module/components/listBoxF/listBoxF'
   import mProgressBar from '@/module/components/progressBar/progressBar'
@@ -107,6 +108,8 @@
         progress: 0,
         // file
         file: '',
+        currentDir: localStore.getItem('currentDir'),
+        pid: this.id,
         // Whether to drag upload
         dragOver: false
       }
@@ -114,7 +117,8 @@
     watch: {
     },
     props: {
-      type: String
+      type: String,
+      id: Number
     },
     methods: {
       /**
@@ -124,7 +128,7 @@
         this.$refs['popup'].spinnerLoading = true
         if (this._validation()) {
           this.store.dispatch('resource/resourceVerifyName', {
-            name: this.name,
+            fullName: this.currentDir+'/'+this.name,
             type: this.type
           }).then(res => {
             const isLt1024M = this.file.size / 1024 / 1024 < 1024
@@ -172,6 +176,8 @@
           formData.append('file', this.file)
           formData.append('type', this.type)
           formData.append('name', this.name)
+          formData.append('pid', this.pid)
+          formData.append('currentDir', this.currentDir)
           formData.append('description', this.description)
           io.post(`resources/create`, res => {
             this.$message.success(res.msg)
diff --git a/dolphinscheduler-ui/src/js/module/components/fileUpdate/fileUpdate.vue b/dolphinscheduler-ui/src/js/module/components/fileUpdate/fileUpdate.vue
index b7cef4e..5e06dda 100644
--- a/dolphinscheduler-ui/src/js/module/components/fileUpdate/fileUpdate.vue
+++ b/dolphinscheduler-ui/src/js/module/components/fileUpdate/fileUpdate.vue
@@ -107,6 +107,8 @@
         progress: 0,
         // file
         file: '',
+        currentDir: '/',
+        pid: -1,
         // Whether to drag upload
         dragOver: false
       }
@@ -124,7 +126,7 @@
         this.$refs['popup'].spinnerLoading = true
         if (this._validation()) {
           this.store.dispatch('resource/resourceVerifyName', {
-            name: this.name,
+            fullName: '/'+this.name,
             type: this.type
           }).then(res => {
             const isLt1024M = this.file.size / 1024 / 1024 < 1024
@@ -172,6 +174,8 @@
           formData.append('file', this.file)
           formData.append('type', this.type)
           formData.append('name', this.name)
+          formData.append('pid', this.pid)
+          formData.append('currentDir', this.currentDir)
           formData.append('description', this.description)
           io.post(`resources/create`, res => {
             this.$message.success(res.msg)
diff --git a/dolphinscheduler-ui/src/js/module/components/fileUpdate/fileUpdate.vue b/dolphinscheduler-ui/src/js/module/components/fileUpdate/resourceChildUpdate.vue
old mode 100644
new mode 100755
similarity index 96%
copy from dolphinscheduler-ui/src/js/module/components/fileUpdate/fileUpdate.vue
copy to dolphinscheduler-ui/src/js/module/components/fileUpdate/resourceChildUpdate.vue
index b7cef4e..05d12b1
--- a/dolphinscheduler-ui/src/js/module/components/fileUpdate/fileUpdate.vue
+++ b/dolphinscheduler-ui/src/js/module/components/fileUpdate/resourceChildUpdate.vue
@@ -90,6 +90,7 @@
   import io from '@/module/io'
   import i18n from '@/module/i18n'
   import store from '@/conf/home/store'
+  import localStore from '@/module/util/localStorage'
   import mPopup from '@/module/components/popup/popup'
   import mListBoxF from '@/module/components/listBoxF/listBoxF'
   import mProgressBar from '@/module/components/progressBar/progressBar'
@@ -107,6 +108,8 @@
         progress: 0,
         // file
         file: '',
+        currentDir: localStore.getItem('currentDir'),
+        pid: this.id,
         // Whether to drag upload
         dragOver: false
       }
@@ -114,7 +117,8 @@
     watch: {
     },
     props: {
-      type: String
+      type: String,
+      id: Number
     },
     methods: {
       /**
@@ -124,7 +128,7 @@
         this.$refs['popup'].spinnerLoading = true
         if (this._validation()) {
           this.store.dispatch('resource/resourceVerifyName', {
-            name: this.name,
+            fullName: this.currentDir+'/'+this.name,
             type: this.type
           }).then(res => {
             const isLt1024M = this.file.size / 1024 / 1024 < 1024
@@ -172,6 +176,8 @@
           formData.append('file', this.file)
           formData.append('type', this.type)
           formData.append('name', this.name)
+          formData.append('pid', this.pid)
+          formData.append('currentDir', this.currentDir)
           formData.append('description', this.description)
           io.post(`resources/create`, res => {
             this.$message.success(res.msg)
diff --git a/dolphinscheduler-ui/src/js/module/components/fileUpdate/udfUpdate.vue b/dolphinscheduler-ui/src/js/module/components/fileUpdate/udfUpdate.vue
index 4285df5..7c852c5 100644
--- a/dolphinscheduler-ui/src/js/module/components/fileUpdate/udfUpdate.vue
+++ b/dolphinscheduler-ui/src/js/module/components/fileUpdate/udfUpdate.vue
@@ -25,7 +25,7 @@
                     size="small"
                     v-model="udfName"
                     :disabled="progress !== 0"
-                    style="width: 268px"
+                    style="width: 535px"
                     :placeholder="$t('Please enter resource name')"
                     autocomplete="off">
             </x-input>
@@ -66,7 +66,9 @@
         udfDesc: '',
         file: '',
         progress: 0,
-        spinnerLoading: false
+        spinnerLoading: false,
+        pid: null,
+        currentDir: ''
       }
     },
     props: {
@@ -77,6 +79,10 @@
        * validation
        */
       _validation () {
+        if (!this.currentDir) {
+          this.$message.warning(`${i18n.$t('Please select UDF resources directory')}`)
+          return false
+        }
         if (!this.udfName) {
           this.$message.warning(`${i18n.$t('Please enter file name')}`)
           return false
@@ -90,7 +96,7 @@
       _verifyName () {
         return new Promise((resolve, reject) => {
           this.store.dispatch('resource/resourceVerifyName', {
-            name: this.udfName,
+            fullName: '/'+this.udfName,
             type: 'UDF'
           }).then(res => {
             resolve()
@@ -100,11 +106,17 @@
           })
         })
       },
+      receivedValue(pid,name) {
+        this.pid = pid
+        this.currentDir = name
+      },
       _formDataUpdate () {
         let self = this
         let formData = new FormData()
         formData.append('file', this.file)
         formData.append('type', 'UDF')
+        formData.append('pid', this.pid)
+        formData.append('currentDir', this.currentDir)
         formData.append('name', this.udfName)
         formData.append('description', this.udfDesc)
         this.spinnerLoading = true
diff --git a/dolphinscheduler-ui/src/js/module/components/nav/nav.vue b/dolphinscheduler-ui/src/js/module/components/nav/nav.vue
index 7212f51..a46ff6f 100644
--- a/dolphinscheduler-ui/src/js/module/components/nav/nav.vue
+++ b/dolphinscheduler-ui/src/js/module/components/nav/nav.vue
@@ -155,6 +155,8 @@
   import { mapState, mapActions } from 'vuex'
   import { findComponentDownward } from '@/module/util/'
   import mFileUpdate from '@/module/components/fileUpdate/fileUpdate'
+  import mFileChildUpdate from '@/module/components/fileUpdate/fileChildUpdate'
+  import mResourceChildUpdate from '@/module/components/fileUpdate/resourceChildUpdate'
   import mDefinitionUpdate from '@/module/components/fileUpdate/definitionUpdate'
   import mProgressBar from '@/module/components/progressBar/progressBar'
 
@@ -260,6 +262,86 @@
           }
         })
       },
+      _fileChildUpdate (type,data) {
+        if (this.progress) {
+          this._toggleArchive()
+          return
+        }
+        let self = this
+        let modal = this.$modal.dialog({
+          closable: false,
+          showMask: true,
+          escClose: true,
+          className: 'update-file-modal',
+          transitionName: 'opacityp',
+          render (h) {
+            return h(mFileChildUpdate, {
+              on: {
+                onProgress (val) {
+                  self.progress = val
+                },
+                onUpdate () {
+                  findComponentDownward(self.$root, `resource-list-index-${type}`)._updateList(data)
+                  self.isUpdate = false
+                  self.progress = 0
+                  modal.remove()
+                },
+                onArchive () {
+                  self.isUpdate = true
+                },
+                close () {
+                  self.progress = 0
+                  modal.remove()
+                }
+              },
+              props: {
+                type: type,
+                id: data
+              }
+            })
+          }
+        })
+      },
+      _resourceChildUpdate (type,data) {
+        if (this.progress) {
+          this._toggleArchive()
+          return
+        }
+        let self = this
+        let modal = this.$modal.dialog({
+          closable: false,
+          showMask: true,
+          escClose: true,
+          className: 'update-file-modal',
+          transitionName: 'opacityp',
+          render (h) {
+            return h(mResourceChildUpdate, {
+              on: {
+                onProgress (val) {
+                  self.progress = val
+                },
+                onUpdate () {
+                  findComponentDownward(self.$root, `resource-list-index-${type}`)._updateList(data)
+                  self.isUpdate = false
+                  self.progress = 0
+                  modal.remove()
+                },
+                onArchive () {
+                  self.isUpdate = true
+                },
+                close () {
+                  self.progress = 0
+                  modal.remove()
+                }
+              },
+              props: {
+                type: type,
+                id: data
+              }
+            })
+          }
+        })
+      },
       /**
        * Upload popup layer display
        */
diff --git a/dolphinscheduler-ui/src/js/module/components/secondaryMenu/_source/menu.js b/dolphinscheduler-ui/src/js/module/components/secondaryMenu/_source/menu.js
index 2ed0fc1..baf2cf7 100644
--- a/dolphinscheduler-ui/src/js/module/components/secondaryMenu/_source/menu.js
+++ b/dolphinscheduler-ui/src/js/module/components/secondaryMenu/_source/menu.js
@@ -148,13 +148,13 @@ let menu = {
       children: [
         {
           name: `${i18n.$t('Resource manage')}`,
-          path: 'resource-udf-resource',
+          path: 'resource-udf',
           id: 0,
           disabled: true
         },
         {
           name: `${i18n.$t('Function manage')}`,
-          path: 'resource-udf-function',
+          path: 'resource-func',
           id: 1,
           disabled: true
         }
diff --git a/dolphinscheduler-ui/src/js/module/components/transfer/resource.vue b/dolphinscheduler-ui/src/js/module/components/transfer/resource.vue
index 72205de..97397c1 100644
--- a/dolphinscheduler-ui/src/js/module/components/transfer/resource.vue
+++ b/dolphinscheduler-ui/src/js/module/components/transfer/resource.vue
@@ -20,26 +20,21 @@
       <div class="clearfix transfer-model" style="width: 660px">
         <div>
             <x-button-group v-model="checkedValue" size="small">
-              <x-button type="ghost" value="fileResource" @click="_ckFile">{{$t('File resources')}}</x-button>
-              <x-button type="ghost" value="udfResource" @click="_ckUDf">{{$t('UDF resources')}}</x-button>
+                <x-button type="ghost" value="fileResource" @click="_ckFile">{{$t('File resources')}}</x-button>
+                <x-button type="ghost" value="udfResource" @click="_ckUDf">{{$t('UDF resources')}}</x-button>
             </x-button-group>
         </div>
-        <div class="select-list-box">
+        <treeselect v-show="checkedValue=='fileResource'" v-model="selectFileSource" :multiple="true" :options="fileList" :normalizer="normalizer" :placeholder="$t('Please select resources')">
+          <div slot="value-label" slot-scope="{ node }">{{ node.raw.fullName }}</div>
+        </treeselect>
+        <treeselect v-show="checkedValue=='udfResource'" v-model="selectUdfSource" :multiple="true" :options="udfList" :normalizer="normalizer" :placeholder="$t('Please select resources')">
+          <div slot="value-label" slot-scope="{ node }">{{ node.raw.fullName }}</div>
+        </treeselect>
+        <!-- <div class="select-list-box">
           <div class="tf-header">
             <div class="title">{{type.name}}{{$t('List')}}</div>
             <div class="count">({{cacheSourceList.length}})</div>
           </div>
-          <!--<div class="tf-search">
-            <x-input v-model="searchSourceVal"
-                     @on-enterkey="_sourceQuery"
-                     @on-click-icon="_sourceQuery"
-                     size="small"
-                     placeholder="Please enter keyword"
-                     type="text"
-                     style="width:202px;">
-              <em slot="suffix" class="ans-icon-search"></em>
-            </x-input>
-          </div>-->
           <div class="scrollbar tf-content">
             <ul>
               <li v-for="(item,$index) in sourceList" :key="$index" @click="_ckSource(item)">
@@ -55,23 +50,12 @@
             <div class="title">{{$t('Selected')}}{{type.name}}</div>
             <div class="count">({{cacheTargetList.length}})</div>
           </div>
-          <!--<div class="tf-search">
-            <x-input v-model="searchTargetVal"
-                     @on-enterkey="_targetQuery"
-                     @on-click-icon="_targetQuery"
-                     size="small"
-                     placeholder="Please enter keyword"
-                     type="text"
-                     style="width:202px;">
-              <em slot="suffix" class="ans-icon-search"></em>
-            </x-input>
-          </div>-->
           <div class="scrollbar tf-content">
             <ul>
               <li v-for="(item,$index) in targetList" :key="$index" @click="_ckTarget(item)"><span :title="item.name">{{item.name}}</span></li>
             </ul>
           </div>
-        </div>
+        </div> -->
       </div>
     </template>
   </m-popup>
@@ -80,6 +64,9 @@
   import _ from 'lodash'
   import mPopup from '@/module/components/popup/popup'
   import mListBoxF from '@/module/components/listBoxF/listBoxF'
+  import Treeselect from '@riophae/vue-treeselect'
+  import '@riophae/vue-treeselect/dist/vue-treeselect.css'
+
 
   export default {
     name: 'transfer',
@@ -92,11 +79,22 @@
         cacheTargetList: this.fileTargetList,
 
         fileSource: this.fileSourceList,
+        fileList: [],
+        udfList: [],
+        selectFileSource: [],
+        selectUdfSource: [],
         fileTarget: this.fileTargetList,
         udfSource: this.udfSourceList,
         udfTarget: this.udfTargetList,
         searchSourceVal: '',
-        searchTargetVal: ''
+        searchTargetVal: '',
+        // define default value
+        value: null,
+        normalizer(node) {
+          return {
+            label: node.name
+          }
+        },
       }
     },
     props: {
@@ -106,12 +104,22 @@
       fileTargetList: Array,
       udfTargetList: Array,
     },
+    created() {
+      let file = this.fileSourceList
+      let udf = this.udfSourceList
+      this.diGuiTree(file)
+      this.diGuiTree(udf)
+      this.fileList = file
+      this.udfList = udf
+      this.selectFileSource = this.fileTargetList
+      this.selectUdfSource = this.udfTargetList
+    },
     methods: {
       _ok () {
         this.$refs['popup'].spinnerLoading = true
         setTimeout(() => {
           this.$refs['popup'].spinnerLoading = false
-          this.$emit('onUpdate', _.map(this.fileTarget.concat(this.udfTarget), v => v.id).join(','))
+          this.$emit('onUpdate', _.map(this.selectFileSource.concat(this.selectUdfSource), v => v).join(','))
         }, 800)
       },
       _ckFile() {
@@ -169,6 +177,12 @@
             this.udfSource = this.sourceList
             this.udfTarget = this.targetList
         }
+      },
+      diGuiTree(item) {  // Recursive convenience tree structure
+        item.forEach(item => {
+          item.children === '' || item.children === undefined || item.children === null || item.children.length === 0?        
+            delete item.children : this.diGuiTree(item.children);
+        })
       }
     },
     watch: {
@@ -187,7 +201,7 @@
         this._targetQuery()
       }
     },
-    components: { mPopup, mListBoxF }
+    components: { mPopup, mListBoxF, Treeselect }
   }
 </script>
 
diff --git a/dolphinscheduler-ui/src/js/module/i18n/locale/en_US.js b/dolphinscheduler-ui/src/js/module/i18n/locale/en_US.js
index 819af7c..53a40af 100755
--- a/dolphinscheduler-ui/src/js/module/i18n/locale/en_US.js
+++ b/dolphinscheduler-ui/src/js/module/i18n/locale/en_US.js
@@ -138,6 +138,7 @@ export default {
   'jdbc connect parameters': 'jdbc connect parameters',
   'Test Connect': 'Test Connect',
   'Please enter resource name': 'Please enter resource name',
+  'Please enter resource folder name': 'Please enter resource folder name',
   'Please enter a non-query SQL statement': 'Please enter a non-query SQL statement',
   'Please enter IP/hostname': 'Please enter IP/hostname',
   'jdbc connection parameters is not a correct JSON format': 'jdbc connection parameters is not a correct JSON format',
@@ -183,6 +184,8 @@ export default {
   'Authorize': 'Authorize',
   'File resources': 'File resources',
   'UDF resources': 'UDF resources',
+  'Please select UDF resources directory': 'Please select UDF resources directory',
+  'UDF resources directory' : 'UDF resources directory',
   'Upload File Size': 'Upload File size cannot exceed 1g',
   'Edit alarm group': 'Edit alarm group',
   'Create alarm group': 'Create alarm group',
@@ -226,8 +229,11 @@ export default {
   'execution': 'execution',
   'finish': 'finish',
   'Create File': 'Create File',
+  'Create folder': 'Create folder',
   'File Name': 'File Name',
+  'Folder Name': 'Folder Name',
   'File Format': 'File Format',
+  'Folder Format': 'Folder Format',
   'File Content': 'File Content',
   'Create': 'Create',
   'Please enter the resource content': 'Please enter the resource content',
@@ -274,6 +280,9 @@ export default {
   'Edit UDF Function': 'Edit UDF Function',
   'type': 'type',
   'UDF Function Name': 'UDF Function Name',
+  'FILE': 'FILE',
+  'UDF': 'UDF',
+  'File Subdirectory': 'File Subdirectory',
   'Please enter a function name': 'Please enter a function name',
   'Package Name': 'Package Name',
   'Please enter a Package name': 'Please enter a Package name',
@@ -523,6 +532,10 @@ export default {
   '0 means unlimited by byte': '0 means unlimited',
   '0 means unlimited by count': '0 means unlimited',
   'Modify User': 'Modify User',
+  'Whether directory': 'Whether directory',
+  'Yes': 'Yes',
+  'No': 'No',
+  'Modify User': 'Modify User',
   'Please enter Mysql Database(required)': 'Please enter Mysql Database(required)',
   'Please enter Mysql Table(required)': 'Please enter Mysql Table(required)',
   'Please enter Columns (Comma separated)': 'Please enter Columns (Comma separated)',
diff --git a/dolphinscheduler-ui/src/js/module/i18n/locale/zh_CN.js b/dolphinscheduler-ui/src/js/module/i18n/locale/zh_CN.js
index fe67bae..9b78f36 100755
--- a/dolphinscheduler-ui/src/js/module/i18n/locale/zh_CN.js
+++ b/dolphinscheduler-ui/src/js/module/i18n/locale/zh_CN.js
@@ -120,6 +120,9 @@ export default {
   'SQL Parameter': 'sql参数',
   'SQL Statement': 'sql语句',
   'UDF Function': 'UDF函数',
+  'FILE': '文件',
+  'UDF': 'UDF',
+  'File Subdirectory': '文件子目录',
   'Please enter a SQL Statement(required)': '请输入sql语句(必填)',
   'Please enter a JSON Statement(required)': '请输入json语句(必填)',
   'One form or attachment must be selected': '表格、附件必须勾选一个',
@@ -139,6 +142,7 @@ export default {
   'jdbc connect parameters': 'jdbc连接参数',
   'Test Connect': '测试连接',
   'Please enter resource name': '请输入数据源名称',
+  'Please enter resource folder name': '请输入资源文件夹名称',
   'Please enter a non-query SQL statement': '请输入非查询sql语句',
   'Please enter IP/hostname': '请输入IP/主机名',
   'jdbc connection parameters is not a correct JSON format': 'jdbc连接参数不是一个正确的JSON格式',
@@ -182,6 +186,8 @@ export default {
   'Authorize': '授权',
   'File resources': '文件资源',
   'UDF resources': 'UDF资源',
+  'UDF resources directory': 'UDF资源目录',
+  'Please select UDF resources directory': '请选择UDF资源目录',
   'Edit alarm group': '编辑告警组',
   'Create alarm group': '创建告警组',
   'Group Name': '组名称',
@@ -224,8 +230,11 @@ export default {
   'execution': '执行中',
   'finish': '完成',
   'Create File': '创建文件',
+  'Create folder': '创建文件夹',
   'File Name': '文件名称',
+  'Folder Name': '文件夹名称',
   'File Format': '文件格式',
+  'Folder Format': '文件夹格式',
   'File Content': '文件内容',
   'Upload File Size': '文件大小不能超过1G',
   'Create': '创建',
@@ -523,6 +532,10 @@ export default {
   '0 means unlimited by byte': 'KB,0代表不限制',
   '0 means unlimited by count': '0代表不限制',
   'Modify User': '修改用户',
+  'Whether directory' : '是否文件夹',
+  'Yes': '是',
+  'No': '否',
+  'Modify User': '修改用户',
   'Please enter Mysql Database(required)': '请输入Mysql数据库(必填)',
   'Please enter Mysql Table(required)': '请输入Mysql表名(必填)',
   'Please enter Columns (Comma separated)': '请输入列名,用 , 隔开',
diff --git a/dolphinscheduler-ui/src/js/module/util/routerUtil.js b/dolphinscheduler-ui/src/js/module/util/routerUtil.js
index 7ae91f0..c19a8e7 100644
--- a/dolphinscheduler-ui/src/js/module/util/routerUtil.js
+++ b/dolphinscheduler-ui/src/js/module/util/routerUtil.js
@@ -19,7 +19,7 @@ import merge from 'webpack-merge'
 import router from '@/conf/home/router'
 
 export function setUrlParams (o) {
-  router.push({
-    query: merge(router.history.current.query, o)
-  })
+  // router.push({
+  //   query: merge(router.history.current.query, o)
+  // })
 }
diff --git a/dolphinscheduler-ui/src/sass/common/_mixin.scss b/dolphinscheduler-ui/src/sass/common/_mixin.scss
deleted file mode 100644
index c6a5afe..0000000
--- a/dolphinscheduler-ui/src/sass/common/_mixin.scss
+++ /dev/null
@@ -1,16 +0,0 @@
-/*
- * 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.
- */
\ No newline at end of file
diff --git a/dolphinscheduler-ui/src/sass/common/index.scss b/dolphinscheduler-ui/src/sass/common/index.scss
index 403f3c6..8e47b03 100644
--- a/dolphinscheduler-ui/src/sass/common/index.scss
+++ b/dolphinscheduler-ui/src/sass/common/index.scss
@@ -14,8 +14,6 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
-@import "mixin";
 @import "animation";
 @import "scrollbar";
 @import "table";