diff --git a/.eslintrc b/.eslintrc index 0a25792..1541dc7 100644 --- a/.eslintrc +++ b/.eslintrc @@ -30,7 +30,8 @@ "no-use-before-define": [ "error", { - "functions": false + "functions": false, + "classes ": false } ], "new-cap": [ @@ -179,7 +180,7 @@ "array-bracket-spacing": ["error", "never"], // 数组紧贴括号部分不允许包含空格 "object-curly-spacing": ["error", "always"], // 对象紧贴花括号部分不允许包含空格 "no-regex-spaces": "error", // 禁止正则表达式字面量中出现多个空格 - "no-multi-spaces": "error", // 禁止出现多个空格而且不是用来作缩进的 + // "no-multi-spaces": "error", // 禁止出现多个空格而且不是用来作缩进的 "block-spacing": ["error", "never"], // 单行代码块中紧贴括号部分不允许包含空格 "computed-property-spacing": ["error", "never"], // 禁止括号和其内部值之间的空格 "no-trailing-spaces": [ diff --git a/package.json b/package.json index d7f4eac..5431bfb 100644 --- a/package.json +++ b/package.json @@ -18,8 +18,8 @@ "devDependencies": { "@fui/babel-preset-fineui": "^1.0.0", "@types/jest": "24.0.11", - "@typescript-eslint/eslint-plugin": "1.7.0", - "@typescript-eslint/parser": "1.7.0", + "@typescript-eslint/eslint-plugin": "^5.0.0", + "@typescript-eslint/parser": "^5.0.0", "axios": "0.18.0", "babel-loader": "8.0.6", "body-parser": "1.18.3", diff --git a/src/modules/components/file_chooser/file_chooser.model.ts b/src/modules/components/file_chooser/file_chooser.model.ts new file mode 100644 index 0000000..4850d0c --- /dev/null +++ b/src/modules/components/file_chooser/file_chooser.model.ts @@ -0,0 +1,68 @@ +import { model, Model } from '@core/core'; + +type RootInfo = { + url: string; // api url + prefix: string; // 路径前缀 + root: string; // 根文件夹名称 +}; + +export const ROOT_INFO_MAP: Record = { + // 证书 resources/certificates/ + certificates: { + url: '/v10/certificates/all', + prefix: 'resources/', + root: 'certificates', + }, +}; + +@model() +export class FileChooserModel extends Model { + static xtype = 'dec.dcm.model.components.file_chooser'; + + private options: { + root: string; + }; + + state() { + return { + keyword: '', // 搜索关键字 + items: [], // 文件项 + }; + } + + actions = { + /** + * 请求获取items + * @param callback 回调 + */ + requestGetItems: (callback?: Function) => { + const { keyword } = this.model; + const { url, prefix, root } = ROOT_INFO_MAP[this.options.root]; + const requestUrl = `${url}?keyword=${encodeURIComponent(keyword)}`; + Dec.reqGetHandle(requestUrl, '', (data) => { + this.model.items = data + .concat({ + id: root, + text: root, + value: prefix + root, + }) + .map((item) => ({ + ...item, + text: item.id, + value: prefix + item.path, + open: item.id === root || BI.isKey(keyword), + })); + BI.isFunction(callback) && callback(); + }); + }, + + /** + * 设置keyword + * @param value + */ + setKeyword: (value: string) => { + this.model.keyword = value; + this.requestGetItems(); + }, + }; +} diff --git a/src/modules/components/file_chooser/file_chooser.ts b/src/modules/components/file_chooser/file_chooser.ts new file mode 100644 index 0000000..53200f7 --- /dev/null +++ b/src/modules/components/file_chooser/file_chooser.ts @@ -0,0 +1,182 @@ +import { EVENT_CHANGE } from './../collapse/collapse'; +import { shortcut, store } from '@core/core'; +import { SignEditor, MultiLayerSingleLevelTree, SearchEditor, Button, Editor } from '@fui/core'; +import { FileChooserModel } from './file_chooser.model'; + +@shortcut() +@store(FileChooserModel, { + props(this: FileChooser) { + return this.options; + }, +}) +export class FileChooser extends BI.Widget { + static xtype = 'dec.dcm.components.file_chooser'; + + props = { + width: 300, + root: '', // 含义见model中的RootInfo + watermark: '', + value: '', + }; + + model: FileChooserModel['model']; + store: FileChooserModel['store']; + watch = { + items: (value) => { + this.fileTree.populate(value); + }, + }; + + textEditor: SignEditor; + keywordEditor: SearchEditor; + fileTree: MultiLayerSingleLevelTree; + sureButton: Button; + + render() { + const { width, watermark, value } = this.options; + + return { + type: BI.VerticalAdaptLayout.xtype, + height: 20, + items: [ + { + type: BI.SignEditor.xtype, + cls: 'bi-border bi-focus-shadow', + width, + watermark, + title: value, + value, + ref: (_ref: SignEditor) => { + this.textEditor = _ref; + }, + listeners: [ + { + eventName: BI.SignEditor.EVENT_CHANGE, + action: () => { + const value = this.textEditor.getValue(); + this.setValue(value); + }, + }, + ], + }, + { + el: { + type: BI.Button.xtype, + + text: BI.i18nText('Dec-Basic_Choose_File'), + clear: true, + handler: () => { + this.openFileChoosePopover(); + }, + }, + lgap: 10, + }, + ], + }; + } + + getValue(): string { + return this.textEditor.getValue(); + } + + setValue(value: string) { + this.options.value = value; + this.textEditor.text.setTitle(value); + this.textEditor.setValue(value); + } + + /** + * 打开文件选择弹窗 + */ + private openFileChoosePopover() { + // 重置搜索关键词 + this.store.setKeyword(''); + // 创建并显示窗口 + const popoverName = BI.UUID(); + BI.Popovers.create( + popoverName, + { + header: BI.i18nText('Dec-Data_Set_File_Select_Server_File'), + body: { + type: BI.VTapeLayout.xtype, + items: [ + { + type: BI.SearchEditor.xtype, + ref: (ref: SearchEditor) => { + this.keywordEditor = ref; + }, + height: 24, + value: this.model.keyword, + listeners: [ + { + eventName: BI.SearchEditor.EVENT_CHANGE, + action: () => { + const value = this.keywordEditor.getValue(); + this.store.setKeyword(value); + }, + }, + { + eventName: BI.SearchEditor.EVENT_CLEAR, + action: () => { + this.store.setKeyword(''); + }, + }, + ], + }, + { + el: { + type: BI.MultiLayerSingleLevelTree.xtype, + ref: (ref: MultiLayerSingleLevelTree) => { + this.fileTree = ref; + }, + keywordGetter: () => this.model.keyword, + items: this.model.items, + listeners: [ + { + eventName: BI.MultiLayerSingleLevelTree.EVENT_CHANGE, + action: () => { + this.sureButton.setEnable(true); + }, + }, + ], + }, + tgap: 15, + }, + { + type: BI.RightVerticalAdaptLayout.xtype, + height: 24, + vgap: 10, + items: [ + { + type: BI.Button.xtype, + text: BI.i18nText('BI-Basic_Cancel'), + level: 'ignore', + handler: () => { + BI.Popovers.remove(popoverName); + }, + }, + { + el: { + type: BI.Button.xtype, + ref: (ref: Button) => { + this.sureButton = ref; + }, + text: BI.i18nText('BI-Basic_OK'), + disabled: true, + handler: () => { + const value = this.fileTree.getValue()[0]; + this.setValue(value); + BI.Popovers.remove(popoverName); + }, + }, + lgap: 10, + }, + ], + }, + ], + }, + }, + this + ).show(popoverName); + } +} diff --git a/src/modules/components/text_checker/text_checker.ts b/src/modules/components/text_checker/text_checker.ts index c7984c0..339e1c2 100644 --- a/src/modules/components/text_checker/text_checker.ts +++ b/src/modules/components/text_checker/text_checker.ts @@ -3,87 +3,97 @@ import { Label, TextEditor } from '@fui/core'; @shortcut() export class TextChecker extends BI.Widget { - static xtype = 'dec.dcm.components.text_checker'; + public static xtype = 'dec.dcm.components.text_checker'; - props = { + public props = { width: 300, allowBlank: true, value: '', watermark: '', + inputType: 'text', + autocomplete: '', validationChecker: [] as { errorText: string; checker: (value: string) => boolean; autoFix?: boolean; }[], $value: '', - } + }; - textEditor: TextEditor; - errorLabel: Label; + public textEditor: TextEditor; + public errorLabel: Label; private isError: boolean; private value: string; private errorChecker: { errorText: string; checker: (value: string) => boolean; autoFix?: boolean; - } + }; - render() { - const { width, allowBlank, value, watermark, validationChecker, $value } = this.options; + public render() { + const { width, allowBlank, value, watermark, inputType, autocomplete, validationChecker, $value } = this.options; this.value = value; - + return { type: BI.AbsoluteLayout.xtype, width, height: 20, - items: [{ - el: { - type: BI.TextEditor.xtype, - $value, - width, - allowBlank, - value, - watermark, - ref: (_ref: TextEditor) => { - this.textEditor = _ref; - }, - listeners: [{ - eventName: BI.Editor.EVENT_CHANGE, - action: () => { - const value = this.getValue(); - if (value) { - this.errorChecker = validationChecker.find(item => item.checker && !item.checker(value)); - this.errorLabel.setText(BI.get(this.errorChecker, 'errorText')); - this.isError = !!BI.get(this.errorChecker, 'errorText'); - } else { - this.errorLabel.setText(''); - this.isError = false; - } - if (!this.isError) { - this.value = value; - } - this.fireEvent(BI.Editor.EVENT_CHANGE); - }, - }, { - eventName: BI.TextEditor.EVENT_BLUR, - action: () => { - if (BI.get(this.errorChecker, 'autoFix')) { - this.setValue(this.value); - this.errorLabel.setText(''); - } + items: [ + { + el: { + type: BI.TextEditor.xtype, + $value, + width, + allowBlank, + value, + watermark, + inputType, + autocomplete, + ref: (_ref: TextEditor) => { + this.textEditor = _ref; }, - }], + listeners: [ + { + eventName: BI.Editor.EVENT_CHANGE, + action: () => { + const value = this.getValue(); + if (value) { + this.errorChecker = validationChecker.find((item) => item.checker && !item.checker(value)); + this.errorLabel.setText(BI.get(this.errorChecker, 'errorText')); + this.isError = !!BI.get(this.errorChecker, 'errorText'); + } else { + this.errorLabel.setText(''); + this.isError = false; + } + if (!this.isError) { + this.value = value; + } + this.fireEvent(BI.Editor.EVENT_CHANGE); + }, + }, + { + eventName: BI.TextEditor.EVENT_BLUR, + action: () => { + if (BI.get(this.errorChecker, 'autoFix')) { + this.setValue(this.value); + this.errorLabel.setText(''); + } + }, + }, + ], + }, }, - }, { - el: { - type: BI.Label.xtype, - cls: 'bi-error', - ref: (_ref: Label) => { - this.errorLabel = _ref; + { + el: { + type: BI.Label.xtype, + cls: 'bi-error', + ref: (_ref: Label) => { + this.errorLabel = _ref; + }, }, + top: -15, }, - top: -15, - }], + ], }; } @@ -98,4 +108,8 @@ export class TextChecker extends BI.Widget { public setError(value: string) { this.errorLabel.setText(value); } + + public setWatermark(value: string) { + this.textEditor.setWaterMark(value); + } } diff --git a/src/modules/constants/constant.ts b/src/modules/constants/constant.ts index 37da373..4fabf64 100644 --- a/src/modules/constants/constant.ts +++ b/src/modules/constants/constant.ts @@ -734,6 +734,28 @@ export const CONNECT_CHARSET = [ }, ]; +export const CONNECT_SSH_TYPE = [ + { + text: BI.i18nText('Dec-Dcm_Connection_Form_Password'), + value: 'NORMAL', + privateKeyPathFormVisible: false, + secretFormName: BI.i18nText('Dec-Dcm_Connection_Form_Password'), + }, + { + text: BI.i18nText('Dec-Dcm_Connection_Form_PublicKey'), + value: 'KEY', + privateKeyPathFormVisible: true, + secretFormName: BI.i18nText('Dec-Dcm_Connection_Form_Passphrase'), + }, +]; + +export const CONNECT_SSL_TYPE = [ + { + text: BI.i18nText('Dec-Dcm_Connection_Form_Password'), + value: 'NORMAL', + }, +]; + export const TEST_STATUS = { LOADING: 'loading', SUCCESS: 'success', diff --git a/src/modules/crud/crud.typings.d.ts b/src/modules/crud/crud.typings.d.ts index 9f0f69f..43d6dee 100644 --- a/src/modules/crud/crud.typings.d.ts +++ b/src/modules/crud/crud.typings.d.ts @@ -1,3 +1,7 @@ +export interface CrudParams { + [key: string]: string | number | { [key: string]: any }; +} + export interface CrudReqOpts { url?: string; type?: 'GET' | 'POST' | 'DELETE' | 'PUT'; @@ -9,28 +13,104 @@ export interface CrudReqOpts { params?: CrudParams; } -export interface CrudParams { - [key: string]: string | number | { [key: string]: any }; +export interface ConnectionLicInfo { + currentConnectionNum: number; + maxConnectionNum: number; } -export interface Connection { - connectionId: string; - connectionType: string; - connectionName: string; - creator?: string; - connectionData: ConnectionJDBC | ConnectionJNDI | ConnectionPlugin | string; - privilegeDetailBeanList?: { - privilegeType: number; - privilegeValue: number; - }[]; +export interface ConnectionPoolType { + maxActive: number; + maxIdle: number; + numActive: number; + numIdle: number; } -export interface ConnectionLicInfo { - currentConnectionNum: number; - maxConnectionNum: number; +type ConnectionDataOfSSH = { + usingSsh: boolean; // 使用SSH通道 + sshIp: string; // 主机 + sshPort: number; // 端口 + sshUser: string; // 用户名 + redirectPort: number; + redirectIp: string; + sshTimeOut: number; + sshKeepAlive: number; +} & ( + | { + sshType: 'NORMAL'; // 验证方法:密码 + sshPrivateKeyPath: ''; // 没啥意义,该验证方法下为空字符串 + sshSecret: string; // 密码 + } + | { + sshType: 'KEY'; // 验证方法:公钥 + sshPrivateKeyPath: string; // 私钥 + sshSecret: string; // 密码短语 + } +); + +type ConnectionDataOfSSL = { + usingSsl: boolean; // 使用SSL通道 + sslType: 'NORMAL'; // SSL类型,只有NORMAL一种 + caCertificate: string; // CA证书 + verifyCa: boolean; // 验证针对CA的服务器证书 + sslClientPrivateKey: string; // 客户端密钥 + sslClientCertificate: string; // 客户端证书 +}; + +export interface ConnectionPoolJDBC { + /** + * 初始化连接数量 + */ + initialSize?: number; + /** + * 最大连接数 + */ + maxActive?: number; + /** + * 最大空闲数 + */ + maxIdle?: number; + /** + * 最小空闲数 + */ + minIdle?: number; + /** + * 最大等待时间 + */ + maxWait?: number; + /** + * sql查询 + */ + validationQuery?: string; + + /** + * 连接前校验 + */ + testOnBorrow?: boolean; + + /** + * 归还前校验 + */ + testOnReturn?: boolean; + + /** + * 空闲校验 + */ + testWhileIdle?: boolean; + /** + * 在空闲连接回收器线程运行期间休眠的时间值,毫秒。 + */ + timeBetweenEvictionRunsMillis?: number; + /** + * 每次空闲连接回收器现成运行时检查的连接数量 + */ + numTestsPerEvictionRun?: number; + /** + * 连接在池中保持空闲而不被空闲连接回收器回收的最小时间,单位毫秒 + */ + minEvictableIdleTimeMillis?: number; } -export interface ConnectionJDBC { +export type ConnectionJDBC ={ /** * 数据库名称 */ @@ -44,6 +124,10 @@ export interface ConnectionJDBC { * 驱动 */ driver: string; + /** + * 驱动来源 + */ + driverSource: 'default' | 'custom'; /** * 数据库连接url */ @@ -118,72 +202,8 @@ export interface ConnectionJDBC { identity?: string; connectionPoolAttr: ConnectionPoolJDBC; -} - -export interface ConnectionPoolJDBC { - /** - * 初始化连接数量 - */ - initialSize?: number; - /** - * 最大连接数 - */ - maxActive?: number; - /** - * 最大空闲数 - */ - maxIdle?: number; - /** - * 最小空闲数 - */ - minIdle?: number; - /** - * 最大等待时间 - */ - maxWait?: number; - /** - * sql查询 - */ - validationQuery?: string; - - /** - * 连接前校验 - */ - testOnBorrow?: boolean; - - /** - * 归还前校验 - */ - testOnReturn?: boolean; - - /** - * 空闲校验 - */ - testWhileIdle?: boolean; - /** - * 在空闲连接回收器线程运行期间休眠的时间值,毫秒。 - */ - timeBetweenEvictionRunsMillis?: number; - /** - * 每次空闲连接回收器现成运行时检查的连接数量 - */ - numTestsPerEvictionRun?: number; - /** - * 连接在池中保持空闲而不被空闲连接回收器回收的最小时间,单位毫秒 - */ - minEvictableIdleTimeMillis?: number; -} - -export interface ConnectionJNDI { - jndiName: string; - /** - * 编码 - */ - originalCharsetName: string; - newCharsetName: string; - creator?: string; - contextHashtable: ContextHashtable; -} +}& ConnectionDataOfSSH & +ConnectionDataOfSSL export interface ContextHashtable { 'java.naming.factory.initial': string; @@ -203,25 +223,41 @@ export interface ContextHashtable { 'java.naming.applet': string; } +export interface ConnectionJNDI { + jndiName: string; + /** + * 编码 + */ + originalCharsetName: string; + newCharsetName: string; + creator?: string; + contextHashtable: ContextHashtable; +} + export interface ConnectionPlugin { pluginType: 'json'; creator: ''; pluginData: any; } +export interface Connection { + connectionId: string; + connectionType: string; + connectionName: string; + creator?: string; + connectionData: ConnectionJDBC | ConnectionJNDI | ConnectionPlugin | string; + privilegeDetailBeanList?: { + privilegeType: number; + privilegeValue: number; + }[]; +} + export interface TestRequest { data?: string[]; errorCode?: string; errorMsg?: string; } -export interface ConnectionPoolType { - maxActive: number; - maxIdle: number; - numActive: number; - numIdle: number; -} - export interface SocketResult { data?: string; errorCode?: string; diff --git a/src/modules/pages/connection/connection_jdbc/connection_jdbc.ts b/src/modules/pages/connection/connection_jdbc/connection_jdbc.ts index a65d97b..d4e37dd 100644 --- a/src/modules/pages/connection/connection_jdbc/connection_jdbc.ts +++ b/src/modules/pages/connection/connection_jdbc/connection_jdbc.ts @@ -4,7 +4,7 @@ import { Collapse, EVENT_CHANGE } from 'src/modules/components/collapse/collapse import { ConnectionJdecModel } from './connection_jdbc.model'; import { ConnectionJDBC } from 'src/modules/crud/crud.typings'; import { getAllDatabaseTypes, getJdbcDatabaseType, resolveUrlInfo } from '../../../app.service'; -import { CONNECTION_LAYOUT } from '@constants/constant'; +import { CONNECTION_LAYOUT, CONNECT_SSH_TYPE } from '@constants/constant'; import { VerticalLayout } from '@fui/core'; import { ApiFactory } from '../../../crud/apiFactory'; @@ -15,10 +15,13 @@ const api = new ApiFactory().create(); export class ConnectionJdbc extends BI.Widget { static xtype = 'dec.dcm.connection_jdbc'; - advancedSet: any; model: ConnectionJdecModel['model']; allDatabaseTypes = getAllDatabaseTypes(); + sshSet: VerticalLayout; + sslSet: VerticalLayout; + advancedSet: VerticalLayout; + render() { const connectionData = this.model.connectionSelectedOne.connectionData as ConnectionJDBC; const { @@ -33,6 +36,20 @@ export class ConnectionJdbc extends BI.Widget { principal, url, fetchSize, + // ssh + usingSsh, + sshIp, + sshPort, + sshUser, + sshType, + sshSecret, + sshPrivateKeyPath, + // ssl + usingSsl, + caCertificate, + verifyCa, + sslClientPrivateKey, + sslClientCertificate, } = connectionData; const databaseType = getJdbcDatabaseType(database, driver); const { host, port, databaseName } = resolveUrlInfo(url, database); @@ -63,14 +80,15 @@ export class ConnectionJdbc extends BI.Widget { name: BI.i18nText('Dec-Dcm_Connection_Form_Database_Port'), value: port, }, - authType ? - { - type: FormItem.xtype, - name: BI.i18nText('Dec-Dcm_Connection_Form_AuthType'), - value: authType, - } : { - type: BI.Layout.xtype, - }, + authType + ? { + type: FormItem.xtype, + name: BI.i18nText('Dec-Dcm_Connection_Form_AuthType'), + value: authType, + } + : { + type: BI.Layout.xtype, + }, { type: FormItem.xtype, name: authType ? BI.i18nText('Dec-Dcm_Connection_Form_Principal') : BI.i18nText('Dec-Dcm_Connection_Form_UserName'), @@ -118,9 +136,114 @@ export class ConnectionJdbc extends BI.Widget { value: connectionPoolAttr.maxWait, unit: BI.i18nText('Dec-Dcm_Millisecond'), }, + // ssh设置 + { + type: Collapse.xtype, + width: 100, + invisible: !usingSsh, + name: BI.i18nText('Dec-Dcm_Connection_Setting', 'SSH'), + listeners: [ + { + eventName: EVENT_CHANGE, + action: (isCollapse: boolean) => { + this.sshSet.setVisible(!isCollapse); + }, + }, + ], + }, + { + type: BI.VerticalLayout.xtype, + tgap: -15, + vgap, + invisible: true, + ref: (_ref: VerticalLayout) => { + this.sshSet = _ref; + }, + items: [ + { + type: FormItem.xtype, + name: BI.i18nText('Dec-Dcm_Connection_Form_Host'), + value: sshIp, + }, + { + type: FormItem.xtype, + name: BI.i18nText('Dec-Dcm_Connection_Form_Database_Port'), + value: sshPort, + }, + { + type: FormItem.xtype, + name: BI.i18nText('Dec-Dcm_Connection_Form_UserName'), + value: sshUser, + }, + { + type: FormItem.xtype, + name: BI.i18nText('Dec-Dcm_Connection_Form_VerifyType'), + value: CONNECT_SSH_TYPE.find((SSH_TYPE) => sshType === SSH_TYPE.value).text, + }, + { + type: FormItem.xtype, + invisible: sshType !== 'KEY', + name: BI.i18nText('Dec-Dcm_Connection_Form_PrivateKey'), + value: sshPrivateKeyPath, + }, + { + type: FormItem.xtype, + name: CONNECT_SSH_TYPE.find((SSH_TYPE) => sshType === SSH_TYPE.value).secretFormName, + value: sshSecret, + }, + ], + }, + // ssl设置 { type: Collapse.xtype, - width: 70, + width: 100, + invisible: !usingSsl, + name: BI.i18nText('Dec-Dcm_Connection_Setting', 'SSL'), + listeners: [ + { + eventName: EVENT_CHANGE, + action: (isCollapse: boolean) => { + this.sslSet.setVisible(!isCollapse); + }, + }, + ], + }, + { + type: BI.VerticalLayout.xtype, + tgap: -15, + vgap, + invisible: true, + ref: (_ref: VerticalLayout) => { + this.sslSet = _ref; + }, + items: [ + { + type: FormItem.xtype, + name: BI.i18nText('Dec-Dcm_Connection_Form_CA_Certificate'), + value: caCertificate, + }, + { + type: FormItem.xtype, + invisible: !caCertificate, + name: BI.i18nText('Dec-Dcm_Connection_Form_Verify_CA_Certificate'), + value: verifyCa ? BI.i18nText('Dec-Dcm_Yes') : BI.i18nText('Dec-Dcm_No'), + }, + { + type: FormItem.xtype, + name: BI.i18nText('Dec-Dcm_Connection_Client') + BI.i18nText('Dec-Dcm_Connection_Form_SecretKey'), + value: sslClientPrivateKey, + }, + { + type: FormItem.xtype, + name: BI.i18nText('Dec-Dcm_Connection_Client') + BI.i18nText('Dec-Dcm_Connection_Form_Certificate'), + value: sslClientCertificate, + }, + ], + }, + // 更多设置 + { + type: Collapse.xtype, + width: 100, name: BI.i18nText('Dec-Dcm_Connection_Form_Database_More_Setting'), listeners: [ { @@ -176,7 +299,8 @@ export class ConnectionJdbc extends BI.Widget { name: BI.i18nText('Dec-Dcm_Connection_Form_Database_Min_Evictable_Idle_Time_Millis'), value: connectionPoolAttr.minEvictableIdleTimeMillis, unit: BI.i18nText('BI-Basic_Seconds'), - }, { + }, + { type: FormItem.xtype, invisible: fetchSize < 0 && fetchSize !== -2, name: 'Fetchsize', diff --git a/src/modules/pages/maintain/components/form_item/form_item.ts b/src/modules/pages/maintain/components/form_item/form_item.ts index 00b6f1a..a0d54eb 100644 --- a/src/modules/pages/maintain/components/form_item/form_item.ts +++ b/src/modules/pages/maintain/components/form_item/form_item.ts @@ -1,4 +1,5 @@ import { shortcut } from '@core/core'; +import { Label } from '@fui/core'; import { CONNECTION_LAYOUT } from '@constants/constant'; @shortcut() @@ -11,14 +12,19 @@ export class FormItem extends BI.Widget { nameWidth: 140, isBold: true, $testId: 'dec-dcm-maintain-form-item', - } + }; + + nameLabel: Label; - render () { + render() { return { type: BI.FloatLeftLayout.xtype, items: [ { type: BI.Label.xtype, + ref: (ref: Label) => { + this.nameLabel = ref; + }, cls: this.options.isBold ? 'bi-font-bold' : '', width: this.options.nameWidth, textAlign: 'left', @@ -29,4 +35,12 @@ export class FormItem extends BI.Widget { ], }; } + + /** + * 设置表单名称 + * @param name + */ + setName(name: string) { + this.nameLabel.setText(name); + } } diff --git a/src/modules/pages/maintain/forms/components/form.jdbc.ts b/src/modules/pages/maintain/forms/components/form.jdbc.ts index b432d04..ffdbb1d 100644 --- a/src/modules/pages/maintain/forms/components/form.jdbc.ts +++ b/src/modules/pages/maintain/forms/components/form.jdbc.ts @@ -3,19 +3,13 @@ import { Collapse, EVENT_CHANGE } from 'src/modules/components/collapse/collapse import { FormItem } from '../../components/form_item/form_item'; import { Connection, ConnectionJDBC, ConnectionPoolJDBC } from 'src/modules/crud/crud.typings'; import { connectionType } from '@constants/env'; -import { CONNECT_CHARSET, CONNECTION_LAYOUT, INT_MAX_VALUE, INT_MIN_VALUE } from '@constants/constant'; +import { CONNECT_CHARSET, CONNECTION_LAYOUT, INT_MAX_VALUE, INT_MIN_VALUE, CONNECT_SSH_TYPE, CONNECT_SSL_TYPE } from '@constants/constant'; import { getAllDatabaseTypes, getJdbcDatabaseType, resolveUrlInfo, splitUrl } from '../../../../app.service'; +import { DatabaseType } from 'src/modules/app.typings'; import { TextChecker } from '../../../../components/text_checker/text_checker'; +import { FileChooser } from '../../../../components/file_chooser/file_chooser'; import { ApiFactory } from 'src/modules/crud/apiFactory'; -import { - Editor, - EditorIconCheckCombo, - Label, - TextAreaEditor, - TextEditor, - TextValueCombo, - VerticalLayout, -} from '@fui/core'; +import { Editor, Label, TextAreaEditor, TextEditor, TextValueCombo, VerticalLayout, MultiSelectItem } from '@fui/core'; import { DriverSelector } from '../../components/driverselector/driverselector'; const api = new ApiFactory().create(); @@ -29,8 +23,15 @@ export class FormJdbc extends BI.Widget { }; oldPassword = ''; + oldSshSecret = ''; + + databaseType: DatabaseType; allDatabaseTypes = getAllDatabaseTypes(); + sshSet: VerticalLayout; + sshForm: VerticalLayout; + sslSet: VerticalLayout; + sslForm: VerticalLayout; advancedSet: VerticalLayout; formUser: FormItem; formPassword: FormItem; @@ -55,6 +56,23 @@ export class FormJdbc extends BI.Widget { initialSize: null, maxActive: null, maxWait: null, + // ssh + usingSsh: null, + sshIp: null, + sshPort: null, + sshUser: null, + sshType: null, + sshPrivateKeyPathForm: null, + sshPrivateKeyPath: null, + sshSecretForm: null, + sshSecret: null, + // ssl + usingSsl: null, + caCertificate: null, + verifyCa: null, + sslClientPrivateKey: null, + sslClientCertificate: null, + // more validationQuery: null, testOnBorrow: null, testOnReturn: null, @@ -82,7 +100,24 @@ export class FormJdbc extends BI.Widget { principal, keyPath, fetchSize, + // ssh + usingSsh = false, + sshIp, // sshIp默认值在表单那用||设置,因为在这可能是空字符串,解构默认值没用 + sshPort = 22, + sshUser = '', + sshType = CONNECT_SSH_TYPE[0].value, + sshPrivateKeyPath = '', + sshSecret = '', + // ssl + usingSsl = false, + caCertificate = '', + verifyCa = false, + sslClientPrivateKey = '', + sslClientCertificate = '', } = connectionData as ConnectionJDBC; + this.oldPassword = password; + this.oldSshSecret = sshSecret; + const { initialSize, maxActive, @@ -97,7 +132,8 @@ export class FormJdbc extends BI.Widget { minEvictableIdleTimeMillis, } = connectionPoolAttr as ConnectionPoolJDBC; const databaseType = getJdbcDatabaseType(database, driver); - this.oldPassword = password; + this.databaseType = databaseType; + const { host, port, databaseName } = resolveUrlInfo(url, database); const { hgap, vgap } = CONNECTION_LAYOUT; @@ -112,21 +148,25 @@ export class FormJdbc extends BI.Widget { hgap, vgap, items: [ + // 数据连接名称 { type: FormItem.xtype, name: BI.i18nText('Dec-Dcm_Connection_Name'), - forms: [{ - type: TextChecker.xtype, - $value: 'connection-name', - width: 300, - value: connectionName, - allowBlank: true, - ref: (_ref: TextChecker) => { - this.form.connectionName = _ref; - }, - watermark: BI.i18nText('Dec-Dcm_Data_Connections'), - }], + forms: [ + { + type: TextChecker.xtype, + $value: 'connection-name', + width: 300, + value: connectionName, + allowBlank: true, + ref: (_ref: TextChecker) => { + this.form.connectionName = _ref; + }, + watermark: BI.i18nText('Dec-Dcm_Data_Connections'), + }, + ], }, + // 驱动 { type: FormItem.xtype, name: BI.i18nText('Dec-Dcm_Connection_Form_Driver'), @@ -159,111 +199,133 @@ export class FormJdbc extends BI.Widget { }, ], }, + // 数据库名称 { type: FormItem.xtype, name: BI.i18nText('Dec-Dcm_Connection_Form_Database_Name'), - forms: [{ - type: BI.TextEditor.xtype, - $value: 'database-name', - width: 300, - allowBlank: true, - watermark: BI.i18nText('Dec-Dcm_Connection_Form_Database_Name'), - value: databaseName, - ref: (_ref: any) => { - this.form.database = _ref; - }, - listeners: [{ - eventName: BI.Editor.EVENT_CHANGE, - action: () => { - this.onHostPortChange(databaseType); + forms: [ + { + type: BI.TextEditor.xtype, + $value: 'database-name', + width: 300, + allowBlank: true, + watermark: BI.i18nText('Dec-Dcm_Connection_Form_Database_Name'), + value: databaseName, + ref: (_ref: any) => { + this.form.database = _ref; }, - }], - }], + listeners: [ + { + eventName: BI.Editor.EVENT_CHANGE, + action: () => { + this.onHostPortChange(databaseType); + }, + }, + ], + }, + ], }, + // 主机 { type: FormItem.xtype, name: BI.i18nText('Dec-Dcm_Connection_Form_Host'), - forms: [{ - type: BI.TextEditor.xtype, - $value: 'database-host', - width: 300, - allowBlank: true, - value: host, - watermark: BI.i18nText('Dec-Dcm_Connection_Form_Host'), - ref: (_ref: any) => { - this.form.host = _ref; - }, - listeners: [{ - eventName: BI.Editor.EVENT_CHANGE, - action: () => { - this.onHostPortChange(databaseType); + forms: [ + { + type: BI.TextEditor.xtype, + $value: 'database-host', + width: 300, + allowBlank: true, + value: host, + watermark: BI.i18nText('Dec-Dcm_Connection_Form_Host'), + ref: (_ref: any) => { + this.form.host = _ref; }, - }], - }], + listeners: [ + { + eventName: BI.Editor.EVENT_CHANGE, + action: () => { + this.onHostPortChange(databaseType); + }, + }, + ], + }, + ], }, + // 端口 { type: FormItem.xtype, name: BI.i18nText('Dec-Dcm_Connection_Form_Database_Port'), - forms: [{ - type: TextChecker.xtype, - $value: 'database-port', - width: 300, - allowBlank: true, - value: port, - watermark: BI.i18nText('Dec-Dcm_Connection_Form_Database_Port'), - validationChecker: [{ - errorText: BI.i18nText('Dec-Dcm_Connection_Check_Integer'), - checker: (value: string) => this.checkInteger(value), - autoFix: true, - }, valueRangeConfig], - ref: (_ref: TextChecker) => { - this.form.port = _ref; - }, - listeners: [{ - eventName: BI.Editor.EVENT_CHANGE, - action: () => { - this.onHostPortChange(databaseType); + forms: [ + { + type: TextChecker.xtype, + $value: 'database-port', + width: 300, + allowBlank: true, + value: port, + watermark: BI.i18nText('Dec-Dcm_Connection_Form_Database_Port'), + validationChecker: [ + { + errorText: BI.i18nText('Dec-Dcm_Connection_Check_Integer'), + checker: (value: string) => this.checkInteger(value), + autoFix: true, + }, + valueRangeConfig, + ], + ref: (_ref: TextChecker) => { + this.form.port = _ref; }, - }], - }], + listeners: [ + { + eventName: BI.Editor.EVENT_CHANGE, + action: () => { + this.onHostPortChange(databaseType); + }, + }, + ], + }, + ], }, + // 认证方式 { type: FormItem.xtype, name: BI.i18nText('Dec-Dcm_Connection_Form_AuthType'), invisible: !databaseType.kerberos, - forms: [{ - type: BI.TextValueCombo.xtype, - $value: 'auth-type', - width: 300, - value: authType, - ref: (_ref: TextValueCombo) => { - this.form.authType = _ref; - }, - items: [ - { - text: BI.i18nText('Dec-Dcm_Connection_Form_UserName_Password'), - value: '', - }, - { - text: 'Kerberos', - value: 'kerberos', + forms: [ + { + type: BI.TextValueCombo.xtype, + $value: 'auth-type', + width: 300, + value: authType, + ref: (_ref: TextValueCombo) => { + this.form.authType = _ref; }, - ], - listeners: [ - { - eventName: BI.Combo.EVENT_CHANGE, - action: () => { - const type = this.form.authType.getValue()[0]; - this.formPrincipal.setVisible(!!type); - this.formKeyPath.setVisible(!!type); - this.formUser.setVisible(!type); - this.formPassword.setVisible(!type); - this.labelTips.setVisible(!!type); + items: [ + { + text: BI.i18nText('Dec-Dcm_Connection_Form_UserName_Password'), + value: '', }, - }, - ], - }], + { + text: 'Kerberos', + value: 'kerberos', + }, + ], + listeners: [ + { + eventName: BI.Combo.EVENT_CHANGE, + action: () => { + const type = this.form.authType.getValue()[0]; + this.formPrincipal.setVisible(!!type); + this.formKeyPath.setVisible(!!type); + this.formUser.setVisible(!type); + this.formPassword.setVisible(!type); + this.labelTips.setVisible(!!type); + }, + }, + ], + }, + ], }, + // 用户名 { type: FormItem.xtype, name: BI.i18nText('Dec-Dcm_Connection_Form_UserName'), @@ -271,18 +333,21 @@ export class FormJdbc extends BI.Widget { ref: (_ref: FormItem) => { this.formUser = _ref; }, - forms: [{ - type: BI.TextEditor.xtype, - $value: 'username', - width: 300, - allowBlank: true, - value: user, - watermark: BI.i18nText('Dec-Dcm_Connection_Form_UserName'), - ref: (_ref: TextEditor) => { - this.form.user = _ref; - }, - }], + forms: [ + { + type: BI.TextEditor.xtype, + $value: 'username', + width: 300, + allowBlank: true, + value: user, + watermark: BI.i18nText('Dec-Dcm_Connection_Form_UserName'), + ref: (_ref: TextEditor) => { + this.form.user = _ref; + }, + }, + ], }, + // 密码 { type: FormItem.xtype, name: BI.i18nText('Dec-Dcm_Connection_Form_Password'), @@ -290,22 +355,25 @@ export class FormJdbc extends BI.Widget { ref: (_ref: FormItem) => { this.formPassword = _ref; }, - forms: [{ - type: BI.Editor.xtype, - $value: 'password', - cls: 'bi-border bi-border-radius', - width: 300, - height: 20, - allowBlank: true, - value: password, - inputType: 'password', - autocomplete: 'new-password', - watermark: BI.i18nText('Dec-Dcm_Connection_Form_Password'), - ref: (_ref: Editor) => { - this.form.password = _ref; - }, - }], + forms: [ + { + type: BI.Editor.xtype, + $value: 'password', + cls: 'bi-border bi-border-radius', + width: 300, + height: 20, + allowBlank: true, + value: password, + inputType: 'password', + autocomplete: 'new-password', + watermark: BI.i18nText('Dec-Dcm_Connection_Form_Password'), + ref: (_ref: Editor) => { + this.form.password = _ref; + }, + }, + ], }, + // 客户端principal { type: FormItem.xtype, name: BI.i18nText('Dec-Dcm_Connection_Form_Principal'), @@ -313,18 +381,21 @@ export class FormJdbc extends BI.Widget { ref: (_ref: FormItem) => { this.formPrincipal = _ref; }, - forms: [{ - type: BI.TextEditor.xtype, - $value: 'principal', - width: 300, - allowBlank: true, - value: principal, - watermark: BI.i18nText('Dec-Dcm_Connection_Form_Principal'), - ref: (_ref: TextEditor) => { - this.form.principal = _ref; - }, - }], + forms: [ + { + type: BI.TextEditor.xtype, + $value: 'principal', + width: 300, + allowBlank: true, + value: principal, + watermark: BI.i18nText('Dec-Dcm_Connection_Form_Principal'), + ref: (_ref: TextEditor) => { + this.form.principal = _ref; + }, + }, + ], }, + // keytab密钥路径 { type: FormItem.xtype, name: BI.i18nText('Dec-Dcm_Connection_Form_KeyPath'), @@ -332,20 +403,23 @@ export class FormJdbc extends BI.Widget { ref: (_ref: FormItem) => { this.formKeyPath = _ref; }, - forms: [{ - type: BI.Editor.xtype, - $value: 'key-path', - cls: 'bi-border', - width: 300, - height: 20, - allowBlank: true, - value: keyPath, - watermark: BI.i18nText('Dec-Dcm_Connection_Form_KeyPath'), - ref: (_ref: Editor) => { - this.form.keyPath = _ref; - }, - }], + forms: [ + { + type: BI.Editor.xtype, + $value: 'key-path', + cls: 'bi-border', + width: 300, + height: 20, + allowBlank: true, + value: keyPath, + watermark: BI.i18nText('Dec-Dcm_Connection_Form_KeyPath'), + ref: (_ref: Editor) => { + this.form.keyPath = _ref; + }, + }, + ], }, + // 关于krb5的提示 { type: BI.Label.xtype, cls: 'bi-tips', @@ -356,138 +430,169 @@ export class FormJdbc extends BI.Widget { this.labelTips = _ref; }, }, + // 编码 { type: FormItem.xtype, name: BI.i18nText('Dec-Dcm_Connection_Form_OriginalCharsetName'), - forms: [{ - type: BI.TextValueCombo.xtype, - $value: 'original-charset-name', - width: 300, - value: originalCharsetName ? originalCharsetName : '', - items: CONNECT_CHARSET, - ref: (_ref: TextValueCombo) => { - this.form.originalCharsetName = _ref; - }, - }], + forms: [ + { + type: BI.TextValueCombo.xtype, + $value: 'original-charset-name', + width: 300, + value: originalCharsetName ? originalCharsetName : '', + items: CONNECT_CHARSET, + ref: (_ref: TextValueCombo) => { + this.form.originalCharsetName = _ref; + }, + }, + ], }, + // 模式 { type: FormItem.xtype, invisible: !databaseType.hasSchema, height: 64, name: BI.i18nText('Dec-Dcm_Connection_Form_Pattern'), - forms: [{ - type: BI.VerticalLayout.xtype, - items: [{ - type: BI.FloatLeftLayout.xtype, - items: [{ - type: BI.TextButton.xtype, - cls: 'bi-high-light', - text: BI.i18nText('Dec-Dcm_Connection_Click_Connect_Database'), - handler: () => { - this.fireEvent('EVENT_TEST_CONNECTION'); - }, - }, { - type: BI.Label.xtype, - cls: 'bi-tips', - lgap: 3, - text: BI.i18nText('Dec-Dcm_Connection_Read_Mode_List'), - }], - }, { - type: BI.TextValueCombo.xtype, - $value: 'schema', - width: 300, - vgap: 15, - disabled: true, - value: schema, - items: schema ? [{ text: schema, value: schema }] : [], - ref: (_ref: TextValueCombo) => { - this.form.schema = _ref; - }, - }], - }], + forms: [ + { + type: BI.VerticalLayout.xtype, + items: [ + { + type: BI.FloatLeftLayout.xtype, + items: [ + { + type: BI.TextButton.xtype, + cls: 'bi-high-light', + text: BI.i18nText('Dec-Dcm_Connection_Click_Connect_Database'), + handler: () => { + this.fireEvent('EVENT_TEST_CONNECTION'); + }, + }, + { + type: BI.Label.xtype, + cls: 'bi-tips', + lgap: 3, + text: BI.i18nText('Dec-Dcm_Connection_Read_Mode_List'), + }, + ], + }, + { + type: BI.TextValueCombo.xtype, + $value: 'schema', + width: 300, + vgap: 15, + disabled: true, + value: schema, + items: schema ? [{ text: schema, value: schema }] : [], + ref: (_ref: TextValueCombo) => { + this.form.schema = _ref; + }, + }, + ], + }, + ], }, + // 分隔线 { type: BI.Layout.xtype, cls: 'bi-border-top', bgap: 8, }, + // 数据连接URL { type: FormItem.xtype, name: BI.i18nText('Dec-Dcm_Connection_Form_Database_URL'), - forms: [{ - type: BI.TextEditor.xtype, - $value: 'database-url', - width: 300, - allowBlank: true, - value: url, - watermark: BI.i18nText('Dec-Dcm_Connection_Form_Database_URL'), - ref: (_ref: TextEditor) => { - this.form.url = _ref; - }, - listeners: [{ - eventName: 'EVENT_CHANGE', - action: () => { - const urlInfo = resolveUrlInfo(this.form.url.getValue(), database); - this.form.host.setValue(urlInfo.host); - this.form.database.setValue(urlInfo.databaseName); - this.form.port.setValue(urlInfo.port); + forms: [ + { + type: BI.TextEditor.xtype, + $value: 'database-url', + width: 300, + allowBlank: true, + value: url, + watermark: BI.i18nText('Dec-Dcm_Connection_Form_Database_URL'), + ref: (_ref: TextEditor) => { + this.form.url = _ref; }, - }], - }], + listeners: [ + { + eventName: 'EVENT_CHANGE', + action: () => { + const urlInfo = resolveUrlInfo(this.form.url.getValue(), database); + this.form.host.setValue(urlInfo.host); + this.form.database.setValue(urlInfo.databaseName); + this.form.port.setValue(urlInfo.port); + }, + }, + ], + }, + ], }, + // 最大活动连接数 { type: FormItem.xtype, name: BI.i18nText('Dec-Dcm_Connection_Form_Database_Max_Active'), - forms: [{ - type: TextChecker.xtype, - $value: 'max-active', - width: 300, - allowBlank: false, - value: maxActive, - watermark: BI.i18nText('Dec-Dcm_Connection_Form_Database_Max_Active'), - validationChecker: [{ - errorText: BI.i18nText('Dec-Dcm_Connection_Check_Integer'), - checker: (value: string) => this.checkInteger(value), - autoFix: true, - }, valueRangeConfig], - ref: (_ref: TextChecker) => { - this.form.maxActive = _ref; - }, - }], + forms: [ + { + type: TextChecker.xtype, + $value: 'max-active', + width: 300, + allowBlank: false, + value: maxActive, + watermark: BI.i18nText('Dec-Dcm_Connection_Form_Database_Max_Active'), + validationChecker: [ + { + errorText: BI.i18nText('Dec-Dcm_Connection_Check_Integer'), + checker: (value: string) => this.checkInteger(value), + autoFix: true, + }, + valueRangeConfig, + ], + ref: (_ref: TextChecker) => { + this.form.maxActive = _ref; + }, + }, + ], }, + // 获取连接前检验 { type: FormItem.xtype, name: BI.i18nText('Dec-Dcm_Connection_Form_Database_Test_On_Borrow'), - forms: [{ - type: BI.TextValueCombo.xtype, - $value: 'check', - width: 300, - allowBlank: true, - value: testOnBorrow, - items: this.getBooleanItem(), - watermark: BI.i18nText('Dec-Dcm_Connection_Form_Database_Test_On_Borrow'), - ref: (_ref: TextValueCombo) => { - this.form.testOnBorrow = _ref; - }, - }], + forms: [ + { + type: BI.TextValueCombo.xtype, + $value: 'check', + width: 300, + allowBlank: true, + value: testOnBorrow, + items: this.getBooleanItem(), + watermark: BI.i18nText('Dec-Dcm_Connection_Form_Database_Test_On_Borrow'), + ref: (_ref: TextValueCombo) => { + this.form.testOnBorrow = _ref; + }, + }, + ], }, + // 校验语句 { type: FormItem.xtype, name: BI.i18nText('Dec-Dcm_Connection_Form_SQL_Validation_Query'), - forms: [{ - type: BI.TextAreaEditor.xtype, - $value: 'validation-query', - cls: 'bi-border', - allowBlank: true, - watermark: BI.i18nText('Dec-Dcm_Connection_Form_SQL_Validation_Query_Watermark'), - value: api.getPlain(validationQuery || ''), - width: 300, - height: 100, - ref: (_ref: TextAreaEditor) => { - this.form.validationQuery = _ref; - }, - }], + forms: [ + { + type: BI.TextAreaEditor.xtype, + $value: 'validation-query', + cls: 'bi-border', + allowBlank: true, + watermark: BI.i18nText('Dec-Dcm_Connection_Form_SQL_Validation_Query_Watermark'), + value: api.getPlain(validationQuery || ''), + width: 300, + height: 100, + ref: (_ref: TextAreaEditor) => { + this.form.validationQuery = _ref; + }, + }, + ], }, + // 最大等待时间 { type: FormItem.xtype, name: BI.i18nText('Dec-Dcm_Connection_Form_Database_Max_Wait'), @@ -499,11 +604,14 @@ export class FormJdbc extends BI.Widget { allowBlank: false, value: maxWait, watermark: BI.i18nText('Dec-Dcm_Connection_Form_Database_Max_Wait'), - validationChecker: [{ - errorText: BI.i18nText('Dec-Dcm_Connection_Check_Integer'), - checker: (value: string) => this.checkInteger(value), - autoFix: true, - }, valueRangeConfig], + validationChecker: [ + { + errorText: BI.i18nText('Dec-Dcm_Connection_Check_Integer'), + checker: (value: string) => this.checkInteger(value), + autoFix: true, + }, + valueRangeConfig, + ], ref: (_ref: TextChecker) => { this.form.maxWait = _ref; }, @@ -516,10 +624,303 @@ export class FormJdbc extends BI.Widget { }, ], }, + // SSH设置 + { + type: Collapse.xtype, + width: 100, + name: BI.i18nText('Dec-Dcm_Connection_Setting', 'SSH'), + listeners: [ + { + eventName: EVENT_CHANGE, + action: (isCollapse: boolean) => { + this.sshSet.setVisible(!isCollapse); + }, + }, + ], + }, + { + type: BI.VerticalLayout.xtype, + ref: (_ref: VerticalLayout) => { + this.sshSet = _ref; + }, + invisible: true, + items: [ + { + type: FormItem.xtype, + bgap: -15, + name: BI.i18nText('Dec-Dcm_Connection_Tunnel', 'SSH'), + forms: [ + { + type: BI.MultiSelectItem.xtype, + ref: (_ref: MultiSelectItem) => { + this.form.usingSsh = _ref; + }, + logic: { dynamic: true }, + text: BI.i18nText('Dec-Basic_Use') + BI.i18nText('Dec-Dcm_Connection_Tunnel', 'SSH'), + selected: usingSsh, + listeners: [ + { + eventName: BI.MultiSelectItem.EVENT_CHANGE, + action: () => { + const value = this.form.usingSsh.isSelected(); + this.sshForm.setVisible(value); + }, + }, + ], + }, + ], + }, + { + type: BI.VerticalLayout.xtype, + ref: (_ref: VerticalLayout) => { + this.sshForm = _ref; + }, + vgap, + invisible: !usingSsh, + items: [ + { + type: FormItem.xtype, + name: BI.i18nText('Dec-Dcm_Connection_Form_Host'), + forms: [ + { + type: TextChecker.xtype, + ref: (_ref: TextChecker) => { + this.form.sshIp = _ref; + }, + watermark: BI.i18nText('Dec-Dcm_Connection_Form_Host'), + allowBlank: false, + value: sshIp || 'hostname', + }, + ], + }, + { + type: FormItem.xtype, + name: BI.i18nText('Dec-Dcm_Connection_Form_Database_Port'), + forms: [ + { + type: TextChecker.xtype, + ref: (_ref: TextChecker) => { + this.form.sshPort = _ref; + }, + watermark: BI.i18nText('Dec-Dcm_Connection_Form_Database_Port'), + allowBlank: false, + validationChecker: [ + { + errorText: BI.i18nText('Dec-Dcm_Connection_Check_Integer'), + checker: (value: string) => this.checkInteger(value), + autoFix: true, + }, + valueRangeConfig, + ], + value: String(sshPort || 22), + }, + ], + }, + { + type: FormItem.xtype, + name: BI.i18nText('Dec-Dcm_Connection_Form_UserName'), + forms: [ + { + type: TextChecker.xtype, + ref: (_ref: TextChecker) => { + this.form.sshUser = _ref; + }, + watermark: BI.i18nText('Dec-Dcm_Connection_Form_UserName'), + value: sshUser, + }, + ], + }, + { + type: FormItem.xtype, + name: BI.i18nText('Dec-Dcm_Connection_Form_VerifyType'), + forms: [ + { + type: BI.TextValueCombo.xtype, + ref: (_ref: TextValueCombo) => { + this.form.sshType = _ref; + }, + width: 300, + watermark: BI.i18nText('Dec-Dcm_Connection_Form_VerifyType'), + items: CONNECT_SSH_TYPE, + value: sshType, + listeners: [ + { + eventName: BI.TextValueCombo.EVENT_CHANGE, + action: () => { + const sshType = this.form.sshType.getValue()[0]; + this.onSshTypeChange(sshType); + }, + }, + ], + }, + ], + }, + { + type: FormItem.xtype, + ref: (_ref: FormItem) => { + this.form.sshPrivateKeyPathForm = _ref; + }, + name: BI.i18nText('Dec-Dcm_Connection_Form_PrivateKey'), + forms: [ + { + type: FileChooser.xtype, + ref: (_ref: TextChecker) => { + this.form.sshPrivateKeyPath = _ref; + }, + root: 'certificates', + watermark: BI.i18nText('Dec-Dcm_Connection_Form_PrivateKey'), + value: sshPrivateKeyPath, + }, + ], + }, + { + type: FormItem.xtype, + ref: (ref: FormItem) => { + this.form.sshSecretForm = ref; + }, + name: BI.i18nText(''), + forms: [ + { + type: TextChecker.xtype, + ref: (_ref: TextChecker) => { + this.form.sshSecret = _ref; + }, + watermark: BI.i18nText(''), + inputType: 'password', + autocomplete: 'new-password', + value: sshSecret, + }, + ], + }, + ], + }, + ], + }, + // SSL设置 + { + type: Collapse.xtype, + width: 100, + name: BI.i18nText('Dec-Dcm_Connection_Setting', 'SSL'), + invisible: !this.getSslSetEnabled(), + listeners: [ + { + eventName: EVENT_CHANGE, + action: (isCollapse: boolean) => { + this.sslSet.setVisible(!isCollapse); + }, + }, + ], + }, + { + type: BI.VerticalLayout.xtype, + ref: (_ref: VerticalLayout) => { + this.sslSet = _ref; + }, + invisible: true, + items: [ + { + type: FormItem.xtype, + bgap: -15, + name: BI.i18nText('Dec-Dcm_Connection_Tunnel', 'SSL'), + forms: [ + { + type: BI.MultiSelectItem.xtype, + ref: (_ref: MultiSelectItem) => { + this.form.usingSsl = _ref; + }, + logic: { dynamic: true }, + text: BI.i18nText('Dec-Basic_Use') + BI.i18nText('Dec-Dcm_Connection_Tunnel', 'SSL'), + selected: usingSsl, + listeners: [ + { + eventName: BI.MultiSelectItem.EVENT_CHANGE, + action: () => { + const value = this.form.usingSsl.isSelected(); + this.sslForm.setVisible(value); + }, + }, + ], + }, + ], + }, + { + type: BI.VerticalLayout.xtype, + ref: (_ref: VerticalLayout) => { + this.sslForm = _ref; + }, + vgap, + invisible: !usingSsl, + items: [ + { + type: FormItem.xtype, + name: BI.i18nText('Dec-Dcm_Connection_Form_CA_Certificate'), + forms: [ + { + type: FileChooser.xtype, + ref: (_ref: FileChooser) => { + this.form.caCertificate = _ref; + }, + root: 'certificates', + watermark: BI.i18nText('Dec-Dcm_Connection_Form_CA_Certificate'), + value: caCertificate, + }, + ], + }, + { + type: FormItem.xtype, + name: BI.i18nText('Dec-Dcm_Connection_Form_Verify_CA_Certificate'), + forms: [ + { + type: BI.TextValueCombo.xtype, + ref: (_ref: TextValueCombo) => { + this.form.verifyCa = _ref; + }, + width: 300, + watermark: BI.i18nText('Dec-Dcm_Connection_Form_Verify_CA_Certificate'), + items: this.getBooleanItem(), + value: verifyCa, + }, + ], + }, + { + type: FormItem.xtype, + name: BI.i18nText('Dec-Dcm_Connection_Client') + BI.i18nText('Dec-Dcm_Connection_Form_SecretKey'), + forms: [ + { + type: FileChooser.xtype, + ref: (_ref: FileChooser) => { + this.form.sslClientPrivateKey = _ref; + }, + root: 'certificates', + watermark: BI.i18nText('Dec-Dcm_Connection_Client') + BI.i18nText('Dec-Dcm_Connection_Form_SecretKey'), + value: sslClientPrivateKey, + }, + ], + }, + { + type: FormItem.xtype, + name: BI.i18nText('Dec-Dcm_Connection_Client') + BI.i18nText('Dec-Dcm_Connection_Form_Certificate'), + forms: [ + { + type: FileChooser.xtype, + ref: (_ref: FileChooser) => { + this.form.sslClientCertificate = _ref; + }, + root: 'certificates', + watermark: BI.i18nText('Dec-Dcm_Connection_Client') + BI.i18nText('Dec-Dcm_Connection_Form_Certificate'), + value: sslClientCertificate, + }, + ], + }, + ], + }, + ], + }, + // 高级设置 { type: Collapse.xtype, bgap: -15, - width: 70, + width: 100, name: BI.i18nText('Dec-Dcm_Connection_Form_Database_More_Setting'), listeners: [ { @@ -543,74 +944,88 @@ export class FormJdbc extends BI.Widget { type: FormItem.xtype, tgap: 15, name: BI.i18nText('Dec-Dcm_Connection_Form_Database_Initial_Size'), - forms: [{ - type: TextChecker.xtype, - $value: 'initial-size', - width: 300, - allowBlank: false, - value: initialSize, - validationChecker: [{ - errorText: BI.i18nText('Dec-Dcm_Connection_Check_Integer'), - checker: (value: string) => this.checkInteger(value), - autoFix: true, - }, valueRangeConfig], - watermark: BI.i18nText('Dec-Dcm_Connection_Form_Database_Initial_Size'), - ref: (_ref: TextChecker) => { - this.form.initialSize = _ref; + forms: [ + { + type: TextChecker.xtype, + $value: 'initial-size', + width: 300, + allowBlank: false, + value: initialSize, + validationChecker: [ + { + errorText: BI.i18nText('Dec-Dcm_Connection_Check_Integer'), + checker: (value: string) => this.checkInteger(value), + autoFix: true, + }, + valueRangeConfig, + ], + watermark: BI.i18nText('Dec-Dcm_Connection_Form_Database_Initial_Size'), + ref: (_ref: TextChecker) => { + this.form.initialSize = _ref; + }, }, - }], + ], }, { type: FormItem.xtype, name: BI.i18nText('Dec-Dcm_Connection_Form_Database_Min_Idle'), - forms: [{ - type: TextChecker.xtype, - $value: 'min-idle', - width: 300, - allowBlank: false, - value: minIdle, - watermark: BI.i18nText('Dec-Dcm_Connection_Form_Database_Min_Idle'), - validationChecker: [{ - errorText: BI.i18nText('Dec-Dcm_Connection_Check_Integer'), - checker: (value: string) => this.checkInteger(value), - autoFix: true, - }, valueRangeConfig], - ref: (_ref: TextChecker) => { - this.form.minIdle = _ref; + forms: [ + { + type: TextChecker.xtype, + $value: 'min-idle', + width: 300, + allowBlank: false, + value: minIdle, + watermark: BI.i18nText('Dec-Dcm_Connection_Form_Database_Min_Idle'), + validationChecker: [ + { + errorText: BI.i18nText('Dec-Dcm_Connection_Check_Integer'), + checker: (value: string) => this.checkInteger(value), + autoFix: true, + }, + valueRangeConfig, + ], + ref: (_ref: TextChecker) => { + this.form.minIdle = _ref; + }, }, - }], + ], }, { type: FormItem.xtype, name: BI.i18nText('Dec-Dcm_Connection_Form_Database_Test_On_Return'), - forms: [{ - type: BI.TextValueCombo.xtype, - $value: 'test-on-return', - width: 300, - allowBlank: true, - value: testOnReturn, - items: this.getBooleanItem(), - watermark: BI.i18nText('Dec-Dcm_Connection_Form_Database_Test_On_Return'), - ref: (_ref: TextValueCombo) => { - this.form.testOnReturn = _ref; + forms: [ + { + type: BI.TextValueCombo.xtype, + $value: 'test-on-return', + width: 300, + allowBlank: true, + value: testOnReturn, + items: this.getBooleanItem(), + watermark: BI.i18nText('Dec-Dcm_Connection_Form_Database_Test_On_Return'), + ref: (_ref: TextValueCombo) => { + this.form.testOnReturn = _ref; + }, }, - }], + ], }, { type: FormItem.xtype, name: BI.i18nText('Dec-Dcm_Connection_Form_Database_Test_While_Idle'), - forms: [{ - type: BI.TextValueCombo.xtype, - $value: 'test-while-idle', - width: 300, - allowBlank: true, - value: testWhileIdle, - items: this.getBooleanItem(), - watermark: BI.i18nText('Dec-Dcm_Connection_Form_Database_Test_While_Idle'), - ref: (_ref: TextValueCombo) => { - this.form.testWhileIdle = _ref; + forms: [ + { + type: BI.TextValueCombo.xtype, + $value: 'test-while-idle', + width: 300, + allowBlank: true, + value: testWhileIdle, + items: this.getBooleanItem(), + watermark: BI.i18nText('Dec-Dcm_Connection_Form_Database_Test_While_Idle'), + ref: (_ref: TextValueCombo) => { + this.form.testWhileIdle = _ref; + }, }, - }], + ], }, { type: FormItem.xtype, @@ -623,11 +1038,14 @@ export class FormJdbc extends BI.Widget { allowBlank: false, value: timeBetweenEvictionRunsMillis, watermark: BI.i18nText('Dec-Dcm_Connection_Form_Database_Test_Between_Eviction_Millis'), - validationChecker: [{ - errorText: BI.i18nText('Dec-Dcm_Connection_Check_Number'), - checker: (value: string) => this.checkNumber(value), - autoFix: true, - }, valueRangeConfig], + validationChecker: [ + { + errorText: BI.i18nText('Dec-Dcm_Connection_Check_Number'), + checker: (value: string) => this.checkNumber(value), + autoFix: true, + }, + valueRangeConfig, + ], ref: (_ref: TextChecker) => { this.form.timeBetweenEvictionRunsMillis = _ref; }, @@ -643,22 +1061,27 @@ export class FormJdbc extends BI.Widget { { type: FormItem.xtype, name: BI.i18nText('Dec-Dcm_Connection_Form_Database_Tests_PerEviction_Run_Num'), - forms: [{ - type: TextChecker.xtype, - $value: 'test-pereviction-run-num', - width: 300, - allowBlank: false, - value: numTestsPerEvictionRun, - watermark: BI.i18nText('Dec-Dcm_Connection_Form_Database_Tests_PerEviction_Run_Num'), - validationChecker: [{ - errorText: BI.i18nText('Dec-Dcm_Connection_Check_Integer'), - checker: (value: string) => this.checkInteger(value), - autoFix: true, - }, valueRangeConfig], - ref: (_ref: TextChecker) => { - this.form.numTestsPerEvictionRun = _ref; + forms: [ + { + type: TextChecker.xtype, + $value: 'test-pereviction-run-num', + width: 300, + allowBlank: false, + value: numTestsPerEvictionRun, + watermark: BI.i18nText('Dec-Dcm_Connection_Form_Database_Tests_PerEviction_Run_Num'), + validationChecker: [ + { + errorText: BI.i18nText('Dec-Dcm_Connection_Check_Integer'), + checker: (value: string) => this.checkInteger(value), + autoFix: true, + }, + valueRangeConfig, + ], + ref: (_ref: TextChecker) => { + this.form.numTestsPerEvictionRun = _ref; + }, }, - }], + ], }, { type: FormItem.xtype, @@ -671,11 +1094,14 @@ export class FormJdbc extends BI.Widget { allowBlank: false, value: minEvictableIdleTimeMillis, watermark: BI.i18nText('Dec-Dcm_Connection_Form_Database_Min_Evictable_Idle_Time_Millis'), - validationChecker: [{ - errorText: BI.i18nText('Dec-Dcm_Connection_Check_Integer'), - checker: (value: string) => this.checkInteger(value), - autoFix: true, - }, valueRangeConfig], + validationChecker: [ + { + errorText: BI.i18nText('Dec-Dcm_Connection_Check_Integer'), + checker: (value: string) => this.checkInteger(value), + autoFix: true, + }, + valueRangeConfig, + ], ref: (_ref: TextChecker) => { this.form.minEvictableIdleTimeMillis = _ref; }, @@ -687,7 +1113,8 @@ export class FormJdbc extends BI.Widget { text: BI.i18nText('BI-Basic_Seconds'), }, ], - }, { + }, + { el: { type: BI.VerticalLayout.xtype, cls: 'bi-border-top', @@ -697,22 +1124,27 @@ export class FormJdbc extends BI.Widget { el: { type: FormItem.xtype, name: 'Fetchsize', - forms: [{ - type: TextChecker.xtype, - $value: 'fetch-size', - width: 300, - allowBlank: true, - value: fetchSize === -2 ? '' : fetchSize, - watermark: 'Fetchsize', - validationChecker: [{ - errorText: BI.i18nText('Dec-Dcm_Connection_Check_Fetch_Size_Range'), - checker: (value: string) => BI.isInteger(value) && BI.parseInt(value) >= 0 && BI.parseInt(value) <= 1000000, - autoFix: true, - }], - ref: (_ref: TextChecker) => { - this.form.fetchSize = _ref; + forms: [ + { + type: TextChecker.xtype, + $value: 'fetch-size', + width: 300, + allowBlank: true, + value: fetchSize === -2 ? '' : fetchSize, + watermark: 'Fetchsize', + validationChecker: [ + { + errorText: BI.i18nText('Dec-Dcm_Connection_Check_Fetch_Size_Range'), + checker: (value: string) => + BI.isInteger(value) && BI.parseInt(value) >= 0 && BI.parseInt(value) <= 1000000, + autoFix: true, + }, + ], + ref: (_ref: TextChecker) => { + this.form.fetchSize = _ref; + }, }, - }], + ], }, vgap: 15, }, @@ -725,6 +1157,11 @@ export class FormJdbc extends BI.Widget { }; } + public mounted() { + const sshType = this.form.sshType.getValue()[0]; + this.onSshTypeChange(sshType); + } + public setError(value: string) { this.form.connectionName.setError(value); } @@ -744,19 +1181,21 @@ export class FormJdbc extends BI.Widget { private getDrivers() { const connectionData = this.options.formData.connectionData as ConnectionJDBC; const connectionType = getJdbcDatabaseType(connectionData.database, connectionData.driver); - const drivers = connectionType.drivers ? - connectionType.drivers.map(item => { - return { - text: item, - value: item, - }; - }) : - [{ - text: connectionType.driver, - value: connectionType.driver, - }]; + const drivers = connectionType.drivers + ? connectionType.drivers.map((item) => { + return { + text: item, + value: item, + }; + }) + : [ + { + text: connectionType.driver, + value: connectionType.driver, + }, + ]; - if (!drivers.some(item => item.text === connectionData.driver)) { + if (!drivers.some((item) => item.text === connectionData.driver)) { return [ { text: connectionData.driver, @@ -792,22 +1231,39 @@ export class FormJdbc extends BI.Widget { this.form.url.setValue(splitUrl(host, port, database, selectUrl)); } + private onSshTypeChange(sshType) { + const { privateKeyPathFormVisible, secretFormName } = CONNECT_SSH_TYPE.find((SSH_TYPE) => sshType === SSH_TYPE.value); + this.form.sshPrivateKeyPathForm.setVisible(privateKeyPathFormVisible); + this.form.sshSecretForm.setName(secretFormName); + this.form.sshSecret.setWatermark(secretFormName); + } + + private getSslSetEnabled(): boolean { + const { databaseType } = this.databaseType; + return databaseType === 'mysql'; + } + public setSchemas(schemas: string[]) { this.form.schema.setEnable(true); if (schemas.length > 0) { const value = this.form.schema.getValue()[0]; - this.form.schema.populate(schemas.map(item => { - return { - text: item, - value: item, - }; - })); - this.form.schema.setValue(value && schemas.some(item => item === value) ? value : schemas[0]); + this.form.schema.populate( + schemas.map((item) => { + return { + text: item, + value: item, + }; + }) + ); + this.form.schema.setValue(value && schemas.some((item) => item === value) ? value : schemas[0]); } } public validation(): boolean { - return this.form.driver.validation(); + const driver = this.form.driver.validation(); + const sshSet = !this.form.usingSsh.isSelected() || (this.form.sshIp.getValue() !== '' && this.form.sshPort.getValue() !== ''); + + return driver && sshSet; } public getSubmitValue(): Connection { @@ -837,6 +1293,26 @@ export class FormJdbc extends BI.Widget { principal: this.form.principal.getValue(), keyPath: this.form.keyPath.getValue(), fetchSize: BI.isEmptyString(this.form.fetchSize.getValue()) ? -2 : BI.parseInt(this.form.fetchSize.getValue()), + // ssh + usingSsh: this.form.usingSsh.isSelected(), + // redirectPort: 0, + // redirectIp: '', + // sshKeepAlive: 10000, + // sshTimeOut: 10000, + sshIp: this.form.sshIp.getValue(), + sshPort: Number(this.form.sshPort.getValue()), + sshUser: this.form.sshUser.getValue(), + sshType: this.form.sshType.getValue()[0], + sshPrivateKeyPath: this.form.sshPrivateKeyPath.getValue(), + sshSecret: this.oldSshSecret === this.form.sshSecret.getValue() ? this.oldSshSecret : api.getCipher(this.form.sshSecret.getValue()), + // ssl + usingSsl: this.getSslSetEnabled() && this.form.usingSsl.isSelected(), + caCertificate: this.form.caCertificate.getValue(), + verifyCa: this.form.verifyCa.getValue()[0], + sslType: CONNECT_SSL_TYPE[0].value, + sslClientPrivateKey: this.form.sslClientPrivateKey.getValue(), + sslClientCertificate: this.form.sslClientCertificate.getValue(), + // 连接池 connectionPoolAttr: { initialSize: this.form.initialSize.getValue(), maxActive: this.form.maxActive.getValue(), diff --git a/tsconfig.json b/tsconfig.json index 4e9e3db..0506075 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -19,7 +19,7 @@ // "noUnusedParameters": true, // "noImplicitReturns": true, "noFallthroughCasesInSwitch": true, - "skipLibCheck": true, + "skipLibCheck": false, "paths": { "ui": ["./src/ui"], "ReportCst": ["./private/constants"], diff --git a/types/globals.d.ts b/types/globals.d.ts index 09a8987..4d1c456 100644 --- a/types/globals.d.ts +++ b/types/globals.d.ts @@ -2,6 +2,8 @@ interface Obj { [key: string]: any; } +type RequestFunction = (url: string, data: any, callback: (re: any) => void) => void; + declare let BI: Obj & import('@fui/core').BI & import('@fui/materials').BI; declare const Fix: Obj; declare const DecCst: Obj; @@ -10,15 +12,19 @@ declare const Dec: { socket: { connected: boolean; }; - system: { - - }; + system: {}; personal: { username: string; }; socketEmit: (type: string, name: string, callback: (re: any) => void) => void; - reqGet: (url: string, data: any, callback: (re: any) => void) => void; - reqPost: (url: string, data: any, callback: (re: any) => void) => void; - reqPut: (url: string, data: any, callback: (re: any) => void) => void; - reqDelete: (url: string, data: any, callback: (re: any) => void) => void; -}; \ No newline at end of file + // req + reqGet: RequestFunction; + reqPost: RequestFunction; + reqPut: RequestFunction; + reqDelete: RequestFunction; + // reqHandle + reqGetHandle: RequestFunction; + reqPostHandle: RequestFunction; + reqPutHandle: RequestFunction; + reqDeleteHandle: RequestFunction; +};