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

xxyu pushed a commit to branch kylin5
in repository https://gitbox.apache.org/repos/asf/kylin.git

commit 2878bb8279c6d5c9e7614ff461ddc6f67c3386c2
Author: Qian Xia <lauraxiaq...@gmail.com>
AuthorDate: Mon Jun 5 17:54:59 2023 +0800

    KYLIN-5543 support ddl
---
 .../src/components/common/DataSourceBar/index.vue  |  48 ++-
 .../src/components/common/DataSourceBar/locales.js |   5 +-
 .../components/layout/layout_left_right_top.vue    |  17 +-
 kystudio/src/components/studio/DDL/ddl.vue         | 377 +++++++++++++++++++++
 .../src/components/studio/StudioSource/index.vue   |   1 +
 kystudio/src/config/index.js                       |   3 +-
 kystudio/src/config/spec.js                        |  14 +-
 kystudio/src/locale/en.js                          |   2 +
 kystudio/src/router/index.js                       |   4 +
 kystudio/src/service/datasource.js                 |   6 +
 kystudio/src/store/datasource.js                   |   8 +
 kystudio/src/store/system.js                       |   4 +-
 kystudio/src/store/types.js                        |   3 +
 13 files changed, 466 insertions(+), 26 deletions(-)

diff --git a/kystudio/src/components/common/DataSourceBar/index.vue 
b/kystudio/src/components/common/DataSourceBar/index.vue
index 5c5b7c482e..bd5b8c11d5 100644
--- a/kystudio/src/components/common/DataSourceBar/index.vue
+++ b/kystudio/src/components/common/DataSourceBar/index.vue
@@ -1,21 +1,32 @@
 <template>
 <div style="height: 100%;" class="clearfix">
   <aside class="data-source-bar" :style="dataSourceStyle">
-    <section class="header clearfix" v-if="isShowActionGroup && !hideBarTitle">
+    <section class="header" v-if="isShowActionGroup && !hideBarTitle">
       <div class="header-text ksd-title-module">
-        <span>{{$t('kylinLang.common.dataSource')}}</span>
+        <span>{{$t('kylinLang.common.dataSourceTable')}}</span>
       </div>
-      <div class="icon-btns clearfix">
+      <div class="icon-btns">
         <!-- <div :class="['header-icons', 'clearfix', {selected: 
isSwitchSource}]" v-if="isShowSourceSwitch">
           <el-tooltip :content="$t('sourceManagement')" effect="dark" 
placement="top">
             <i class="ksd-fs-14 el-icon-ksd-setting" 
@click="handleSwitchSource"></i>
           </el-tooltip>
         </div> -->
-        <div class="add-source-table-icon" v-if="isShowLoadTable">
+        <!-- <div class="add-source-table-icon" v-if="isShowLoadTable">
           <el-tooltip :content="$t('addDatasource')" effect="dark" 
placement="top">
             <i class="ksd-fs-14 el-icon-ksd-project_add"  
@click="importDataSource('selectSource', currentProjectData)"></i>
           </el-tooltip>
-        </div>
+        </div> -->
+        <el-dropdown @command="addDataSource">
+          <el-button text type="primary" icon-button-mini 
icon="el-ksd-n-icon-plus-outlined"></el-button>
+          <el-dropdown-menu slot="dropdown">
+            <el-dropdown-item command="default" 
:disabled="!isShowLoadTable">{{$t('importFromDatasource')}}</el-dropdown-item>
+            <!-- <el-tooltip effect="dark" placement="top" 
:disabled="!hasSecData || hasOrderbyOrSkipIndex('orderBy', 'current')">
+              <span slot="content">{{$t('disableAddOrderByIndexTip')}}<a 
href="javascript:void(0)" 
@click="$emit('jumpToSegment')">{{$t('goToDelete')}}</a></span>
+              <span><el-dropdown-item command="orderBy" :disabled="hasSecData 
|| hasOrderbyOrSkipIndex('orderBy', 
'current')">{{$t('orderByIndex')}}</el-dropdown-item></span>
+            </el-tooltip> -->
+            <el-dropdown-item command="ddl" v-if="$store.state.config.platform 
!== 'iframe' && datasourceActions.includes('ddl') && showDDL && 
$store.state.system.ddlEnabled === 'true'">{{$t('createByDDL')}} <el-tooltip 
effect="dark" :content="$t('createDDLTip')" placement="bottom"><i 
class="info-icon 
el-ksd-n-icon-info-circle-filled"></i></el-tooltip></el-dropdown-item>
+          </el-dropdown-menu>
+        </el-dropdown>
       </div>
     </section>
     <section class="body">
