Browse Source

feat: KERNEL-1582 完成redis数据集页面

pull/14/head
alan 5 years ago
parent
commit
0811f9f637
  1. 21
      src/main/resources/com/fr/plugin/db/redis/locale/redis_zh_CN.properties
  2. 8
      src/web/index.html
  3. 19
      src/web/private/i18n.ts
  4. 6
      src/web/src/index.dataset.ts
  5. 6
      src/web/src/index.program.ts
  6. 2
      src/web/src/less/background.less
  7. 12
      src/web/src/less/font.less
  8. 3
      src/web/src/less/index.less
  9. 2
      src/web/src/less/lib/background.less
  10. 13
      src/web/src/less/lib/font.less
  11. 1
      src/web/src/less/utils.less
  12. 116
      src/web/src/modules/app.dataset.ts
  13. 25
      src/web/src/modules/app.edit.ts
  14. 136
      src/web/src/modules/app.program.ts
  15. 22
      src/web/src/modules/app.show.ts
  16. 6
      src/web/src/modules/components/form_item/form_item.ts
  17. 40
      src/web/src/modules/components/parameter/parameter.model.ts
  18. 172
      src/web/src/modules/components/parameter/parameter.ts
  19. 9
      src/web/src/modules/components/parameter/parameter.typings.d.ts
  20. 20
      src/web/src/modules/components/parameter/parameter_input/input/input.service.ts
  21. 6
      src/web/src/modules/components/parameter/parameter_input/input/input.ts
  22. 41
      src/web/src/modules/components/parameter/parameter_input/input/input_boolean.ts
  23. 42
      src/web/src/modules/components/parameter/parameter_input/input/input_date.ts
  24. 45
      src/web/src/modules/components/parameter/parameter_input/input/input_formula.ts
  25. 42
      src/web/src/modules/components/parameter/parameter_input/input/input_int.ts
  26. 42
      src/web/src/modules/components/parameter/parameter_input/input/input_number.ts
  27. 41
      src/web/src/modules/components/parameter/parameter_input/input/input_string.ts
  28. 5
      src/web/src/modules/components/parameter/parameter_input/parameter_input.less
  29. 40
      src/web/src/modules/components/parameter/parameter_input/parameter_input.model.ts
  30. 165
      src/web/src/modules/components/parameter/parameter_input/parameter_input.ts
  31. 16
      src/web/src/modules/components/pool/pool.ts
  32. 16
      src/web/src/modules/components/pool/pool_edit.ts
  33. 20
      src/web/src/modules/components/proxy/proxy.ts
  34. 20
      src/web/src/modules/components/proxy/proxy_edit.ts
  35. 2
      src/web/src/modules/core/core.ts
  36. 29
      src/web/src/modules/table_list/list_item.ts
  37. 89
      src/web/src/modules/table_list/table_list.ts
  38. 150
      src/web/src/ui/fineui.ts
  39. 22
      src/web/webpack/webpack.dev.js
  40. 4
      src/web/yarn.lock

21
src/main/resources/com/fr/plugin/db/redis/locale/redis_zh_CN.properties

@ -39,4 +39,23 @@ Plugin-Redis_Script_Engine_Type=\u811A\u672C\u5F15\u64CE
Plugin-Redis_Script_Engine_Type_Default=\u9ED8\u8BA4 Plugin-Redis_Script_Engine_Type_Default=\u9ED8\u8BA4
Plugin-Redis_Script_Engine_Type_V8=V8\u9AD8\u901F\u5F15\u64CE Plugin-Redis_Script_Engine_Type_V8=V8\u9AD8\u901F\u5F15\u64CE
Plugin-Redis_Proxy_Private_Key_Path_Mark=\u8bf7\u8f93\u5165\u670d\u52a1\u5668\u6587\u4ef6\u8def\u5f84 Plugin-Redis_Proxy_Private_Key_Path_Mark=\u8bf7\u8f93\u5165\u670d\u52a1\u5668\u6587\u4ef6\u8def\u5f84
Plugin-Redis_Connection_Form_OriginalCharsetName= \u7f16\u7801 Plugin-Redis_Connection_Form_OriginalCharsetName= \u7f16\u7801
Plugin-Redis_Check_Integer=\u8bf7\u8f93\u5165\u4e0d\u5c0f\u4e8e\u0030\u7684\u6574\u6570
Plugin-Redis_Parameter_Insert=\u63D2\u5165
Plugin-Redis_Parameter_Delete=\u5220\u9664
Plugin-Redis_Parameter_Move_Up=\u4E0A\u79FB
Plugin-Redis_Parameter_Move_Down=\u4E0B\u79FB
Plugin-Redis_Parameter_Refresh=\u5237\u65B0
Plugin-Redis_Dataset_Parameter_Name=\u53C2\u6570
Plugin-Redis_Dataset_Parameter_Value=\u503C
Plugin-Redis_Parameter_Please_Set_Parameter_Name=\u8BF7\u5148\u8BBE\u7F6E\u53C2\u6570\u540D
Plugin-Redis_Parameter_Type_String=\u5B57\u7B26\u4E32
Plugin-Redis_Parameter_Type_Int=\u6574\u578B
Plugin-Redis_Parameter_Type_Number=\u53CC\u7CBE\u5EA6\u578B
Plugin-Redis_Parameter_Type_Date=\u65E5\u671F
Plugin-Redis_Parameter_Type_Boolean=\u5E03\u5C14\u578B
Plugin-Redis_Parameter_Type_Formula=\u516C\u5F0F
Plugin-Redis_Parameter_Delete_Confirm=\u4F60\u786E\u5B9A\u51B3\u5B9A\u5220\u9664\u9009\u4E2D\u7684\u9879\uFF1F
Plugin-Redis_Parameter_Delete_Alert=\u5F53\u524D\u5217\u8868\u4E3A\u7A7A\u6216\u8005\u4F60\u6CA1\u6709\u9009\u4E2D\u4EFB\u4F55\u9879
Plugin-Redis_View=\u89c6\u56fe
Plugin-Redis_Table=\u8868

8
src/web/index.html

@ -2,7 +2,7 @@
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="UTF-8" /> <meta charset="UTF-8" />
<title>Fine Report</title> <title><%= htmlWebpackPlugin.options.title %></title>
<!--核心css文件--> <!--核心css文件-->
<link <link
rel="preload" rel="preload"
@ -16,6 +16,11 @@
type="text/css" type="text/css"
href="./node_modules/fineui/dist/fineui.css" href="./node_modules/fineui/dist/fineui.css"
/> />
<link
rel="stylesheet"
type="text/css"
href="./node_modules/fineui-materials/docs/materials.min.css"
/>
</head> </head>
<script> <script>
var DecCst = null; var DecCst = null;
@ -25,6 +30,7 @@
<body id="body"> <body id="body">
<div id="wrapper"></div> <div id="wrapper"></div>
<script src="./node_modules/fineui/dist/fineui.js"></script> <script src="./node_modules/fineui/dist/fineui.js"></script>
<script src="./node_modules/fineui-materials/docs/materials.min.js"></script>
<script src="./node_modules/fineui/i18n/i18n.cn.js"></script> <script src="./node_modules/fineui/i18n/i18n.cn.js"></script>
</body> </body>
</html> </html>

19
src/web/private/i18n.ts

@ -41,4 +41,23 @@ export const i18n = {
'Plugin-Redis_Script_Engine_Type_V8': 'V8高速引擎', 'Plugin-Redis_Script_Engine_Type_V8': 'V8高速引擎',
'Plugin-Redis_Proxy_Private_Key_Path_Mark': '请输入服务器文件路径', 'Plugin-Redis_Proxy_Private_Key_Path_Mark': '请输入服务器文件路径',
'Plugin-Redis_Connection_Form_OriginalCharsetName': '编码', 'Plugin-Redis_Connection_Form_OriginalCharsetName': '编码',
'Plugin-Redis_Check_Integer': '请输入不小于0的整数',
'Plugin-Redis_Parameter_Insert': '插入',
'Plugin-Redis_Parameter_Delete': '删除',
'Plugin-Redis_Parameter_Move_Up': '上移',
'Plugin-Redis_Parameter_Move_Down': '下移',
'Plugin-Redis_Parameter_Refresh': '刷新',
'Plugin-Redis_Dataset_Parameter_Name': '参数',
'Plugin-Redis_Dataset_Parameter_Value': '值',
'Plugin-Redis_Parameter_Please_Set_Parameter_Name': '请先设置参数名',
'Plugin-Redis_Parameter_Type_String': '字符串',
'Plugin-Redis_Parameter_Type_Int': '整型',
'Plugin-Redis_Parameter_Type_Number': '双精度型',
'Plugin-Redis_Parameter_Type_Date': '日期',
'Plugin-Redis_Parameter_Type_Boolean': '布尔型',
'Plugin-Redis_Parameter_Type_Formula': '公式',
'Plugin-Redis_Parameter_Delete_Confirm': '你确定决定删除选中的项?',
'Plugin-Redis_Parameter_Delete_Alert': '当前列表为空或者你没有选中任何项',
'Plugin-Redis_View': '视图',
'Plugin-Redis_Table': '表',
}; };

6
src/web/src/index.dataset.ts

@ -0,0 +1,6 @@
import { RedisDataset } from './modules/app.dataset';
BI.createWidget({
type: RedisDataset.xtype,
element: '#wrapper',
});

6
src/web/src/index.program.ts

@ -0,0 +1,6 @@
import { RedisProgram } from './modules/app.program';
BI.createWidget({
type: RedisProgram.xtype,
element: '#wrapper',
});

