From 4ea603bb43c5d31cbdc50fa6276ec6a08fe9ae77 Mon Sep 17 00:00:00 2001 From: Amy0104 <97265214+Amy0104@users.noreply.github.com> Date: Sat, 15 Jan 2022 12:01:14 +0800 Subject: [PATCH] [Feature][UI Next] Add data source (#8058) --- .../src/components/modal/index.module.scss | 9 - .../src/components/modal/index.tsx | 16 +- .../src/locales/modules/en_US.ts | 51 ++- .../src/locales/modules/zh_CN.ts | 48 ++- .../src/router/modules/datasource.ts | 2 +- .../src/service/modules/data-source/index.ts | 26 +- .../src/service/modules/data-source/types.ts | 32 +- .../datasource/datasource-list/detail.tsx | 332 ++++++++++++++++++ .../datasource-list/index.module.scss | 32 ++ .../datasource/datasource-list/index.tsx | 150 ++++++++ .../json-highlight.module.scss | 26 ++ .../datasource-list/json-highlight.tsx | 67 ++++ .../views/datasource/datasource-list/types.ts | 47 +++ .../datasource/datasource-list/use-columns.ts | 136 +++++++ .../datasource/datasource-list/use-detail.ts | 103 ++++++ .../datasource/datasource-list/use-form.ts | 209 +++++++++++ .../datasource/datasource-list/use-table.ts | 82 +++++ 17 files changed, 1328 insertions(+), 40 deletions(-) create mode 100644 dolphinscheduler-ui-next/src/views/datasource/datasource-list/detail.tsx create mode 100644 dolphinscheduler-ui-next/src/views/datasource/datasource-list/index.module.scss create mode 100644 dolphinscheduler-ui-next/src/views/datasource/datasource-list/index.tsx create mode 100644 dolphinscheduler-ui-next/src/views/datasource/datasource-list/json-highlight.module.scss create mode 100644 dolphinscheduler-ui-next/src/views/datasource/datasource-list/json-highlight.tsx create mode 100644 dolphinscheduler-ui-next/src/views/datasource/datasource-list/types.ts create mode 100644 dolphinscheduler-ui-next/src/views/datasource/datasource-list/use-columns.ts create mode 100644 dolphinscheduler-ui-next/src/views/datasource/datasource-list/use-detail.ts create mode 100644 dolphinscheduler-ui-next/src/views/datasource/datasource-list/use-form.ts create mode 100644 dolphinscheduler-ui-next/src/views/datasource/datasource-list/use-table.ts diff --git a/dolphinscheduler-ui-next/src/components/modal/index.module.scss b/dolphinscheduler-ui-next/src/components/modal/index.module.scss index 325e7c0f88..8044aa2474 100644 --- a/dolphinscheduler-ui-next/src/components/modal/index.module.scss +++ b/dolphinscheduler-ui-next/src/components/modal/index.module.scss @@ -18,12 +18,3 @@ .container { width: 600px; } - -.btn-box { - display: flex; - justify-content: flex-end; - - button:last-child { - margin-left: 20px; - } -} diff --git a/dolphinscheduler-ui-next/src/components/modal/index.tsx b/dolphinscheduler-ui-next/src/components/modal/index.tsx index 7758ddbc23..c8a09b8e0a 100644 --- a/dolphinscheduler-ui-next/src/components/modal/index.tsx +++ b/dolphinscheduler-ui-next/src/components/modal/index.tsx @@ -16,7 +16,7 @@ */ import { defineComponent, PropType, renderSlot } from 'vue' -import { NModal, NCard, NButton } from 'naive-ui' +import { NModal, NCard, NButton, NSpace } from 'naive-ui' import { useI18n } from 'vue-i18n' import styles from './index.module.scss' @@ -42,6 +42,10 @@ const props = { confirmDisabled: { type: Boolean as PropType, default: false + }, + confirmLoading: { + type: Boolean as PropType, + default: false } } @@ -63,7 +67,8 @@ const Modal = defineComponent({ return { t, onCancel, onConfirm } }, render() { - const { $slots, t, onCancel, onConfirm, confirmDisabled } = this + const { $slots, t, onCancel, onConfirm, confirmDisabled, confirmLoading } = + this return ( renderSlot($slots, 'default'), footer: () => ( -
+ {this.cancelShow && ( {this.cancelText || t('modal.cancel')} )} + {/* TODO: Add left and right slots later */} + {renderSlot($slots, 'btn-middle')} {this.confirmText || t('modal.confirm')} -
+ ) }} diff --git a/dolphinscheduler-ui-next/src/locales/modules/en_US.ts b/dolphinscheduler-ui-next/src/locales/modules/en_US.ts index 44e1a1ab18..7a4286e68e 100644 --- a/dolphinscheduler-ui-next/src/locales/modules/en_US.ts +++ b/dolphinscheduler-ui-next/src/locales/modules/en_US.ts @@ -267,6 +267,54 @@ const security = { worker_group_tips: 'Please select worker group' } } +const datasource = { + datasource: 'DataSource', + create_datasource: 'Create DataSource', + search_input_tips: 'Please input the keywords', + serial_number: '#', + datasource_name: 'Datasource Name', + datasource_name_tips: 'Please enter datasource name', + datasource_user_name: 'Owner', + datasource_type: 'Datasource Type', + datasource_parameter: 'Datasource Parameter', + description: 'Description', + description_tips: 'Please enter description', + create_time: 'Create Time', + update_time: 'Update Time', + operation: 'Operation', + click_to_view: 'Click to view', + delete: 'Delete', + confirm: 'Confirm', + cancel: 'Cancel', + create: 'Create', + edit: 'Edit', + success: 'Success', + test_connect: 'Test Connect', + ip: 'IP', + ip_tips: 'Please enter IP', + port: 'Port', + port_tips: 'Please enter port', + database_name: 'Database Name', + database_name_tips: 'Please enter database name', + oracle_connect_type: 'ServiceName or SID', + oracle_connect_type_tips: 'Please select serviceName or SID', + oracle_service_name: 'ServiceName', + oracle_sid: 'SID', + jdbc_connect_parameters: 'jdbc connect parameters', + principal_tips: 'Please enter Principal', + krb5_conf_tips: + 'Please enter the kerberos authentication parameter java.security.krb5.conf', + keytab_username_tips: + 'Please enter the kerberos authentication parameter login.user.keytab.username', + keytab_path_tips: + 'Please enter the kerberos authentication parameter login.user.keytab.path', + format_tips: 'Please enter format', + connection_parameter: 'connection parameter', + user_name: 'User Name', + user_name_tips: 'Please enter your username', + user_password: 'Password', + user_password_tips: 'Please enter your password' +} export default { login, @@ -280,5 +328,6 @@ export default { monitor, resource, project, - security + security, + datasource } diff --git a/dolphinscheduler-ui-next/src/locales/modules/zh_CN.ts b/dolphinscheduler-ui-next/src/locales/modules/zh_CN.ts index 1050abd306..21a69114cd 100644 --- a/dolphinscheduler-ui-next/src/locales/modules/zh_CN.ts +++ b/dolphinscheduler-ui-next/src/locales/modules/zh_CN.ts @@ -266,6 +266,51 @@ const security = { worker_group_tips: '请选择Worker分组' } } +const datasource = { + datasource: '数据源', + create_datasource: '创建数据源', + search_input_tips: '请输入关键字', + serial_number: '编号', + datasource_name: '数据源名称', + datasource_name_tips: '请输入数据源名称', + datasource_user_name: '所属用户', + datasource_type: '数据源类型', + datasource_parameter: '数据源参数', + description: '描述', + description_tips: '请输入描述', + create_time: '创建时间', + update_time: '更新时间', + operation: '操作', + click_to_view: '点击查看', + delete: '删除', + confirm: '确定', + cancel: '取消', + create: '创建', + edit: '编辑', + success: '成功', + test_connect: '测试连接', + ip: 'IP主机名', + ip_tips: '请输入IP主机名', + port: '端口', + port_tips: '请输入端口', + database_name: '数据库名', + database_name_tips: '请输入数据库名', + oracle_connect_type: '服务名或SID', + oracle_connect_type_tips: '请选择服务名或SID', + oracle_service_name: '服务名', + oracle_sid: 'SID', + jdbc_connect_parameters: 'jdbc连接参数', + principal_tips: '请输入Principal', + krb5_conf_tips: '请输入kerberos认证参数 java.security.krb5.conf', + keytab_username_tips: '请输入kerberos认证参数 login.user.keytab.username', + keytab_path_tips: '请输入kerberos认证参数 login.user.keytab.path', + format_tips: '请输入格式为', + connection_parameter: '连接参数', + user_name: '用户名', + user_name_tips: '请输入用户名', + user_password: '密码', + user_password_tips: '请输入密码' +} export default { login, @@ -279,5 +324,6 @@ export default { monitor, resource, project, - security + security, + datasource } diff --git a/dolphinscheduler-ui-next/src/router/modules/datasource.ts b/dolphinscheduler-ui-next/src/router/modules/datasource.ts index 1c4e7a98f3..2c8848223e 100644 --- a/dolphinscheduler-ui-next/src/router/modules/datasource.ts +++ b/dolphinscheduler-ui-next/src/router/modules/datasource.ts @@ -32,7 +32,7 @@ export default { { path: '/datasource/list', name: 'datasource-list', - component: components['home'], + component: components['datasource-list'], meta: { title: '数据源中心' } diff --git a/dolphinscheduler-ui-next/src/service/modules/data-source/index.ts b/dolphinscheduler-ui-next/src/service/modules/data-source/index.ts index 78eb556697..b3aae9b624 100644 --- a/dolphinscheduler-ui-next/src/service/modules/data-source/index.ts +++ b/dolphinscheduler-ui-next/src/service/modules/data-source/index.ts @@ -18,7 +18,7 @@ import { axios } from '@/service/service' import { ListReq, - DataSourceReq, + IDataSource, UserIdReq, TypeReq, NameReq, @@ -33,11 +33,15 @@ export function queryDataSourceListPaging(params: ListReq): any { }) } -export function createDataSource(data: DataSourceReq): any { +export function createDataSource(data: IDataSource): any { return axios({ url: '/datasources', method: 'post', - data + data, + headers: { + 'Content-Type': 'application/json;charset=UTF-8' + }, + transformRequest: (params) => JSON.stringify(params) }) } @@ -49,11 +53,15 @@ export function authedDatasource(params: UserIdReq): any { }) } -export function connectDataSource(data: DataSourceReq): any { +export function connectDataSource(data: IDataSource): any { return axios({ url: '/datasources/connect', method: 'post', - data + data, + headers: { + 'Content-Type': 'application/json;charset=UTF-8' + }, + transformRequest: (params) => JSON.stringify(params) }) } @@ -95,11 +103,15 @@ export function queryDataSource(id: IdReq): any { }) } -export function updateDataSource(data: DataSourceReq, id: IdReq): any { +export function updateDataSource(data: IDataSource, id: IdReq): any { return axios({ url: `/datasources/${id}`, method: 'put', - data + data, + headers: { + 'Content-Type': 'application/json;charset=UTF-8' + }, + transformRequest: (params) => JSON.stringify(params) }) } diff --git a/dolphinscheduler-ui-next/src/service/modules/data-source/types.ts b/dolphinscheduler-ui-next/src/service/modules/data-source/types.ts index 212e96594e..e17c6a241c 100644 --- a/dolphinscheduler-ui-next/src/service/modules/data-source/types.ts +++ b/dolphinscheduler-ui-next/src/service/modules/data-source/types.ts @@ -15,7 +15,7 @@ * limitations under the License. */ -type DataBase = +type IDataBase = | 'MYSQL' | 'POSTGRESQL' | 'HIVE' @@ -25,19 +25,23 @@ type DataBase = | 'SQLSERVER' | 'DB2' | 'PRESTO' - | 'H2' -interface DataSource { - database?: string - host?: string +interface IDataSource { id?: number + type?: IDataBase name?: string note?: string - other?: object - password?: string + host?: string port?: number - type?: DataBase + principal?: string + javaSecurityKrb5Conf?: string + loginUserKeytabUsername?: string + loginUserKeytabPath?: string userName?: string + password?: string + database?: string + connectType?: string + other?: object } interface ListReq { @@ -46,24 +50,18 @@ interface ListReq { searchVal?: string } -interface DataSourceReq { - dataSourceParam: DataSource -} - interface UserIdReq { userId: number } interface TypeReq { - type: DataBase + type: IDataBase } interface NameReq { name: string } -interface IdReq { - id: number -} +type IdReq = number -export { ListReq, DataSourceReq, UserIdReq, TypeReq, NameReq, IdReq } +export { ListReq, IDataBase, IDataSource, UserIdReq, TypeReq, NameReq, IdReq } diff --git a/dolphinscheduler-ui-next/src/views/datasource/datasource-list/detail.tsx b/dolphinscheduler-ui-next/src/views/datasource/datasource-list/detail.tsx new file mode 100644 index 0000000000..93c7a8e6de --- /dev/null +++ b/dolphinscheduler-ui-next/src/views/datasource/datasource-list/detail.tsx @@ -0,0 +1,332 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { defineComponent, PropType, toRefs, watch } from 'vue' +import { + NButton, + NSpin, + NForm, + NFormItem, + NSelect, + NInput, + NInputNumber, + NRadioGroup, + NRadio, + NSpace +} from 'naive-ui' +import Modal from '@/components/modal' +import { useI18n } from 'vue-i18n' +import { useForm, datasourceTypeList } from './use-form' +import { useDetail } from './use-detail' + +const props = { + show: { + type: Boolean as PropType, + default: false + }, + id: { + type: Number as PropType + } +} + +const DetailModal = defineComponent({ + name: 'DetailModal', + props, + emits: ['cancel', 'update'], + setup(props, ctx) { + const { t } = useI18n() + + const { + state, + changeType, + changePort, + resetFieldsValue, + setFieldsValue, + getFieldsValue + } = useForm(props.id) + + const { status, queryById, testConnect, createOrUpdate } = + useDetail(getFieldsValue) + + const onCancel = () => { + resetFieldsValue() + ctx.emit('cancel') + } + + const onSubmit = async () => { + await state.detailFormRef.validate() + const res = await createOrUpdate(props.id) + if (res) { + onCancel() + ctx.emit('update') + } + } + + const onTest = async () => { + await state.detailFormRef.validate() + testConnect() + } + + const onChangeType = changeType + const onChangePort = changePort + + watch( + () => props.show, + async () => { + props.show && props.id && setFieldsValue(await queryById(props.id)) + } + ) + + return { + t, + ...toRefs(state), + ...toRefs(status), + onChangeType, + onChangePort, + onSubmit, + onTest, + onCancel + } + }, + render() { + const { + show, + id, + t, + detailForm, + rules, + requiredDataBase, + showConnectType, + showPrincipal, + loading, + saving, + testing, + onChangeType, + onChangePort, + onCancel, + onTest, + onSubmit + } = this + return ( + + {{ + default: () => ( + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {t('datasource.oracle_service_name')} + + + {t('datasource.oracle_sid')} + + + + + + + + + + ), + 'btn-middle': () => ( + + {t('datasource.test_connect')} + + ) + }} + + ) + } +}) + +export default DetailModal diff --git a/dolphinscheduler-ui-next/src/views/datasource/datasource-list/index.module.scss b/dolphinscheduler-ui-next/src/views/datasource/datasource-list/index.module.scss new file mode 100644 index 0000000000..fc5f4cc948 --- /dev/null +++ b/dolphinscheduler-ui-next/src/views/datasource/datasource-list/index.module.scss @@ -0,0 +1,32 @@ +/* + * 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. + */ + +.conditions { + display: flex; + justify-content: space-between; + align-items: center; +} +.conditions-search-input { + width: 250px; +} +.pagination { + margin-top: 20px; + justify-content: center; +} +.mt-8 { + margin-top: 8px; +} diff --git a/dolphinscheduler-ui-next/src/views/datasource/datasource-list/index.tsx b/dolphinscheduler-ui-next/src/views/datasource/datasource-list/index.tsx new file mode 100644 index 0000000000..01d6d2e050 --- /dev/null +++ b/dolphinscheduler-ui-next/src/views/datasource/datasource-list/index.tsx @@ -0,0 +1,150 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { defineComponent, onMounted, ref, toRefs } from 'vue' +import { + NButton, + NInput, + NIcon, + NDataTable, + NPagination, + NSpace +} from 'naive-ui' +import Card from '@/components/card' +import DetailModal from './detail' +import { SearchOutlined } from '@vicons/antd' +import { useI18n } from 'vue-i18n' +import { useColumns } from './use-columns' +import { useTable } from './use-table' +import styles from './index.module.scss' + +const list = defineComponent({ + name: 'list', + setup() { + const { t } = useI18n() + let showDetailModal = ref(false) + let selectId = ref() + + const { columnsRef } = useColumns((id: number, type: 'edit' | 'delete') => { + if (type === 'edit') { + showDetailModal.value = true + selectId.value = id + } else { + deleteRecord(id) + } + }) + + const { data, changePage, changePageSize, deleteRecord, updateList } = + useTable() + + const onCreate = () => { + selectId.value = null + showDetailModal.value = true + } + + onMounted(() => { + changePage(1) + }) + + return { + t, + showDetailModal, + id: selectId, + columnsRef, + ...toRefs(data), + changePage, + changePageSize, + onCreate, + onUpdatedList: updateList + } + }, + render() { + const { + t, + id, + showDetailModal, + columnsRef, + list, + page, + pageSize, + itemCount, + loading, + changePage, + changePageSize, + onCreate, + onUpdatedList + } = this + + return ( + <> + + {{ + default: () => ( +
+ {`${t( + 'datasource.create_datasource' + )}`} + + +
+ +
+ + + + + +
+
+ ) + }} +
+ + + + + void (this.showDetailModal = false)} + onUpdate={onUpdatedList} + /> + + ) + } +}) +export default list diff --git a/dolphinscheduler-ui-next/src/views/datasource/datasource-list/json-highlight.module.scss b/dolphinscheduler-ui-next/src/views/datasource/datasource-list/json-highlight.module.scss new file mode 100644 index 0000000000..a6f09f0fad --- /dev/null +++ b/dolphinscheduler-ui-next/src/views/datasource/datasource-list/json-highlight.module.scss @@ -0,0 +1,26 @@ +/* + * 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. + */ + +.json-highlight { + display: block; + line-height: 1.5; + font-size: 12px; + padding: 5px; +} +.line { + padding-left: 8px; +} diff --git a/dolphinscheduler-ui-next/src/views/datasource/datasource-list/json-highlight.tsx b/dolphinscheduler-ui-next/src/views/datasource/datasource-list/json-highlight.tsx new file mode 100644 index 0000000000..474e3caf22 --- /dev/null +++ b/dolphinscheduler-ui-next/src/views/datasource/datasource-list/json-highlight.tsx @@ -0,0 +1,67 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { defineComponent, PropType, h } from 'vue' +import { NText } from 'naive-ui' +import { isBoolean, isNumber, isPlainObject } from 'lodash' +import styles from './json-highlight.module.scss' + +const props = { + json: { + type: String as PropType, + default: '' + } +} + +const JsonHighlight = defineComponent({ + name: 'JsonHighlight', + props, + render() { + return ( +
{syntaxHighlight(this.json)}
+ ) + } +}) + +const syntaxHighlight = (json: string) => { + if (!isPlainObject(JSON.parse(json))) return '' + const lines = [] + const entries = Object.entries(JSON.parse(json)) + for (let i = 0, len = entries.length; i < len; i++) { + const [key, value] = entries[i] + let type: string = '' + if (isBoolean(value) || value === null) { + type = 'info' + } else if (isNumber(value)) { + type = 'warning' + } else { + type = 'success' + } + lines.push( + + "{key}": + + "{value}"{i !== len - 1 ? ',' : ''} + + + ) + } + lines.push() + return lines +} + +export default JsonHighlight diff --git a/dolphinscheduler-ui-next/src/views/datasource/datasource-list/types.ts b/dolphinscheduler-ui-next/src/views/datasource/datasource-list/types.ts new file mode 100644 index 0000000000..a3dc8b3c40 --- /dev/null +++ b/dolphinscheduler-ui-next/src/views/datasource/datasource-list/types.ts @@ -0,0 +1,47 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import type { + IDataSource, + IDataBase +} from '@/service/modules/data-source/types' +import type { TableColumns } from 'naive-ui/es/data-table/src/interface' +import type { SelectBaseOption } from 'naive-ui/es/select/src/interface' + +interface IDataSourceDetail extends Omit { + other?: string +} + +interface IDataBaseOption extends SelectBaseOption { + label: string + value: string + defaultPort: number + previousPort?: number +} + +type IDataBaseOptionKeys = { + [key in IDataBase]: IDataBaseOption +} + +export { + IDataSource, + IDataSourceDetail, + IDataBase, + IDataBaseOption, + IDataBaseOptionKeys, + TableColumns +} diff --git a/dolphinscheduler-ui-next/src/views/datasource/datasource-list/use-columns.ts b/dolphinscheduler-ui-next/src/views/datasource/datasource-list/use-columns.ts new file mode 100644 index 0000000000..57ec39cf96 --- /dev/null +++ b/dolphinscheduler-ui-next/src/views/datasource/datasource-list/use-columns.ts @@ -0,0 +1,136 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { h } from 'vue' +import { useI18n } from 'vue-i18n' +import { NPopover, NButton, NIcon, NPopconfirm, NSpace } from 'naive-ui' +import { EditOutlined, DeleteOutlined } from '@vicons/antd' +import JsonHighlight from './json-highlight' +import styles from './index.module.scss' +import { TableColumns } from './types' + +export function useColumns(onCallback: Function) { + const { t } = useI18n() + + const columnsRef: TableColumns = [ + { + title: t('datasource.serial_number'), + key: 'index', + render: (rowData, rowIndex) => rowIndex + 1 + }, + { + title: t('datasource.datasource_name'), + key: 'name' + }, + { + title: t('datasource.datasource_user_name'), + key: 'userName' + }, + { + title: t('datasource.datasource_type'), + key: 'type' + }, + { + title: t('datasource.datasource_parameter'), + key: 'parameter', + render: (rowData) => { + return h( + NPopover, + { trigger: 'click' }, + { + trigger: () => + h( + NButton, + { + quaternary: true, + type: 'primary' + }, + { + default: () => t('datasource.click_to_view') + } + ), + default: () => + h(JsonHighlight, { json: rowData.connectionParams }, null) + } + ) + } + }, + { + title: t('datasource.description'), + key: 'note' + }, + { + title: t('datasource.create_time'), + key: 'createTime' + }, + { + title: t('datasource.update_time'), + key: 'updateTime' + }, + { + title: t('datasource.operation'), + key: 'operation', + width: 150, + render: (rowData, rowIndex) => { + return h(NSpace, null, { + default: () => [ + h( + NButton, + { + circle: true, + class: styles['mr-10'], + type: 'info', + onClick: () => void onCallback(rowData.id, 'edit') + }, + { + default: () => + h(NIcon, null, { default: () => h(EditOutlined) }) + } + ), + h( + NPopconfirm, + { + onPositiveClick: () => void onCallback(rowData.id, 'delete'), + negativeText: t('datasource.cancel'), + positiveText: t('datasource.confirm') + }, + { + trigger: () => + h( + NButton, + { + circle: true, + type: 'error' + }, + { + default: () => + h(NIcon, null, { default: () => h(DeleteOutlined) }) + } + ), + default: () => t('datasource.delete') + } + ) + ] + }) + } + } + ] + + return { + columnsRef + } +} diff --git a/dolphinscheduler-ui-next/src/views/datasource/datasource-list/use-detail.ts b/dolphinscheduler-ui-next/src/views/datasource/datasource-list/use-detail.ts new file mode 100644 index 0000000000..a8d0f33aad --- /dev/null +++ b/dolphinscheduler-ui-next/src/views/datasource/datasource-list/use-detail.ts @@ -0,0 +1,103 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { reactive } from 'vue' +import { + queryDataSource, + createDataSource, + updateDataSource, + connectDataSource, + verifyDataSourceName +} from '@/service/modules/data-source' +import { useI18n } from 'vue-i18n' +import type { IDataSource } from './types' + +export function useDetail(getFieldsValue: Function) { + const { t } = useI18n() + const status = reactive({ + saving: false, + testing: false, + loading: false + }) + + let PREV_NAME: string + + const formatParams = (): IDataSource => { + const values = getFieldsValue() + return { + ...values, + other: values.other ? JSON.parse(values.other) : null + } + } + + const queryById = async (id: number) => { + if (status.loading) return {} + status.loading = true + try { + const dataSourceRes = await queryDataSource(id) + status.loading = false + PREV_NAME = dataSourceRes.name + return dataSourceRes + } catch (e) { + window.$message.error((e as Error).message) + status.loading = false + return {} + } + } + + const testConnect = async () => { + if (status.testing) return + status.testing = true + try { + const res = await connectDataSource(formatParams()) + window.$message.success( + res + ? res.msg + : `${t('datasource.test_connect')} ${t('datasource.success')}` + ) + status.testing = false + } catch (e) { + window.$message.error((e as Error).message) + status.testing = false + } + } + + const createOrUpdate = async (id?: number) => { + const values = getFieldsValue() + if (status.saving || !values.name) return false + status.saving = true + + try { + if (PREV_NAME !== values.name) { + await verifyDataSourceName({ name: values.name }) + } + + id + ? await updateDataSource(formatParams(), id) + : await createDataSource(formatParams()) + + status.saving = false + return true + } catch (e) { + window.$message.error((e as Error).message) + status.saving = false + return false + } + } + + return { status, queryById, testConnect, createOrUpdate } +} diff --git a/dolphinscheduler-ui-next/src/views/datasource/datasource-list/use-form.ts b/dolphinscheduler-ui-next/src/views/datasource/datasource-list/use-form.ts new file mode 100644 index 0000000000..7ff67659dc --- /dev/null +++ b/dolphinscheduler-ui-next/src/views/datasource/datasource-list/use-form.ts @@ -0,0 +1,209 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { reactive, ref } from 'vue' +import { useI18n } from 'vue-i18n' +import { getKerberosStartupState } from '@/service/modules/data-source' +import type { FormRules } from 'naive-ui' +import type { + IDataSourceDetail, + IDataBase, + IDataBaseOption, + IDataBaseOptionKeys +} from './types' + +export function useForm(id?: number) { + const { t } = useI18n() + + const initialValues = { + type: 'MYSQL', + name: '', + note: '', + host: '', + port: datasourceType['MYSQL'].defaultPort, + principal: '', + javaSecurityKrb5Conf: '', + loginUserKeytabUsername: '', + loginUserKeytabPath: '', + userName: '', + password: '', + database: '', + connectType: '', + other: '' + } as IDataSourceDetail + + const state = reactive({ + detailFormRef: ref(), + detailForm: { ...initialValues }, + requiredDataBase: true, + showConnectType: false, + showPrincipal: false, + rules: { + name: { + trigger: ['input'], + validator() { + if (!state.detailForm.name) { + return new Error(t('datasource.datasource_name_tips')) + } + } + }, + host: { + trigger: ['input'], + validator() { + if (!state.detailForm.host) { + return new Error(t('datasource.ip_tips')) + } + } + }, + port: { + trigger: ['input'], + validator() { + if (!state.detailForm.port) { + return new Error(t('datasource.port_tips')) + } + } + }, + principal: { + trigger: ['input'], + validator() { + if (!state.detailForm.principal && state.showPrincipal) { + return new Error(t('datasource.principal_tips')) + } + } + }, + userName: { + trigger: ['input'], + validator() { + if (!state.detailForm.userName) { + return new Error(t('datasource.user_name_tips')) + } + } + }, + database: { + trigger: ['input'], + validator() { + if (!state.detailForm.database && state.requiredDataBase) { + return new Error(t('datasource.database_name_tips')) + } + } + }, + connectType: { + trigger: ['update'], + validator() { + if (!state.detailForm.connectType && state.showConnectType) { + return new Error(t('datasource.oracle_connect_type_tips')) + } + } + } + } as FormRules + }) + + const changeType = async (type: IDataBase, options: IDataBaseOption) => { + state.detailForm.port = options.previousPort || options.defaultPort + state.detailForm.type = type + + if (type === 'ORACLE' && !id) { + state.detailForm.connectType = 'ORACLE_SERVICE_NAME' + } + state.requiredDataBase = type !== 'POSTGRESQL' + state.showConnectType = type === 'ORACLE' + + if (type === 'HIVE' || type === 'SPARK') { + try { + state.showPrincipal = await getKerberosStartupState() + } catch (e) { + window.$message.error((e as Error).message) + } + } else { + state.showPrincipal = false + } + } + + const changePort = async () => { + if (!state.detailForm.type) return + const currentDataBaseOption = datasourceType[state.detailForm.type] + currentDataBaseOption.previousPort = state.detailForm.port + } + + const resetFieldsValue = () => { + state.detailForm = { ...initialValues } + } + const setFieldsValue = (values: object) => { + state.detailForm = { ...state.detailForm, ...values } + } + const getFieldsValue = () => state.detailForm + + return { + state, + changeType, + changePort, + resetFieldsValue, + setFieldsValue, + getFieldsValue + } +} + +const datasourceType: IDataBaseOptionKeys = { + MYSQL: { + value: 'MYSQL', + label: 'MYSQL', + defaultPort: 3306 + }, + POSTGRESQL: { + value: 'POSTGRESQL', + label: 'POSTGRESQL', + defaultPort: 5432 + }, + HIVE: { + value: 'HIVE', + label: 'HIVE/IMPALA', + defaultPort: 10000 + }, + SPARK: { + value: 'SPARK', + label: 'SPARK', + defaultPort: 10015 + }, + CLICKHOUSE: { + value: 'CLICKHOUSE', + label: 'CLICKHOUSE', + defaultPort: 8123 + }, + ORACLE: { + value: 'ORACLE', + label: 'ORACLE', + defaultPort: 1521 + }, + SQLSERVER: { + value: 'SQLSERVER', + label: 'SQLSERVER', + defaultPort: 1433 + }, + DB2: { + value: 'DB2', + label: 'DB2', + defaultPort: 50000 + }, + PRESTO: { + value: 'PRESTO', + label: 'PRESTO', + defaultPort: 8080 + } +} + +export const datasourceTypeList: IDataBaseOption[] = + Object.values(datasourceType) diff --git a/dolphinscheduler-ui-next/src/views/datasource/datasource-list/use-table.ts b/dolphinscheduler-ui-next/src/views/datasource/datasource-list/use-table.ts new file mode 100644 index 0000000000..bcb3c3df0c --- /dev/null +++ b/dolphinscheduler-ui-next/src/views/datasource/datasource-list/use-table.ts @@ -0,0 +1,82 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { reactive } from 'vue' +import { + queryDataSourceListPaging, + deleteDataSource +} from '@/service/modules/data-source' + +export function useTable() { + const data = reactive({ + page: 1, + pageSize: 10, + itemCount: 0, + searchVal: '', + list: [], + loading: false + }) + + const getList = async () => { + if (data.loading) return + data.loading = true + + try { + const listRes = await queryDataSourceListPaging({ + pageNo: data.page, + pageSize: data.pageSize, + searchVal: data.searchVal + }) + data.loading = false + data.list = listRes.totalList + data.itemCount = listRes.total + } catch (e) { + window.$message.error((e as Error).message) + data.loading = false + data.list = [] + } + } + + const updateList = () => { + if (data.list.length === 1 && data.page > 1) { + --data.page + } + getList() + } + + const deleteRecord = async (id: number) => { + try { + const res = await deleteDataSource(id) + updateList() + } catch (e) { + window.$message.error((e as Error).message) + } + } + + const changePage = (page: number) => { + data.page = page + getList() + } + + const changePageSize = (pageSize: number) => { + data.page = 1 + data.pageSize = pageSize + getList() + } + + return { data, changePage, changePageSize, deleteRecord, updateList } +}