@@ -173,6 +184,10 @@ import { handleSuccessAsync, handleError, objectClone } 
from '../../../util'
     isSecondStorageEnabled: {
       type: Boolean,
       default: false
+    },
+    showDDL: {
+      type: Boolean,
+      default: false
     }
   },
   components: {
@@ -182,7 +197,8 @@ import { handleSuccessAsync, handleError, objectClone } 
from '../../../util'
     ...mapGetters([
       'isAdminRole',
       'isProjectAdmin',
-      'currentProjectData'
+      'currentProjectData',
+      'datasourceActions'
     ])
   },
   methods: {
@@ -330,6 +346,16 @@ export default class DataSourceBar extends Vue {
   hideLoading (data) {
     data.isLoading = false
   }
+  addDataSource (command) {
+    switch (command) {
+      case 'default':
+        this.importDataSource('selectSource', this.currentProjectData)
+        break
+      case 'ddl':
+        this.$router.push('/studio/ddl')
+        break
+    }
+  }
   async initTree () {
     try {
       this.isSearchIng = false
@@ -476,7 +502,7 @@ export default class DataSourceBar extends Vue {
       !isNotResetDefaultExpandedKeys && this.resetDefaultExpandedKeys()
       this.filterText = filterText
       freshTreeOrder(this)
-      this.selectFirstTable()
+      // this.selectFirstTable()
       resolve()
     })
   }
@@ -729,12 +755,13 @@ export default class DataSourceBar extends Vue {
     padding: 24px 16px 16px 16px;
     font-size: 16px;
     color: @text-title-color;
+    display: flex;
+    justify-content: space-between;
   }
   .body {
     padding: 0px 16px 16px;
   }
   .header-text {
-    float: left;
     span {
       line-height: 20px;
     }
@@ -742,7 +769,7 @@ export default class DataSourceBar extends Vue {
   .icon-btns {
     position: relative;
     height: 22px;
-    top: 2px;
+    // top: 2px;
   }
   .header-icons {
     float: right;
@@ -959,4 +986,7 @@ export default class DataSourceBar extends Vue {
     left: 0;
   }
 }
+.info-icon {
+  color: @text-placeholder-color;
+}
 </style>
diff --git a/kystudio/src/components/common/DataSourceBar/locales.js 
b/kystudio/src/components/common/DataSourceBar/locales.js
index 01ca76d98c..6429a88f26 100644
--- a/kystudio/src/components/common/DataSourceBar/locales.js
+++ b/kystudio/src/components/common/DataSourceBar/locales.js
@@ -19,6 +19,9 @@ export default {
     databases: 'Database',
     tables: 'Table',
     cloudHive: 'Object Storage',
-    factTable: 'Fact Table'
+    factTable: 'Fact Table',
+    importFromDatasource: 'Import from Data Source',
+    createByDDL: 'DDL Create',
+    createDDLTip: 'Data Definition Language Create Table'
   }
 }
diff --git a/kystudio/src/components/layout/layout_left_right_top.vue 
b/kystudio/src/components/layout/layout_left_right_top.vue
index 63dbeff82d..d07f7bfa81 100644
--- a/kystudio/src/components/layout/layout_left_right_top.vue
+++ b/kystudio/src/components/layout/layout_left_right_top.vue
@@ -329,15 +329,16 @@ export default class LayoutLeftRightTop extends Vue {
     }
   }
   showMenuByRole (menuName) {
-    let isShowSnapshot = true
-    let isShowStreamingJob = true
-    if (menuName === 'snapshot') {
-      isShowSnapshot = 
this.$store.state.project.snapshot_manual_management_enabled
+    switch (menuName) {
+      case 'snapshot':
+        return this.availableMenus.includes(menuName.toLowerCase()) && 
this.$store.state.project.snapshot_manual_management_enabled
+      case 'streamingjob':
+        return this.availableMenus.includes(menuName.toLowerCase()) && 
this.$store.state.system.streamingEnabled === 'true'
+      case 'ddl':
+        return this.availableMenus.includes(menuName.toLowerCase()) && 
this.$store.state.system.ddlEnabled === 'true'
+      default:
+        return this.availableMenus.includes(menuName.toLowerCase())
     }
-    if (menuName === 'streamingjob') {
-      isShowStreamingJob = this.$store.state.system.streamingEnabled === 'true'
-    }
-    return this.availableMenus.includes(menuName.toLowerCase()) && 
isShowSnapshot && isShowStreamingJob
   }
   defaultVal (obj) {
     if (!obj) {
diff --git a/kystudio/src/components/studio/DDL/ddl.vue 
b/kystudio/src/components/studio/DDL/ddl.vue
new file mode 100644
index 0000000000..40dfb12078
--- /dev/null
+++ b/kystudio/src/components/studio/DDL/ddl.vue
@@ -0,0 +1,377 @@
+<template>
+    <div class="ddl-container">
+      <div class="left-layout">
+        <div class="header">
+          <span class="title">{{$t('newDDLTable')}}</span>
+        </div>
+        <el-alert type="warning" show-icon v-if="showCreateSuccessAlert"><span 
slot="title">{{$t('createViewSuccessAlert')}} <a class="import-link" 
href="javascript:void(0);" 
@click="importDataSource">{{$t('goToImport')}}</a></span></el-alert>
+        <div class="editor-content">
+          <editor class="ddl-editor" v-model="content" ref="ddlEditor" 
lang="sql" theme="chrome" @keydown.meta.enter.native="runSql" 
@keydown.ctrl.enter.native="runSql"></editor>
+          <div class="run-btn">
+            <el-tooltip effect="dark" placement="left">
+              <div slot="content">{{$t('runBtnTip')}}<span 
class="accelerator-key">⌃/⌘ enter</span></div>
+              <el-button :loading="running" type="primary" icon-button 
size="big" icon="el-ksd-n-icon-play-filled" @click="runSql"></el-button>
+            </el-tooltip>
+          </div>
+        </div>
+      </div>
+      <div :class="['right-layout', {'expand': !!activeType}]">
+        <div class="action-btns">
+          <el-tooltip :content="$t('datasourceTable')" effect="dark" 
placement="left">
+            <el-badge is-dot class="sign-item" :hidden="true">
+              <el-button :class="{'is-active': activeType === 'database'}" 
text type="primary" icon-button-mini icon="icon 
el-ksd-n-icon-node-database-filled" @click="activeType = 
'database'"></el-button>
+            </el-badge>
+          </el-tooltip>
+          <el-tooltip :content="$t('syntaxRules')" effect="dark" 
placement="left">
+            <el-badge is-dot class="sign-item" :hidden="!ddlError">
+              <el-button :class="{'is-active': activeType === 'result'}" text 
type="primary" icon-button-mini icon="icon el-ksd-n-icon-node-thunder-filled" 
@click="activeType = 'result'"></el-button>
+            </el-badge>
+          </el-tooltip>
+        </div>
+        <div class="panel-content-layout">
+          <div class="panel-header" v-if="activeType">
+            <span class="title">{{activeType === 'database' ? 
$t('datasourceTable') : $t('syntaxRules')}}</span>
+            <i class="el-ksd-n-icon-close-L-outlined close-btn" 
@click="activeType = ''"></i>
+          </div>
+          <div class="datasource-layout" v-show="activeType === 'database'">
+            <data-source-bar
+              ref="ddlDataSource"
+              class="data-source-layout"
+              :project-name="currentSelectedProject"
+              :is-show-action-group="false"
+              :is-show-load-source="false"
+              :is-show-load-table="datasourceActions.includes('loadSource') && 
$store.state.config.platform !== 'iframe'"
+              :is-expand-on-click-node="false"
+              :is-show-drag-width-bar="true"
+              :default-width="240"
+              :expand-node-types="['datasource', 'database']"
+              :hide-bar-title="$store.state.config.platform === 'iframe'"
+              :custom-tree-title="$store.state.config.platform !== 'iframe' ? 
'' : 'kylinLang.common.dataDirectory'"
+              @autoComplete="handleAutoComplete"
+              @click="clickTable">
+            </data-source-bar>
+          </div>
+          <div class="import-btn" v-if="activeType === 'database'"><el-button 
@click="importDataSource" type="primary" size="big" 
icon="el-ksd-n-icon-inport-outlined">{{$t('importDataSource')}}</el-button></div>
+          <template v-if="activeType === 'result'">
+            <div class="feedback-suggestions">
+              <div class="suggestion-list">
+                <div class="label">{{$t('createDDLSuggestionTitle')}}</div>
+                <el-alert v-if="errorMsg" class="ksd-mb-16" :title="errorMsg" 
type="error" show-icon :closable="false"></el-alert>
+                <div v-if="stacktrace" class="trance-msg">{{stacktrace}}</div>
+                <div class="item" v-for="(item, index) in ($lang === 'en' ? 
rules[0] : rules[1])" :key="index">{{index + 1}}. {{item}}</div>
+              </div>
+            </div>
+          </template>
+        </div>
+      </div>
+    </div>
+  </template>
+  <script>
+  import { Component, Vue } from 'vue-property-decorator'
+  import { mapActions, mapGetters } from 'vuex'
+  import DataSourceBar from '../../common/DataSourceBar'
+  import { insightKeyword } from '../../../config'
+  import { handleSuccessAsync, handleError } from '../../../util'
+  @Component({
+    computed: {
+      ...mapGetters([
+        'currentSelectedProject',
+        'datasourceActions',
+        'currentProjectData'
+      ])
+    },
+    methods: {
+      ...mapActions({
+        getDDLDescription: 'DDL_DESCRIPTION',
+        runDDL: 'RUN_DDL'
+      })
+    },
+    components: {
+      DataSourceBar
+    },
+    locales: {
+      en: {
+        newDDLTable: 'New DDL Table',
+        datasourceTable: 'Data Source Table',
+        syntaxRules: 'Syntax Rules',
+        createDDLSuggestionTitle: '在 KE 中创建 DDL Table 需要遵循 KE 的语法规则。',
+        importDataSource: 'Import',
+        runBtnTip: '执行 ',
+        runSuccess: 'Dexecute succeed.',
+        runFailed: 'Execute Failed,Please check and try again.',
+        createViewSuccessAlert: 'The DDL Table is created to hive after 
executing "Create View". Please importing the table to data source to be 
available.',
+        goToImport: 'Go to Import'
+      },
+      'zh-cn': {
+        newDDLTable: '新的 DDL 表',
+        datasourceTable: '数据源表',
+        syntaxRules: '语法规则',
+        createDDLSuggestionTitle: '在 KE 中创建 DDL Table 需要遵循 KE 的语法规则。',
+        importDataSource: '导入',
+        runBtnTip: 'Dexecute ',
+        runSuccess: '执行成功',
+        runFailed: '执行失败,请检查后重试',
+        createViewSuccessAlert: '“Create View” 执行后 DDL Table 创建至 
Hive,需从数据源导入后可用。',
+        goToImport: '立即导入'
+      }
+    }
+  })
+  export default class DDL extends Vue {
+    content = ''
+    activeType = ''
+    rules = []
+    ddlError = false
+    errorMsg = ''
+    stacktrace = ''
+    running = false
+    showCreateSuccessAlert = false
+    setOption (option) {
+      let editor = this.$refs.ddlEditor.editor
+      editor.setOptions(Object.assign({
+        wrap: 'free',
+        enableBasicAutocompletion: true,
+        enableSnippets: true,
+        enableLiveAutocompletion: true
+      }, option))
+    }
+    handleAutoComplete (data) {
+      this.completeData = [...data, ...insightKeyword]
+    }
+    clickTable (leaf) {
+      this.$nextTick(() => {
+        if (leaf) {
+          this.insertEditorContent(leaf.label)
+        }
+      })
+    }
+    importDataSource () {
+      this.$refs.ddlDataSource && 
this.$refs.ddlDataSource.importDataSource('selectSource', 
this.currentProjectData)
+    }
+    insertEditorContent (data) {
+      const editor = this.$refs.ddlEditor.editor
+      editor.focus()
+      editor.insert(data)
+      this.content = editor.getValue()
+    }
+    async runSql () {
+      try {
+        this.ddlError = false
+        this.running = true
+        const res = await this.runDDL({
+          sql: this.content,
+          project: this.currentSelectedProject
+        })
+        const resultData = await handleSuccessAsync(res)
+        this.running = false
+        this.showCreateSuccessAlert = 
this.content.toLocaleLowerCase().indexOf('create view') > -1
+        this.showCreateSuccessAlert && 
this.insertEditorContent(`\n\n${resultData}`)
+        this.resetErrorMsg()
+        this.$message({ type: 'success', message: this.$t('runSuccess') })
+      } catch (e) {
+        const err = e.body
+        this.ddlError = true
+        this.errorMsg = err.msg
+        this.stacktrace = err.stacktrace
+        this.activeType = 'result'
+        this.running = false
+        this.showCreateSuccessAlert = false
+        this.$message({ type: 'error', message: this.$t('runFailed') })
+        // handleError(e)
+      }
+    }
+    resetErrorMsg () {
+      this.errorMsg = ''
+      this.stacktrace = ''
+    }
+    async getDDLRules () {
+      try {
+        const result = await this.getDDLDescription({project: 
this.currentSelectedProject, page_type: 'hive'})
+        const rules = await handleSuccessAsync(result)
+        this.rules = rules
+      } catch (e) {
+        handleError(e)
+      }
+    }
+    created () {
+      this.getDDLRules()
+    }
+    mounted () {
+      this.setOption()
+    }
+  }
+  </script>
+  
+  <style lang="less" scoped>
+  .ddl-container {
+    width: 100%;
+    height: 100%;
+    display: flex;
+    .left-layout {
+      flex: 1;
+      display: flex;
+      flex-direction: column;
+      .editor-content {
+        flex: 1;
+        position: relative;
+        .run-btn {
+          width: 40px;
+          height: 38px;
+          position: absolute;
+          right: 16px;
+          bottom: 16px;
+        }
+      }
+      .import-link {
+        color: #1268FB;
+      }
+    }
+    .right-layout {
+      width: 46px;
+      transition: width .5s;
+      display: flex;
+      &.expand {
+        width: 330px;
+      }
+      .sign-item {
+        .is-dot {
+          right: 7px;
+          margin-top: 2px;
+        }
+      }
+      .action-btns {
+        width: 46px;
+        height: 100%;
+        display: flex;
+        flex-direction: column;
+        align-items: center;
+        gap: 8px;
+        border-left: 1px solid #E6EBF4;
+        padding: 8px 8px;
+        box-sizing: border-box;
+        .el-button {
+          color: #8B99AE;
+          &.is-active {
+            background: #ECF0F8 !important;
+          }
+        }
+      }
+      .feedback-suggestions {
+        padding: 16px 8px;
+        box-sizing: border-box;
+        .suggestion-list {
+          .label {
+            font-size: 14px;
+            font-weight: 400;
+            color: #8B99AE;
+            line-height: 22px;
+            margin-bottom: 16px;
+          }
+          .item {
+            font-size: 14px;
+            color: #2F374C;
+            line-height: 22px;
+          }
+          .trance-msg {
+            height: 270px;
+            overflow: auto;
+            background: #F8F9FB;
+            border: 1px solid #E6EBF4;
+            border-radius: 4px;
+            margin-bottom: 16px;
+            padding: 8px 16px;
+            box-sizing: border-box;
+            word-break: break-word;
+          }
+        }
+      }
+      .panel-content-layout {
+        height: 100%;
+        width: 284px;
+        flex: 1;
+        display: flex;
+        flex-direction: column;
+        .panel-header {
+          height: 60px;
+          padding: 0 8px;
+          box-sizing: border-box;
+          position: relative;
+          .title {
+            line-height: 60px;
+            font-weight: 600;
+            font-size: 16px;
+          }
+          .close-btn {
+            position: absolute;
+            line-height: 60px;
+            right: 25px;
+            cursor: pointer;
+          }
+        }
+        .datasource-layout {
+          flex: 1;
+          height: 0;
+        }
+        .data-source-layout {
+          overflow: hidden;
+        }
+        .import-btn {
+          height: 70px;
+          padding: 16px;
+          box-sizing: border-box;
+          .el-button {
+            width: 100%;
+          }
+        }
+      }
+    }
+    .header {
+      height: 60px;
+      display: flex;
+      align-items: center;
+      padding: 0 16px;
+      box-sizing: border-box;
+      border-bottom: 1px solid #E6EBF4;
+      .title {
+        font-weight: 600;
+        font-size: 16px;
+      }
+    }
+  }
+  </style>
+  <style lang="less">
+  .ddl-editor {
+    .ace_content {
+      width: 100% !important;
+    }
+    .ace_print-margin {
+      visibility: hidden !important;
+    }
+  }
+  .panel-content-layout {
+    .data-source-bar {
+      width: 100% !important;
+      height: 100%;
+      .body {
+        width: 100%;
+        height: 100%;
+        padding: 0;
+        .el-tree {
+          border: 0;
+        }
+      }
+      .el-input__inner {
+        border: 0;
+        box-shadow: none;
+      }
+    }
+  }
+  .sign-item {
+    .el-badge__content.is-fixed.is-dot {
+      right: 7px;
+      margin-top: 2px;
+    }
+  }
+  .accelerator-key {
+    color: #8B99AE;
+  }
+  </style>
diff --git a/kystudio/src/components/studio/StudioSource/index.vue 
b/kystudio/src/components/studio/StudioSource/index.vue
index ad9ef9f008..7aa6d0fbf5 100644
--- a/kystudio/src/components/studio/StudioSource/index.vue
+++ b/kystudio/src/components/studio/StudioSource/index.vue
@@ -6,6 +6,7 @@
         <DataSourceBar
           :ignore-node-types="['column']"
           ref="datasource-bar"
+          :showDDL="true"
           :project-name="currentSelectedProject"
           :is-show-load-source="true"
           :is-show-load-table="datasourceActions.includes('loadSource')"
diff --git a/kystudio/src/config/index.js b/kystudio/src/config/index.js
index 1c9e1da646..b8ecc8af02 100644
--- a/kystudio/src/config/index.js
+++ b/kystudio/src/config/index.js
@@ -57,7 +57,8 @@ export const menusData = [
     children: [
       { name: 'source', path: '/studio/source' },
       { name: 'modelList', path: '/studio/model' },
-      { name: 'snapshot', path: '/studio/snapshot' }
+      { name: 'snapshot', path: '/studio/snapshot' },
+      { name: 'ddl', path: '/studio/ddl' }
     ]
   },
   {
diff --git a/kystudio/src/config/spec.js b/kystudio/src/config/spec.js
index 1227a5b5ed..236d4d168e 100644
--- a/kystudio/src/config/spec.js
+++ b/kystudio/src/config/spec.js
@@ -18,6 +18,7 @@ export default {
       { "id": "modelDetails", "value": "modeldetails", "title": "Model 
Details" },
       { "id": "modelSubPartitionValues", "value": "modelsubpartitionvalues", 
"title": "Model SubPartition Values" },
       { "id": "snapshot", "value": "snapshot", "title": "Snapshot" },
+      { "id": "ddl", "value": "ddl", "title": "DDL" },
       { "id": "monitor", "value": "monitor", "title": "Monitor" },
       { "id": "job", "value": "job", "title": "Job" },
       { "id": "streamingJob", "value": "streamingjob", "title": "streamingJob" 
},
@@ -76,7 +77,8 @@ export default {
       { "id": "tableIndexActions" },
       { "id": "viewDataSource" },
       { "id": "changeBuildType" },
-      { "id": "changePartition" }
+      { "id": "changePartition" },
+      { "id": "ddl" }
     ],
     "modelActions": [
       { "id": "dataLoad" },
@@ -150,12 +152,12 @@ export default {
       "keyPattern": "groupRole-projectRole-menu",
       "entries": [
         { "key": 
"systemAdmin-*-[project,user,group,groupDetail,projectAuthority,diagnostic]", 
"value": "admin,project,user,group,groupDetail,diagnostic,projectAuthority" },
-        { "key": 
"systemAdmin-*-[dashboard,query,insight,queryHistory,studio,setting,source,model,index,modelEdit,modelDetails,modelSubPartitionValues,snapshot,monitor,job,streamingJob]",
 "value": 
"dashboard,query,insight,queryHistory,studio,setting,source,model,index,modelEdit,modelDetails,modelSubPartitionValues,snapshot,monitor,job,streamingJob,admin"
 },
+        { "key": 
"systemAdmin-*-[dashboard,query,insight,queryHistory,studio,setting,source,model,index,modelEdit,modelDetails,modelSubPartitionValues,snapshot,ddl,monitor,job,streamingJob]",
 "value": 
"dashboard,query,insight,queryHistory,studio,setting,source,model,index,modelEdit,modelDetails,modelSubPartitionValues,snapshot,ddl,monitor,job,streamingJob,admin"
 },
         { "key": 
"systemUser-admin-[project,user,group,groupDetail,projectAuthority]", "value": 
"project,admin,projectAuthority" },
-        { "key": 
"systemUser-admin-[dashboard,query,insight,queryHistory,studio,setting,source,model,index,modelEdit,modelDetails,modelSubPartitionValues,snapshot,monitor,job,streamingJob]",
 "value": 
"dashboard,query,insight,queryHistory,studio,setting,source,model,index,modelEdit,modelDetails,modelSubPartitionValues,snapshot,monitor,job,streamingJob,admin"
 },
-        { "key": "systemUser-management-*", "value": 
"dashboard,query,insight,queryHistory,studio,source,model,index,modelEdit,modelDetails,modelSubPartitionValues,snapshot,monitor,job,streamingJob"
 },
-        { "key": "systemUser-operation-*", "value": 
"dashboard,query,insight,queryHistory,studio,model,modelDetails,snapshot,index,monitor,job,streamingJob,modelSubPartitionValues"
 },
-        { "key": "systemUser-read-*", "value": 
"dashboard,query,insight,queryHistory,studio,model,modelDetails,snapshot,index" 
},
+        { "key": 
"systemUser-admin-[dashboard,query,insight,queryHistory,studio,setting,source,model,index,modelEdit,modelDetails,modelSubPartitionValues,snapshot,ddl,monitor,job,streamingJob]",
 "value": 
"dashboard,query,insight,queryHistory,studio,setting,source,model,index,modelEdit,modelDetails,modelSubPartitionValues,snapshot,ddl,monitor,job,streamingJob,admin"
 },
+        { "key": "systemUser-management-*", "value": 
"dashboard,query,insight,queryHistory,studio,source,model,index,modelEdit,modelDetails,modelSubPartitionValues,snapshot,ddl,monitor,job,streamingJob"
 },
+        { "key": "systemUser-operation-*", "value": 
"dashboard,query,insight,queryHistory,studio,model,modelDetails,snapshot,ddl,index,monitor,job,streamingJob,modelSubPartitionValues"
 },
+        { "key": "systemUser-read-*", "value": 
"dashboard,query,insight,queryHistory,studio,model,modelDetails,snapshot,ddl,index"
 },
         { "key": "systemUser-default-*", "value": "dashboard" }
       ]
     },
diff --git a/kystudio/src/locale/en.js b/kystudio/src/locale/en.js
index fa9d97ad4c..22357326e7 100644
--- a/kystudio/src/locale/en.js
+++ b/kystudio/src/locale/en.js
@@ -68,6 +68,7 @@ exports.default = {
     jobs: 'Jobs',
     cubes: 'Cubes',
     dataSource: 'Data Source',
+    dataSourceTable: 'Data Source Table',
     fact: 'Fact Table',
     limitfact: 'Lookup Table(limited)',
     lookup: 'Lookup Table',
@@ -490,6 +491,7 @@ exports.default = {
     index: 'Index',
     modeledit: 'Model Edit',
     snapshot: 'Snapshot',
+    ddl: 'DDL',
     refresh: 'Refresh',
     systemcapacity: 'Capacity'
   },
diff --git a/kystudio/src/router/index.js b/kystudio/src/router/index.js
index b0b6b3c545..4c75e0a7e7 100644
--- a/kystudio/src/router/index.js
+++ b/kystudio/src/router/index.js
@@ -80,6 +80,10 @@ let routerOptions = {
         name: 'Snapshot',
         path: 'studio/snapshot',
         component: () => import('../components/studio/snapshot/snapshot.vue')
+      }, {
+        name: 'DDL',
+        path: 'studio/ddl',
+        component: () => import('../components/studio/DDL/ddl.vue')
       }, {
         name: 'Project',
         path: 'admin/project',
diff --git a/kystudio/src/service/datasource.js 
b/kystudio/src/service/datasource.js
index e70b0d67b0..7e00128f44 100644
--- a/kystudio/src/service/datasource.js
+++ b/kystudio/src/service/datasource.js
@@ -315,5 +315,11 @@ export default {
   },
   exportCSV (data) {
     return Vue.http.post(apiUrl + 'query/format/csv', data, {emulateJSON: 
true})
+  },
+  getDDLDescrition (data) {
+    return Vue.resource(apiUrl + 'spark_source/ddl/description').get(data)
+  },
+  runDDL (data) {
+    return Vue.resource(apiUrl + 'spark_source/ddl').save(data)
   }
 }
diff --git a/kystudio/src/store/datasource.js b/kystudio/src/store/datasource.js
index 199d27154d..ac31bd3994 100644
--- a/kystudio/src/store/datasource.js
+++ b/kystudio/src/store/datasource.js
@@ -394,6 +394,14 @@ export default {
     },
     [types.EXPORT_CSV]: function ({commit}, data) {
       return api.datasource.exportCSV(data)
+    },
+    // 获取 ddl 规则
+    [types.DDL_DESCRIPTION]: function (_, data) {
+      return api.datasource.getDDLDescrition(data)
+    },
+    // 执行 ddl 语句
+    [types.RUN_DDL]: function (_, data) {
+      return api.datasource.runDDL(data)
     }
   }
 }
diff --git a/kystudio/src/store/system.js b/kystudio/src/store/system.js
index b662f17c36..7607926d28 100644
--- a/kystudio/src/store/system.js
+++ b/kystudio/src/store/system.js
@@ -59,7 +59,8 @@ export default {
     isShowSecondStorage: false,
     isNonAdminGenQueryDiagPackage: 'true',
     streamingEnabled: 'false',
-    storageQuery: 'true'
+    storageQuery: 'true',
+    ddlEnabled: 'false'
   },
   mutations: {
     [types.COLLECT_MESSAGE_DIRECTIVES]: (state, directive) => {
@@ -183,6 +184,7 @@ export default {
           commit(types.GET_CONF_BY_NAME, {name: 
'kylin.model.measure-name-check-enabled', key: 'enableCheckName', defaultValue: 
'true'})
           commit(types.GET_CONF_BY_NAME, {name: 'kylin.streaming.enabled', 
key: 'streamingEnabled', defaultValue: 'false'})
           commit(types.GET_CONF_BY_NAME, {name: 
'kylin.second-storage.query-metric-collect', key: 'storageQuery', defaultValue: 
'true'})
+          commit(types.GET_CONF_BY_NAME, {name: 'kylin.source.ddl.enabled', 
key: 'ddlEnabled', defaultValue: 'false'})
           resolve(response)
         }, () => {
           reject()
diff --git a/kystudio/src/store/types.js b/kystudio/src/store/types.js
index 29a4f333de..7ce238b2e7 100644
--- a/kystudio/src/store/types.js
+++ b/kystudio/src/store/types.js
@@ -180,6 +180,9 @@ export const SUBMIT_ACCESS_DATA = 'SUBMIT_ACCESS_DATA'
 export const EXPORT_CSV = 'EXPORT_CSV'
 
 export const LOAD_DATASOURCE_OF_MODEL = 'LOAD_DATASOURCE_OF_MODEL'
+
+export const DDL_DESCRIPTION = 'DDL_DESCRIPTION'
+export const RUN_DDL = 'RUN_DDL'
 // acl table
 export const GET_ACL_SET_TABLE = 'GET_ACL_SET_TABLE'
 export const SAVE_ACL_SET_TABLE = 'SAVE_ACL_SET_TABLE'

Reply via email to