From 1bc8831fc723044f02e044e4a62f41a951cd7988 Mon Sep 17 00:00:00 2001 From: dataeaseShu <106045316+dataeaseShu@users.noreply.github.com> Date: Tue, 27 Dec 2022 17:00:56 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E6=95=B0=E6=8D=AE=E6=BA=90=E6=8C=89?= =?UTF-8?q?=E5=AD=97=E6=AF=8D=E9=A1=BA=E5=BA=8F=E8=BF=9B=E8=A1=8C=E6=8E=92?= =?UTF-8?q?=E5=BA=8F=20=E5=88=A0=E9=99=A4=E6=95=B0=E6=8D=AE=E6=BA=90?= =?UTF-8?q?=E6=95=B0=E6=8D=AE=E9=9B=86=E6=8F=90=E7=A4=BA=E8=A1=80=E7=BC=98?= =?UTF-8?q?=20=E4=BB=AA=E8=A1=A8=E6=9D=BF=E6=93=8D=E4=BD=9C=E6=A0=8F?= =?UTF-8?q?=E9=AB=98=E5=BA=A6=E7=BB=9F=E4=B8=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/components/msgCfm/index.js | 43 +++++++++++++ frontend/src/lang/en.js | 6 +- frontend/src/lang/tw.js | 14 +++-- frontend/src/lang/zh.js | 6 +- frontend/src/views/dataset/group/Group.vue | 51 ++++++++++++++- .../src/views/panel/list/PanelViewShow.vue | 9 +-- .../src/views/system/datasource/ContenVue.vue | 30 +++++++++ .../system/datasource/DriverFormDetail.vue | 1 + .../src/views/system/datasource/DsTree.vue | 63 ++++++++++++++++--- .../src/views/system/relationship/index.vue | 30 ++++++++- 10 files changed, 228 insertions(+), 25 deletions(-) create mode 100644 frontend/src/views/system/datasource/ContenVue.vue diff --git a/frontend/src/components/msgCfm/index.js b/frontend/src/components/msgCfm/index.js index f3d99bfa99..36da4db467 100644 --- a/frontend/src/components/msgCfm/index.js +++ b/frontend/src/components/msgCfm/index.js @@ -40,6 +40,49 @@ export default { .finally(() => { finallyCb() }) + }, + withLink(options, confirmButtonTextInfo) { + const h = this.$createElement; + const that = this + const { title, content, type = 'danger', cb, confirmButtonText = confirmButtonTextInfo || this.$t('commons.delete'), showCancelButton = true, cancelButtonText = this.$t('commons.cancel'), cancelCb = () => {}, finallyCb = () => {}, link = '', templateDel, linkTo } = options + const customClass = `de-confirm de-confirm-fail de-use-html` + const confirmButtonClass = `de-confirm-${type}-btn de-confirm-btn` + this.$msgbox({ + message: h('p', null, [ + h(templateDel, { + props: { + someProp: { + title, + content, + link + }, + }, + on: { + change: () => { + linkTo() + } + } + }), + ]), + duration: 0, + confirmButtonText, + cancelButtonText, + showCancelButton, + cancelButtonClass: 'de-confirm-btn de-confirm-plain-cancel', + confirmButtonClass, + customClass, + iconClass: 'el-icon-warning', + }).then(action => { + if ('confirm' === action) { + cb() + } + }) + .catch((action) => { + cancelCb(action) + }) + .finally(() => { + finallyCb() + }) } } } diff --git a/frontend/src/lang/en.js b/frontend/src/lang/en.js index af97fd524f..e546369cd5 100644 --- a/frontend/src/lang/en.js +++ b/frontend/src/lang/en.js @@ -1933,7 +1933,11 @@ export default { all: 'All', other: 'other', this_data_source: 'Are you sure to delete this data source?', - cannot_be_deleted: '4 datasets are using this data source and cannot be deleted', + delete_this_dataset: 'Are you sure to delete this dataset?', + cannot_be_deleted_dataset: 'This dataset has the following blood relationship. Deleting it will cause the view of related dashboard to be invalid. Are you sure to delete it?', + cannot_be_deleted_datasource: 'This datasource has the following blood relationship. Deleting it will cause the view of related dashboard to be invalid. Are you sure to delete it?', + edit_folder: 'Edit Folder', + click_to_check: 'Click to check the blood relationship', delete_this_item: 'Do you want to delete this item?', can_be_uploaded: 'Only files in jar format can be uploaded', query_timeout: 'query timeout', diff --git a/frontend/src/lang/tw.js b/frontend/src/lang/tw.js index 7e35b8d5a1..2c12bd832c 100644 --- a/frontend/src/lang/tw.js +++ b/frontend/src/lang/tw.js @@ -494,7 +494,7 @@ export default { display: '顯示', row: '行', restricted_objects: '受限對象', - select_data_source: '選擇資料來源', + select_data_source: '選擇數據源', by_table_name: '通過表名稱搜索', run_a_query: '運行査詢', running_results: '運行結果', @@ -1916,7 +1916,7 @@ export default { add_driver: '添加驅動', diver_on_the_left: '請在左側選擇驅動', no_data_table: '暫無資料表', - on_the_left: '請在左側選擇資料來源', + on_the_left: '請在左側選擇數據源', table_name: '表名稱', create_dataset: '創建數據集', field_description: '欄位描述', @@ -1926,12 +1926,16 @@ export default { non_relational_database: '非關係型數據庫', all: '所有', other: '其他', - this_data_source: '確定刪除該資料來源嗎?', - cannot_be_deleted: '4個數據集正在使用此資料來源,無法刪除', + this_data_source: '確定刪除該數據源嗎?', + delete_this_dataset: '確定删除該數据集嗎?', + cannot_be_deleted_dataset: '該數据集存在如下血緣關係,删除會造成相關儀錶板的視圖失效,確定删除?', + cannot_be_deleted_datasource: '該數據源存在如下血緣關係,删除會造成相關儀錶板的視圖失效,確定删除?', + edit_folder: '編輯資料夾', + click_to_check: '點擊去查看血緣關係', delete_this_item: '是否要刪除此項?', can_be_uploaded: '僅支持上傳JAR格式的檔案', query_timeout: '査詢超時', - add_data_source: '添加資料來源', + add_data_source: '添加數據源', delete_this_driver: '確定刪除該驅動嗎?', basic_info: '基本信息' }, diff --git a/frontend/src/lang/zh.js b/frontend/src/lang/zh.js index c48403deaa..5264fcc78c 100644 --- a/frontend/src/lang/zh.js +++ b/frontend/src/lang/zh.js @@ -1926,7 +1926,11 @@ export default { all: '所有', other: '其他', this_data_source: '确定删除该数据源吗?', - cannot_be_deleted: '4个数据集正在使用此数据源,无法删除', + delete_this_dataset: '确定删除该数据集吗?', + cannot_be_deleted_dataset: '该数据集存在如下血缘关系,删除会造成相关仪表板的视图失效,确定删除?', + cannot_be_deleted_datasource: '该数据源存在如下血缘关系,删除会造成相关仪表板的视图失效,确定删除?', + edit_folder: '编辑文件夹', + click_to_check: '点击去查看血缘关系', please_select: '请选择', delete_this_item: '是否要删除此项?', can_be_uploaded: '仅支持上传JAR格式的文件', diff --git a/frontend/src/views/dataset/group/Group.vue b/frontend/src/views/dataset/group/Group.vue index cd5366caa2..c589a91046 100644 --- a/frontend/src/views/dataset/group/Group.vue +++ b/frontend/src/views/dataset/group/Group.vue @@ -545,6 +545,11 @@ import { isKettleRunning, alter } from '@/api/dataset/dataset' +import { + getDatasetRelationship, +} from '@/api/chart/chart.js' + +import ContenVue from '@/views/system/datasource/ContenVue.vue' import GroupMoveSelector from './GroupMoveSelector' import CreatDsGroup from './CreatDsGroup' import { queryAuthModel } from '@/api/authModel/authModel' @@ -631,6 +636,7 @@ export default { { required: true, trigger: 'blur', validator: this.filedValidator } ] }, + treeData: [], moveGroup: false, tGroup: {}, moveDs: false, @@ -711,6 +717,26 @@ export default { sessionStorage.setItem('dataset-current-node', this.currentNodeId) }, methods: { + getDatasetRelationship({ queryType, label, id }) { + return getDatasetRelationship(id).then((res) => { + const arr = res.data ? [res.data] : [] + this.treeData = [] + this.dfsTree(arr, { queryType, label }) + }) + }, + dfsTree(arr = [], { queryType, label }, item) { + arr.forEach((ele) => { + const { name, type, subRelation = [] } = ele + const obj = {} + obj[type] = name + obj[queryType] = label + if (subRelation.length) { + this.dfsTree(subRelation, { queryType: type, label: name }, obj) + } else { + this.treeData.push({ ...item, ...obj }) + } + }) + }, dfsTableData(arr, id) { arr.some((ele) => { if (ele.id === id) { @@ -777,7 +803,7 @@ export default { switch (type) { case 'rename': this.originName = data.label - this.dialogTitle = this.$t('编辑文件夹') + this.dialogTitle = this.$t('datasource.edit_folder') this.dfsTdata(this.tData, data.id) this.add(data.modelInnerType) this.groupForm = JSON.parse(JSON.stringify(data)) @@ -876,7 +902,7 @@ export default { .catch(() => {}) }, - deleteTable(data) { + async deleteTable(data) { let confirm_delete_msg = '' if (data.modelInnerType === 'union' || data.modelInnerType === 'custom') { confirm_delete_msg = this.$t('dataset.confirm_delete') @@ -884,7 +910,7 @@ export default { confirm_delete_msg = this.$t('dataset.confirm_delete_msg') } const options = { - title: '确定删除该数据集吗?', + title: 'datasource.delete_this_dataset', content: confirm_delete_msg, type: 'primary', confirmButtonText: this.$t('commons.confirm'), @@ -897,8 +923,27 @@ export default { }) } } + + const { queryType = 'dataset', name: label, id } = data + await this.getDatasetRelationship({ queryType, label, id }) + if (this.treeData.length) { + options.title = this.$t('datasource.delete_this_dataset') + options.link = this.$t('datasource.click_to_check') + options.content = this.$t('datasource.cannot_be_deleted_dataset') + options.templateDel = ContenVue + + options.linkTo = this.linkTo.bind(this, { queryType, id }) + this.withLink(options) + return + } this.handlerConfirm(options) }, + linkTo(query) { + window.open(this.$router.resolve({ + path: '/system/relationship', + query + }).href, '_blank') + }, close() { this.$refs['groupForm'].resetFields() diff --git a/frontend/src/views/panel/list/PanelViewShow.vue b/frontend/src/views/panel/list/PanelViewShow.vue index c5bde619c0..671b63ae69 100644 --- a/frontend/src/views/panel/list/PanelViewShow.vue +++ b/frontend/src/views/panel/list/PanelViewShow.vue @@ -98,7 +98,7 @@ - + + diff --git a/frontend/src/views/system/datasource/ContenVue.vue b/frontend/src/views/system/datasource/ContenVue.vue new file mode 100644 index 0000000000..9caf290eea --- /dev/null +++ b/frontend/src/views/system/datasource/ContenVue.vue @@ -0,0 +1,30 @@ + + + \ No newline at end of file diff --git a/frontend/src/views/system/datasource/DriverFormDetail.vue b/frontend/src/views/system/datasource/DriverFormDetail.vue index e76959f5f9..83b6ec7ae8 100644 --- a/frontend/src/views/system/datasource/DriverFormDetail.vue +++ b/frontend/src/views/system/datasource/DriverFormDetail.vue @@ -291,6 +291,7 @@ export default { font-family: PingFang SC; width: 100%; height: 100%; + overflow: auto; .name { font-size: 16px; diff --git a/frontend/src/views/system/datasource/DsTree.vue b/frontend/src/views/system/datasource/DsTree.vue index 83a1fa6718..4aff7a86ea 100644 --- a/frontend/src/views/system/datasource/DsTree.vue +++ b/frontend/src/views/system/datasource/DsTree.vue @@ -339,6 +339,11 @@ import { listDriverByType, updateDriver } from '@/api/system/datasource' +import { + getDatasourceRelationship, +} from '@/api/chart/chart.js' + +import ContenVue from './ContenVue.vue' import deTextarea from '@/components/deCustomCm/DeTextarea.vue' import msgCfm from '@/components/msgCfm' export default { @@ -354,6 +359,7 @@ export default { data() { return { tabActive: 'OLTP', + treeData: [], databaseList: [], currentNodeId: '', dsTypeRelate: false, @@ -361,7 +367,7 @@ export default { tData: [], nameMap: ['OLTP', 'OLAP', 'dataWarehouseLake', 'OTHER'], nameClassMap: ['OLTP', 'OLAP', this.$t(`datasource.data_warehouse_lake`), this.$t(`datasource.other`)], - typeList: [['Db2', 'DM', 'KingBase', 'MariaDB', 'MongoDB', 'Mongodb-BI', 'MySQL', 'Oracle', 'PostgreSQL', 'SQL Server', 'TiDB'], ['Doris', 'Apache Impala', 'ClickHouse', 'Elasticsearch', 'Presto', 'StarRocks'], ['Apache Hive', 'Kylin', 'AWS Redshift', 'Maxcompute'], ['API']], + typeList: ['OLTP', 'OLAP', 'DL', 'OTHER'], treeLoading: false, dsTypes: [], dsTypesForDriver: [], @@ -426,6 +432,26 @@ export default { this.datasourceTypes() }, methods: { + getDatasourceRelationship({ queryType, label, id }) { + return getDatasourceRelationship(id).then((res) => { + const arr = res.data || [] + this.treeData = [] + this.dfsTree(arr, { queryType, label }) + }) + }, + dfsTree(arr = [], { queryType, label }, item) { + arr.forEach((ele) => { + const { name, type, subRelation = [] } = ele + const obj = {} + obj[type] = name + obj[queryType] = label + if (subRelation.length) { + this.dfsTree(subRelation, { queryType: type, label: name }, obj) + } else { + this.treeData.push({ ...item, ...obj }) + } + }) + }, handleClick() { document.querySelector(`.${this.tabActive}`).scrollIntoView() }, @@ -503,7 +529,7 @@ export default { this.dsTypes = res.data const databaseList = [[], [], [], []] this.dsTypes.forEach((item) => { - const index = this.typeList.findIndex(ele => ele.includes(item.name)) + const index = this.typeList.findIndex(ele => ele === item.databaseClassification) // databaseClassification if (index !== -1) { databaseList[index].push(item) } @@ -511,7 +537,11 @@ export default { this.dsTypesForDriver.push(item) } }) - this.databaseList = databaseList + this.databaseList = databaseList.map(ele => { + return ele.sort((a, b) => { + return a.name.toLowerCase().charCodeAt(0) - b.name.toLowerCase().charCodeAt(0) + }) + }) }) }, refreshType(datasource) { @@ -695,7 +725,7 @@ export default { this.dialogTitle = this.$t('commons.copy') this.driverForm = { ...row } }, - _handleDelete(datasource) { + async _handleDelete(datasource) { const params = { title: this.showView === 'Datasource' @@ -722,17 +752,34 @@ export default { }) } } + const { queryType = 'datasource', name: label, id } = datasource + if (this.showView === 'Datasource') { + await this.getDatasourceRelationship({ queryType, label, id }) + if (this.treeData.length) { + params.title = this.$t('datasource.this_data_source') + params.link = this.$t('datasource.click_to_check') + params.content = this.$t('datasource.cannot_be_deleted_dataset') + params.templateDel = ContenVue + + params.linkTo = this.linkTo.bind(this, { queryType, id }) + this.withLink(params) + return + } + } this.handlerConfirm(params) }, + linkTo(query) { + window.open(this.$router.resolve({ + path: '/system/relationship', + query + }).href, '_blank') + }, switchMain(component, componentParam, tData, dsTypes) { if (component === 'dsTable') { - const { id, type, showModel } = componentParam this.$emit('switch-main', { component, componentParam: { - id, - type, - showModel, + ...componentParam, msgNodeId: this.msgNodeId }, tData, diff --git a/frontend/src/views/system/relationship/index.vue b/frontend/src/views/system/relationship/index.vue index e35ae371eb..b6b0aae437 100644 --- a/frontend/src/views/system/relationship/index.vue +++ b/frontend/src/views/system/relationship/index.vue @@ -149,6 +149,7 @@ export default { }, treeData: [], loading: false, + routerWithParams: {}, activeIcon: 'date', paginationConfig: { currentPage: 1, @@ -187,6 +188,12 @@ export default { } }, created() { + this.routerWithParams = this.$route.query + const { id, queryType } = this.routerWithParams + if (id && queryType) { + this.searchDetail(id, queryType) + return + } this.listDatasource() }, beforeDestroy() { @@ -197,6 +204,23 @@ export default { this.getChartSize() }, methods: { + async searchDetail(id, queryType) { + switch (queryType) { + case 'datasource': + await this.listDatasource() + break + case 'dataset': + await this.getDatasetList() + break + case 'panel': + await this.getPanelGroupList() + break + default: + break + } + this.formInline = { queryType, dataSourceName: id } + this.getChartData() + }, getChartData() { const { queryType, dataSourceName: id } = this.formInline switch (queryType) { @@ -280,7 +304,7 @@ export default { } }, 200), listDatasource() { - listDatasource().then((res) => { + return listDatasource().then((res) => { const arr = res?.data || [] this.dataSourceNameList = arr.map((ele) => ({ value: ele.id, @@ -289,7 +313,7 @@ export default { }) }, getDatasetList() { - getDatasetList().then((res) => { + return getDatasetList().then((res) => { const arr = res?.data || [] this.dataSourceNameList = arr.map((ele) => ({ value: ele.id, @@ -298,7 +322,7 @@ export default { }) }, getPanelGroupList() { - getPanelGroupList().then((res) => { + return getPanelGroupList().then((res) => { const arr = res?.data || [] this.dataSourceNameList = arr.map((ele) => ({ value: ele.id,