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 63fcd76885c4e333c433a911dbad1899d527ea9c Author: Qian Xia <lauraxiaq...@gmail.com> AuthorDate: Wed Jul 12 17:57:59 2023 +0800 KYLIN-5622 logic view issue --- .../src/components/common/DataSourceBar/handler.js | 29 ++++-- .../src/components/common/DataSourceBar/index.vue | 83 +++++++++++----- .../src/components/common/DataSourceBar/locales.js | 11 ++- .../components/layout/layout_left_right_top.vue | 2 + kystudio/src/components/studio/DDL/ddl.vue | 3 +- .../EditLogicalDialog/EditLogicalDialog.vue | 110 +++++++++++++++++++++ .../LogicalView/EditLogicalDialog/locales.js | 9 ++ .../studio/LogicalView/EditLogicalDialog/store.js | 41 ++++++++ .../{DDL/ddl.vue => LogicalView/LogicalView.vue} | 101 ++++++++++++++++--- kystudio/src/config/index.js | 9 +- kystudio/src/config/spec.js | 7 +- kystudio/src/locale/en.js | 1 + kystudio/src/router/index.js | 4 + kystudio/src/service/datasource.js | 3 + kystudio/src/store/datasource.js | 3 + kystudio/src/store/system.js | 12 ++- kystudio/src/store/types.js | 1 + 17 files changed, 369 insertions(+), 60 deletions(-) diff --git a/kystudio/src/components/common/DataSourceBar/handler.js b/kystudio/src/components/common/DataSourceBar/handler.js index 06aa9acef5..a6a70aa5aa 100644 --- a/kystudio/src/components/common/DataSourceBar/handler.js +++ b/kystudio/src/components/common/DataSourceBar/handler.js @@ -26,7 +26,7 @@ export const render = { }, table: { render (h, { node, data, store }) { - const { label, tags, dateRange, isTopSet } = data + const { label, tags, dateRange, isTopSet, datasource, isCurrentProLogicalTable } = data // datasource 为L 是逻辑视图表 const dataRangeTitle = this.$t('dataRange') const nodeClass = { class: [ @@ -40,14 +40,22 @@ export const render = { return ( <div> <div {...nodeClass}> - <span title={label}>{label}</span> + <span title={label} class={datasource === 'L' && !isCurrentProLogicalTable ? 'is-disabled' : ''}>{label}</span> <div class="right"> - <span class="tree-icon" slot="reference"> - <el-tooltip effect="dark" enterable={false} content={isTopSet ? this.$t('cancelTopSet') : this.$t('topSet')} placement="top"> - <i class="table-date-tip top" onClick={event => this.handleToggleTop(data, node, event)} - { ...{class: data.isTopSet ? ['el-icon-ksd-arrow_up_clean'] : ['el-icon-ksd-arrow_up']} }></i> - </el-tooltip> - </span> + { datasource === 'L' ? ( + <span class="tree-icon" slot="reference"> + <el-tooltip effect="dark" enterable={false} content={isCurrentProLogicalTable ? this.$t('editLogicalSql') : this.$t('disabledEditLogicalSql') } placement="top"> + <i class="table-date-tip top" onClick={event => this.edit(data, node, event)} + { ...{class: isCurrentProLogicalTable ? ['el-ksd-n-icon-edit-outlined'] : ['el-ksd-n-icon-edit-outlined', 'is-disabled']} }></i> + </el-tooltip> + </span> + ) : ( + <span class="tree-icon" slot="reference"> + <el-tooltip effect="dark" enterable={false} content={isTopSet ? this.$t('cancelTopSet') : this.$t('topSet')} placement="top"> + <i class="table-date-tip top" onClick={event => this.handleToggleTop(data, node, event)} + { ...{class: data.isTopSet ? ['el-icon-ksd-arrow_up_clean'] : ['el-icon-ksd-arrow_up']} }></i> + </el-tooltip> + </span>) } { dateRange ? ( <el-popover placement="right" @@ -123,7 +131,7 @@ export function getDatasourceObj (that, sourceType) { const sourceName = sourceTypes[sourceType] let sourceNameStr = 'kylin.source.jdbc.source.enable' in override_kylin_properties && override_kylin_properties['kylin.source.jdbc.source.enable'] === 'true' && override_kylin_properties['kylin.source.default'] === '8' ? override_kylin_properties['kylin.source.jdbc.source.name'] || sourceNameMapping[sourceName] - : sourceNameMapping[sourceName] + : that.$t(sourceNameMapping[sourceName]) return { id: sourceType, label: customTreeTitle !== '' ? `${that.$t(customTreeTitle)}` : `${that.$t('source')}${sourceNameStr}`, @@ -191,7 +199,7 @@ export function getTableObj (that, database, table, ignoreColumn) { const dateRangeStr = _getDateRangeStr(that, dataRange) const tableObj = { id: table.uuid, - label: table.name, + label: table.name || table.table_name, children: [], render: render.table.render.bind(that), tags, @@ -200,6 +208,7 @@ export function getTableObj (that, database, table, ignoreColumn) { datasource, isCentral: table.increment_loading, isTopSet: table.top, + isCurrentProLogicalTable: table.created_project === that.currentProjectData.name, // 逻辑视图表是否是当前项目的 isHideFactIcon: that.hideFactIcon, dateRange: dateRangeStr, isSelected: false, diff --git a/kystudio/src/components/common/DataSourceBar/index.vue b/kystudio/src/components/common/DataSourceBar/index.vue index bd5b8c11d5..afafea0360 100644 --- a/kystudio/src/components/common/DataSourceBar/index.vue +++ b/kystudio/src/components/common/DataSourceBar/index.vue @@ -31,7 +31,7 @@ </section> <section class="body"> <div v-if="isShowLoadTable" class="btn-group"> - <el-button plain size="medium" v-if="!isLoadingTreeData && showAddDatasourceBtn" type="primary" icon="el-ksd-icon-add_data_source_old" @click="importDataSource('selectSource', currentProjectData)"> + <el-button plain size="medium" v-if="!isLoadingTreeData && showAddDatasourceBtn && !isLogicalView" type="primary" v-guide.addDatasource icon="el-ksd-icon-add_data_source_old" @click="importDataSource('selectSource', currentProjectData)"> {{$t('addDatasource')}} </el-button> </div> @@ -188,6 +188,10 @@ import { handleSuccessAsync, handleError, objectClone } from '../../../util' showDDL: { type: Boolean, default: false + }, + isLogicalView: { + type: Boolean, + default: false } }, components: { @@ -198,7 +202,8 @@ import { handleSuccessAsync, handleError, objectClone } from '../../../util' 'isAdminRole', 'isProjectAdmin', 'currentProjectData', - 'datasourceActions' + 'datasourceActions', + 'logicalViewDatabaseName' ]) }, methods: { @@ -212,7 +217,8 @@ import { handleSuccessAsync, handleError, objectClone } from '../../../util' fetchDatabases: 'FETCH_DATABASES', fetchTables: 'FETCH_TABLES', updateTopTable: 'UPDATE_TOP_TABLE', - fetchDBandTables: 'FETCH_DB_AND_TABLES' + fetchDBandTables: 'FETCH_DB_AND_TABLES', + fetchLogicalViewTables: 'FETCH_LOGICAL_VIEW_TABLES' }), ...mapMutations({ cacheDatasource: 'CACHE_DATASOURCE' @@ -359,27 +365,42 @@ export default class DataSourceBar extends Vue { async initTree () { try { this.isSearchIng = false - // await this.loadDatasources() - // await this.loadDataBases() - // await this.loadTables({ isReset: true }) - // 有加载数据源的情况,才去加载db 和 table,否则就处理loading字段 - // if (this.datasources.length > 0) { - // await this.loadTreeData() - // this.freshAutoCompleteWords() - // } else { - // this.isLoadingTreeData = false - // } - // freshTreeOrder(this) - // this.selectFirstTable() - // this.isLoadingTreeData = false - await this.loadTreeData() + if (this.isLogicalView) { + await this.loadLogicalViewData() + } else { + await this.loadTreeData() + } } catch (e) { handleError(e) } } - // async loadDatasources () { - // this.datasources = this.currentSourceTypes.map(sourceType => getDatasourceObj(this, sourceType)) - // } + async loadLogicalViewData (filter) { + if (this.$store.state.system.logicalViewEnabled === 'true') { + try { + this.datasources = [] + const res = await this.fetchLogicalViewTables({ project: this.currentProjectData.name, table: filter }) + const logicalData = await handleSuccessAsync(res) + if (logicalData.length) { + const datasource = getDatasourceObj(this, 'L') + const resultDatabse = { + dbname: this.logicalViewDatabaseName, + size: logicalData.length, + tables: logicalData + } + datasource.children.push(getDatabaseTablesObj(this, datasource, resultDatabse)) + datasource.children.forEach((database, index) => { + database.children = database.originTables.map(resultTable => getTableObj(this, database, resultTable, this.ignoreNodeTypes.indexOf('column') >= 0)) + this.addPagination(database) + }) + this.datasources.push(datasource) + this.defaultExpandedKeys.push(datasource.id) + } + } catch (e) { + handleError(e) + } + } + } + async loadTreeData (filterText) { // 根据数据源获取dbs 和tables this.isLoadingTreeData = true this.treeKey = 'pageTree_' + filterText + Number(new Date()) @@ -493,6 +514,10 @@ export default class DataSourceBar extends Vue { } async handleFilter (filterText, isNotResetDefaultExpandedKeys) { this.isSearchIng = true + if (this.isLogicalView) { + await this.loadLogicalViewData(filterText) + return + } const scrollDom = this.$el.querySelector('.scroll-content') const scrollBarY = this.$el.querySelector('.scrollbar-thumb.scrollbar-thumb-y') scrollDom && (scrollDom.style.transform = null) @@ -568,6 +593,9 @@ export default class DataSourceBar extends Vue { }) this.defaultExpandedKeys = defaultExpandedKeysClone } + edit (data, node, event) { + this.$emit('edit', data, node, event) + } async handleToggleTop (data, node, event) { event && event.stopPropagation() event && event.preventDefault() @@ -852,6 +880,9 @@ export default class DataSourceBar extends Vue { font-size: 12px; } } + .is-disabled { + color: @text-disabled-color; + } .datatype { color: @text-placeholder-color !important; } @@ -909,19 +940,23 @@ export default class DataSourceBar extends Vue { } // .el-tree-node { // .el-tree-node__content:hover > .tree-item { - // color: #087AC8; + // color: @base-color-11; // } // } .table-date-tip { color: #8E9FA8; &:hover { - color: #087AC8; + color: @base-color-11; + } + &.is-disabled:hover { + color: @text-disabled-color; + cursor: not-allowed; } } .table-action { color: #000000; &:hover { - color: #087AC8; + color: @base-color-11; } } .table-tag { @@ -935,7 +970,7 @@ export default class DataSourceBar extends Vue { .column-tag { display: inline-block; font-size: 16px; - color: #087AC8; + color: @base-color-11; margin-right: 2px; font-style: normal; } diff --git a/kystudio/src/components/common/DataSourceBar/locales.js b/kystudio/src/components/common/DataSourceBar/locales.js index 6429a88f26..331b042175 100644 --- a/kystudio/src/components/common/DataSourceBar/locales.js +++ b/kystudio/src/components/common/DataSourceBar/locales.js @@ -22,6 +22,15 @@ export default { factTable: 'Fact Table', importFromDatasource: 'Import from Data Source', createByDDL: 'DDL Create', - createDDLTip: 'Data Definition Language Create Table' + createDDLTip: 'Data Definition Language Create Table', + Hive: 'Hive', + RDBMS: 'RDBMS', + Kafka: 'Kafka', + RDBMS2: 'RDBMS', + CSV: 'CSV', + GBASE: 'GBASE', + logicalView: 'Logical View', + editLogicalSql: 'Edit/View', + disabledEditLogicalSql: 'Not current project Logical View Table' } } diff --git a/kystudio/src/components/layout/layout_left_right_top.vue b/kystudio/src/components/layout/layout_left_right_top.vue index d07f7bfa81..77c49829cb 100644 --- a/kystudio/src/components/layout/layout_left_right_top.vue +++ b/kystudio/src/components/layout/layout_left_right_top.vue @@ -336,6 +336,8 @@ export default class LayoutLeftRightTop extends Vue { 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' + case 'logicalView': + return this.availableMenus.includes(menuName.toLowerCase()) && this.$store.state.system.logicalViewEnabled === 'true' default: return this.availableMenus.includes(menuName.toLowerCase()) } diff --git a/kystudio/src/components/studio/DDL/ddl.vue b/kystudio/src/components/studio/DDL/ddl.vue index 13a11c2381..c83751e25f 100644 --- a/kystudio/src/components/studio/DDL/ddl.vue +++ b/kystudio/src/components/studio/DDL/ddl.vue @@ -148,7 +148,8 @@ this.running = true const res = await this.runDDL({ sql: this.content, - project: this.currentSelectedProject + ddl_project: this.currentSelectedProject, + restrict: 'hive' }) const resultData = await handleSuccessAsync(res) this.running = false diff --git a/kystudio/src/components/studio/LogicalView/EditLogicalDialog/EditLogicalDialog.vue b/kystudio/src/components/studio/LogicalView/EditLogicalDialog/EditLogicalDialog.vue new file mode 100644 index 0000000000..9b109b64e0 --- /dev/null +++ b/kystudio/src/components/studio/LogicalView/EditLogicalDialog/EditLogicalDialog.vue @@ -0,0 +1,110 @@ +<template> + <el-dialog class="edit-logical-modal" + width="800px" + :title="$t('editLogical')" + :visible="isShow" + top="10vh" + :close-on-press-escape="false" + :close-on-click-modal="false" + @close="handleClose"> + <el-alert type="tip" :closable="false" class="ksd-mb-4" show-icon> + <span slot="title">{{$t('replaceTips')}} <a class="import-link" v-if="sql.toLocaleLowerCase().indexOf('create') > -1" href="javascript:void(0);" @click="goToReplace">{{'create -> replace'}}</a></span> + <span class="ksd-fs-12">{{$t('dropTips')}}</span> + </el-alert> + <kap-editor + width="100%" + :height="400" + lang="sql" + ref="logicalSql" + theme="chrome" + :dragable="false" + :isAbridge="true" + :value="sql" + @input="handleChangeSql"> + </kap-editor> + <div slot="footer" class="dialog-footer ky-no-br-space"> + <el-button size="medium" @click="handleCancel">{{$t('kylinLang.common.cancel')}}</el-button> + <el-button type="primary" size="medium" @click="handleSubmit" :loading="running">{{$t('kylinLang.common.save')}}</el-button> + </div> + </el-dialog> + </template> + + <script> + import Vue from 'vue' + import { Component } from 'vue-property-decorator' + import { mapState, mapMutations, mapActions, mapGetters } from 'vuex' + import { handleError } from 'util' + import vuex, { actionTypes } from 'store' + import locales from './locales' + import store from './store' + vuex.registerModule(['modals', 'EditLogicalDialog'], store) + @Component({ + computed: { + ...mapGetters([ + 'currentSelectedProject' + ]), + ...mapState('EditLogicalDialog', { + sql: state => state.sql, + isShow: state => state.isShow, + callback: state => state.callback + }) + }, + methods: { + ...mapMutations('EditLogicalDialog', { + setModal: actionTypes.SET_MODAL, + hideModal: actionTypes.HIDE_MODAL, + initModal: actionTypes.INIT_MODAL + }), + ...mapActions({ + runDDL: 'RUN_DDL' + }) + }, + locales + }) + export default class EditLogicalDialog extends Vue { + running = false + handleClose (isSubmit = false) { + this.hideModal() + this.callback && this.callback(isSubmit) + } + handleCancel () { + this.handleClose(false) + } + goToReplace () { + const replaceSql = this.sql.replace(/create/i, 'replace') + this.setModal({ sql: replaceSql }) + } + handleChangeSql () { + const val = this.$refs.logicalSql.getValue() + this.setModal({ sql: val }) + } + goToDataSource () { + this.$router.push('/studio/source') + } + async handleSubmit () { + try { + this.running = true + await this.runDDL({ + sql: this.sql, + ddl_project: this.currentSelectedProject, + restrict: 'replaceLogicalView' + }) + this.running = false + this.$message({ + type: 'success', + message: ( + <div> + <span>{this.$t('editSuccess') }</span> + <a href="javascript:void(0)" onClick={() => this.goToDataSource()}>{this.$t('goToDataSource')}</a> + </div> + ) + }) + this.handleClose(true) + } catch (e) { + handleError(e) + this.running = false + } + } + } + </script> + \ No newline at end of file diff --git a/kystudio/src/components/studio/LogicalView/EditLogicalDialog/locales.js b/kystudio/src/components/studio/LogicalView/EditLogicalDialog/locales.js new file mode 100644 index 0000000000..97634b5107 --- /dev/null +++ b/kystudio/src/components/studio/LogicalView/EditLogicalDialog/locales.js @@ -0,0 +1,9 @@ +export default { + 'en': { + editLogical: 'Edit Logical Table SQL', + replaceTips: 'Only supports `replace logical view` syntax. ', + dropTips: 'If you want to delete logcial view,please enter Create View Page and type \'drop view\' command.', + editSuccess: 'If you create,edit or delete columns in logical view,you need to reload table to make it take effect.', + goToDataSource: 'Go to Data Source reload' + } +} diff --git a/kystudio/src/components/studio/LogicalView/EditLogicalDialog/store.js b/kystudio/src/components/studio/LogicalView/EditLogicalDialog/store.js new file mode 100644 index 0000000000..29816d449d --- /dev/null +++ b/kystudio/src/components/studio/LogicalView/EditLogicalDialog/store.js @@ -0,0 +1,41 @@ +import * as actionTypes from '../../../../store/types' + +export function getInitialState () { + return { + isShow: false, + callback: null, + sql: '' + } +} + +export default { + state: getInitialState(), + mutations: { + [actionTypes.SHOW_MODAL] (state) { + state.isShow = true + }, + [actionTypes.HIDE_MODAL] (state) { + state.isShow = false + }, + [actionTypes.SET_MODAL] (state, payload) { + for (const [key, value] of Object.entries(payload)) { + state[key] = value + } + }, + [actionTypes.INIT_MODAL] (state) { + for (const [key, value] of Object.entries(getInitialState())) { + state[key] = value + } + } + }, + actions: { + [actionTypes.CALL_MODAL] ({ commit }, payload) { + return new Promise(resolve => { + commit(actionTypes.INIT_MODAL) + commit(actionTypes.SET_MODAL, { ...payload, callback: resolve }) + commit(actionTypes.SHOW_MODAL) + }) + } + }, + namespaced: true +} diff --git a/kystudio/src/components/studio/DDL/ddl.vue b/kystudio/src/components/studio/LogicalView/LogicalView.vue similarity index 72% copy from kystudio/src/components/studio/DDL/ddl.vue copy to kystudio/src/components/studio/LogicalView/LogicalView.vue index 13a11c2381..ab3ce8404e 100644 --- a/kystudio/src/components/studio/DDL/ddl.vue +++ b/kystudio/src/components/studio/LogicalView/LogicalView.vue @@ -1,10 +1,10 @@ <template> - <div class="ddl-container"> + <div class="logical-view-container"> <div class="left-layout"> <div class="header"> - <span class="title">{{$t('newDDLTable')}}</span> + <span class="title">{{$t('newLogicalView')}}</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> + <el-alert type="warning" show-icon v-if="showCreateSuccessAlert"><span slot="title">{{$t('createViewSuccessAlert', {databaseName: logicalViewDatabaseName})}} <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"> @@ -17,6 +17,11 @@ </div> <div :class="['right-layout', {'expand': !!activeType}]"> <div class="action-btns"> + <el-tooltip :content="$t('logicalView')" effect="dark" placement="left"> + <el-badge is-dot class="sign-item" :hidden="true"> + <el-button :class="{'is-active': activeType === 'logicalView'}" text type="primary" icon-button-mini icon="el-ksd-n-icon-symbol-l-filled" @click="activeType = 'logicalView'"></el-button> + </el-badge> + </el-tooltip> <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> @@ -30,11 +35,34 @@ </div> <div class="panel-content-layout"> <div class="panel-header" v-if="activeType"> - <span class="title">{{activeType === 'database' ? $t('datasourceTable') : $t('syntaxRules')}}</span> + <span class="title">{{expandBlockTitle}}</span> <i class="el-ksd-n-icon-close-L-outlined close-btn" @click="activeType = ''"></i> </div> + <div class="datasource-layout" v-if="activeType === 'logicalView'"> + <data-source-bar + key="logicalView" + ref="logicalViewDataSource" + 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']" + :ignore-node-types="['column']" + :is-logical-view="true" + :hide-bar-title="$store.state.config.platform === 'iframe'" + :custom-tree-title="$store.state.config.platform !== 'iframe' ? '' : 'kylinLang.common.dataDirectory'" + @autoComplete="handleAutoComplete" + @click="clickTable" + @edit="editLogicalSql"> + </data-source-bar> + </div> <div class="datasource-layout" v-show="activeType === 'database'"> <data-source-bar + key="database" ref="ddlDataSource" class="data-source-layout" :project-name="currentSelectedProject" @@ -64,6 +92,7 @@ </template> </div> </div> + <EditLogicalDialog /> </div> </template> <script> @@ -72,36 +101,59 @@ import DataSourceBar from '../../common/DataSourceBar' import { insightKeyword } from '../../../config' import { handleSuccessAsync, handleError } from '../../../util' + import EditLogicalDialog from './EditLogicalDialog/EditLogicalDialog' @Component({ computed: { ...mapGetters([ 'currentSelectedProject', 'datasourceActions', - 'currentProjectData' + 'currentProjectData', + 'logicalViewDatabaseName' ]) }, methods: { ...mapActions({ getDDLDescription: 'DDL_DESCRIPTION', runDDL: 'RUN_DDL' + }), + ...mapActions('EditLogicalDialog', { + callEditLogicalDialog: 'CALL_MODAL' }) }, components: { - DataSourceBar + DataSourceBar, + EditLogicalDialog }, locales: { en: { - newDDLTable: 'New DDL Table', + newLogicalView: 'New Logical View', + logicalView: 'Logical View', + logicalViewTable: 'Logical View Table', datasourceTable: 'Data Source Table', syntaxRules: 'Syntax Rules', - createDDLSuggestionTitle: 'To create a DDL Table in KE, you need to follow the syntax rules of KE.', + createDDLSuggestionTitle: 'To create a Logical View in KE, you need to follow the syntax rules of KE.', importDataSource: 'Import', runBtnTip: 'Execute ', acceleratorKey: '⌃/⌘ enter', runSuccess: 'Execute 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.', + runFailed: 'Execute Failed,Please check and try again.', + createViewSuccessAlert: 'The Logical View is created in virtual database {databaseName} after executing "Create Logical View". Please import it from the data source to use it.', goToImport: 'Go to Import' + }, + 'zh-cn': { + newLogicalView: '新的逻辑视图', + logicalView: '逻辑视图', + logicalViewTable: '逻辑视图表', + datasourceTable: '数据源表', + syntaxRules: '语法规则', + createDDLSuggestionTitle: '在 KE 中创建 Logical View 需要遵循 KE 的语法规则。', + importDataSource: '导入', + runBtnTip: '执行 ', + acceleratorKey: '⌃/⌘ 回车', + runSuccess: '执行成功', + runFailed: '执行失败,请检查后重试', + createViewSuccessAlert: '“Create Logical View” 执行后逻辑视图创建至虚拟库 {databaseName},需要从数据源导入后可用。', + goToImport: '立即导入' } } }) @@ -114,8 +166,19 @@ stacktrace = '' running = false showCreateSuccessAlert = false + get expandBlockTitle () { + switch (this.activeType) { + case 'logicalView': + return this.$t('logicalViewTable') + case 'database': + return this.$t('datasourceTable') + default: + return this.$t('syntaxRules') + } + } setOption (option) { let editor = this.$refs.ddlEditor.editor + if (!editor) return editor.setOptions(Object.assign({ wrap: 'free', enableBasicAutocompletion: true, @@ -133,6 +196,14 @@ } }) } + async editLogicalSql (data, node, event) { + event.stopPropagation() + if (!data.isCurrentProLogicalTable) return + const isSubmit = await this.callEditLogicalDialog({ sql: data.__data.created_sql }) + if (isSubmit) { + this.$refs.logicalViewDataSource.initTree() + } + } importDataSource () { this.$refs.ddlDataSource && this.$refs.ddlDataSource.importDataSource('selectSource', this.currentProjectData) } @@ -148,11 +219,12 @@ this.running = true const res = await this.runDDL({ sql: this.content, - project: this.currentSelectedProject + ddl_project: this.currentSelectedProject, + restrict: 'logic' }) const resultData = await handleSuccessAsync(res) this.running = false - this.showCreateSuccessAlert = this.content.toLocaleLowerCase().indexOf('create view') > -1 + this.showCreateSuccessAlert = this.content.toLocaleLowerCase().indexOf('create logical view') > -1 resultData && this.insertEditorContent(`\n\n${resultData}`) this.resetErrorMsg() this.$message({ type: 'success', message: this.$t('runSuccess') }) @@ -174,7 +246,7 @@ } async getDDLRules () { try { - const result = await this.getDDLDescription({project: this.currentSelectedProject, page_type: 'hive'}) + const result = await this.getDDLDescription({project: this.currentSelectedProject, page_type: 'logic'}) const rules = await handleSuccessAsync(result) this.rules = rules } catch (e) { @@ -192,7 +264,7 @@ <style lang="less" scoped> @import '../../../assets/styles/variables.less'; - .ddl-container { + .logical-view-container { width: 100%; height: 100%; display: flex; @@ -367,3 +439,4 @@ color: @text-disabled-color; } </style> + \ No newline at end of file diff --git a/kystudio/src/config/index.js b/kystudio/src/config/index.js index 160a285fa0..bd269fe1d2 100644 --- a/kystudio/src/config/index.js +++ b/kystudio/src/config/index.js @@ -58,7 +58,8 @@ export const menusData = [ { name: 'source', path: '/studio/source' }, { name: 'modelList', path: '/studio/model' }, { name: 'snapshot', path: '/studio/snapshot' }, - { name: 'ddl', path: '/studio/ddl' } + { name: 'ddl', path: '/studio/ddl' }, + { name: 'logicalView', path: '/studio/logicalview' } ] }, { @@ -709,7 +710,8 @@ export const sourceTypes = getFullMapping({ RDBMS: 16, KAFKA: 1, CSV: 13, - GBASE: 8 + GBASE: 8, + LOGIC: 'L' }) export const sourceNameMapping = { @@ -718,7 +720,8 @@ export const sourceNameMapping = { KAFKA: 'Kafka', RDBMS2: 'RDBMS', CSV: 'CSV', - GBASE: 'GBASE' + GBASE: 'GBASE', + LOGIC: 'logicalView' } export const pageSizeMapping = { diff --git a/kystudio/src/config/spec.js b/kystudio/src/config/spec.js index 236d4d168e..0bf9717b25 100644 --- a/kystudio/src/config/spec.js +++ b/kystudio/src/config/spec.js @@ -19,6 +19,7 @@ export default { { "id": "modelSubPartitionValues", "value": "modelsubpartitionvalues", "title": "Model SubPartition Values" }, { "id": "snapshot", "value": "snapshot", "title": "Snapshot" }, { "id": "ddl", "value": "ddl", "title": "DDL" }, + { "id": "logicalView", "value": "logicalview", "title": "Logical View" }, { "id": "monitor", "value": "monitor", "title": "Monitor" }, { "id": "job", "value": "job", "title": "Job" }, { "id": "streamingJob", "value": "streamingjob", "title": "streamingJob" }, @@ -152,10 +153,10 @@ 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,ddl,monitor,job,streamingJob]", "value": "dashboard,query,insight,queryHistory,studio,setting,source,model,index,modelEdit,modelDetails,modelSubPartitionValues,snapshot,ddl,monitor,job,streamingJob,admin" }, + { "key": "systemAdmin-*-[dashboard,query,insight,queryHistory,studio,setting,source,model,index,modelEdit,modelDetails,modelSubPartitionValues,snapshot,ddl,logicalView,monitor,job,streamingJob]", "value": "dashboard,query,insight,queryHistory,studio,setting,source,model,index,modelEdit,modelDetails,modelSubPartitionValues,snapshot,ddl,logicalView,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,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-admin-[dashboard,query,insight,queryHistory,studio,setting,source,model,index,modelEdit,modelDetails,modelSubPartitionValues,snapshot,ddl,logicalView,monitor,job,streamingJob]", "value": "dashboard,query,insight,queryHistory,studio,setting,source,model,index,modelEdit,modelDetails,modelSubPartitionValues,snapshot,ddl,logicalView,monitor,job,streamingJob,admin" }, + { "key": "systemUser-management-*", "value": "dashboard,query,insight,queryHistory,studio,source,model,index,modelEdit,modelDetails,modelSubPartitionValues,snapshot,ddl,logicalView,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 855036173d..687c4f382b 100644 --- a/kystudio/src/locale/en.js +++ b/kystudio/src/locale/en.js @@ -493,6 +493,7 @@ exports.default = { modeledit: 'Model Edit', snapshot: 'Snapshot', ddl: 'DDL', + logicalView: 'Logical View', refresh: 'Refresh', systemcapacity: 'Capacity' }, diff --git a/kystudio/src/router/index.js b/kystudio/src/router/index.js index 29e93ab054..148c3756f8 100644 --- a/kystudio/src/router/index.js +++ b/kystudio/src/router/index.js @@ -89,6 +89,10 @@ let routerOptions = { name: 'DDL', path: 'studio/ddl', component: () => import('../components/studio/DDL/ddl.vue') + }, { + name: 'LogicalView', + path: 'studio/logicalview', + component: () => import('../components/studio/LogicalView/LogicalView.vue') }, { name: 'Project', path: 'admin/project', diff --git a/kystudio/src/service/datasource.js b/kystudio/src/service/datasource.js index 7e00128f44..b1112c18d9 100644 --- a/kystudio/src/service/datasource.js +++ b/kystudio/src/service/datasource.js @@ -321,5 +321,8 @@ export default { }, runDDL (data) { return Vue.resource(apiUrl + 'spark_source/ddl').save(data) + }, + fetchLogicalViewTables (data) { + return Vue.resource(apiUrl + 'spark_source/ddl/view_list').get(data) } } diff --git a/kystudio/src/store/datasource.js b/kystudio/src/store/datasource.js index ac31bd3994..40b4014f56 100644 --- a/kystudio/src/store/datasource.js +++ b/kystudio/src/store/datasource.js @@ -402,6 +402,9 @@ export default { // 执行 ddl 语句 [types.RUN_DDL]: function (_, data) { return api.datasource.runDDL(data) + }, + [types.FETCH_LOGICAL_VIEW_TABLES]: function ({ commit }, data) { + return api.datasource.fetchLogicalViewTables(data) } } } diff --git a/kystudio/src/store/system.js b/kystudio/src/store/system.js index 7607926d28..2d713afbca 100644 --- a/kystudio/src/store/system.js +++ b/kystudio/src/store/system.js @@ -60,7 +60,9 @@ export default { isNonAdminGenQueryDiagPackage: 'true', streamingEnabled: 'false', storageQuery: 'true', - ddlEnabled: 'false' + ddlEnabled: 'false', + logicalViewEnabled: 'false', + logicalViewDatabase: 'KYLIN_LOGICAL_VIEW' }, mutations: { [types.COLLECT_MESSAGE_DIRECTIVES]: (state, directive) => { @@ -184,7 +186,9 @@ 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'}) + commit(types.GET_CONF_BY_NAME, {name: 'kylin.source.ddl.hive.enabled', key: 'ddlEnabled', defaultValue: 'false'}) + commit(types.GET_CONF_BY_NAME, {name: 'kylin.source.ddl.logical-view.enabled', key: 'logicalViewEnabled', defaultValue: 'false'}) + commit(types.GET_CONF_BY_NAME, {name: 'kylin.source.ddl.logical-view-database', key: 'logicalViewDatabase', defaultValue: 'KYLIN_LOGICAL_VIEW'}) resolve(response) }, () => { reject() @@ -239,8 +243,8 @@ export default { isNonAdminGenQueryDiagPackage: (state) => { return state.isNonAdminGenQueryDiagPackage === 'true' }, - isStreamingEnabled: (state) => { - return state.streamingEnabled === 'true' + logicalViewDatabaseName: (state) => { + return state.logicalViewDatabase } } } diff --git a/kystudio/src/store/types.js b/kystudio/src/store/types.js index 7ec5311e22..f88d6607c7 100644 --- a/kystudio/src/store/types.js +++ b/kystudio/src/store/types.js @@ -182,6 +182,7 @@ export const EXPORT_CSV = 'EXPORT_CSV' export const LOAD_DATASOURCE_OF_MODEL = 'LOAD_DATASOURCE_OF_MODEL' +export const FETCH_LOGICAL_VIEW_TABLES = 'FETCH_LOGICAL_VIEW_TABLES' export const DDL_DESCRIPTION = 'DDL_DESCRIPTION' export const RUN_DDL = 'RUN_DDL' // acl table