DatasourceForm.tsx 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190
  1. import React from 'react';
  2. import { Dialog, ReactWidget } from '@jupyterlab/apputils';
  3. import { IDatasourceForm, textDatasource } from './api/datasource';
  4. import { Widget } from '@lumino/widgets';
  5. import { Input, message, Select } from 'antd';
  6. interface IProps {
  7. value: Partial<IDatasourceForm>;
  8. error: keyof IDatasourceForm | null;
  9. onChange: (v: Partial<IDatasourceForm>) => void;
  10. onConnection: (v: Partial<IDatasourceForm>) => void;
  11. }
  12. const DatasourceForm: React.FunctionComponent<IProps> = ({
  13. value,
  14. error,
  15. onChange,
  16. onConnection
  17. }) => {
  18. return (
  19. <form className="jldbq-form">
  20. <label className={error === 'datasource' ? 'jldbq-form-error' : ''}>
  21. <span className="jldbq-form-label">数据源类型:</span>
  22. <Select
  23. className="jldbq-form-select"
  24. placeholder="请选择数据源类型"
  25. onChange={(val: any) => onChange({ datasource: val })}
  26. >
  27. <Select.Option value="mysql">MySQL</Select.Option>
  28. <Select.Option value="hive">Hive</Select.Option>
  29. </Select>
  30. </label>
  31. <label className={error === 'datasource_name' ? 'jldbq-form-error' : ''}>
  32. <span className="jldbq-form-label">数据源名称:</span>
  33. <Input
  34. className="jldbq-form-input"
  35. placeholder="请输入数据源名称"
  36. value={value.datasource_name || ''}
  37. onChange={evt => onChange({ datasource_name: evt.target.value })}
  38. />
  39. </label>
  40. <label className={error === 'jdbc_url' ? 'jldbq-form-error' : ''}>
  41. <span className="jldbq-form-label">数据库地址:</span>
  42. <Input
  43. className="jldbq-form-input"
  44. placeholder="示例:host:port"
  45. value={value.jdbc_url || ''}
  46. onChange={evt => onChange({ jdbc_url: evt.target.value })}
  47. />
  48. </label>
  49. <label className={error === 'database_name' ? 'jldbq-form-error' : ''}>
  50. <span className="jldbq-form-label">数据库名称:</span>
  51. <Input
  52. className="jldbq-form-input"
  53. placeholder={
  54. value.datasource === 'hive' ? '选填' : '请输入数据库名称'
  55. }
  56. value={value.database_name || ''}
  57. onChange={evt => onChange({ database_name: evt.target.value })}
  58. />
  59. </label>
  60. <label className={error === 'jdbc_username' ? 'jldbq-form-error' : ''}>
  61. <span className="jldbq-form-label">用户名:</span>
  62. <Input
  63. className="jldbq-form-input"
  64. placeholder="请输入用户名"
  65. value={value.jdbc_username || ''}
  66. onChange={evt => onChange({ jdbc_username: evt.target.value })}
  67. />
  68. </label>
  69. <label className={error === 'jdbc_password' ? 'jldbq-form-error' : ''}>
  70. <span className="jldbq-form-label">密码:</span>
  71. <Input.Password
  72. className="jldbq-form-input"
  73. placeholder="请输入密码"
  74. value={value.jdbc_password || ''}
  75. onChange={evt => onChange({ jdbc_password: evt.target.value })}
  76. />
  77. </label>
  78. <span className="jldbq-form-link" onClick={() => onConnection(value)}>
  79. 测试连接
  80. </span>
  81. </form>
  82. );
  83. };
  84. export class DatasourceFormDialogBody
  85. extends ReactWidget
  86. implements Dialog.IBodyWidget<IDatasourceForm> {
  87. constructor(manager: string, options?: Widget.IOptions) {
  88. super(options);
  89. // this._manager = manager;
  90. }
  91. render(): JSX.Element {
  92. return (
  93. <DatasourceForm
  94. value={this._datasourceItem}
  95. error={this._error}
  96. onChange={v => {
  97. this._datasourceItem = { ...this._datasourceItem, ...v };
  98. this._error = null;
  99. this.update();
  100. }}
  101. onConnection={async v => {
  102. const res = await textDatasource({ ...v } as IDatasourceForm);
  103. if (res && res !== 'error') {
  104. void message.success('测试成功');
  105. } else {
  106. void message.error('测试失败');
  107. }
  108. }}
  109. />
  110. );
  111. }
  112. getValue(): IDatasourceForm {
  113. const {
  114. jdbc_url,
  115. jdbc_username,
  116. jdbc_password,
  117. database_name,
  118. datasource_name,
  119. datasource
  120. } = this._datasourceItem;
  121. if (!datasource) {
  122. this._setError('datasource');
  123. }
  124. if (!jdbc_url || !validateIpAndPort(jdbc_url)) {
  125. this._setError('jdbc_url');
  126. }
  127. if (!jdbc_username) {
  128. this._setError('jdbc_username');
  129. }
  130. if (!jdbc_password) {
  131. this._setError('jdbc_password');
  132. }
  133. if (!database_name && datasource === 'mysql') {
  134. this._setError('database_name');
  135. }
  136. if (!datasource_name) {
  137. this._setError('datasource_name');
  138. }
  139. return {
  140. jdbc_url,
  141. jdbc_username,
  142. jdbc_password,
  143. database_name: database_name as any,
  144. datasource_name,
  145. datasource
  146. // manager: this._manager
  147. };
  148. }
  149. private _setError(error: keyof IDatasourceForm): never {
  150. this._error = error;
  151. this.update();
  152. throw new Error(error);
  153. }
  154. private _datasourceItem: Partial<IDatasourceForm> = {};
  155. private _error: IProps['error'] = null;
  156. // private _manager: string;
  157. }
  158. function validateIpAndPort(input: string): boolean {
  159. const parts = input.split(':');
  160. if (parts.length > 2) {
  161. return false;
  162. }
  163. const ip = parts[0].split('.');
  164. if (
  165. ip.length !== 4 ||
  166. !ip.every(function (segment) {
  167. return validateNum(segment, 0, 255);
  168. })
  169. ) {
  170. return false;
  171. }
  172. const port = parts[1];
  173. if (port && !validateNum(port, 1, 65535)) {
  174. return false;
  175. }
  176. return true;
  177. }
  178. function validateNum(input: string, min: number, max: number): boolean {
  179. const num = +input;
  180. return num >= min && num <= max && input === num.toString();
  181. }