2
src/web/src/less/background.less

@ -0,0 +1,2 @@
@import "../../node_modules/fineui/src/less/image.less";
@import "./lib/background.less";

12
src/web/src/less/font.less

@ -0,0 +1,12 @@
@import "../../node_modules/fineui/src/less/resource/font.less";
@import "./lib/font.less";
.font(refresh-font, @font-refresh);
.font(input-string-font, @font-input-string);
.font(input-formula-font, @font-input-formula);
.font(input-date-font, @font-input-date);
.font(input-boolean-font, @font-input-boolean);
.font(input-int-font, @font-input-int);
.font(input-number-font, @font-input-number);
.font(site-font, @font-site);
.font(column-font, @font-column);

3
src/web/src/less/index.less

@ -0,0 +1,3 @@
@import "background.less";
@import "font.less";
@import "utils.less";

2
src/web/src/less/lib/background.less

@ -0,0 +1,2 @@
@imageUrl: '$imageUrl/'; //图片的基本地址
@image2xUrl: '$image2xUrl/'; //2倍图片的基本地址

13
src/web/src/less/lib/font.less

@ -0,0 +1,13 @@
@fontUrl: '$fontUrl/';
@fontReportUrl: '$fontReportUrl/';
@fontName: "report";
@font-refresh: "e6ef";
@font-input-string: "e6e9";
@font-input-formula: "e6c6";
@font-input-date: "e733";
@font-input-boolean: "e656";
@font-input-int: "e7c2";
@font-input-number: "e60b";
@font-site: "e7c5";
@font-column: "e76f";

1
src/web/src/less/utils.less

@ -0,0 +1 @@
@import '../../node_modules/fineui/src/less/visual.less';

116
src/web/src/modules/app.dataset.ts

@ -0,0 +1,116 @@
import { shortcut } from '@core/core';
import { VerticalXtype, TextEditorXtype, HtapeXtype, LabelXtype, IconComboXtype, TabXtype, CodeEditorXtype } from 'ui';
import { Parameter } from './components/parameter/parameter';
import { TableList } from './table_list/table_list';
import '../less/index.less';
@shortcut()
export class RedisDataset extends BI.Widget {
static xtype = 'dec.dcm.connection.plugin.redis.dataset'
private textWidth = 100;
databaseNoTab: any;
iconCombo: any;
render() {
return {
type: HtapeXtype,
items: [{
el: {
type: TableList.xtype,
cls: 'bi-border-right',
},
width: 300,
}, {
type: VerticalXtype,
hgap: 5,
vgap: 10,
items: [{
type: HtapeXtype,
height: 22,
items: [{
el: {
type: LabelXtype,
text: BI.i18nText('Plugin-Redis_DB_Index'),
textAlign: 'left',
},
width: this.textWidth,
}, {
type: HtapeXtype,
items: [{
el: {
type: IconComboXtype,
height: 22,
width: 28,
value: 'int',
items: [{
text: BI.i18nText('Plugin-Redis_Parameter_Type_Int'),
value: 'int',
iconCls: 'input-int-font',
}, {
text: BI.i18nText('Plugin-Redis_Parameter_Type_Formula'),
value: 'formula',
iconCls: 'input-formula-font',
}],
ref: (_ref: any) => {
this.iconCombo = _ref;
},
listeners: [{
eventName: 'EVENT_CHANGE',
action: () => {
const typeValue = this.iconCombo.getValue()[0];
this.databaseNoTab.setSelect(typeValue);
},
}],
},
width: 28,
}, {
type: TabXtype,
single: true,
showIndex: 'int',
ref: (_ref: any) => {
this.databaseNoTab = _ref;
},
cardCreator: (index: 'int'|'formula') => {
if (index === 'int') {
return {
type: TextEditorXtype,
warningTitle: '',
value: 0,
validationChecker: (v: string) => this.checkInteger(v),
errorText: BI.i18nText('Plugin-Redis_Check_Integer'),
};
}
return {
type: TextEditorXtype,
allowBlank: true,
};
},
}],
}],
}, {
type: HtapeXtype,
height: 200,
items: [{
el: {
type: LabelXtype,
text: BI.i18nText('Plugin-Redis_Query_Condition'),
textAlign: 'left',
},
width: this.textWidth,
}, {
type: CodeEditorXtype,
cls: 'bi-border',
height: 200,
}],
}, {
type: Parameter.xtype,
}],
}],
};
}
private checkInteger(value: string) {
return /^[\d]+$/.test(value);
}
}

25
src/web/src/modules/app.edit.ts

