From 7275f1c8de1ba3e032ec72da57b86233ca8f6fe0 Mon Sep 17 00:00:00 2001 From: jaime <819519812@qq.com> Date: Fri, 11 Feb 2022 15:57:39 +0800 Subject: [PATCH] Support MySQL field filter and mongo collection show --- lib/api/mongo/mongo_tables_api.dart | 33 +++ lib/api/mysql/mysql_databases_api.dart | 96 ++++++-- lib/l10n/intl_en.arb | 1 + lib/l10n/intl_zh.arb | 1 + lib/main.dart | 5 + lib/module/mongo/mongo_sql_result.dart | 50 ++++ lib/module/mysql/mysql_sql_result.dart | 6 +- lib/route/page_route_const.dart | 1 + lib/route/route_gen.dart | 11 + lib/ui/component/dynamic_filter_table.dart | 230 ++++++++++++++++++ lib/ui/mongo/widget/mongo_table_data.dart | 93 +++++++ lib/ui/mongo/widget/mongo_table_list.dart | 19 +- lib/ui/mysql/widget/mysql_table_data.dart | 29 ++- lib/vm/mongo/mongo_table_view_model.dart | 35 ++- lib/vm/mysql/mysql_table_data_view_model.dart | 24 +- 15 files changed, 598 insertions(+), 36 deletions(-) create mode 100644 lib/module/mongo/mongo_sql_result.dart create mode 100644 lib/ui/component/dynamic_filter_table.dart create mode 100644 lib/ui/mongo/widget/mongo_table_data.dart diff --git a/lib/api/mongo/mongo_tables_api.dart b/lib/api/mongo/mongo_tables_api.dart index 264f600..6101033 100644 --- a/lib/api/mongo/mongo_tables_api.dart +++ b/lib/api/mongo/mongo_tables_api.dart @@ -17,7 +17,10 @@ // under the License. // +import 'dart:collection'; + import 'package:mongo_dart/mongo_dart.dart'; +import 'package:paas_dashboard_flutter/module/mongo/mongo_sql_result.dart'; import 'package:paas_dashboard_flutter/module/mongo/mongo_table.dart'; class MongoTablesApi { @@ -26,8 +29,38 @@ class MongoTablesApi { var db = await Db.create(addr + "/" + databaseName); await db.open(); var collectionNames = await db.getCollectionNames(); + db.close(); return collectionNames.whereType().map((name) { return new TableResp(name); }).toList(); } + + static Future getTableData( + String addr, String username, String password, String databaseName, String tableName) async { + var db = await Db.create(addr + "/" + databaseName); + await db.open(); + var collection = await db.collection(tableName); + SelectorBuilder builder = SelectorBuilder().limit(100); + List> data = await collection.find(builder).toList(); + db.close(); + MongoSqlResult result = MongoSqlResult.create(); + if (data.isEmpty) { + return result; + } + LinkedHashSet fieldNames = new LinkedHashSet(); + List> sqldata = []; + data.forEach((element) { + fieldNames.addAll(element.keys); + }); + data.forEach((element) { + List temp = []; + fieldNames.forEach((fieldName) { + temp.add(element[fieldName]); + }); + sqldata.add(temp); + }); + result.fieldName = fieldNames; + result.data = sqldata; + return result; + } } diff --git a/lib/api/mysql/mysql_databases_api.dart b/lib/api/mysql/mysql_databases_api.dart index 369330d..30718ef 100644 --- a/lib/api/mysql/mysql_databases_api.dart +++ b/lib/api/mysql/mysql_databases_api.dart @@ -22,10 +22,11 @@ import 'package:paas_dashboard_flutter/module/mysql/mysql_database.dart'; import 'package:paas_dashboard_flutter/module/mysql/mysql_sql_result.dart'; import 'package:paas_dashboard_flutter/module/mysql/mysql_table.dart'; import 'package:paas_dashboard_flutter/persistent/po/mysql_instance_po.dart'; +import 'package:paas_dashboard_flutter/ui/component/dynamic_filter_table.dart'; import 'package:sprintf/sprintf.dart'; class MysqlDatabaseApi { - static const String SELECT_ALL = "select * from %s limit 100"; + static const String SELECT_ALL = "select * from %s %s limit 100"; static const String SCHEMA_DB = "information_schema"; static const String TABLE_COLUMN = @@ -59,21 +60,30 @@ class MysqlDatabaseApi { return result; } - static Future getData(MysqlInstancePo mysqlConn, String dbname, String? tableName) async { - final setting = new ConnectionSettings( - host: mysqlConn.host, port: mysqlConn.port, user: mysqlConn.username, password: mysqlConn.password, db: dbname); - final MySqlConnection conn = await MySqlConnection.connect(setting); - var queryResult = await conn.query(sprintf(SELECT_ALL, [tableName])); - List> data = []; - for (var row in queryResult) { - if (row.values != null) { - data.add(row.values!.map((e) => e == null ? "" : e).toList()); + static Future getData( + MysqlInstancePo mysqlConn, String dbname, String tableName, String where) async { + MysqlSqlResult result = MysqlSqlResult.create(); + try { + final setting = new ConnectionSettings( + host: mysqlConn.host, + port: mysqlConn.port, + user: mysqlConn.username, + password: mysqlConn.password, + db: dbname); + final MySqlConnection conn = await MySqlConnection.connect(setting); + var queryResult = await conn.query(sprintf(SELECT_ALL, [tableName, where])); + List> data = []; + for (var row in queryResult) { + if (row.values != null) { + data.add(row.values!); + } } + result.setFieldName = queryResult.fields.map((e) => e.name!.isNotEmpty ? e.name.toString() : "").toList(); + result.setData = data; + await conn.close(); + } catch (e) { + throw Exception('Exception: ${e.toString()}'); } - MysqlSqlResult result = MysqlSqlResult.create(); - result.setFieldName = queryResult.fields.map((e) => e.name!.isNotEmpty ? e.name.toString() : "").toList(); - result.setData = data; - await conn.close(); return result; } @@ -108,4 +118,62 @@ class MysqlDatabaseApi { await conn.close(); return result; } + + static String getWhere(List? filters) { + String where = ""; + if (filters == null || filters.isEmpty) { + return where; + } + where += "where "; + for (int i = 0; i < filters.length; i++) { + String column = filters[i].column; + String op = getWhereOP(filters[i].op); + where = where + column + sprintf(op, [getOPValue(filters[i].value!, filters[i].type, filters[i].op)]); + if (i != filters.length - 1) { + where += filters[i].join ? " and " : " or "; + } + } + return where; + } + + static String getOPValue(String value, TYPE type, OP op) { + if (OP.BEGIN == op || OP.END == op || OP.CONTAIN == op || OP.EXCLUDE == op || OP.INCLUDE == op) { + return value; + } else if (OP.NULL == op || OP.NOT_NULL == op) { + return ""; + } else { + return type == TYPE.TEXT ? sprintf("'%s'", [value]) : value; + } + } + + static String getWhereOP(OP op) { + switch (op) { + case OP.EQ: + return " = %s "; + case OP.NOT_EQ: + return " != %s "; + case OP.LT: + return " < %s "; + case OP.GT: + return " > %s "; + case OP.LT_EQ: + return " <= %s "; + case OP.GT_EQ: + return " >= %s "; + case OP.NULL: + return " is null "; + case OP.NOT_NULL: + return " is not null "; + case OP.INCLUDE: + return " in (%s) "; + case OP.EXCLUDE: + return " not in (%s) "; + case OP.BEGIN: + return " like '%s%%' "; + case OP.END: + return " like '%%%s' "; + case OP.CONTAIN: + return " like '%%%s%%' "; + } + } } diff --git a/lib/l10n/intl_en.arb b/lib/l10n/intl_en.arb index 8337b75..d5442c8 100644 --- a/lib/l10n/intl_en.arb +++ b/lib/l10n/intl_en.arb @@ -25,6 +25,7 @@ "email": "email", "entryId": "entryId", "execute": "execute", + "filter": "filter", "forceDelete": "forceDelete", "isLeader": "Is Leader", "languageSettings": "Language Settings", diff --git a/lib/l10n/intl_zh.arb b/lib/l10n/intl_zh.arb index 0b9acfc..0c68635 100644 --- a/lib/l10n/intl_zh.arb +++ b/lib/l10n/intl_zh.arb @@ -25,6 +25,7 @@ "email": "邮箱", "entryId": "编号", "execute": "执行", + "filter": "过滤", "forceDelete": "强制删除", "isLeader": "是否是主节点", "languageSettings": "语言设置", diff --git a/lib/main.dart b/lib/main.dart index 3c087b0..b3dc93b 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -41,6 +41,7 @@ import 'package:paas_dashboard_flutter/vm/kubernetes/k8s_instance_list_view_mode import 'package:paas_dashboard_flutter/vm/mongo/mongo_database_view_model.dart'; import 'package:paas_dashboard_flutter/vm/mongo/mongo_instance_list_view_model.dart'; import 'package:paas_dashboard_flutter/vm/mongo/mongo_instance_view_model.dart'; +import 'package:paas_dashboard_flutter/vm/mongo/mongo_table_view_model.dart'; import 'package:paas_dashboard_flutter/vm/mysql/mysql_instance_list_view_model.dart'; import 'package:paas_dashboard_flutter/vm/mysql/mysql_instance_view_model.dart'; import 'package:paas_dashboard_flutter/vm/mysql/mysql_sql_query_view_model.dart'; @@ -144,6 +145,10 @@ class MyApp extends StatelessWidget { final args = settings.arguments as MongoDatabaseViewModel; return RouteGen.mongoDatabase(args); } + if (settings.name == PageRouteConst.MongoTable) { + final args = settings.arguments as MongoTableViewModel; + return RouteGen.mongoTableData(args); + } if (settings.name == PageRouteConst.MysqlInstance) { final args = settings.arguments as MysqlInstanceViewModel; return RouteGen.mysqlInstance(args); diff --git a/lib/module/mongo/mongo_sql_result.dart b/lib/module/mongo/mongo_sql_result.dart new file mode 100644 index 0000000..59c225a --- /dev/null +++ b/lib/module/mongo/mongo_sql_result.dart @@ -0,0 +1,50 @@ +// +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +// + +import 'dart:collection'; + +class MongoSqlResult { + Set fieldName; + + List> data; + + MongoSqlResult(this.fieldName, this.data); + + Set get getFieldName { + return fieldName; + } + + set setFieldName(Set fieldName) { + this.fieldName = fieldName; + } + + List> get getData { + return data; + } + + set setData(List> data) { + this.data = data; + } + + factory MongoSqlResult.create() { + return MongoSqlResult(HashSet.identity(), [ + [''] + ]); + } +} diff --git a/lib/module/mysql/mysql_sql_result.dart b/lib/module/mysql/mysql_sql_result.dart index 7090287..fb419d9 100644 --- a/lib/module/mysql/mysql_sql_result.dart +++ b/lib/module/mysql/mysql_sql_result.dart @@ -20,7 +20,7 @@ class MysqlSqlResult { List fieldName; - List> data; + List> data; MysqlSqlResult(this.fieldName, this.data); @@ -32,11 +32,11 @@ class MysqlSqlResult { this.fieldName = fieldName; } - List> get getData { + List> get getData { return data; } - set setData(List> data) { + set setData(List> data) { this.data = data; } diff --git a/lib/route/page_route_const.dart b/lib/route/page_route_const.dart index 0ef3a68..17f97ac 100644 --- a/lib/route/page_route_const.dart +++ b/lib/route/page_route_const.dart @@ -27,6 +27,7 @@ class PageRouteConst { static const String Mongo = '/mongo'; static const String MongoInstance = '/mongo/instance'; static const String MongoDatabase = '/mongo/instance/database'; + static const String MongoTable = '/mongo/instance/database/table'; static const String Mysql = '/mysql'; static const String MysqlInstance = '/mysql/instance'; static const String MysqlDatabase = '/mysql/instance/database'; diff --git a/lib/route/route_gen.dart b/lib/route/route_gen.dart index 19f1b6b..1aa2cb1 100644 --- a/lib/route/route_gen.dart +++ b/lib/route/route_gen.dart @@ -21,6 +21,7 @@ import 'package:flutter/material.dart'; import 'package:paas_dashboard_flutter/ui/code/screen/code_execute_screen.dart'; import 'package:paas_dashboard_flutter/ui/mongo/mongo_instance.dart'; import 'package:paas_dashboard_flutter/ui/mongo/screen/mongo_database.dart'; +import 'package:paas_dashboard_flutter/ui/mongo/widget/mongo_table_data.dart'; import 'package:paas_dashboard_flutter/ui/mysql/mysql_instance.dart'; import 'package:paas_dashboard_flutter/ui/mysql/widget/mysql_sql_query.dart'; import 'package:paas_dashboard_flutter/ui/mysql/widget/mysql_table_column.dart'; @@ -38,6 +39,7 @@ import 'package:paas_dashboard_flutter/ui/sql/screen/sql_execute_screen.dart'; import 'package:paas_dashboard_flutter/vm/code/code_view_model.dart'; import 'package:paas_dashboard_flutter/vm/mongo/mongo_database_view_model.dart'; import 'package:paas_dashboard_flutter/vm/mongo/mongo_instance_view_model.dart'; +import 'package:paas_dashboard_flutter/vm/mongo/mongo_table_view_model.dart'; import 'package:paas_dashboard_flutter/vm/mysql/mysql_instance_view_model.dart'; import 'package:paas_dashboard_flutter/vm/mysql/mysql_sql_query_view_model.dart'; import 'package:paas_dashboard_flutter/vm/mysql/mysql_table_column_view_model.dart'; @@ -82,6 +84,15 @@ class RouteGen { )); } + static Route mongoTableData(MongoTableViewModel viewModel) { + // deep copy view model + return MaterialPageRoute( + builder: (context) => ChangeNotifierProvider( + create: (context) => viewModel, + child: MongoTableDataWidget(), + )); + } + static Route mysqlInstance(MysqlInstanceViewModel viewModel) { return MaterialPageRoute( builder: (context) => ChangeNotifierProvider( diff --git a/lib/ui/component/dynamic_filter_table.dart b/lib/ui/component/dynamic_filter_table.dart new file mode 100644 index 0000000..5e11e28 --- /dev/null +++ b/lib/ui/component/dynamic_filter_table.dart @@ -0,0 +1,230 @@ +// +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +// + +import 'package:flutter/material.dart'; +import 'package:paas_dashboard_flutter/generated/l10n.dart'; + +class DynamicFilterTable extends StatefulWidget { + ColumnNotifier _notifier; + + FilterCallBack callBack; + + DynamicFilterTable(this._notifier, this.callBack); + + @override + State createState() { + return new _DynamicFilterTableState(_notifier, callBack); + } +} + +class ColumnNotifier extends ChangeNotifier { + List _columns = []; + + List get columns => _columns; + + setColumns(List columns) { + _columns = columns; + notifyListeners(); + } +} + +class _DynamicFilterTableState extends State { + ColumnNotifier _notifier; + + List rowData = []; + + DataTable? table; + + FilterCallBack callBack; + + _DynamicFilterTableState(this._notifier, this.callBack); + + @override + void initState() { + super.initState(); + } + + addRow() async { + setState(() { + DropDownButtonData data = new DropDownButtonData(_notifier.columns[0], OP.EQ, rowData.length, true); + rowData.add(data); + }); + } + + deleteRow() async { + setState(() { + if (rowData.isNotEmpty) { + rowData.removeLast(); + } + }); + } + + @override + Widget build(BuildContext context) { + var filterButton = TextButton( + onPressed: () { + if (rowData.isNotEmpty) { + callBack.execute(rowData); + } + }, + child: Text(S.of(context).filter)); + var addButton = TextButton(onPressed: () => {addRow()}, child: Text("+")); + var deleteButton = TextButton(onPressed: () => {deleteRow()}, child: Text("-")); + DataColumn filterColumn = new DataColumn(label: filterButton); + DataColumn addColumn = new DataColumn(label: addButton); + DataColumn deleteColumn = new DataColumn(label: deleteButton); + DataColumn joinColumn = new DataColumn(label: Text("")); + + table = DataTable( + columns: [filterColumn, addColumn, deleteColumn, joinColumn], + rows: rowData.map((e) => getDataRow(e)).toList(), + headingTextStyle: new TextStyle(color: Colors.grey)); + + return ListView( + scrollDirection: Axis.vertical, + shrinkWrap: true, + children: [Container(child: table!)], + ); + } + + List> getOpMenu() { + List> rs = []; + rs.add(new DropdownMenuItem(child: Text("="), value: OP.EQ)); + rs.add(new DropdownMenuItem(child: Text("!="), value: OP.NOT_EQ)); + rs.add(new DropdownMenuItem(child: Text("<"), value: OP.LT)); + rs.add(new DropdownMenuItem(child: Text(">"), value: OP.GT)); + rs.add(new DropdownMenuItem(child: Text("<="), value: OP.LT_EQ)); + rs.add(new DropdownMenuItem(child: Text(">="), value: OP.GT_EQ)); + rs.add(new DropdownMenuItem(child: Text("is null"), value: OP.NULL)); + rs.add(new DropdownMenuItem(child: Text("is not null"), value: OP.NOT_NULL)); + rs.add(new DropdownMenuItem(child: Text("include"), value: OP.INCLUDE)); + rs.add(new DropdownMenuItem(child: Text("exclude"), value: OP.EXCLUDE)); + rs.add(new DropdownMenuItem(child: Text("begin with"), value: OP.BEGIN)); + rs.add(new DropdownMenuItem(child: Text("end with"), value: OP.END)); + rs.add(new DropdownMenuItem(child: Text("contain"), value: OP.CONTAIN)); + return rs; + } + + List> getJoinMenu() { + List> rs = []; + rs.add(new DropdownMenuItem(child: Text("AND"), value: true)); + rs.add(new DropdownMenuItem(child: Text("OR"), value: false)); + return rs; + } + + List> getTypeMenu() { + List> rs = []; + rs.add(new DropdownMenuItem(child: Text("TEXT"), value: TYPE.TEXT)); + rs.add(new DropdownMenuItem(child: Text("NUMBER"), value: TYPE.NUMBER)); + return rs; + } + + DataRow getDataRow(DropDownButtonData data) { + List cells = []; + DropdownButton itemButton = DropdownButton( + items: _notifier.columns.map((e) => new DropdownMenuItem(child: Text(e.toString()), value: e)).toList(), + onChanged: (value) { + setState(() { + rowData[data.index].column = value; + }); + }, + value: rowData[data.index].column, + isExpanded: true, + ); + DropdownButton opButton = DropdownButton( + items: getOpMenu(), + onChanged: (value) { + setState(() { + rowData[data.index].op = value; + if (value == OP.NULL || value == OP.NOT_NULL) { + rowData[data.index].hiddenValue = true; + } else { + rowData[data.index].hiddenValue = false; + } + }); + }, + value: rowData[data.index].op, + isExpanded: true, + ); + + TextField inputField = new TextField( + onChanged: (text) { + rowData[data.index].value = text; + }, + ); + DropdownButton inputTypeButton = DropdownButton( + items: getTypeMenu(), + onChanged: (value) { + setState(() { + rowData[data.index].type = value; + }); + }, + value: rowData[data.index].type, + isExpanded: true, + ); + DropdownButton joinButton = DropdownButton( + items: getJoinMenu(), + onChanged: (value) { + setState(() { + rowData[data.index].join = value; + }); + }, + value: rowData[data.index].join, + isExpanded: true, + ); + cells.add(new DataCell(itemButton)); + cells.add(new DataCell(opButton)); + if (rowData[data.index].hiddenValue) { + cells.add(new DataCell(new Text(""))); + } else { + cells.add(new DataCell(Expanded( + child: new Row( + children: [Expanded(child: inputField), Expanded(child: inputTypeButton)], + ), + ))); + } + if (data.index + 1 == rowData.length) { + cells.add(new DataCell(new Text(""))); + } else { + cells.add(new DataCell(joinButton)); + } + DataRow row = new DataRow(cells: cells); + return row; + } +} + +enum OP { EQ, NOT_EQ, LT, GT, LT_EQ, GT_EQ, NULL, NOT_NULL, INCLUDE, EXCLUDE, BEGIN, END, CONTAIN } + +enum TYPE { NUMBER, TEXT } + +class DropDownButtonData { + bool hiddenValue = false; + int index; + String column; + OP op; + String? value; + bool join; + TYPE type = TYPE.TEXT; + + DropDownButtonData(this.column, this.op, this.index, this.join); +} + +abstract class FilterCallBack { + void execute(List rowData); +} diff --git a/lib/ui/mongo/widget/mongo_table_data.dart b/lib/ui/mongo/widget/mongo_table_data.dart new file mode 100644 index 0000000..d35d5cc --- /dev/null +++ b/lib/ui/mongo/widget/mongo_table_data.dart @@ -0,0 +1,93 @@ +// +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +// + +import 'package:flutter/material.dart'; +import 'package:paas_dashboard_flutter/generated/l10n.dart'; +import 'package:paas_dashboard_flutter/vm/mongo/mongo_table_view_model.dart'; +import 'package:provider/provider.dart'; + +/// Mongo table data list windows +class MongoTableDataWidget extends StatefulWidget { + MongoTableDataWidget(); + + @override + State createState() { + return new _MongoTableDataState(); + } +} + +class _MongoTableDataState extends State { + @override + void initState() { + super.initState(); + final vm = Provider.of(context, listen: false); + vm.fetchData(); + } + + @override + void dispose() { + super.dispose(); + } + + @override + Widget build(BuildContext context) { + final vm = Provider.of(context); + vm.setDataConverter(vm.getConvert); + var dbsFuture = SingleChildScrollView( + child: PaginatedDataTable( + showCheckboxColumn: false, + columns: vm.getColumns().map((e) => DataColumn(label: SelectableText(e))).toList(), + source: vm, + ), + ); + var refreshButton = TextButton( + onPressed: () { + vm.fetchData(); + }, + child: Text(S.of(context).refresh)); + + var body = ListView( + children: [ + Container( + height: 50, + child: ListView( + scrollDirection: Axis.horizontal, + shrinkWrap: true, + children: [refreshButton], + ), + ), + dbsFuture + ], + ); + + return DefaultTabController( + length: 1, + child: Scaffold( + appBar: AppBar( + title: Text('Mongo ${vm.name} -> ${vm.databaseName} DB -> ${vm.tableName} table'), + bottom: TabBar( + tabs: [Tab(text: S.of(context).data)], + ), + ), + body: TabBarView( + children: [body], + ), + )); + } +} diff --git a/lib/ui/mongo/widget/mongo_table_list.dart b/lib/ui/mongo/widget/mongo_table_list.dart index b41a727..6ef7571 100644 --- a/lib/ui/mongo/widget/mongo_table_list.dart +++ b/lib/ui/mongo/widget/mongo_table_list.dart @@ -19,6 +19,7 @@ import 'package:flutter/material.dart'; import 'package:paas_dashboard_flutter/generated/l10n.dart'; +import 'package:paas_dashboard_flutter/route/page_route_const.dart'; import 'package:paas_dashboard_flutter/ui/component/searchable_title.dart'; import 'package:paas_dashboard_flutter/ui/util/exception_util.dart'; import 'package:paas_dashboard_flutter/ui/util/spinner_util.dart'; @@ -69,12 +70,20 @@ class MongoTableListWidgetState extends State { ), ])); var topicsTable = SingleChildScrollView( - child: PaginatedDataTable( + child: DataTable( showCheckboxColumn: false, - columns: [ - DataColumn(label: Text("Table")), - ], - source: vm), + columns: [DataColumn(label: Text(S.of(context).tables))], + rows: vm.displayList + .map((data) => DataRow( + onSelectChanged: (bool? select) { + Navigator.pushNamed(context, PageRouteConst.MongoTable, arguments: data.deepCopy()); + }, + cells: [ + DataCell( + Text(data.tableName), + ) + ])) + .toList()), ); var refreshButton = TextButton( onPressed: () { diff --git a/lib/ui/mysql/widget/mysql_table_data.dart b/lib/ui/mysql/widget/mysql_table_data.dart index 6ddaf38..980a7ed 100644 --- a/lib/ui/mysql/widget/mysql_table_data.dart +++ b/lib/ui/mysql/widget/mysql_table_data.dart @@ -19,7 +19,9 @@ import 'package:flutter/material.dart'; import 'package:paas_dashboard_flutter/generated/l10n.dart'; +import 'package:paas_dashboard_flutter/ui/component/dynamic_filter_table.dart'; import 'package:paas_dashboard_flutter/ui/mysql/widget/mysql_table_index.dart'; +import 'package:paas_dashboard_flutter/ui/util/exception_util.dart'; import 'package:paas_dashboard_flutter/vm/mysql/mysql_table_column_view_model.dart'; import 'package:paas_dashboard_flutter/vm/mysql/mysql_table_data_view_model.dart'; import 'package:paas_dashboard_flutter/vm/mysql/mysql_table_index_view_model.dart'; @@ -38,11 +40,16 @@ class MysqlTableDataWidget extends StatefulWidget { } class _MysqlTableDataState extends State { + DynamicFilterTable? filterTable; + ColumnNotifier _notifier = new ColumnNotifier(); + @override void initState() { super.initState(); final vm = Provider.of(context, listen: false); - vm.fetchData(); + vm.setDataConverter(vm.getConvert); + vm.fetchData(null); + filterTable = DynamicFilterTable(_notifier, vm); } @override @@ -53,31 +60,37 @@ class _MysqlTableDataState extends State { @override Widget build(BuildContext context) { final vm = Provider.of(context); - vm.setDataConverter(vm.getConvert); - + ExceptionUtil.processOpExceptionPageable(vm, context); var dbsFuture = SingleChildScrollView( child: PaginatedDataTable( showCheckboxColumn: false, - columns: vm.getColumns().map((e) => DataColumn(label: SelectableText(e))).toList(), + columns: vm + .getColumns() + .map((e) => DataColumn( + label: SelectableText( + e, + style: new TextStyle(color: Colors.red, fontSize: 20), + ))) + .toList(), source: vm, ), ); var refreshButton = TextButton( onPressed: () { - vm.fetchData(); + vm.fetchData(null); }, child: Text(S.of(context).refresh)); MysqlTableColumnViewModel tableColumnVm = new MysqlTableColumnViewModel(vm.mysqlInstancePo, vm.dbname, vm.tableName); MysqlTableIndexViewModel indexColumnVm = new MysqlTableIndexViewModel(vm.mysqlInstancePo, vm.dbname, vm.tableName); + _notifier.setColumns(vm.getColumns()); var body = ListView( children: [ Container( - height: 50, child: ListView( - scrollDirection: Axis.horizontal, + scrollDirection: Axis.vertical, shrinkWrap: true, - children: [refreshButton], + children: [refreshButton, filterTable!], ), ), dbsFuture diff --git a/lib/vm/mongo/mongo_table_view_model.dart b/lib/vm/mongo/mongo_table_view_model.dart index db327a3..d259e1a 100644 --- a/lib/vm/mongo/mongo_table_view_model.dart +++ b/lib/vm/mongo/mongo_table_view_model.dart @@ -18,14 +18,18 @@ // import 'package:flutter/material.dart'; +import 'package:paas_dashboard_flutter/api/mongo/mongo_tables_api.dart'; import 'package:paas_dashboard_flutter/module/mongo/mongo_database.dart'; +import 'package:paas_dashboard_flutter/module/mongo/mongo_sql_result.dart'; import 'package:paas_dashboard_flutter/module/mongo/mongo_table.dart'; import 'package:paas_dashboard_flutter/persistent/po/mongo_instance_po.dart'; +import 'package:paas_dashboard_flutter/vm/base_load_list_page_view_model.dart'; -class MongoTableViewModel extends ChangeNotifier { +class MongoTableViewModel extends BaseLoadListPageViewModel { final MongoInstancePo mongoInstancePo; final DatabaseResp databaseResp; final TableResp tableResp; + List? columns; MongoTableViewModel(this.mongoInstancePo, this.databaseResp, this.tableResp); @@ -44,4 +48,33 @@ class MongoTableViewModel extends ChangeNotifier { String get tableName { return tableResp.tableName; } + + List getColumns() { + return this.columns == null ? [''] : this.columns!; + } + + Future fetchData() async { + try { + MongoSqlResult result = await MongoTablesApi.getTableData(mongoInstancePo.addr, mongoInstancePo.username, + mongoInstancePo.password, databaseResp.databaseName, tableResp.tableName); + this.columns = List.from(result.getFieldName); + this.fullList = result.getData; + this.displayList = this.fullList; + loadSuccess(); + } on Exception catch (e) { + loadException = e; + loading = false; + } + notifyListeners(); + } + + DataRow getConvert(dynamic obj) { + List v = obj; + return new DataRow( + cells: v + .map((e) => DataCell(e == null + ? SelectableText("(N/A)", style: new TextStyle(color: Colors.grey)) + : SelectableText(e.toString()))) + .toList()); + } } diff --git a/lib/vm/mysql/mysql_table_data_view_model.dart b/lib/vm/mysql/mysql_table_data_view_model.dart index c2498ce..9b2143d 100644 --- a/lib/vm/mysql/mysql_table_data_view_model.dart +++ b/lib/vm/mysql/mysql_table_data_view_model.dart @@ -21,9 +21,10 @@ import 'package:flutter/material.dart'; import 'package:paas_dashboard_flutter/api/mysql/mysql_databases_api.dart'; import 'package:paas_dashboard_flutter/module/mysql/mysql_sql_result.dart'; import 'package:paas_dashboard_flutter/persistent/po/mysql_instance_po.dart'; +import 'package:paas_dashboard_flutter/ui/component/dynamic_filter_table.dart'; import 'package:paas_dashboard_flutter/vm/base_load_list_page_view_model.dart'; -class MysqlTableDataViewModel extends BaseLoadListPageViewModel { +class MysqlTableDataViewModel extends BaseLoadListPageViewModel implements FilterCallBack { MysqlInstancePo mysqlInstancePo; String dbname; @@ -50,15 +51,18 @@ class MysqlTableDataViewModel extends BaseLoadListPageViewModel { return this.columns == null ? [''] : this.columns!; } - Future fetchData() async { + Future fetchData(List? filters) async { try { - MysqlSqlResult result = await MysqlDatabaseApi.getData(mysqlInstancePo, dbname, tableName); + String where = MysqlDatabaseApi.getWhere(filters); + + MysqlSqlResult result = await MysqlDatabaseApi.getData(mysqlInstancePo, dbname, tableName, where); this.columns = result.getFieldName; this.fullList = result.getData; this.displayList = this.fullList; loadSuccess(); } on Exception catch (e) { loadException = e; + opException = e; loading = false; } notifyListeners(); @@ -86,11 +90,21 @@ class MysqlTableDataViewModel extends BaseLoadListPageViewModel { } DataRow getConvert(dynamic obj) { - List v = obj; - return new DataRow(cells: v.map((e) => DataCell(SelectableText(e.toString()))).toList()); + List v = obj; + return new DataRow( + cells: v + .map((e) => DataCell(e == null + ? SelectableText("(N/A)", style: new TextStyle(color: Colors.grey)) + : SelectableText(e.toString()))) + .toList()); } MysqlTableDataViewModel deepCopy() { return new MysqlTableDataViewModel(mysqlInstancePo.deepCopy(), dbname, tableName); } + + @override + void execute(List rowData) { + fetchData(rowData); + } }