@ -1,6 +1,6 @@
import { shortcut } from '@core/core'; import { shortcut } from '@core/core';
import { POOL_CONFIG, PROXY_CONFIG, BASIC_CONFIG, CONNECT_CHARSET } from '@constants/constant'; import { POOL_CONFIG, PROXY_CONFIG, BASIC_CONFIG, CONNECT_CHARSET } from '@constants/constant';
import { Vertical, TextEditor, TextValueCombo, Left, TextButton, BarPopOver, Editor } from 'ui'; import { VerticalXtype, TextEditorXtype, TextValueComboXtype, LeftXtype, TextButtonXtype, BarPopOverXtype, EditorXtype } from 'ui';
import { FormItem } from './components/form_item/form_item'; import { FormItem } from './components/form_item/form_item';
import { PoolEdit } from './components/pool/pool_edit'; import { PoolEdit } from './components/pool/pool_edit';
import { ProxyEdit } from './components/proxy/proxy_edit'; import { ProxyEdit } from './components/proxy/proxy_edit';
@ -43,7 +43,7 @@ export class RedisEdit extends BI.Widget {
this.oldPassword = password; this.oldPassword = password;
return { return {
type: Vertical, type: VerticalXtype,
hgap: 15, hgap: 15,
vgap: 10, vgap: 10,
items: [ items: [
@ -51,7 +51,7 @@ export class RedisEdit extends BI.Widget {
type: FormItem.xtype, type: FormItem.xtype,
name: BI.i18nText('Plugin-Redis_Host'), name: BI.i18nText('Plugin-Redis_Host'),
forms: [{ forms: [{
type: TextEditor, type: TextEditorXtype,
width: 300, width: 300,
allowBlank: true, allowBlank: true,
ref: _ref => { ref: _ref => {
@ -64,7 +64,7 @@ export class RedisEdit extends BI.Widget {
type: FormItem.xtype, type: FormItem.xtype,
name: BI.i18nText('Plugin-Redis_Port'), name: BI.i18nText('Plugin-Redis_Port'),
forms: [{ forms: [{
type: TextEditor, type: TextEditorXtype,
width: 300, width: 300,
allowBlank: true, allowBlank: true,
ref: _ref => { ref: _ref => {
@ -77,7 +77,7 @@ export class RedisEdit extends BI.Widget {
type: FormItem.xtype, type: FormItem.xtype,
name: BI.i18nText('Plugin-Redis_Password'), name: BI.i18nText('Plugin-Redis_Password'),
forms: [{ forms: [{
type: Editor, type: EditorXtype,
cls: 'bi-border', cls: 'bi-border',
height: 20, height: 20,
width: 300, width: 300,
@ -90,17 +90,17 @@ export class RedisEdit extends BI.Widget {
}], }],
}, },
{ {
type: Left, type: LeftXtype,
hgap: 20, hgap: 20,
items: [ items: [
{ {
type: TextButton, type: TextButtonXtype,
cls: 'bi-high-light', cls: 'bi-high-light',
text: BI.i18nText('Plugin-Redis_Pool_Config'), text: BI.i18nText('Plugin-Redis_Pool_Config'),
handler: () => { handler: () => {
const id = BI.UUID(); const id = BI.UUID();
BI.Popovers.create(id, { BI.Popovers.create(id, {
type: BarPopOver, type: BarPopOverXtype,
width: 500, width: 500,
height: 320, height: 320,
header: BI.i18nText('Plugin-Redis_Pool_Config'), header: BI.i18nText('Plugin-Redis_Pool_Config'),
@ -121,13 +121,13 @@ export class RedisEdit extends BI.Widget {
}, },
}, },
{ {
type: TextButton, type: TextButtonXtype,
cls: 'bi-high-light', cls: 'bi-high-light',
text: BI.i18nText('Plugin-Redis_Proxy_Config'), text: BI.i18nText('Plugin-Redis_Proxy_Config'),
handler: () => { handler: () => {
const id = BI.UUID(); const id = BI.UUID();
BI.Popovers.create(id, { BI.Popovers.create(id, {
type: BarPopOver, type: BarPopOverXtype,
width: 650, width: 650,
height: 320, height: 320,
header: BI.i18nText('Plugin-Redis_Pool_Config'), header: BI.i18nText('Plugin-Redis_Pool_Config'),
@ -153,7 +153,7 @@ export class RedisEdit extends BI.Widget {
type: FormItem.xtype, type: FormItem.xtype,
name: BI.i18nText('Plugin-Redis_Connection_Form_OriginalCharsetName'), name: BI.i18nText('Plugin-Redis_Connection_Form_OriginalCharsetName'),
forms: [{ forms: [{
type: TextValueCombo, type: TextValueComboXtype,
width: 300, width: 300,
value: originalCharsetName ? originalCharsetName : '', value: originalCharsetName ? originalCharsetName : '',
items: CONNECT_CHARSET, items: CONNECT_CHARSET,
@ -167,7 +167,8 @@ export class RedisEdit extends BI.Widget {
} }
public getSubmitValue() { public getSubmitValue() {
const originalCharsetName = this.originalCharsetName.getValue()[0] || '' const originalCharsetName = this.originalCharsetName.getValue()[0] || '';
return { return {
basicConfig: { basicConfig: {
host: this.host.getValue(), host: this.host.getValue(),

136
src/web/src/modules/app.program.ts

@ -0,0 +1,136 @@
import { shortcut } from '@core/core';
import { VerticalXtype, TextEditorXtype, HtapeXtype, LabelXtype, IconComboXtype, TabXtype, CodeEditorXtype, TextValueComboXtype } from 'ui';
import { Parameter } from './components/parameter/parameter';
import { TableList } from './table_list/table_list';
import '../less/index.less';
@shortcut()
export class RedisProgram extends BI.Widget {
static xtype = 'dec.dcm.connection.plugin.redis.program'
private textWidth = 100;
databaseNoTab: any;
iconCombo: any;
render() {
return {
type: HtapeXtype,
items: [{
el: {
type: TableList.xtype,
cls: 'bi-border-right',
},
width: 300,
}, {
type: VerticalXtype,
hgap: 5,
vgap: 10,
items: [{
type: HtapeXtype,
height: 22,
items: [{
el: {
type: LabelXtype,
text: BI.i18nText('Plugin-Redis_DB_Index'),
textAlign: 'left',
},
width: this.textWidth,
}, {
type: HtapeXtype,
items: [{
el: {
type: IconComboXtype,
height: 22,
width: 28,
value: 'int',
items: [{
text: BI.i18nText('Plugin-Redis_Parameter_Type_Int'),
value: 'int',
iconCls: 'input-int-font',
}, {
text: BI.i18nText('Plugin-Redis_Parameter_Type_Formula'),
value: 'formula',
iconCls: 'input-formula-font',
}],
ref: (_ref: any) => {
this.iconCombo = _ref;
},
listeners: [{
eventName: 'EVENT_CHANGE',
action: () => {
const typeValue = this.iconCombo.getValue()[0];
this.databaseNoTab.setSelect(typeValue);
},
}],
},
width: 28,
}, {
type: TabXtype,
single: true,
showIndex: 'int',
ref: (_ref: any) => {
this.databaseNoTab = _ref;
},
cardCreator: (index: 'int'|'formula') => {
if (index === 'int') {
return {
type: TextEditorXtype,
warningTitle: '',
value: 0,
validationChecker: (v: string) => this.checkInteger(v),
errorText: BI.i18nText('Plugin-Redis_Check_Integer'),
};
}
return {
type: TextEditorXtype,
allowBlank: true,
};
},
}],
}],
}, {
type: HtapeXtype,
height: 22,
items: [{
el: {
type: LabelXtype,
text: BI.i18nText('Plugin-Redis_Script_Engine_Type'),
textAlign: 'left',
},
width: this.textWidth,
}, {
type: TextValueComboXtype,
items: [{
text: BI.i18nText('Plugin-Redis_Script_Engine_Type_Default'),
value: '',
}, {
text: BI.i18nText('Plugin-Redis_Script_Engine_Type_V8'),
value: 'v8',
}],
}],
}, {
type: HtapeXtype,
height: 200,
items: [{
el: {
type: LabelXtype,
text: BI.i18nText('Plugin-Redis_Query_Condition'),
textAlign: 'left',
},
width: this.textWidth,
}, {
type: CodeEditorXtype,
cls: 'bi-border',
height: 200,
}],
}, {
type: Parameter.xtype,
}],
}],
};
}
private checkInteger(value: string) {
return /^[\d]+$/.test(value);
}
}

22
src/web/src/modules/app.show.ts

@ -1,5 +1,5 @@
import { shortcut } from '@core/core'; import { shortcut } from '@core/core';
import { Label, Vertical, Left, TextButton, BarPopOver } from 'ui'; import { LabelXtype, VerticalXtype, LeftXtype, TextButtonXtype, BarPopOverXtype } from 'ui';
import { FormItem } from './components/form_item/form_item'; import { FormItem } from './components/form_item/form_item';
import { PoolConfig } from './components/pool/pool'; import { PoolConfig } from './components/pool/pool';
import { ProxyConfig } from './components/proxy/proxy'; import { ProxyConfig } from './components/proxy/proxy';
@ -29,7 +29,7 @@ export class RedisShow extends BI.Widget {
const { host, port, newCharsetName } = basicConfig; const { host, port, newCharsetName } = basicConfig;
return { return {
type: Vertical, type: VerticalXtype,
hgap: 15, hgap: 15,
vgap: 10, vgap: 10,
items: [ items: [
@ -37,7 +37,7 @@ export class RedisShow extends BI.Widget {
type: FormItem.xtype, type: FormItem.xtype,
name: BI.i18nText('Plugin-Redis_Host'), name: BI.i18nText('Plugin-Redis_Host'),
forms: [{ forms: [{
type: Label, type: LabelXtype,
text: host, text: host,
}], }],
}, },
@ -45,7 +45,7 @@ export class RedisShow extends BI.Widget {
type: FormItem.xtype, type: FormItem.xtype,
name: BI.i18nText('Plugin-Redis_Port'), name: BI.i18nText('Plugin-Redis_Port'),
forms: [{ forms: [{
type: Label, type: LabelXtype,
text: port, text: port,
}], }],
}, },
@ -53,22 +53,22 @@ export class RedisShow extends BI.Widget {
type: FormItem.xtype, type: FormItem.xtype,
name: BI.i18nText('Plugin-Redis_Password'), name: BI.i18nText('Plugin-Redis_Password'),
forms: [{ forms: [{
type: Label, type: LabelXtype,
text: '*****', text: '*****',
}], }],
}, },
{ {
type: Left, type: LeftXtype,
hgap: 20, hgap: 20,
items: [ items: [
{ {
type: TextButton, type: TextButtonXtype,
cls: 'bi-high-light', cls: 'bi-high-light',
text: BI.i18nText('Plugin-Redis_Pool_Config'), text: BI.i18nText('Plugin-Redis_Pool_Config'),
handler: () => { handler: () => {
const id = BI.UUID(); const id = BI.UUID();
BI.Popovers.create(id, { BI.Popovers.create(id, {
type: BarPopOver, type: BarPopOverXtype,
width: 400, width: 400,
height: 300, height: 300,
header: BI.i18nText('Plugin-Redis_Pool_Config'), header: BI.i18nText('Plugin-Redis_Pool_Config'),
@ -81,13 +81,13 @@ export class RedisShow extends BI.Widget {
}, },
}, },
{ {
type: TextButton, type: TextButtonXtype,
cls: 'bi-high-light', cls: 'bi-high-light',
text: BI.i18nText('Plugin-Redis_Proxy_Config'), text: BI.i18nText('Plugin-Redis_Proxy_Config'),
handler: () => { handler: () => {
const id = BI.UUID(); const id = BI.UUID();
BI.Popovers.create(id, { BI.Popovers.create(id, {
type: BarPopOver, type: BarPopOverXtype,
width: 650, width: 650,
height: 280, height: 280,
header: BI.i18nText('Plugin-Redis_Pool_Config'), header: BI.i18nText('Plugin-Redis_Pool_Config'),
@ -105,7 +105,7 @@ export class RedisShow extends BI.Widget {
type: FormItem.xtype, type: FormItem.xtype,
name: BI.i18nText('Plugin-Redis_Connection_Form_OriginalCharsetName'), name: BI.i18nText('Plugin-Redis_Connection_Form_OriginalCharsetName'),
forms: [{ forms: [{
type: Label, type: LabelXtype,
text: newCharsetName ? newCharsetName : BI.i18nText('BI-Basic_Auto'), text: newCharsetName ? newCharsetName : BI.i18nText('BI-Basic_Auto'),
}], }],
}, },

6
src/web/src/modules/components/form_item/form_item.ts

@ -1,5 +1,5 @@
import { shortcut } from '@core/core'; import { shortcut } from '@core/core';
import { Label, Left } from 'ui'; import { LabelXtype, LeftXtype } from 'ui';
@shortcut() @shortcut()
export class FormItem extends BI.Widget { export class FormItem extends BI.Widget {
@ -13,10 +13,10 @@ export class FormItem extends BI.Widget {
render () { render () {
return { return {
type: Left, type: LeftXtype,
items: [ items: [
{ {
type: Label, type: LabelXtype,
cls: 'bi-font-bold', cls: 'bi-font-bold',
width: this.options.nameWidth, width: this.options.nameWidth,
textAlign: 'left', textAlign: 'left',

40
src/web/src/modules/components/parameter/parameter.model.ts

@ -0,0 +1,40 @@
import { model, Model } from '../../core/core';
import { ParametersType } from './parameter.typings';
@model()
export class ParameterModel extends Model {
static xtype = 'plugin.model.report.json.components.parameter';
childContext = <const>['selectedId', 'parameters'];
state() {
return {
parameters: [] as ParametersType[],
selectedId: '',
};
}
actions = {
setParameters: (parameters: ParametersType[]) => {
this.model.parameters = parameters;
},
removeSelectedParameter: () => {
this.setParameters(this.model.parameters.filter(item => item.id !== this.model.selectedId));
},
move: (type: 'up'|'down') => {
if (this.model.selectedId) {
const index = this.model.parameters.findIndex(item => item.id === this.model.selectedId);
if (type === 'up' && index > 0) {
const oldItem = this.model.parameters.splice(index, 1)[0];
this.model.parameters.splice(index - 1, 0, oldItem);
}
if (type === 'down' && index < this.model.parameters.length - 1) {
const oldItem = this.model.parameters.splice(index, 1)[0];
this.model.parameters.splice(index + 1, 0, oldItem);
}
}
},
}
}

172
src/web/src/modules/components/parameter/parameter.ts

@ -0,0 +1,172 @@
import { shortcut, store } from '../../core/core';
import { VtapeXtype, LabelXtype, HtapeXtype, LeftRightVerticalAdaptLayoutXtype, IconButtonXtype, ButtonGroupXtype, VerticalXtype } from 'ui';
import { ParameterInput } from './parameter_input/parameter_input';
import { ParameterModel } from './parameter.model';
import { ParametersType } from './parameter.typings';
@shortcut()
@store(ParameterModel)
export class Parameter extends BI.Widget {
static xtype = 'plugin.report.redis.components.parameter';
props = {
title: '',
showRefresh: true,
height: 200,
value: [] as ParametersType[],
}
parameterInputs: any;
model: ParameterModel['model']
store: ParameterModel['store']
watch = {
parameters: () => {
this.parameterInputs.populate(this.renderParameterInputs());
},
selectedId: (id: string) => {
this.parameterInputs.setValue(id);
},
}
render() {
const { title, showRefresh } = this.options;
this.setDefalue();
return {
type: VtapeXtype,
items: [{
el: {
type: LeftRightVerticalAdaptLayoutXtype,
items: {
left: [{
type: LabelXtype,
lgap: 2,
text: title,
textAlign: 'left',
}],
right: [{
type: IconButtonXtype,
cls: 'text-add-tip-font',
width: 25,
title: BI.i18nText('Plugin-Redis_Parameter_Insert'),
handler: () => {
this.store.setParameters([{
name: '',
value: '',
id: BI.UUID(),
type: 'string',
}, ...this.model.parameters]);
},
}, {
type: IconButtonXtype,
cls: 'close-font bi-error',
width: 25,
title: BI.i18nText('Plugin-Redis_Parameter_Delete'),
handler: () => {
if (this.model.selectedId) {
BI.Msg.confirm(BI.i18nText('BI-Basic_Prompt'), BI.i18nText('Plugin-Redis_Parameter_Delete_Confirm'), (re: boolean) => {
if (re) {
this.store.removeSelectedParameter();
}
});
} else {
BI.Msg.alert(BI.i18nText('BI-Basic_Prompt'), BI.i18nText('Plugin-Redis_Parameter_Delete_Alert'));
}
},
}, {
type: IconButtonXtype,
cls: 'add-up-font',
width: 25,
title: BI.i18nText('Plugin-Redis_Parameter_Move_Up'),
handler: () => {
this.store.move('up');
},
}, {
type: IconButtonXtype,
cls: 'minus-down-font',
width: 25,
title: BI.i18nText('Plugin-Redis_Parameter_Move_Down'),
handler: () => {
this.store.move('down');
},
}, showRefresh ? {
type: IconButtonXtype,
cls: 'refresh-font',
width: 25,
title: BI.i18nText('Plugin-Redis_Parameter_Refresh'),
handler: () => {
this.setDefalue();
},
} : null],
},
},
height: 25,
}, {
el: {
type: HtapeXtype,
cls: 'bi-border',
items: [{
el: {
type: LabelXtype,
text: BI.i18nText('Plugin-Redis_Dataset_Parameter_Name'),
},
width: 0.5,
}, {
el: {
type: LabelXtype,
cls: 'bi-border-left',
text: BI.i18nText('Plugin-Redis_Dataset_Parameter_Value'),
},
width: 0.5,
}],
},
height: 25,
}, {
type: ButtonGroupXtype,
cls: 'bi-border',
layouts: [{
type: VerticalXtype,
}],
items: this.renderParameterInputs(),
ref: (_ref: any) => {
this.parameterInputs = _ref;
},
}],
};
}
public getValue() {
return this.model.parameters.map(item => {
return {
name: item.name,
value: item.value,
type: item.type,
};
});
}
private setDefalue() {
const { value = [] } = this.options;
this.store.setParameters(value.map(item => {
return {
...item,
id: BI.UUID(),
};
}));
}
private renderParameterInputs() {
return this.model.parameters.map(item => {
return {
type: ParameterInput.xtype,
inputName: item.name,
inputValue: item.value,
id: item.id,
value: item.id,
selected: item.id === this.model.selectedId,
};
});
}
}

9
src/web/src/modules/components/parameter/parameter.typings.d.ts vendored

@ -0,0 +1,9 @@
export interface ParametersType {
name: string;
value: string;
id?: string;
type: inputTypes;
}
export type inputTypes = 'string' | 'int' | 'number' | 'date' | 'boolean' | 'formula'

20
src/web/src/modules/components/parameter/parameter_input/input/input.service.ts

@ -0,0 +1,20 @@
import { inputTypes } from '../../parameter.typings';
const inputs: {
[key: string]: any;
} = {};
export function input(key: inputTypes): ClassDecorator {
return (target: object) => {
inputs[key] = target;
};
}
export function getInput(type: inputTypes): string {
const inputWidget = inputs[type];
if (BI.isNull(inputWidget)) {
throw new TypeError();
}
return inputWidget.xtype;
}

6
src/web/src/modules/components/parameter/parameter_input/input/input.ts

@ -0,0 +1,6 @@
import './input_boolean';
import './input_date';
import './input_int';
import './input_number';
import './input_string';
import './input_formula';

41
src/web/src/modules/components/parameter/parameter_input/input/input_boolean.ts

@ -0,0 +1,41 @@
import { shortcut } from '../../../../core/core';
import { MultiSelectItemXtype } from 'ui';
import { input } from './input.service';
@shortcut()
@input('boolean')
export class InputBoolean extends BI.Widget {
static xtype = 'plugin.report.json.components.parameter_input.boolean'
props = {
value: '',
}
input: any;
render() {
const { value } = this.options;
return {
type: MultiSelectItemXtype,
width: 80,
selected: !!value,
text: 'true',
ref: (_ref: any) => {
this.input = _ref;
},
listeners: [{
eventName: BI.TextEditor.EVENT_CHANGE,
action: () => {
const value = this.input.getValue();
this.fireEvent('EVENT_CHANGE', value);
},
}, {
eventName: BI.TextEditor.EVENT_FOCUS,
action: () => {
this.fireEvent('EVENT_FOCUS');
},
}],
};
}
}

42
src/web/src/modules/components/parameter/parameter_input/input/input_date.ts

@ -0,0 +1,42 @@
import { shortcut } from '../../../../core/core';
import { DynamicDateComboXtype } from 'ui';
import { input } from './input.service';
@shortcut()
@input('date')
export class InputDate extends BI.Widget {
static xtype = 'plugin.report.json.components.parameter_input.date'
props = {
value: '',
}
input: any;
render() {
const { value } = this.options;
return {
type: DynamicDateComboXtype,
height: 22,
allowBlank: true,
value,
ref: (_ref: any) => {
this.input = _ref;
},
validationChecker: (v: string) => BI.isNumeric(v),
listeners: [{
eventName: BI.TextEditor.EVENT_CHANGE,
action: () => {
const value = this.input.getValue();
this.fireEvent('EVENT_CHANGE', value);
},
}, {
eventName: BI.TextEditor.EVENT_FOCUS,
action: () => {
this.fireEvent('EVENT_FOCUS');
},
}],
};
}
}

45
src/web/src/modules/components/parameter/parameter_input/input/input_formula.ts

@ -0,0 +1,45 @@
import { shortcut } from '../../../../core/core';
import { EditorXtype } from 'ui';
import { input } from './input.service';
@shortcut()
@input('formula')
export class InputFormula extends BI.Widget {
static xtype = 'plugin.report.json.components.parameter_input.formula'
props = {
value: '',
}
input: any;
mounted() {
}
render() {
const { value } = this.options;
return {
type: EditorXtype,
height: 22,
allowBlank: true,
value,
ref: (_ref: any) => {
this.input = _ref;
},
listeners: [{
eventName: BI.TextEditor.EVENT_CHANGE,
action: () => {
const value = this.input.getValue();
this.fireEvent('EVENT_CHANGE', value);
},
}, {
eventName: BI.TextEditor.EVENT_FOCUS,
action: () => {
this.fireEvent('EVENT_FOCUS');
},
}],
};
}
}

42
src/web/src/modules/components/parameter/parameter_input/input/input_int.ts

@ -0,0 +1,42 @@
import { shortcut } from '../../../../core/core';
import { NumberEditorXtype } from 'ui';
import { input } from './input.service';
@shortcut()
@input('int')
export class InputInt extends BI.Widget {
static xtype = 'plugin.report.json.components.parameter_input.int'
props = {
value: '',
}
input: any;
render() {
const { value } = this.options;
return {
type: NumberEditorXtype,
height: 22,
allowBlank: true,
value,
ref: (_ref: any) => {
this.input = _ref;
},
validationChecker: (v: string) => BI.isInteger(v),
listeners: [{
eventName: BI.TextEditor.EVENT_CHANGE,
action: () => {
const value = this.input.getValue();
this.fireEvent('EVENT_CHANGE', value);
},
}, {
eventName: BI.TextEditor.EVENT_FOCUS,
action: () => {
this.fireEvent('EVENT_FOCUS');
},
}],
};
}
}

42
src/web/src/modules/components/parameter/parameter_input/input/input_number.ts

@ -0,0 +1,42 @@
import { shortcut } from '../../../../core/core';
import { EditorXtype } from 'ui';
import { input } from './input.service';
@shortcut()
@input('number')
export class InputNumber extends BI.Widget {
static xtype = 'plugin.report.json.components.parameter_input.number'
props = {
value: '',
}
input: any;
render() {
const { value } = this.options;
return {
type: EditorXtype,
height: 22,
allowBlank: true,
value,
ref: (_ref: any) => {
this.input = _ref;
},
validationChecker: (v: string) => BI.isNumeric(v),
listeners: [{
eventName: BI.TextEditor.EVENT_CHANGE,
action: () => {
const value = this.input.getValue();
this.fireEvent('EVENT_CHANGE', value);
},
}, {
eventName: BI.TextEditor.EVENT_FOCUS,
action: () => {
this.fireEvent('EVENT_FOCUS');
},
}],
};
}
}

41
src/web/src/modules/components/parameter/parameter_input/input/input_string.ts

@ -0,0 +1,41 @@
import { shortcut } from '../../../../core/core';
import { EditorXtype } from 'ui';
import { input } from './input.service';
@shortcut()
@input('string')
export class InputString extends BI.Widget {
static xtype = 'plugin.report.json.components.parameter_input.string'
props = {
value: '',
}
input: any;
render() {
const { value } = this.options;
return {
type: EditorXtype,
height: 22,
allowBlank: true,
value,
ref: (_ref: any) => {
this.input = _ref;
},
listeners: [{
eventName: BI.TextEditor.EVENT_CHANGE,
action: () => {
const value = this.input.getValue();
this.fireEvent('EVENT_CHANGE', value);
},
}, {
eventName: BI.TextEditor.EVENT_FOCUS,
action: () => {
this.fireEvent('EVENT_FOCUS');
},
}],
};
}
}

5
src/web/src/modules/components/parameter/parameter_input/parameter_input.less

@ -0,0 +1,5 @@
@import '../../../../less/index.less';
.plugin-report-json-parameter-input.active{
background-color: @color-bi-light-blue-60;
}

40
src/web/src/modules/components/parameter/parameter_input/parameter_input.model.ts

@ -0,0 +1,40 @@
import { model, Model } from '../../../core/core';
import { ParameterModel } from '../parameter.model';
import { inputTypes } from '../parameter.typings';
@model()
export class ParameterInputModel extends Model<{
types: {
selectedId: ParameterModel['TYPE']['selectedId'];
parameters: ParameterModel['TYPE']['parameters'];
},
context: ParameterInputModel['context'];
}> {
static xtype = 'plugin.model.report.json.components.parameter_input';
context = <const>['selectedId', 'parameters'];
actions = {
setSelectedId: (id: string) => {
this.model.selectedId = id;
},
setParameterName: (id: string, name: string) => {
const thisParameter = this.getParameter(id);
if (thisParameter) {
thisParameter.name = name;
}
},
setParameterValue: (id: string, value: string, type: inputTypes) => {
const thisParameter = this.getParameter(id);
if (thisParameter) {
thisParameter.value = value;
thisParameter.type = type;
}
},
}
private getParameter(id: string) {
return this.model.parameters.find(item => item.id === id);
}
}

165
src/web/src/modules/components/parameter/parameter_input/parameter_input.ts

@ -0,0 +1,165 @@
import { shortcut, store } from '../../../core/core';
import { HtapeXtype, EditorXtype, TextButtonXtype, TabXtype, IconComboXtype } from 'ui';
import { ParameterInputModel } from './parameter_input.model';
import { inputTypes } from '../parameter.typings';
import { getInput } from './input/input.service';
import './input/input';
import './parameter_input.less';
@shortcut()
@store(ParameterInputModel)
export class ParameterInput extends BI.BasicButton {
static xtype = 'plugin.report.json.components.parameter_input'
props = {
inputName: '',
inputValue: '',
height: 22,
id: '',
baseCls: 'plugin-report-json-parameter-input',
}
store: ParameterInputModel['store']
model: ParameterInputModel['model']
tab: any;
parameterName: any;
parameterValue: any;
iconCombo: any;
render() {
let { inputName, inputValue } = this.options;
const { id } = this.options;
return {
type: HtapeXtype,
cls: 'bi-border',
items: [{
el: {
type: EditorXtype,
height: 22,
allowBlank: true,
value: inputName,
ref: (_ref: any) => {
this.parameterName = _ref;
},
listeners: [{
eventName: BI.TextEditor.EVENT_CHANGE,
action: () => {
inputName = this.parameterName.getValue();
this.tab.setSelect(inputName ? 'string' : 'tip');
inputValue = inputName ? inputValue : '';
this.store.setParameterName(id, inputName);
},
}, {
eventName: BI.TextEditor.EVENT_FOCUS,
action: () => {
this.store.setSelectedId(id);
},
}],
},
width: 0.5,
}, {
el: {
type: HtapeXtype,
items: [{
type: TabXtype,
single: true,
showIndex: inputName ? 'string' : 'tip',
ref: (_ref: any) => {
this.tab = _ref;
},
cardCreator: (index: inputTypes | 'tip') => this.renderInputs(index),
}],
},
width: 0.5,
}],
};
}
private renderInputs(type: inputTypes | 'tip') {
const { inputValue, id } = this.options;
if (type === 'tip') {
return {
type: TextButtonXtype,
cls: 'bi-error bi-border-left',
text: BI.i18nText('Plugin-Redis_Parameter_Please_Set_Parameter_Name'),
handler: () => {
this.parameterName.focus();
},
};
}
const xtype = getInput(type);
return {
type: HtapeXtype,
items: [{
el: {
type: IconComboXtype,
cls: 'bi-border-left bi-border-right',
height: 22,
width: 25,
value: type,
items: this.renderDownList(),
ref: (_ref: any) => {
this.iconCombo = _ref;
},
listeners: [{
eventName: 'EVENT_CHANGE',
action: () => {
this.tab.setSelect('tip');
const typeValue = this.iconCombo.getValue()[0];
if (typeValue) {
this.tab.setSelect(typeValue);
}
},
}],
},
width: 25,
}, {
type: xtype,
value: inputValue,
listeners: [{
eventName: 'EVENT_CHANGE',
action: (value: string) => {
const type = this.iconCombo.getValue()[0];
this.store.setParameterValue(id, value, type);
},
}, {
eventName: 'EVENT_FOCUS',
action: () => {
this.store.setSelectedId(id);
},
}],
}],
};
}
private renderDownList() {
return [{
text: BI.i18nText('Plugin-Redis_Parameter_Type_String'),
value: 'string',
iconCls: 'input-string-font',
}, {
text: BI.i18nText('Plugin-Redis_Parameter_Type_Int'),
value: 'int',
iconCls: 'input-int-font',
}, {
text: BI.i18nText('Plugin-Redis_Parameter_Type_Number'),
value: 'number',
iconCls: 'input-number-font',
}, {
text: BI.i18nText('Plugin-Redis_Parameter_Type_Date'),
value: 'date',
iconCls: 'input-date-font',
}, {
text: BI.i18nText('Plugin-Redis_Parameter_Type_Boolean'),
value: 'boolean',
iconCls: 'input-boolean-font',
}, {
text: BI.i18nText('Plugin-Redis_Parameter_Type_Formula'),
value: 'formula',
iconCls: 'input-formula-font',
}];
}
}

16
src/web/src/modules/components/pool/pool.ts

@ -1,5 +1,5 @@
import { shortcut } from '@core/core'; import { shortcut } from '@core/core';
import { Label, Vertical, MultiSelectItem } from 'ui'; import { LabelXtype, VerticalXtype, MultiSelectItemXtype } from 'ui';
import { POOL_CONFIG } from '@constants/constant'; import { POOL_CONFIG } from '@constants/constant';
import { FormItem } from '../form_item/form_item'; import { FormItem } from '../form_item/form_item';
@shortcut() @shortcut()
@ -16,7 +16,7 @@ export class PoolConfig extends BI.Widget {
const { maxTotal, maxWait, maxIdle, blockWhenExhausted, lifo, timeout } = this.options.poolConfig; const { maxTotal, maxWait, maxIdle, blockWhenExhausted, lifo, timeout } = this.options.poolConfig;
return { return {
type: Vertical, type: VerticalXtype,
hgap: 15, hgap: 15,
vgap: 10, vgap: 10,
items: [ items: [
@ -24,7 +24,7 @@ export class PoolConfig extends BI.Widget {
type: FormItem.xtype, type: FormItem.xtype,
name: BI.i18nText('Plugin-Redis_Pool_Max_Total'), name: BI.i18nText('Plugin-Redis_Pool_Max_Total'),
forms: [{ forms: [{
type: Label, type: LabelXtype,
text: maxTotal, text: maxTotal,
}], }],
}, },
@ -32,7 +32,7 @@ export class PoolConfig extends BI.Widget {
type: FormItem.xtype, type: FormItem.xtype,
name: BI.i18nText('Plugin-Redis_Pool_Max_Wait'), name: BI.i18nText('Plugin-Redis_Pool_Max_Wait'),
forms: [{ forms: [{
type: Label, type: LabelXtype,
text: maxWait, text: maxWait,
}], }],
}, },
@ -40,7 +40,7 @@ export class PoolConfig extends BI.Widget {
type: FormItem.xtype, type: FormItem.xtype,
name: BI.i18nText('Plugin-Redis_Pool_Max_Idle'), name: BI.i18nText('Plugin-Redis_Pool_Max_Idle'),
forms: [{ forms: [{
type: Label, type: LabelXtype,
text: maxIdle, text: maxIdle,
}], }],
}, },
@ -48,7 +48,7 @@ export class PoolConfig extends BI.Widget {
type: FormItem.xtype, type: FormItem.xtype,
name: BI.i18nText('Plugin-Redis_Pool_Block_When_Exhausted'), name: BI.i18nText('Plugin-Redis_Pool_Block_When_Exhausted'),
forms: [{ forms: [{
type: MultiSelectItem, type: MultiSelectItemXtype,
selected: blockWhenExhausted, selected: blockWhenExhausted,
}], }],
}, },
@ -56,7 +56,7 @@ export class PoolConfig extends BI.Widget {
type: FormItem.xtype, type: FormItem.xtype,
name: BI.i18nText('Plugin-Redis_Pool_Lifo'), name: BI.i18nText('Plugin-Redis_Pool_Lifo'),
forms: [{ forms: [{
type: MultiSelectItem, type: MultiSelectItemXtype,
selected: lifo, selected: lifo,
}], }],
}, },
@ -64,7 +64,7 @@ export class PoolConfig extends BI.Widget {
type: FormItem.xtype, type: FormItem.xtype,
name: BI.i18nText('Plugin-Redis_Pool_Timeout'), name: BI.i18nText('Plugin-Redis_Pool_Timeout'),
forms: [{ forms: [{
type: Label, type: LabelXtype,
text: timeout, text: timeout,
}], }],
}, },

16
src/web/src/modules/components/pool/pool_edit.ts

@ -1,5 +1,5 @@
import { shortcut, store } from '@core/core'; import { shortcut, store } from '@core/core';
import { Vertical, MultiSelectItem, TextEditor } from 'ui'; import { VerticalXtype, MultiSelectItemXtype, TextEditorXtype } from 'ui';
import { POOL_CONFIG } from '@constants/constant'; import { POOL_CONFIG } from '@constants/constant';
import { FormItem } from '../form_item/form_item'; import { FormItem } from '../form_item/form_item';
import { PoolEditModel } from './pool_edit.model'; import { PoolEditModel } from './pool_edit.model';
@ -33,7 +33,7 @@ export class PoolEdit extends BI.Widget {
this.store.setLifo(lifo); this.store.setLifo(lifo);
return { return {
type: Vertical, type: VerticalXtype,
hgap: 15, hgap: 15,
vgap: 10, vgap: 10,
items: [ items: [
@ -41,7 +41,7 @@ export class PoolEdit extends BI.Widget {
type: FormItem.xtype, type: FormItem.xtype,
name: BI.i18nText('Plugin-Redis_Pool_Max_Total'), name: BI.i18nText('Plugin-Redis_Pool_Max_Total'),
forms: [{ forms: [{
type: TextEditor, type: TextEditorXtype,
width: 300, width: 300,
allowBlank: true, allowBlank: true,
value: maxTotal, value: maxTotal,
@ -54,7 +54,7 @@ export class PoolEdit extends BI.Widget {
type: FormItem.xtype, type: FormItem.xtype,
name: BI.i18nText('Plugin-Redis_Pool_Max_Wait'), name: BI.i18nText('Plugin-Redis_Pool_Max_Wait'),
forms: [{ forms: [{
type: TextEditor, type: TextEditorXtype,
width: 300, width: 300,
allowBlank: true, allowBlank: true,
value: maxWait, value: maxWait,
@ -67,7 +67,7 @@ export class PoolEdit extends BI.Widget {
type: FormItem.xtype, type: FormItem.xtype,
name: BI.i18nText('Plugin-Redis_Pool_Max_Idle'), name: BI.i18nText('Plugin-Redis_Pool_Max_Idle'),
forms: [{ forms: [{
type: TextEditor, type: TextEditorXtype,
width: 300, width: 300,
allowBlank: true, allowBlank: true,
value: maxIdle, value: maxIdle,
@ -80,7 +80,7 @@ export class PoolEdit extends BI.Widget {
type: FormItem.xtype, type: FormItem.xtype,
name: BI.i18nText('Plugin-Redis_Pool_Block_When_Exhausted'), name: BI.i18nText('Plugin-Redis_Pool_Block_When_Exhausted'),
forms: [{ forms: [{
type: MultiSelectItem, type: MultiSelectItemXtype,
selected: blockWhenExhausted, selected: blockWhenExhausted,
ref: (_ref: any) => { ref: (_ref: any) => {
this.form.blockWhenExhausted = _ref; this.form.blockWhenExhausted = _ref;
@ -94,7 +94,7 @@ export class PoolEdit extends BI.Widget {
type: FormItem.xtype, type: FormItem.xtype,
name: BI.i18nText('Plugin-Redis_Pool_Lifo'), name: BI.i18nText('Plugin-Redis_Pool_Lifo'),
forms: [{ forms: [{
type: MultiSelectItem, type: MultiSelectItemXtype,
selected: lifo, selected: lifo,
ref: (_ref: any) => { ref: (_ref: any) => {
this.form.lifo = _ref; this.form.lifo = _ref;
@ -108,7 +108,7 @@ export class PoolEdit extends BI.Widget {
type: FormItem.xtype, type: FormItem.xtype,
name: BI.i18nText('Plugin-Redis_Pool_Timeout'), name: BI.i18nText('Plugin-Redis_Pool_Timeout'),
forms: [{ forms: [{
type: TextEditor, type: TextEditorXtype,
width: 300, width: 300,
allowBlank: true, allowBlank: true,
value: timeout, value: timeout,

20
src/web/src/modules/components/proxy/proxy.ts

@ -1,5 +1,5 @@
import { shortcut } from '@core/core'; import { shortcut } from '@core/core';
import { Label, Vertical, MultiSelectItem, CenterAdapt } from 'ui'; import { LabelXtype, VerticalXtype, MultiSelectItemXtype, CenterAdaptXtype } from 'ui';
import { PROXY_CONFIG } from '@constants/constant'; import { PROXY_CONFIG } from '@constants/constant';
import { FormItem } from '../form_item/form_item'; import { FormItem } from '../form_item/form_item';
@shortcut() @shortcut()
@ -16,7 +16,7 @@ export class ProxyConfig extends BI.Widget {
const { open, host, port, username, password, privateKeyPath } = this.options.proxyConfig; const { open, host, port, username, password, privateKeyPath } = this.options.proxyConfig;
return { return {
type: Vertical, type: VerticalXtype,
hgap: 15, hgap: 15,
vgap: 10, vgap: 10,
items: [ items: [
@ -24,14 +24,14 @@ export class ProxyConfig extends BI.Widget {
type: FormItem.xtype, type: FormItem.xtype,
name: BI.i18nText('Plugin-Redis_Proxy_Open'), name: BI.i18nText('Plugin-Redis_Proxy_Open'),
forms: [{ forms: [{
type: CenterAdapt, type: CenterAdaptXtype,
items: [ items: [
{ {
type: MultiSelectItem, type: MultiSelectItemXtype,
width: 30, width: 30,
selected: open, selected: open,
}, { }, {
type: Label, type: LabelXtype,
text: BI.i18nText('Plugin-Redis_Proxy_Description'), text: BI.i18nText('Plugin-Redis_Proxy_Description'),
}, },
], ],
@ -41,7 +41,7 @@ export class ProxyConfig extends BI.Widget {
type: FormItem.xtype, type: FormItem.xtype,
name: BI.i18nText('Plugin-Redis_Proxy_Host'), name: BI.i18nText('Plugin-Redis_Proxy_Host'),
forms: [{ forms: [{
type: Label, type: LabelXtype,
text: host, text: host,
}], }],
}, },
@ -49,7 +49,7 @@ export class ProxyConfig extends BI.Widget {
type: FormItem.xtype, type: FormItem.xtype,
name: BI.i18nText('Plugin-Redis_Proxy_Port'), name: BI.i18nText('Plugin-Redis_Proxy_Port'),
forms: [{ forms: [{
type: Label, type: LabelXtype,
text: port, text: port,
}], }],
}, },
@ -57,7 +57,7 @@ export class ProxyConfig extends BI.Widget {
type: FormItem.xtype, type: FormItem.xtype,
name: BI.i18nText('Plugin-Redis_Proxy_Username'), name: BI.i18nText('Plugin-Redis_Proxy_Username'),
forms: [{ forms: [{
type: Label, type: LabelXtype,
text: username, text: username,
}], }],
}, },
@ -65,7 +65,7 @@ export class ProxyConfig extends BI.Widget {
type: FormItem.xtype, type: FormItem.xtype,
name: BI.i18nText('Plugin-Redis_Proxy_Password'), name: BI.i18nText('Plugin-Redis_Proxy_Password'),
forms: [{ forms: [{
type: Label, type: LabelXtype,
text: password, text: password,
}], }],
}, },
@ -73,7 +73,7 @@ export class ProxyConfig extends BI.Widget {
type: FormItem.xtype, type: FormItem.xtype,
name: BI.i18nText('Plugin-Redis_Proxy_Private_Key_Path'), name: BI.i18nText('Plugin-Redis_Proxy_Private_Key_Path'),
forms: [{ forms: [{
type: Label, type: LabelXtype,
text: privateKeyPath, text: privateKeyPath,
}], }],
}, },

20
src/web/src/modules/components/proxy/proxy_edit.ts

@ -1,5 +1,5 @@
import { shortcut } from '@core/core'; import { shortcut } from '@core/core';
import { Label, Vertical, MultiSelectItem, CenterAdapt, TextEditor, Editor } from 'ui'; import { LabelXtype, VerticalXtype, MultiSelectItemXtype, CenterAdaptXtype, TextEditorXtype, EditorXtype } from 'ui';
import { PROXY_CONFIG } from '@constants/constant'; import { PROXY_CONFIG } from '@constants/constant';
import { FormItem } from '../form_item/form_item'; import { FormItem } from '../form_item/form_item';
@shortcut() @shortcut()
@ -30,7 +30,7 @@ export class ProxyEdit extends BI.Widget {
this.oldPassword = password; this.oldPassword = password;
return { return {
type: Vertical, type: VerticalXtype,
hgap: 15, hgap: 15,
vgap: 10, vgap: 10,
items: [ items: [
@ -38,17 +38,17 @@ export class ProxyEdit extends BI.Widget {
type: FormItem.xtype, type: FormItem.xtype,
name: BI.i18nText('Plugin-Redis_Proxy_Open'), name: BI.i18nText('Plugin-Redis_Proxy_Open'),
forms: [{ forms: [{
type: CenterAdapt, type: CenterAdaptXtype,
items: [ items: [
{ {
type: MultiSelectItem, type: MultiSelectItemXtype,
width: 30, width: 30,
selected: this.isOpen, selected: this.isOpen,
handler: () => { handler: () => {
this.isOpen = !this.isOpen; this.isOpen = !this.isOpen;
}, },
}, { }, {
type: Label, type: LabelXtype,
text: BI.i18nText('Plugin-Redis_Proxy_Description'), text: BI.i18nText('Plugin-Redis_Proxy_Description'),
}, },
], ],
@ -58,7 +58,7 @@ export class ProxyEdit extends BI.Widget {
type: FormItem.xtype, type: FormItem.xtype,
name: BI.i18nText('Plugin-Redis_Proxy_Host'), name: BI.i18nText('Plugin-Redis_Proxy_Host'),
forms: [{ forms: [{
type: TextEditor, type: TextEditorXtype,
width: 300, width: 300,
allowBlank: true, allowBlank: true,
value: host, value: host,
@ -71,7 +71,7 @@ export class ProxyEdit extends BI.Widget {
type: FormItem.xtype, type: FormItem.xtype,
name: BI.i18nText('Plugin-Redis_Proxy_Port'), name: BI.i18nText('Plugin-Redis_Proxy_Port'),
forms: [{ forms: [{
type: TextEditor, type: TextEditorXtype,
width: 300, width: 300,
allowBlank: true, allowBlank: true,
value: port, value: port,
@ -84,7 +84,7 @@ export class ProxyEdit extends BI.Widget {
type: FormItem.xtype, type: FormItem.xtype,
name: BI.i18nText('Plugin-Redis_Proxy_Username'), name: BI.i18nText('Plugin-Redis_Proxy_Username'),
forms: [{ forms: [{
type: TextEditor, type: TextEditorXtype,
width: 300, width: 300,
allowBlank: true, allowBlank: true,
value: username, value: username,
@ -97,7 +97,7 @@ export class ProxyEdit extends BI.Widget {
type: FormItem.xtype, type: FormItem.xtype,
name: BI.i18nText('Plugin-Redis_Proxy_Password'), name: BI.i18nText('Plugin-Redis_Proxy_Password'),
forms: [{ forms: [{
type: Editor, type: EditorXtype,
cls: 'bi-border', cls: 'bi-border',
width: 300, width: 300,
height: 20, height: 20,
@ -114,7 +114,7 @@ export class ProxyEdit extends BI.Widget {
name: BI.i18nText('Plugin-Redis_Proxy_Private_Key_Path'), name: BI.i18nText('Plugin-Redis_Proxy_Private_Key_Path'),
forms: [ forms: [
{ {
type: TextEditor, type: TextEditorXtype,
width: 300, width: 300,
allowBlank: true, allowBlank: true,
value: privateKeyPath, value: privateKeyPath,

2
src/web/src/modules/core/core.ts

@ -24,7 +24,7 @@ export function model() {
* @param Model model类 * @param Model model类
* @param opts * @param opts
*/ */
export function store<T>(Model?: Constructor<T> & {xtype: string}, opts: { props?(this: unknown): { [key: string]: unknown } } = {}) { export function store<T>(Model: Constructor<T> & {xtype: string}, opts: { props?(this: unknown): { [key: string]: unknown } } = {}) {
return function classDecorator<U extends {new(...args:any[]):{}}>(constructor:U) { return function classDecorator<U extends {new(...args:any[]):{}}>(constructor:U) {
return class extends constructor { return class extends constructor {
_store() { _store() {

29
src/web/src/modules/table_list/list_item.ts

@ -0,0 +1,29 @@
import { shortcut } from '@core/core';
import { HtapeXtype, IconLabelXtype, LabelXtype } from 'ui';
@shortcut()
export class ListItem extends BI.BasicButton {
static xtype = 'dec.dcm.connection.plugin.redis.table_list.list_item'
props = {
text: '',
height: 20,
baseCls: 'bi-list-item-active',
}
render() {
const { text } = this.options;
return {
type: HtapeXtype,
items: [{
el: {
type: IconLabelXtype,
cls: 'column-font',
},
width: 25,
}, {
type: LabelXtype,
textAlign: 'left',
text,
}],
};
}
}

89
src/web/src/modules/table_list/table_list.ts

@ -0,0 +1,89 @@
import { shortcut } from '@core/core';
import { VtapeXtype, HtapeXtype, IconButtonXtype, TextValueComboXtype, ButtonXtype, TextEditorXtype, ButtonGroupXtype, VerticalXtype, MultiSelectItemXtype, LeftXtype } from 'ui';
import { ListItem } from './list_item';
@shortcut()
export class TableList extends BI.Widget {
static xtype = 'dec.dcm.connection.plugin.redis.table_list'
render() {
return {
type: VtapeXtype,
items: [{
el: {
type: HtapeXtype,
items: [{
type: TextValueComboXtype,
items: [],
}, {
el: {
type: IconButtonXtype,
cls: 'site-font',
},
width: 25,
}, {
el: {
type: IconButtonXtype,
cls: 'refresh-font',
},
width: 25,
}],
},
height: 25,
}, {
el: {
type: HtapeXtype,
items: [{
type: TextEditorXtype,
height: 24,
watermark: BI.i18nText('Plugin-Redis_Keys_Pattern'),
}, {
el: {
type: ButtonXtype,
minWidth: 50,
text: BI.i18nText('Plugin-Redis_Keys_Pattern_Search'),
},
width: 50,
}],
},
height: 25,
}, {
type: VtapeXtype,
items: [{
type: ButtonGroupXtype,
layouts: [{
type: VerticalXtype,
}],
items: this.renderList(),
}, {
el: {
type: LeftXtype,
height: 25,
hgap: 40,
items: [{
type: MultiSelectItemXtype,
width: 80,
selected: true,
text: BI.i18nText('Plugin-Redis_Table'),
}, {
type: MultiSelectItemXtype,
width: 80,
selected: true,
text: BI.i18nText('Plugin-Redis_View'),
}],
},
height: 25,
}],
}],
};
}
private renderList() {
return ['demo1', 'demo2'].map(item => {
return {
type: ListItem.xtype,
text: item,
value: item,
};
});
}
}

150
src/web/src/ui/fineui.ts

@ -1,75 +1,77 @@
export const Icon = 'bi.icon'; export const IconXtype = 'bi.icon';
export const IconTextItem = 'bi.icon_text_item'; export const IconTextItemXtype = 'bi.icon_text_item';
export const IconTextIconItem = 'bi.icon_text_icon_item'; export const IconTextIconItemXtype = 'bi.icon_text_icon_item';
export const IconButton = 'bi.icon_button'; export const IconButtonXtype = 'bi.icon_button';
export const IconChangeButton = 'bi.icon_change_button'; export const IconChangeButtonXtype = 'bi.icon_change_button';
export const TextButton = 'bi.text_button'; export const TextButtonXtype = 'bi.text_button';
export const DownListCombo = 'bi.down_list_combo'; export const DownListComboXtype = 'bi.down_list_combo';
export const Label = 'bi.label'; export const LabelXtype = 'bi.label';
export const SmallTextEditor = 'bi.small_text_editor'; export const SmallTextEditorXtype = 'bi.small_text_editor';
export const MultiFileEditor = 'bi.multifile_editor'; export const MultiFileEditorXtype = 'bi.multifile_editor';
export const SignEditor = 'bi.sign_editor'; export const SignEditorXtype = 'bi.sign_editor';
export const Button = 'bi.button'; export const ButtonXtype = 'bi.button';
export const TextEditor = 'bi.text_editor'; export const TextEditorXtype = 'bi.text_editor';
export const MultiSelectInsertCombo = 'bi.multi_select_insert_combo'; export const MultiSelectInsertComboXtype = 'bi.multi_select_insert_combo';
export const MultiSelectCombo = 'bi.multi_select_combo'; export const MultiSelectComboXtype = 'bi.multi_select_combo';
export const ButtonGroup = 'bi.button_group'; export const ButtonGroupXtype = 'bi.button_group';
export const AllValueChooserCombo = 'bi.all_value_chooser_combo'; export const AllValueChooserComboXtype = 'bi.all_value_chooser_combo';
export const TextAreaEditor = 'bi.textarea_editor'; export const TextAreaEditorXtype = 'bi.textarea_editor';
export const MultiSelectItem = 'bi.multi_select_item'; export const MultiSelectItemXtype = 'bi.multi_select_item';
export const BarPopOver = 'bi.bar_popover'; export const BarPopOverXtype = 'bi.bar_popover';
export const DynamicDateCombo = 'bi.dynamic_date_combo'; export const DynamicDateComboXtype = 'bi.dynamic_date_combo';
export const DynamicDateTimeCombo = 'bi.dynamic_date_time_combo'; export const DynamicDateTimeComboXtype = 'bi.dynamic_date_time_combo';
export const MultiTreeCombo = 'bi.multi_tree_combo'; export const MultiTreeComboXtype = 'bi.multi_tree_combo';
export const RichEditor = 'bi.rich_editor'; export const RichEditorXtype = 'bi.rich_editor';
export const NicEditor = 'bi.nic_editor'; export const NicEditorXtype = 'bi.nic_editor';
export const Editor = 'bi.editor'; export const EditorXtype = 'bi.editor';
export const MultiTreePopupView = 'bi.multi_tree_popup_view'; export const MultiTreePopupViewXtype = 'bi.multi_tree_popup_view';
export const SingleSelectRadioItem = 'bi.single_select_radio_item'; export const SingleSelectRadioItemXtype = 'bi.single_select_radio_item';
export const SingleSelectInsertCombo = 'bi.single_select_insert_combo'; export const SingleSelectInsertComboXtype = 'bi.single_select_insert_combo';
export const SingleSelectCombo = 'bi.single_select_combo'; export const SingleSelectComboXtype = 'bi.single_select_combo';
export const Tab = 'bi.tab'; export const TabXtype = 'bi.tab';
export const DynamicYearMonthCombo = 'bi.dynamic_year_month_combo'; export const DynamicYearMonthComboXtype = 'bi.dynamic_year_month_combo';
export const Text = 'bi.text'; export const TextXtype = 'bi.text';
export const Combo = 'bi.combo'; export const ComboXtype = 'bi.combo';
export const TimeCombo = 'bi.time_combo'; export const TimeComboXtype = 'bi.time_combo';
export const IFrame = 'bi.iframe'; export const IFrameXtype = 'bi.iframe';
export const MultiTreeInsertCombo = 'bi.multi_tree_insert_combo'; export const MultiTreeInsertComboXtype = 'bi.multi_tree_insert_combo';
export const MultiTreeListCombo = 'bi.multi_tree_list_combo'; export const MultiTreeListComboXtype = 'bi.multi_tree_list_combo';
export const MultilayerSingleTreeCombo = 'bi.multilayer_single_tree_combo'; export const MultilayerSingleTreeComboXtype = 'bi.multilayer_single_tree_combo';
export const MultilayerSelectTreeCombo = 'bi.multilayer_select_tree_combo'; export const MultilayerSelectTreeComboXtype = 'bi.multilayer_select_tree_combo';
export const AsyncTree = 'bi.async_tree'; export const AsyncTreeXtype = 'bi.async_tree';
export const ListAsyncTree = 'bi.list_async_tree'; export const ListAsyncTreeXtype = 'bi.list_async_tree';
export const MultilayerSingleTreePopup = 'bi.multilayer_single_tree_popup'; export const MultilayerSingleTreePopupXtype = 'bi.multilayer_single_tree_popup';
export const MultilayerSelectTreePopup = 'bi.multilayer_select_tree_popup'; export const MultilayerSelectTreePopupXtype = 'bi.multilayer_select_tree_popup';
export const IconLabel = 'bi.icon_label'; export const IconLabelXtype = 'bi.icon_label';
export const Radio = 'bi.radio'; export const RadioXtype = 'bi.radio';
export const LinearSegment = 'bi.linear_segment'; export const LinearSegmentXtype = 'bi.linear_segment';
export const SearchEditor = 'bi.search_editor'; export const SearchEditorXtype = 'bi.search_editor';
export const Img = 'bi.img'; export const ImgXtype = 'bi.img';
export const BubbleCombo = 'bi.bubble_combo'; export const BubbleComboXtype = 'bi.bubble_combo';
export const TextBubblePopupBarView = 'bi.text_bubble_bar_popup_view'; export const TextBubblePopupBarViewXtype = 'bi.text_bubble_bar_popup_view';
export const TextValueCombo = 'bi.text_value_combo'; export const TextValueComboXtype = 'bi.text_value_combo';
export const File = 'bi.file'; export const FileXtype = 'bi.file';
export const IconComboXtype = 'bi.icon_combo';
export const NumberEditorXtype = 'bi.number_editor';
export const CodeEditorXtype = 'bi.code_editor';
// 布局 // 布局
export const VerticalAdapt = 'bi.vertical_adapt'; export const VerticalAdaptXtype = 'bi.vertical_adapt';
export const Vtape = 'bi.vtape'; export const VtapeXtype = 'bi.vtape';
export const CenterAdapt = 'bi.center_adapt'; export const CenterAdaptXtype = 'bi.center_adapt';
export const Htape = 'bi.htape'; export const HtapeXtype = 'bi.htape';
export const Layout = 'bi.layout'; export const LayoutXtype = 'bi.layout';
export const Absolute = 'bi.absolute'; export const AbsoluteXtype = 'bi.absolute';
export const Vertical = 'bi.vertical'; export const VerticalXtype = 'bi.vertical';
export const Left = 'bi.left'; export const LeftXtype = 'bi.left';
export const Right = 'bi.right'; export const RightXtype = 'bi.right';
export const HorizontalAdapt = 'bi.horizontal_adapt'; export const HorizontalAdaptXtype = 'bi.horizontal_adapt';
export const AbsoluteCenterAdapt = 'bi.absolute_center_adapt'; export const AbsoluteCenterAdaptXtype = 'bi.absolute_center_adapt';
export const TableAdapt = 'bi.table_adapt'; export const TableAdaptXtype = 'bi.table_adapt';
export const RightVerticalAdapt = 'bi.right_vertical_adapt'; export const RightVerticalAdaptXtype = 'bi.right_vertical_adapt';
export const LeftRightVerticalAdapt = 'bi.left_right_vertical_adapt'; export const LeftRightVerticalAdaptXtype = 'bi.left_right_vertical_adapt';
export const ListView = 'bi.list_view'; export const ListViewXtype = 'bi.list_view';
export const VirtualGroup = 'bi.virtual_group'; export const VirtualGroupXtype = 'bi.virtual_group';
export const HorizotalAuto = 'bi.horizontal_auto'; export const HorizotalAutoXtype = 'bi.horizontal_auto';
export const Horizotal = 'bi.horizontal'; export const HorizotalXtype = 'bi.horizontal';
export const FloatCenter = 'bi.float_center'; export const FloatCenterXtype = 'bi.float_center';
export const LeftRightVerticalAdaptLayoutXtype = 'bi.left_right_vertical_adapt';

22
src/web/webpack/webpack.dev.js

@ -36,6 +36,12 @@ module.exports = merge(common, {
edit: [ edit: [
'./src/index.edit.ts', './src/index.edit.ts',
], ],
dataset: [
'./src/index.dataset.ts',
],
program: [
'./src/index.program.ts',
],
}, },
externals: { externals: {
CodeMirror: 'CodeMirror', CodeMirror: 'CodeMirror',
@ -46,7 +52,7 @@ module.exports = merge(common, {
}, },
devServer: { devServer: {
contentBase: path.join(__dirname, '..'), contentBase: path.join(__dirname, '..'),
port: 10002, port: 10004,
liveReload: true, liveReload: true,
}, },
plugins: [ plugins: [
@ -67,6 +73,20 @@ module.exports = merge(common, {
chunksSortMode: 'manual', chunksSortMode: 'manual',
title: 'Redis插件预览界面', title: 'Redis插件预览界面',
}), }),
new HtmlWebpackPlugin({
filename: 'dataset/index.html',
template: path.resolve(__dirname, '../index.html'),
chunks: ['polyfill', 'i18n', 'dataset'],
chunksSortMode: 'manual',
title: 'Redis插件数据集界面',
}),
new HtmlWebpackPlugin({
filename: 'program/index.html',
template: path.resolve(__dirname, '../index.html'),
chunks: ['polyfill', 'i18n', 'program'],
chunksSortMode: 'manual',
title: 'Redis插件程序数据集界面',
}),
new ForkTsCheckerWebpackPlugin({ new ForkTsCheckerWebpackPlugin({
watch: ['./src'], watch: ['./src'],
}), }),

4
src/web/yarn.lock

@ -3449,6 +3449,10 @@ findup-sync@3.0.0:
micromatch "^3.0.4" micromatch "^3.0.4"
resolve-dir "^1.0.1" resolve-dir "^1.0.1"
"fineui-materials@git+ssh://git@cloud.finedevelop.com:7999/fui/fineui-materials.git#release/10.0":
version "1.0.0"
resolved "git+ssh://git@cloud.finedevelop.com:7999/fui/fineui-materials.git#1a5c8beb09f741ff24758b6f4fb64107f643015f"
"fineui@git+ssh://git@cloud.finedevelop.com:7999/visual/fineui.git": "fineui@git+ssh://git@cloud.finedevelop.com:7999/visual/fineui.git":
version "1.1.2" version "1.1.2"
resolved "git+ssh://git@cloud.finedevelop.com:7999/visual/fineui.git#3e28b67ed0fb06e5754c3cba46b1c14d55df6436" resolved "git+ssh://git@cloud.finedevelop.com:7999/visual/fineui.git#3e28b67ed0fb06e5754c3cba46b1c14d55df6436"

Loading…
Cancel
Save