From 9f1fba96eff919d6c83914e6dcea388f15c347a5 Mon Sep 17 00:00:00 2001 From: Hamatoma Date: Sat, 16 Oct 2021 20:17:00 +0200 Subject: [PATCH] Module benchmarks to implement all widget types. * helper: * new: fromString() * fully tested by unit tests * Generator: ** implements now the data types bool, date, datetime, float, currency ** correction in generating xxx_data.dart ** sql-generation: the SQL statements remember the newlines inside ('|' instead of "") --- lib/base/helper.dart | 149 +++++++++++-- lib/meta/benchmarks_meta.dart | 78 +++++++ lib/meta/modules.dart | 9 +- lib/page/benchmarks/benchmark_data.dart | 110 ++++++++++ .../benchmarks/create_benchmark_custom.dart | 200 +++++++++++++++++ .../benchmarks/create_benchmark_page.dart | 31 +++ .../benchmarks/delete_benchmark_custom.dart | 195 +++++++++++++++++ .../benchmarks/delete_benchmark_page.dart | 32 +++ .../benchmarks/edit_benchmark_custom.dart | 206 ++++++++++++++++++ lib/page/benchmarks/edit_benchmark_page.dart | 32 +++ .../benchmarks/list_benchmark_custom.dart | 126 +++++++++++ lib/page/benchmarks/list_benchmark_page.dart | 31 +++ lib/page/page_manager.dart | 16 ++ lib/page/roles/create_role_custom.dart | 102 ++++++++- lib/page/roles/create_role_page.dart | 2 +- lib/page/roles/edit_role_custom.dart | 101 ++++++++- lib/page/roles/edit_role_page.dart | 2 +- lib/page/roles/list_role_custom.dart | 95 +++++++- lib/page/roles/list_role_page.dart | 2 +- lib/page/roles/role_data.dart | 84 +++---- .../structures/create_structure_custom.dart | 140 +++++++++++- .../structures/create_structure_page.dart | 6 +- .../structures/delete_structure_custom.dart | 134 +++++++++++- .../structures/delete_structure_page.dart | 6 +- .../structures/edit_structure_custom.dart | 142 +++++++++++- lib/page/structures/edit_structure_page.dart | 6 +- .../structures/list_structure_custom.dart | 95 +++++++- lib/page/structures/list_structure_page.dart | 6 +- lib/page/structures/structure_data.dart | 92 ++++++++ lib/page/users/create_user_custom.dart | 14 +- lib/page/users/create_user_page.dart | 2 +- lib/page/users/delete_user_custom.dart | 8 +- lib/page/users/delete_user_page.dart | 2 +- lib/page/users/edit_user_custom.dart | 13 +- lib/page/users/edit_user_page.dart | 2 +- lib/page/users/list_user_custom.dart | 4 +- lib/page/users/list_user_page.dart | 2 +- lib/page/users/user_data.dart | 117 ++++------ lib/services/global_widget.dart | 6 + metatool/bin/generator.dart | 6 +- metatool/bin/generator_base.dart | 5 - metatool/bin/page_generator.dart | 44 ++-- metatool/bin/sql_generator.dart | 59 ++--- metatool/local.properties | 8 + metatool/pubspec.yaml | 6 +- metatool/test/helper_test.dart | 197 +++++++++++++++++ rest_server/data/sql/benchmarks.sql.yaml | 48 ++++ rest_server/data/sql/roles.sql.yaml | 20 +- rest_server/data/sql/structures.sql.yaml | 24 +- rest_server/data/sql/users.sql.yaml | 24 +- test/helper_test.dart | 3 + tools/InitProject | 2 +- 52 files changed, 2539 insertions(+), 307 deletions(-) create mode 100644 lib/meta/benchmarks_meta.dart create mode 100644 lib/page/benchmarks/benchmark_data.dart create mode 100644 lib/page/benchmarks/create_benchmark_custom.dart create mode 100644 lib/page/benchmarks/create_benchmark_page.dart create mode 100644 lib/page/benchmarks/delete_benchmark_custom.dart create mode 100644 lib/page/benchmarks/delete_benchmark_page.dart create mode 100644 lib/page/benchmarks/edit_benchmark_custom.dart create mode 100644 lib/page/benchmarks/edit_benchmark_page.dart create mode 100644 lib/page/benchmarks/list_benchmark_custom.dart create mode 100644 lib/page/benchmarks/list_benchmark_page.dart create mode 100644 lib/page/structures/structure_data.dart create mode 100644 metatool/local.properties create mode 100644 metatool/test/helper_test.dart create mode 100644 rest_server/data/sql/benchmarks.sql.yaml create mode 100644 test/helper_test.dart diff --git a/lib/base/helper.dart b/lib/base/helper.dart index 03aec4a..8658397 100644 --- a/lib/base/helper.dart +++ b/lib/base/helper.dart @@ -1,5 +1,28 @@ +import 'package:intl/intl.dart'; +import 'package:sprintf/sprintf.dart'; + import 'defines.dart'; +import 'i18n.dart'; + +final dbDateFormat = DateFormat('yyyy-MM-dd HH:mm:ss'); +final dbDateOnlyFormat = DateFormat('yyyy-MM-dd'); + +final i18n = I18N(); + +final regExprDateSortable = RegExp(r'(\d{4})[-.](\d\d?)[.-](\d\d?)'); +final regExprDateStandard = RegExp(r'(\d\d?)[-.](\d\d?)[.-](\d{4})'); +final regExprDateTimeSortable = + RegExp(r'(\d{4})[-.](\d\d?)[.-](\d\d?)?(\D(\d\d?):(\d\d?)(:(\d\d?))?)?'); +final regExprDateTimeStandard = + // ......1.....1....2.....2....3.....34..5.....5.6.....67.8.....87.4 + RegExp(r'(\d\d?)[-.](\d\d?)[.-](\d{4})(\D(\d\d?):(\d\d?)(:(\d\d?))?)?'); +final standardDateFormat = DateFormat('dd.MM.yyyy'); +final standardDateTimeFormat = DateFormat('dd.MM.yyyy HH:mm'); + +final standardDateTimeFormatSeconds = DateFormat('dd.MM.yyyy HH:mm:ss'); + +// ..................................1.....1....2.....2....3....3.4.5.....5.6.....67.....7.4 /// Handles the [input] as a pattern in a filter list: /// /// Appends '*' if input does not end with a '*'. @@ -7,43 +30,137 @@ import 'defines.dart'; /// /// Returns a SQL pattern string. String asPattern(String input) { - final rc = input.isEmpty || input.endsWith('*') ? input : input + '*'; + final rc = input.endsWith('*') ? input : input + '*'; return rc.replaceAll('*', '%').replaceAll('?', '_'); } -/// Converts a [name] to a camel case string. +/// Converts an [object] into a string depending on the data type. /// -/// A camelCase string starts with a uppercase character. -String toCamelCase(String name) { - final rc = name.isEmpty ? '' : (name[0].toUpperCase() + name.substring(1)); +/// [dbFormat]: true: the result is stored in the database. +/// +/// [dateOnly]: true: only the date is part of the result, not the time. +/// Only relevant for DateTime objects. +/// +/// [withSeconds]: true: the result contains the seconds of the DateTime instance. +/// Only relevant for DateTime objects. +String asString(dynamic object, + {bool dbFormat = false, bool dateOnly = false, bool withSeconds = false}) { + String rc; + if (object is String) { + rc = object; + } else if (object is int) { + rc = object.toString(); + } else if (object is bool) { + if (dbFormat) { + rc = object ? 'T' : 'F'; + } else { + rc = object ? i18n.tr('Yes') : i18n.tr('No'); + } + } else if (object is DateTime) { + if (dbFormat) { + if (dateOnly) { + rc = dbDateOnlyFormat.format(object); + } else { + rc = dbDateFormat.format(object); + } + } else if (dateOnly) { + rc = standardDateFormat.format(object); + } else if (withSeconds) { + rc = standardDateTimeFormatSeconds.format(object); + } else { + rc = standardDateTimeFormat.format(object); + } + } else if (object is double) { + rc = sprintf('%.2f', [object]); + } else { + rc = object.toString(); + } return rc; } -/// Returns the [dataType] specific value of [data]. -dynamic valueOf(DataType dataType, String data) { +/// Converts a string [value] into a [dataType] specific object. +/// +/// If conversion is not possible (wrong input), the [defaultValue] is returned +dynamic fromString(String value, + {required DataType dataType, dynamic defaultValue}) { dynamic rc; + RegExpMatch? match; switch (dataType) { + case DataType.undefined: + rc = defaultValue; + break; + case DataType.string: + rc = value; + break; case DataType.bool: - rc = data == 'true'; + if (value == 'T' || value == i18n.tr('Yes')) { + rc = true; + } else if (value == 'F' || value == i18n.tr('No')) { + rc = false; + } else { + rc = defaultValue; + } break; case DataType.currency: case DataType.float: - rc = double.tryParse(data); + rc = double.tryParse(value) ?? defaultValue; break; case DataType.date: + if ((match = regExprDateSortable.firstMatch(value)) != null) { + rc = DateTime(int.parse(match!.group(1)!), int.parse(match.group(2)!), + int.parse(match.group(3)!)); + } else if ((match = regExprDateStandard.firstMatch(value)) != null) { + rc = DateTime(int.parse(match!.group(3)!), int.parse(match.group(2)!), + int.parse(match.group(1)!)); + } else { + rc = defaultValue; + } + break; case DataType.datetime: - rc = DateTime.parse(data); + if ((match = regExprDateTimeSortable.firstMatch(value)) != null) { + rc = DateTime( + int.parse(match!.group(1)!), + int.parse(match.group(2)!), + int.parse(match.group(3)!), + match.groupCount < 6 ? 0 : int.parse(match.group(5) ?? '0'), + match.groupCount < 6 ? 0 : int.parse(match.group(6) ?? '0'), + match.groupCount < 8 ? 0 : int.parse(match.group(8) ?? '0'), + ); + } else if ((match = regExprDateTimeStandard.firstMatch(value)) != null) { + rc = DateTime( + int.parse(match!.group(3)!), + int.parse(match.group(2)!), + int.parse(match.group(1)!), + match.groupCount < 6 ? 0 : int.parse(match.group(5) ?? '0'), + match.groupCount < 6 ? 0 : int.parse(match.group(6) ?? '0'), + match.groupCount < 8 ? 0 : int.parse(match.group(8) ?? '0'), + ); + } else { + rc = defaultValue; + } break; case DataType.int: case DataType.nat: case DataType.reference: - rc = int.tryParse(data); - break; - case DataType.string: - rc = data; + rc = int.tryParse(value) ?? defaultValue; + if (dataType == DataType.nat && rc < 0) { + rc = defaultValue; + } break; - case DataType.undefined: - throw FormatException('valueOf(): data type is undefined'); } return rc; } + +/// This function is only used to avoid compiler warning "unused import" +/// for generated code. +void helperDummyUsage() { + // nothing to do +} + +/// Converts a [name] to a camel case string. +/// +/// A camelCase string starts with a uppercase character. +String toCamelCase(String name) { + final rc = name.isEmpty ? '' : (name[0].toUpperCase() + name.substring(1)); + return rc; +} diff --git a/lib/meta/benchmarks_meta.dart b/lib/meta/benchmarks_meta.dart new file mode 100644 index 0000000..7956efd --- /dev/null +++ b/lib/meta/benchmarks_meta.dart @@ -0,0 +1,78 @@ +import '../base/defines.dart'; +import '../base/i18n.dart'; +import 'module_meta_data.dart'; + +final i18n = I18N(); +final M = i18n.module("Benchmarks"); + +class BenchmarkMeta extends ModuleMetaData { + static BenchmarkMeta instance = BenchmarkMeta.internal(); + factory BenchmarkMeta() { + return instance; + } + BenchmarkMeta.internal() + : super('Benchmarks', [ + PropertyMetaData('id', i18n.tr('Id'), DataType.reference, ':primary:', + displayType: DisplayType.combobox), + PropertyMetaData( + 'lastName', i18n.tr('Last Name'), DataType.string, ':notnull:', + size: 64), + PropertyMetaData('firstName', i18n.tr('First Name', M), + DataType.string, ':unique:notnull:', + size: 32), + PropertyMetaData( + 'email', i18n.tr('EMail', M), DataType.string, ':unique:notnull:', + size: 255, validators: ['isEmail(input)']), + PropertyMetaData( + 'birthday', i18n.tr('Birthday'), DataType.date, ':notnull:'), + PropertyMetaData( + 'active', i18n.tr('Active'), DataType.bool, ':notnull:'), + PropertyMetaData( + 'weight', i18n.tr('Weight'), DataType.float, ''), + PropertyMetaData( + 'income', i18n.tr('Income'), DataType.currency, ''), + PropertyMetaData( + 'created', i18n.tr('Created'), DataType.datetime, ':hidden:'), + PropertyMetaData( + 'createdBy', i18n.tr('Created by'), DataType.string, ':hidden:', + size: 32), + PropertyMetaData( + 'changed', i18n.tr('Changed'), DataType.datetime, ':hidden:'), + PropertyMetaData( + 'changedBy', i18n.tr('Changed by'), DataType.string, ':hidden:', + size: 32), + ], [ + PageMetaData( + 'New Benchmark', + PageType.create, + fields: [CopyDbFields('filters')], + ), + PageMetaData( + 'Change Benchmark', + PageType.edit, + fields: [CopyDbFields('filters')], + ), + PageMetaData( + 'Delete Benchmark', + PageType.delete, + fields: [CopyDbFields('filters')], + ), + ListPageMetaData( + 'Benchmarks Overview', + fields: [ + PropertyMetaData( + 'text', i18n.tr('Text'), DataType.string, ':pattern:', + size: 64), + ], + tableColumns: 'benchmark_id;benchmark_lastname;benchmark_firstname;benchmark_birthday', + tableHeaders: i18n.tr(';Id;Last Name;First Name;Birthday'), + whereCondition: '''(:text='' OR benchmark_lastname like :text + OR benchmark_firstname like :text)''', + orderBy: 'benchmark_id', + ), + ]); + @override + void onInitialized() { + super.onInitialized(); + } +} diff --git a/lib/meta/modules.dart b/lib/meta/modules.dart index 2ff718c..484f179 100644 --- a/lib/meta/modules.dart +++ b/lib/meta/modules.dart @@ -1,14 +1,17 @@ // DO NOT CHANGE. This file is created by the meta_tool import 'module_meta_data.dart'; +import 'benchmarks_meta.dart'; import 'roles_meta.dart'; import 'structures_meta.dart'; import 'users_meta.dart'; - /// Returns the meta data of the module given by [name]. /// Returns null if not found. ModuleMetaData? moduleByName(String name) { ModuleMetaData? rc; switch (name) { + case 'Benchmarks': + rc = BenchmarkMeta(); + break; case 'Roles': rc = RoleMeta(); break; @@ -23,10 +26,10 @@ ModuleMetaData? moduleByName(String name) { } return rc; } - /// Returns the module names as string list. -List moduleNames() { +List moduleNames(){ return [ + 'Benchmarks', 'Roles', 'Structures', 'Users', diff --git a/lib/page/benchmarks/benchmark_data.dart b/lib/page/benchmarks/benchmark_data.dart new file mode 100644 index 0000000..929cce3 --- /dev/null +++ b/lib/page/benchmarks/benchmark_data.dart @@ -0,0 +1,110 @@ +// DO NOT CHANGE. This file is created by the meta_tool +import '../../base/defines.dart'; +import '../../base/helper.dart'; +import '../../persistence/data_record.dart'; +class BenchmarkData extends DataRecord{ + int? id; + String? lastName; + String? firstName; + String? email; + DateTime? birthday; + bool? active; + double? weight; + int? income; + DateTime? created; + String? createdBy; + DateTime? changed; + String? changedBy; + BenchmarkData({ + this.id, this.lastName, this.firstName, this.email, this.birthday, this.active, this.weight, this.income, this.created, this.createdBy, this.changed, this.changedBy}); + BenchmarkData.createFromMap(DataMap map) { + fromMap(map); + } + @override + void fromMap(DataMap map) { + id = map.containsKey('benchmark_id') ? fromString(map['benchmark_id'], dataType: DataType.reference) : null; + lastName = map.containsKey('benchmark_lastname') ? fromString(map['benchmark_lastname'], dataType: DataType.string) : null; + firstName = map.containsKey('benchmark_firstname') ? fromString(map['benchmark_firstname'], dataType: DataType.string) : null; + email = map.containsKey('benchmark_email') ? fromString(map['benchmark_email'], dataType: DataType.string) : null; + birthday = map.containsKey('benchmark_birthday') ? fromString(map['benchmark_birthday'], dataType: DataType.date) : null; + active = map.containsKey('benchmark_active') ? fromString(map['benchmark_active'], dataType: DataType.bool) : null; + weight = map.containsKey('benchmark_weight') ? fromString(map['benchmark_weight'], dataType: DataType.float) : null; + income = map.containsKey('benchmark_income') ? fromString(map['benchmark_income'], dataType: DataType.currency) : null; + created = map.containsKey('benchmark_created') ? fromString(map['benchmark_created'], dataType: DataType.datetime) : null; + createdBy = map.containsKey('benchmark_createdby') ? fromString(map['benchmark_createdby'], dataType: DataType.string) : null; + changed = map.containsKey('benchmark_changed') ? fromString(map['benchmark_changed'], dataType: DataType.datetime) : null; + changedBy = map.containsKey('benchmark_changedby') ? fromString(map['benchmark_changedby'], dataType: DataType.string) : null; + } + @override + int keyOf() { + return id ?? 0; + } + @override + String nameOfKey(){ + return 'benchmark_id'; + } + static DataType? dataTypeOf(String name) { + DataType? rc; + switch(name){ + case 'id': + rc = DataType.reference; + break; + case 'lastName': + rc = DataType.string; + break; + case 'firstName': + rc = DataType.string; + break; + case 'email': + rc = DataType.string; + break; + case 'birthday': + rc = DataType.date; + break; + case 'active': + rc = DataType.bool; + break; + case 'weight': + rc = DataType.float; + break; + case 'income': + rc = DataType.currency; + break; + case 'created': + rc = DataType.datetime; + break; + case 'createdBy': + rc = DataType.string; + break; + case 'changed': + rc = DataType.datetime; + break; + case 'changedBy': + rc = DataType.string; + break; + default: + break; + } + return rc; + } + @override + DataMap toMap({DataMap? map, bool clear = true}) { + map ??= DataMap(); + if (clear) { + map.clear(); + } + map['benchmark_id'] = id; + map['benchmark_lastname'] = lastName; + map['benchmark_firstname'] = firstName; + map['benchmark_email'] = email; + map['benchmark_birthday'] = birthday; + map['benchmark_active'] = active; + map['benchmark_weight'] = weight; + map['benchmark_income'] = income; + map['benchmark_created'] = created; + map['benchmark_createdby'] = createdBy; + map['benchmark_changed'] = changed; + map['benchmark_changedby'] = changedBy; + return map; + } +} diff --git a/lib/page/benchmarks/create_benchmark_custom.dart b/lib/page/benchmarks/create_benchmark_custom.dart new file mode 100644 index 0000000..b09328e --- /dev/null +++ b/lib/page/benchmarks/create_benchmark_custom.dart @@ -0,0 +1,200 @@ +// This file is created by the meta_tool. But it can be customized. +// It will never overridden by the meta_tool. +import 'package:flutter/material.dart'; + +import '../../base/defines.dart'; +import '../../base/helper.dart'; +import '../../base/i18n.dart'; +import '../../base/validators.dart'; +import '../../services/global_widget.dart'; +import '../../setting/global_data.dart'; +import '../../widget/attended_page.dart'; +import '../../widget/message_line.dart'; +import '../../widget/widget_form.dart'; +import 'create_benchmark_page.dart'; + +final i18n = I18N(); + +class CreateBenchmarkCustom extends State with MessageLine { + final globalData = GlobalData(); + AttendedPage? attendedPage; + final _fieldData = _FieldData(); + final GlobalKey _formKey = + GlobalKey(debugLabel: 'CreateBenchmark'); + final lastNameController = TextEditingController(); + final firstNameController = TextEditingController(); + final emailController = TextEditingController(); + final birthdayController = TextEditingController(); + final activeController = TextEditingController(); + final weightController = TextEditingController(); + final incomeController = TextEditingController(); + CreateBenchmarkCustom(); + @override + Widget build(BuildContext context) { + final padding = GlobalThemeData.padding; + lastNameController.text = _fieldData.lastName; + firstNameController.text = _fieldData.firstName; + emailController.text = _fieldData.email; + birthdayController.text = asString(_fieldData.birthday); + activeController.text = asString(_fieldData.active); + weightController.text = asString(_fieldData.weight); + incomeController.text = asString(_fieldData.income); + final formItems = [ + FormItem( + TextFormField( + controller: lastNameController, + decoration: InputDecoration(labelText: i18n.tr('Last Name')), + validator: (input) => notEmpty(input), + onSaved: (value) => _fieldData.lastName = value ?? '' + ), + weight: 6), + FormItem( + TextFormField( + controller: firstNameController, + decoration: InputDecoration(labelText: i18n.tr('First Name')), + validator: (input) => notEmpty(input), + onSaved: (value) => _fieldData.firstName = value ?? '' + ), + weight: 6), + FormItem( + TextFormField( + controller: emailController, + decoration: InputDecoration(labelText: i18n.tr('EMail')), + validator: (input) => notEmpty(input), + onSaved: (value) => _fieldData.email = value ?? '' + ), + weight: 6), + FormItem( + TextFormField( + controller: birthdayController, + decoration: InputDecoration(labelText: i18n.tr('Birthday')), + validator: (input) => notEmpty(input), + onSaved: (value) => _fieldData.birthday = fromString(value ?? '', dataType: DataType.date) + ), + weight: 6), + FormItem( + TextFormField( + controller: activeController, + decoration: InputDecoration(labelText: i18n.tr('Active')), + validator: (input) => notEmpty(input), + onSaved: (value) => _fieldData.active = fromString(value ?? '', dataType: DataType.bool) + ), + weight: 6), + FormItem( + TextFormField( + controller: weightController, + decoration: InputDecoration(labelText: i18n.tr('Weight')), + onSaved: (value) => _fieldData.weight = fromString(value ?? '', dataType: DataType.float) + ), + weight: 6), + FormItem( + TextFormField( + controller: incomeController, + decoration: InputDecoration(labelText: i18n.tr('Income')), + onSaved: (value) => _fieldData.income = fromString(value ?? '', dataType: DataType.currency) + ), + weight: 6), + FormItem( + ElevatedButton( + onPressed: () => verifyAndStore(), + child: Text(i18n.tr('Save'))), + weight: 8, + gapAbove: 2 * padding), + FormItem( + ElevatedButton( + onPressed: () { + attendedPage!.pageStates.dbDataState.clear(); + globalData.navigate(context, '/Benchmarks/list'); + }, + child: Text(i18n.tr('Cancel')), + ), + weight: 4) + ]; + final rc = Scaffold( + appBar: globalData.appBarBuilder(i18n.tr('New Benchmark')), + drawer: globalData.drawerBuilder(context), + body: SafeArea( + child: Form( + key: _formKey, + child: Card( + margin: EdgeInsets.symmetric( + vertical: padding, horizontal: padding), + child: Padding( + padding: EdgeInsets.symmetric( + vertical: padding, horizontal: padding), + child: WidgetForm.flexibleGrid( + formItems, + screenWidth: attendedPage!.pageStates.screenWidth, + padding: padding, + )))))); + return rc; + } + + @override + void initState() { + super.initState(); + } + + void store() { + final parameters = { + 'module': 'Benchmarks', + 'sql': 'insert', + }; + _fieldData.toMap(parameters); + globalData.restPersistence! + .store(what: 'store', map: parameters) + .then((answer) { + if (answer.startsWith('id:')) { + final id = int.tryParse(answer.substring(3)); + if (id == null || id == 0) { + setError(i18n.tr('Saving data failed: $answer')); + setState(() => 1); + } else { + attendedPage!.pageStates.dbDataState.clear(); + globalData.navigate(context, '/Benchmarks/edit;$id'); + } + } + }); + } + + void verifyAndStore() { + if (_formKey.currentState!.validate()) { + _formKey.currentState!.save(); + store(); + } + } + + @override + void dispose() { + lastNameController.dispose(); + firstNameController.dispose(); + emailController.dispose(); + birthdayController.dispose(); + activeController.dispose(); + weightController.dispose(); + incomeController.dispose(); + super.dispose(); + } +} + +class _FieldData { + String lastName = ''; + String firstName = ''; + String email = ''; + DateTime? birthday; + bool active = false; + double weight = 0; + double income = 0; + + + void toMap(Map map) { + map[':lastName'] = lastName; + map[':firstName'] = firstName; + map[':email'] = email; + map[':birthday'] = asString(birthday); + map[':active'] = asString(active); + map[':weight'] = asString(weight); + map[':income'] = asString(income); + map[':createdBy'] = GlobalData.loginUserName; + } +} diff --git a/lib/page/benchmarks/create_benchmark_page.dart b/lib/page/benchmarks/create_benchmark_page.dart new file mode 100644 index 0000000..fa02c71 --- /dev/null +++ b/lib/page/benchmarks/create_benchmark_page.dart @@ -0,0 +1,31 @@ +// DO NOT CHANGE. This file is created by the meta_tool! +import 'package:flutter/material.dart'; + +import '../../meta/benchmarks_meta.dart'; +import '../../setting/global_data.dart'; +import '../../widget/attended_page.dart'; +import 'create_benchmark_custom.dart'; + +class CreateBenchmarkPage extends StatefulWidget { + final PageStates pageStates = PageStates(); + CreateBenchmarkPage() : super(); + @override + _CreateBenchmarkPageState createState() { + final rc = _CreateBenchmarkPageState(); + rc.attendedPage = + AttendedPage(this, rc, GlobalData(), BenchmarkMeta.instance, pageStates); + pageStates.attendedPage = rc.attendedPage; + return rc; + } +} + +class _CreateBenchmarkPageState extends CreateBenchmarkCustom { + _CreateBenchmarkPageState(): super(); + @override + void didChangeDependencies() { + final size = MediaQuery.of(context).size; + attendedPage!.pageStates.screenWidth = size.width; + attendedPage!.pageStates.screenHeight = size.height; + super.didChangeDependencies(); + } +} diff --git a/lib/page/benchmarks/delete_benchmark_custom.dart b/lib/page/benchmarks/delete_benchmark_custom.dart new file mode 100644 index 0000000..812cfb8 --- /dev/null +++ b/lib/page/benchmarks/delete_benchmark_custom.dart @@ -0,0 +1,195 @@ +// This file is created by the meta_tool. But it can be customized. +// It will never overridden by the meta_tool. +import 'package:flutter/material.dart'; + +import '../../base/defines.dart'; +import '../../base/helper.dart'; +import '../../base/i18n.dart'; +import '../../base/validators.dart'; +import '../../services/global_widget.dart'; +import '../../setting/global_data.dart'; +import '../../widget/attended_page.dart'; +import '../../widget/message_line.dart'; +import '../../widget/widget_form.dart'; +import 'delete_benchmark_page.dart'; + +final i18n = I18N(); + +class DeleteBenchmarkCustom extends State with MessageLine { + final int primaryKey; + final globalData = GlobalData(); + AttendedPage? attendedPage; + final _fieldData = _FieldData(); + final GlobalKey _formKey = + GlobalKey(debugLabel: 'DeleteBenchmark'); + final lastNameController = TextEditingController(); + final firstNameController = TextEditingController(); + final emailController = TextEditingController(); + final birthdayController = TextEditingController(); + final activeController = TextEditingController(); + final weightController = TextEditingController(); + final incomeController = TextEditingController(); + DeleteBenchmarkCustom(this.primaryKey); + @override + Widget build(BuildContext context) { + final padding = GlobalThemeData.padding; + attendedPage?.loadRecord( + name: 'record', + reload: () => setState(() => 1), + onDone: (record) => _fieldData.fromMap(record), + parameters: {'module': 'Benchmarks', 'sql': 'byId', ':id': primaryKey}); + lastNameController.text = _fieldData.lastName; + firstNameController.text = _fieldData.firstName; + emailController.text = _fieldData.email; + birthdayController.text = asString(_fieldData.birthday); + activeController.text = asString(_fieldData.active); + weightController.text = asString(_fieldData.weight); + incomeController.text = asString(_fieldData.income); + final formItems = [ + FormItem( + TextFormField( + controller: lastNameController, + decoration: InputDecoration(labelText: i18n.tr('Last Name')), + validator: (input) => notEmpty(input), + onSaved: (value) => _fieldData.lastName = value ?? '' + ), + weight: 6), + FormItem( + TextFormField( + controller: firstNameController, + decoration: InputDecoration(labelText: i18n.tr('First Name')), + validator: (input) => notEmpty(input), + onSaved: (value) => _fieldData.firstName = value ?? '' + ), + weight: 6), + FormItem( + TextFormField( + controller: emailController, + decoration: InputDecoration(labelText: i18n.tr('EMail')), + validator: (input) => notEmpty(input), + onSaved: (value) => _fieldData.email = value ?? '' + ), + weight: 6), + FormItem( + TextFormField( + controller: birthdayController, + decoration: InputDecoration(labelText: i18n.tr('Birthday')), + validator: (input) => notEmpty(input), + onSaved: (value) => _fieldData.birthday = fromString(value ?? '', dataType: DataType.date) + ), + weight: 6), + FormItem( + TextFormField( + controller: activeController, + decoration: InputDecoration(labelText: i18n.tr('Active')), + validator: (input) => notEmpty(input), + onSaved: (value) => _fieldData.active = fromString(value ?? '', dataType: DataType.bool) + ), + weight: 6), + FormItem( + TextFormField( + controller: weightController, + decoration: InputDecoration(labelText: i18n.tr('Weight')), + onSaved: (value) => _fieldData.weight = fromString(value ?? '', dataType: DataType.float) + ), + weight: 6), + FormItem( + TextFormField( + controller: incomeController, + decoration: InputDecoration(labelText: i18n.tr('Income')), + onSaved: (value) => _fieldData.income = fromString(value ?? '', dataType: DataType.currency) + ), + weight: 6), + FormItem( + ElevatedButton( + onPressed: () => verifyAndDelete(), + child: Text(i18n.tr('Delete'))), + weight: 8, + gapAbove: 2 * padding), + FormItem( + ElevatedButton( + onPressed: () { + attendedPage!.pageStates.dbDataState.clear(); + globalData.navigate(context, '/Benchmarks/list'); + }, + child: Text(i18n.tr('Cancel')), + ), + weight: 4) + ]; + final rc = Scaffold( + appBar: globalData.appBarBuilder(i18n.tr('Delete Benchmark')), + drawer: globalData.drawerBuilder(context), + body: SafeArea( + child: Form( + key: _formKey, + child: Card( + margin: EdgeInsets.symmetric( + vertical: padding, horizontal: padding), + child: Padding( + padding: EdgeInsets.symmetric( + vertical: padding, horizontal: padding), + child: WidgetForm.flexibleGrid( + formItems, + screenWidth: attendedPage!.pageStates.screenWidth, + padding: padding, + )))))); + return rc; + } + + @override + void initState() { + super.initState(); + } + + void delete() { + final parameters = { + 'module': 'Benchmarks', + 'sql': 'delete', + }; + parameters[':id'] = primaryKey; + globalData.restPersistence! + .store(what: 'store', map: parameters) + .then((answer) { + globalData.navigate(context, '/Benchmarks/list'); + }); + } + + void verifyAndDelete() { + if (_formKey.currentState!.validate()) { + _formKey.currentState!.save(); + delete(); + } + } + + @override + void dispose() { + lastNameController.dispose(); + firstNameController.dispose(); + emailController.dispose(); + birthdayController.dispose(); + activeController.dispose(); + weightController.dispose(); + incomeController.dispose(); + super.dispose(); + } +} + +class _FieldData { + String lastName = ''; + String firstName = ''; + String email = ''; + DateTime? birthday; + bool active = false; + double weight = 0; + double income = 0; + + void fromMap(Map map) { + lastName = map['benchmark_lastname']; + firstName = map['benchmark_firstname']; + email = map['benchmark_email']; + birthday = map['benchmark_birthday']; + active = map['benchmark_active']; + weight = map['benchmark_weight']; + income = map['benchmark_income']; + } +} diff --git a/lib/page/benchmarks/delete_benchmark_page.dart b/lib/page/benchmarks/delete_benchmark_page.dart new file mode 100644 index 0000000..0955fbf --- /dev/null +++ b/lib/page/benchmarks/delete_benchmark_page.dart @@ -0,0 +1,32 @@ +// DO NOT CHANGE. This file is created by the meta_tool! +import 'package:flutter/material.dart'; + +import '../../meta/benchmarks_meta.dart'; +import '../../setting/global_data.dart'; +import '../../widget/attended_page.dart'; +import 'delete_benchmark_custom.dart'; + +class DeleteBenchmarkPage extends StatefulWidget { + final int primaryKey; + final PageStates pageStates = PageStates(); + DeleteBenchmarkPage(this.primaryKey) : super(); + @override + _DeleteBenchmarkPageState createState() { + final rc = _DeleteBenchmarkPageState(this.primaryKey); + rc.attendedPage = + AttendedPage(this, rc, GlobalData(), BenchmarkMeta.instance, pageStates); + pageStates.attendedPage = rc.attendedPage; + return rc; + } +} + +class _DeleteBenchmarkPageState extends DeleteBenchmarkCustom { + _DeleteBenchmarkPageState(int primaryKey): super(primaryKey); + @override + void didChangeDependencies() { + final size = MediaQuery.of(context).size; + attendedPage!.pageStates.screenWidth = size.width; + attendedPage!.pageStates.screenHeight = size.height; + super.didChangeDependencies(); + } +} diff --git a/lib/page/benchmarks/edit_benchmark_custom.dart b/lib/page/benchmarks/edit_benchmark_custom.dart new file mode 100644 index 0000000..0b151a1 --- /dev/null +++ b/lib/page/benchmarks/edit_benchmark_custom.dart @@ -0,0 +1,206 @@ +// This file is created by the meta_tool. But it can be customized. +// It will never overridden by the meta_tool. +import 'package:flutter/material.dart'; + +import '../../base/defines.dart'; +import '../../base/helper.dart'; +import '../../base/i18n.dart'; +import '../../base/validators.dart'; +import '../../services/global_widget.dart'; +import '../../setting/global_data.dart'; +import '../../widget/attended_page.dart'; +import '../../widget/message_line.dart'; +import '../../widget/widget_form.dart'; +import 'edit_benchmark_page.dart'; + +final i18n = I18N(); + +class EditBenchmarkCustom extends State with MessageLine { + final int primaryKey; + final globalData = GlobalData(); + AttendedPage? attendedPage; + final _fieldData = _FieldData(); + final GlobalKey _formKey = + GlobalKey(debugLabel: 'EditBenchmark'); + final lastNameController = TextEditingController(); + final firstNameController = TextEditingController(); + final emailController = TextEditingController(); + final birthdayController = TextEditingController(); + final activeController = TextEditingController(); + final weightController = TextEditingController(); + final incomeController = TextEditingController(); + EditBenchmarkCustom(this.primaryKey); + @override + Widget build(BuildContext context) { + final padding = GlobalThemeData.padding; + attendedPage?.loadRecord( + name: 'record', + reload: () => setState(() => 1), + onDone: (record) => _fieldData.fromMap(record), + parameters: {'module': 'Benchmarks', 'sql': 'byId', ':id': primaryKey}); + lastNameController.text = _fieldData.lastName; + firstNameController.text = _fieldData.firstName; + emailController.text = _fieldData.email; + birthdayController.text = asString(_fieldData.birthday); + activeController.text = asString(_fieldData.active); + weightController.text = asString(_fieldData.weight); + incomeController.text = asString(_fieldData.income); + final formItems = [ + FormItem( + TextFormField( + controller: lastNameController, + decoration: InputDecoration(labelText: i18n.tr('Last Name')), + validator: (input) => notEmpty(input), + onSaved: (value) => _fieldData.lastName = value ?? '' + ), + weight: 6), + FormItem( + TextFormField( + controller: firstNameController, + decoration: InputDecoration(labelText: i18n.tr('First Name')), + validator: (input) => notEmpty(input), + onSaved: (value) => _fieldData.firstName = value ?? '' + ), + weight: 6), + FormItem( + TextFormField( + controller: emailController, + decoration: InputDecoration(labelText: i18n.tr('EMail')), + validator: (input) => notEmpty(input), + onSaved: (value) => _fieldData.email = value ?? '' + ), + weight: 6), + FormItem( + TextFormField( + controller: birthdayController, + decoration: InputDecoration(labelText: i18n.tr('Birthday')), + validator: (input) => notEmpty(input), + onSaved: (value) => _fieldData.birthday = fromString(value ?? '', dataType: DataType.date) + ), + weight: 6), + FormItem( + TextFormField( + controller: activeController, + decoration: InputDecoration(labelText: i18n.tr('Active')), + validator: (input) => notEmpty(input), + onSaved: (value) => _fieldData.active = fromString(value ?? '', dataType: DataType.bool) + ), + weight: 6), + FormItem( + TextFormField( + controller: weightController, + decoration: InputDecoration(labelText: i18n.tr('Weight')), + onSaved: (value) => _fieldData.weight = fromString(value ?? '', dataType: DataType.float) + ), + weight: 6), + FormItem( + TextFormField( + controller: incomeController, + decoration: InputDecoration(labelText: i18n.tr('Income')), + onSaved: (value) => _fieldData.income = fromString(value ?? '', dataType: DataType.currency) + ), + weight: 6), + FormItem( + ElevatedButton( + onPressed: () => verifyAndStore(), + child: Text(i18n.tr('Save'))), + weight: 8, + gapAbove: 2 * padding), + FormItem( + ElevatedButton( + onPressed: () { + attendedPage!.pageStates.dbDataState.clear(); + globalData.navigate(context, '/Benchmarks/list'); + }, + child: Text(i18n.tr('Cancel')), + ), + weight: 4) + ]; + final rc = Scaffold( + appBar: globalData.appBarBuilder(i18n.tr('Change Benchmark')), + drawer: globalData.drawerBuilder(context), + body: SafeArea( + child: Form( + key: _formKey, + child: Card( + margin: EdgeInsets.symmetric( + vertical: padding, horizontal: padding), + child: Padding( + padding: EdgeInsets.symmetric( + vertical: padding, horizontal: padding), + child: WidgetForm.flexibleGrid( + formItems, + screenWidth: attendedPage!.pageStates.screenWidth, + padding: padding, + )))))); + return rc; + } + + @override + void initState() { + super.initState(); + } + + void store() { + final parameters = { + 'module': 'Benchmarks', + 'sql': 'update', + }; + parameters[':id'] = primaryKey; + _fieldData.toMap(parameters); + globalData.restPersistence! + .store(what: 'store', map: parameters) + .then((answer) {}); + } + + void verifyAndStore() { + if (_formKey.currentState!.validate()) { + _formKey.currentState!.save(); + store(); + } + } + + @override + void dispose() { + lastNameController.dispose(); + firstNameController.dispose(); + emailController.dispose(); + birthdayController.dispose(); + activeController.dispose(); + weightController.dispose(); + incomeController.dispose(); + super.dispose(); + } +} + +class _FieldData { + String lastName = ''; + String firstName = ''; + String email = ''; + DateTime? birthday; + bool active = false; + double weight = 0; + double income = 0; + + void fromMap(Map map) { + lastName = map['benchmark_lastname']; + firstName = map['benchmark_firstname']; + email = map['benchmark_email']; + birthday = map['benchmark_birthday']; + active = map['benchmark_active']; + weight = map['benchmark_weight']; + income = map['benchmark_income']; + } + + void toMap(Map map) { + // please set outside: map[':id'] = primaryKey; + map[':lastName'] = lastName; + map[':firstName'] = firstName; + map[':email'] = email; + map[':birthday'] = asString(birthday); + map[':active'] = asString(active); + map[':weight'] = asString(weight); + map[':income'] = asString(income); + map[':changedBy'] = GlobalData.loginUserName; + } +} diff --git a/lib/page/benchmarks/edit_benchmark_page.dart b/lib/page/benchmarks/edit_benchmark_page.dart new file mode 100644 index 0000000..32f631a --- /dev/null +++ b/lib/page/benchmarks/edit_benchmark_page.dart @@ -0,0 +1,32 @@ +// DO NOT CHANGE. This file is created by the meta_tool! +import 'package:flutter/material.dart'; + +import '../../meta/benchmarks_meta.dart'; +import '../../setting/global_data.dart'; +import '../../widget/attended_page.dart'; +import 'edit_benchmark_custom.dart'; + +class EditBenchmarkPage extends StatefulWidget { + final int primaryKey; + final PageStates pageStates = PageStates(); + EditBenchmarkPage(this.primaryKey) : super(); + @override + _EditBenchmarkPageState createState() { + final rc = _EditBenchmarkPageState(this.primaryKey); + rc.attendedPage = + AttendedPage(this, rc, GlobalData(), BenchmarkMeta.instance, pageStates); + pageStates.attendedPage = rc.attendedPage; + return rc; + } +} + +class _EditBenchmarkPageState extends EditBenchmarkCustom { + _EditBenchmarkPageState(int primaryKey): super(primaryKey); + @override + void didChangeDependencies() { + final size = MediaQuery.of(context).size; + attendedPage!.pageStates.screenWidth = size.width; + attendedPage!.pageStates.screenHeight = size.height; + super.didChangeDependencies(); + } +} diff --git a/lib/page/benchmarks/list_benchmark_custom.dart b/lib/page/benchmarks/list_benchmark_custom.dart new file mode 100644 index 0000000..c1701f0 --- /dev/null +++ b/lib/page/benchmarks/list_benchmark_custom.dart @@ -0,0 +1,126 @@ +// This file is created by the meta_tool. But it can be customized. +// It will never overridden by the meta_tool. +import 'package:flutter/material.dart'; + +import '../../base/helper.dart'; +import '../../base/i18n.dart'; +import '../../services/global_widget.dart'; +import '../../setting/global_data.dart'; +import '../../widget/attended_page.dart'; +import '../../widget/widget_form.dart'; +import 'list_benchmark_page.dart'; + +final i18n = I18N(); + +class ListBenchmarkCustom extends State { + final globalData = GlobalData(); + AttendedPage? attendedPage; + final _fieldData = _FieldData(); + final GlobalKey _formKey = + GlobalKey(debugLabel: 'CreateBenchmark'); + final textController = TextEditingController(); + ListBenchmarkCustom(); + @override + Widget build(BuildContext context) { + final padding = GlobalThemeData.padding; + final formItems = [ + FormItem( + TextFormField( + controller: textController, + decoration: InputDecoration(labelText: i18n.tr('Text')), + onSaved: (value) => _fieldData.text = value ?? '' + ), + weight: 6), + FormItem( + ElevatedButton( + onPressed: () => search(), child: Text(i18n.tr('Search'))), + weight: 12, + gapAbove: padding), + ]; + final form = Form( + key: _formKey, + child: Card( + color: GlobalThemeData.formBackgroundColor, + elevation: GlobalThemeData.formElevation, + margin: + EdgeInsets.symmetric(vertical: padding, horizontal: padding), + child: Padding( + padding: EdgeInsets.symmetric( + vertical: padding, horizontal: padding), + child: WidgetForm.flexibleGrid(formItems, + screenWidth: attendedPage!.pageStates.screenWidth, + padding: padding)))); + final rows = attendedPage!.getRows( + columnList: 'benchmark_id;benchmark_lastname;benchmark_firstname;benchmark_birthday', + what: 'query', + parameters: { + 'module': 'Benchmarks', + 'sql': 'list', + 'offset': '0', + 'size': '10', + ':text': asPattern(_fieldData.text), + }, + onDone: () => setState(() => 1), + routeEdit: '/Benchmarks/edit', + context: context); + final table = DataTable( + columns: [ + DataColumn( + label: Text(i18n.tr('Id')), + ), + DataColumn( + label: Text(i18n.tr('Last Name')), + ), + DataColumn( + label: Text(i18n.tr('First Name')), + ), + DataColumn( + label: Text(i18n.tr('Birthday')), + ), + ], + rows: rows, + ); + final frameWidget = Column(children: [ + form, + SizedBox(height: padding), + SizedBox(width: double.infinity, child: table), + ]); + final rc = Scaffold( + appBar: globalData.appBarBuilder(i18n.tr('Overview benchmarks')), + drawer: globalData.drawerBuilder(context), + floatingActionButton: FloatingActionButton( + onPressed: () { + globalData.navigate(context, '/Benchmarks/create'); + }, + child: const Icon(Icons.add), + //backgroundColor: Colors.green, + ), + body: SafeArea(child: frameWidget)); + return rc; + } + + @override + void dispose() { + helperDummyUsage(); + globalWidgetDummyUsage(); + textController.dispose(); + super.dispose(); + } + + @override + void initState() { + super.initState(); + } + + void search() { + attendedPage!.pageStates.dbDataState.clear(); + if (_formKey.currentState!.validate()) { + _formKey.currentState!.save(); + setState(() => 1); + } + } +} + +class _FieldData { + String text = ''; +} diff --git a/lib/page/benchmarks/list_benchmark_page.dart b/lib/page/benchmarks/list_benchmark_page.dart new file mode 100644 index 0000000..d65dcc5 --- /dev/null +++ b/lib/page/benchmarks/list_benchmark_page.dart @@ -0,0 +1,31 @@ +// DO NOT CHANGE. This file is created by the meta_tool! +import 'package:flutter/material.dart'; + +import '../../meta/benchmarks_meta.dart'; +import '../../setting/global_data.dart'; +import '../../widget/attended_page.dart'; +import 'list_benchmark_custom.dart'; + +class ListBenchmarkPage extends StatefulWidget { + final PageStates pageStates = PageStates(); + ListBenchmarkPage() : super(); + @override + _ListBenchmarkPageState createState() { + final rc = _ListBenchmarkPageState(); + rc.attendedPage = + AttendedPage(this, rc, GlobalData(), BenchmarkMeta.instance, pageStates); + pageStates.attendedPage = rc.attendedPage; + return rc; + } +} + +class _ListBenchmarkPageState extends ListBenchmarkCustom { + _ListBenchmarkPageState(): super(); + @override + void didChangeDependencies() { + final size = MediaQuery.of(context).size; + attendedPage!.pageStates.screenWidth = size.width; + attendedPage!.pageStates.screenHeight = size.height; + super.didChangeDependencies(); + } +} diff --git a/lib/page/page_manager.dart b/lib/page/page_manager.dart index 77d4168..cea3c73 100644 --- a/lib/page/page_manager.dart +++ b/lib/page/page_manager.dart @@ -2,6 +2,10 @@ import 'package:flutter/material.dart'; import 'page_manager_custom.dart'; +import 'benchmarks/create_benchmark_page.dart'; +import 'benchmarks/edit_benchmark_page.dart'; +import 'benchmarks/delete_benchmark_page.dart'; +import 'benchmarks/list_benchmark_page.dart'; import 'roles/create_role_page.dart'; import 'roles/edit_role_page.dart'; import 'roles/list_role_page.dart'; @@ -30,6 +34,18 @@ class PageManager { final parts = route.split(';'); final arg1 = parts.length < 2 ? 0 : int.parse(parts[1]); switch (parts[0]) { + case '/Benchmarks/create': + rc = CreateBenchmarkPage(); + break; + case '/Benchmarks/edit': + rc = EditBenchmarkPage(arg1); + break; + case '/Benchmarks/delete': + rc = DeleteBenchmarkPage(arg1); + break; + case '/Benchmarks/list': + rc = ListBenchmarkPage(); + break; case '/Roles/create': rc = CreateRolePage(); break; diff --git a/lib/page/roles/create_role_custom.dart b/lib/page/roles/create_role_custom.dart index 15a4f82..3a38b41 100644 --- a/lib/page/roles/create_role_custom.dart +++ b/lib/page/roles/create_role_custom.dart @@ -2,30 +2,73 @@ // It will never overridden by the meta_tool. import 'package:flutter/material.dart'; +import '../../base/defines.dart'; +import '../../base/helper.dart'; import '../../base/i18n.dart'; +import '../../base/validators.dart'; +import '../../services/global_widget.dart'; import '../../setting/global_data.dart'; import '../../widget/attended_page.dart'; +import '../../widget/message_line.dart'; import '../../widget/widget_form.dart'; import 'create_role_page.dart'; final i18n = I18N(); -class CreateRoleCustom extends State { +class CreateRoleCustom extends State with MessageLine { final globalData = GlobalData(); AttendedPage? attendedPage; - + final _fieldData = _FieldData(); + final GlobalKey _formKey = + GlobalKey(debugLabel: 'CreateRole'); + final nameController = TextEditingController(); CreateRoleCustom(); @override Widget build(BuildContext context) { final padding = GlobalThemeData.padding; + nameController.text = _fieldData.name; + final formItems = [ + FormItem( + TextFormField( + controller: nameController, + decoration: InputDecoration(labelText: i18n.tr('Name')), + validator: (input) => notEmpty(input), + onSaved: (value) => _fieldData.name = value ?? '' + ), + weight: 6), + FormItem( + ElevatedButton( + onPressed: () => verifyAndStore(), + child: Text(i18n.tr('Save'))), + weight: 8, + gapAbove: 2 * padding), + FormItem( + ElevatedButton( + onPressed: () { + attendedPage!.pageStates.dbDataState.clear(); + globalData.navigate(context, '/Roles/list'); + }, + child: Text(i18n.tr('Cancel')), + ), + weight: 4) + ]; final rc = Scaffold( - appBar: globalData.appBarBuilder(i18n.tr('Change Role data')), + appBar: globalData.appBarBuilder(i18n.tr('New Role')), drawer: globalData.drawerBuilder(context), body: SafeArea( - child: WidgetForm.flexibleGridAttended( - attendedPage!.attendedWidgets(), - screenWidth: attendedPage!.pageStates.screenWidth, - padding: padding))); + child: Form( + key: _formKey, + child: Card( + margin: EdgeInsets.symmetric( + vertical: padding, horizontal: padding), + child: Padding( + padding: EdgeInsets.symmetric( + vertical: padding, horizontal: padding), + child: WidgetForm.flexibleGrid( + formItems, + screenWidth: attendedPage!.pageStates.screenWidth, + padding: padding, + )))))); return rc; } @@ -33,4 +76,49 @@ class CreateRoleCustom extends State { void initState() { super.initState(); } + + void store() { + final parameters = { + 'module': 'Roles', + 'sql': 'insert', + }; + _fieldData.toMap(parameters); + globalData.restPersistence! + .store(what: 'store', map: parameters) + .then((answer) { + if (answer.startsWith('id:')) { + final id = int.tryParse(answer.substring(3)); + if (id == null || id == 0) { + setError(i18n.tr('Saving data failed: $answer')); + setState(() => 1); + } else { + attendedPage!.pageStates.dbDataState.clear(); + globalData.navigate(context, '/Roles/edit;$id'); + } + } + }); + } + + void verifyAndStore() { + if (_formKey.currentState!.validate()) { + _formKey.currentState!.save(); + store(); + } + } + + @override + void dispose() { + nameController.dispose(); + super.dispose(); + } +} + +class _FieldData { + String name = ''; + + + void toMap(Map map) { + map[':name'] = name; + map[':createdBy'] = GlobalData.loginUserName; + } } diff --git a/lib/page/roles/create_role_page.dart b/lib/page/roles/create_role_page.dart index 2cd8530..4ec6c88 100644 --- a/lib/page/roles/create_role_page.dart +++ b/lib/page/roles/create_role_page.dart @@ -20,7 +20,7 @@ class CreateRolePage extends StatefulWidget { } class _CreateRolePageState extends CreateRoleCustom { - _CreateRolePageState() : super(); + _CreateRolePageState(): super(); @override void didChangeDependencies() { final size = MediaQuery.of(context).size; diff --git a/lib/page/roles/edit_role_custom.dart b/lib/page/roles/edit_role_custom.dart index e5326de..fe67f51 100644 --- a/lib/page/roles/edit_role_custom.dart +++ b/lib/page/roles/edit_role_custom.dart @@ -2,31 +2,79 @@ // It will never overridden by the meta_tool. import 'package:flutter/material.dart'; +import '../../base/defines.dart'; +import '../../base/helper.dart'; import '../../base/i18n.dart'; +import '../../base/validators.dart'; +import '../../services/global_widget.dart'; import '../../setting/global_data.dart'; import '../../widget/attended_page.dart'; +import '../../widget/message_line.dart'; import '../../widget/widget_form.dart'; import 'edit_role_page.dart'; final i18n = I18N(); -class EditRoleCustom extends State { +class EditRoleCustom extends State with MessageLine { final int primaryKey; final globalData = GlobalData(); AttendedPage? attendedPage; - + final _fieldData = _FieldData(); + final GlobalKey _formKey = + GlobalKey(debugLabel: 'EditRole'); + final nameController = TextEditingController(); EditRoleCustom(this.primaryKey); @override Widget build(BuildContext context) { final padding = GlobalThemeData.padding; + attendedPage?.loadRecord( + name: 'record', + reload: () => setState(() => 1), + onDone: (record) => _fieldData.fromMap(record), + parameters: {'module': 'Roles', 'sql': 'byId', ':id': primaryKey}); + nameController.text = _fieldData.name; + final formItems = [ + FormItem( + TextFormField( + controller: nameController, + decoration: InputDecoration(labelText: i18n.tr('Name')), + validator: (input) => notEmpty(input), + onSaved: (value) => _fieldData.name = value ?? '' + ), + weight: 6), + FormItem( + ElevatedButton( + onPressed: () => verifyAndStore(), + child: Text(i18n.tr('Save'))), + weight: 8, + gapAbove: 2 * padding), + FormItem( + ElevatedButton( + onPressed: () { + attendedPage!.pageStates.dbDataState.clear(); + globalData.navigate(context, '/Roles/list'); + }, + child: Text(i18n.tr('Cancel')), + ), + weight: 4) + ]; final rc = Scaffold( - appBar: globalData.appBarBuilder(i18n.tr('Change Role data')), + appBar: globalData.appBarBuilder(i18n.tr('Change Role')), drawer: globalData.drawerBuilder(context), body: SafeArea( - child: WidgetForm.flexibleGridAttended( - attendedPage!.attendedWidgets(), - screenWidth: attendedPage!.pageStates.screenWidth, - padding: padding))); + child: Form( + key: _formKey, + child: Card( + margin: EdgeInsets.symmetric( + vertical: padding, horizontal: padding), + child: Padding( + padding: EdgeInsets.symmetric( + vertical: padding, horizontal: padding), + child: WidgetForm.flexibleGrid( + formItems, + screenWidth: attendedPage!.pageStates.screenWidth, + padding: padding, + )))))); return rc; } @@ -34,4 +82,43 @@ class EditRoleCustom extends State { void initState() { super.initState(); } + + void store() { + final parameters = { + 'module': 'Roles', + 'sql': 'update', + }; + parameters[':id'] = primaryKey; + _fieldData.toMap(parameters); + globalData.restPersistence! + .store(what: 'store', map: parameters) + .then((answer) {}); + } + + void verifyAndStore() { + if (_formKey.currentState!.validate()) { + _formKey.currentState!.save(); + store(); + } + } + + @override + void dispose() { + nameController.dispose(); + super.dispose(); + } +} + +class _FieldData { + String name = ''; + + void fromMap(Map map) { + name = map['role_name']; + } + + void toMap(Map map) { + // please set outside: map[':id'] = primaryKey; + map[':name'] = name; + map[':changedBy'] = GlobalData.loginUserName; + } } diff --git a/lib/page/roles/edit_role_page.dart b/lib/page/roles/edit_role_page.dart index 6c32f01..ef15ac4 100644 --- a/lib/page/roles/edit_role_page.dart +++ b/lib/page/roles/edit_role_page.dart @@ -21,7 +21,7 @@ class EditRolePage extends StatefulWidget { } class _EditRolePageState extends EditRoleCustom { - _EditRolePageState(int primaryKey) : super(primaryKey); + _EditRolePageState(int primaryKey): super(primaryKey); @override void didChangeDependencies() { final size = MediaQuery.of(context).size; diff --git a/lib/page/roles/list_role_custom.dart b/lib/page/roles/list_role_custom.dart index b73090e..32e6ed8 100644 --- a/lib/page/roles/list_role_custom.dart +++ b/lib/page/roles/list_role_custom.dart @@ -2,7 +2,9 @@ // It will never overridden by the meta_tool. import 'package:flutter/material.dart'; +import '../../base/helper.dart'; import '../../base/i18n.dart'; +import '../../services/global_widget.dart'; import '../../setting/global_data.dart'; import '../../widget/attended_page.dart'; import '../../widget/widget_form.dart'; @@ -13,24 +15,103 @@ final i18n = I18N(); class ListRoleCustom extends State { final globalData = GlobalData(); AttendedPage? attendedPage; - + final _fieldData = _FieldData(); + final GlobalKey _formKey = + GlobalKey(debugLabel: 'CreateRole'); + final textController = TextEditingController(); ListRoleCustom(); @override Widget build(BuildContext context) { final padding = GlobalThemeData.padding; + final formItems = [ + FormItem( + TextFormField( + controller: textController, + decoration: InputDecoration(labelText: i18n.tr('Text')), + onSaved: (value) => _fieldData.text = value ?? '' + ), + weight: 6), + FormItem( + ElevatedButton( + onPressed: () => search(), child: Text(i18n.tr('Search'))), + weight: 12, + gapAbove: padding), + ]; + final form = Form( + key: _formKey, + child: Card( + color: GlobalThemeData.formBackgroundColor, + elevation: GlobalThemeData.formElevation, + margin: + EdgeInsets.symmetric(vertical: padding, horizontal: padding), + child: Padding( + padding: EdgeInsets.symmetric( + vertical: padding, horizontal: padding), + child: WidgetForm.flexibleGrid(formItems, + screenWidth: attendedPage!.pageStates.screenWidth, + padding: padding)))); + final rows = attendedPage!.getRows( + columnList: 'role_id;role_name', + what: 'query', + parameters: { + 'module': 'Roles', + 'sql': 'list', + 'offset': '0', + 'size': '10', + ':text': _fieldData.text, + }, + onDone: () => setState(() => 1), + routeEdit: '/Roles/edit', + context: context); + final table = DataTable( + columns: [ + DataColumn( + label: Text(i18n.tr('d;Name')), + ), + ], + rows: rows, + ); + final frameWidget = Column(children: [ + form, + SizedBox(height: padding), + SizedBox(width: double.infinity, child: table), + ]); final rc = Scaffold( - appBar: globalData.appBarBuilder(i18n.tr('Change Role data')), + appBar: globalData.appBarBuilder(i18n.tr('Overview roles')), drawer: globalData.drawerBuilder(context), - body: SafeArea( - child: WidgetForm.flexibleGridAttended( - attendedPage!.attendedWidgets(), - screenWidth: attendedPage!.pageStates.screenWidth, - padding: padding))); + floatingActionButton: FloatingActionButton( + onPressed: () { + globalData.navigate(context, '/Roles/create'); + }, + child: const Icon(Icons.add), + //backgroundColor: Colors.green, + ), + body: SafeArea(child: frameWidget)); return rc; } + @override + void dispose() { + helperDummyUsage(); + globalWidgetDummyUsage(); + textController.dispose(); + super.dispose(); + } + @override void initState() { super.initState(); } + + void search() { + attendedPage!.pageStates.dbDataState.clear(); + if (_formKey.currentState!.validate()) { + _formKey.currentState!.save(); + setState(() => 1); + } + } +} + +class _FieldData { + String text = ''; } diff --git a/lib/page/roles/list_role_page.dart b/lib/page/roles/list_role_page.dart index 0915e10..b42f052 100644 --- a/lib/page/roles/list_role_page.dart +++ b/lib/page/roles/list_role_page.dart @@ -20,7 +20,7 @@ class ListRolePage extends StatefulWidget { } class _ListRolePageState extends ListRoleCustom { - _ListRolePageState() : super(); + _ListRolePageState(): super(); @override void didChangeDependencies() { final size = MediaQuery.of(context).size; diff --git a/lib/page/roles/role_data.dart b/lib/page/roles/role_data.dart index 3a0da8b..74cd990 100644 --- a/lib/page/roles/role_data.dart +++ b/lib/page/roles/role_data.dart @@ -2,83 +2,61 @@ import '../../base/defines.dart'; import '../../base/helper.dart'; import '../../persistence/data_record.dart'; - -class RoleData extends DataRecord { +class RoleData extends DataRecord{ int? id; String? name; DateTime? created; String? createdBy; DateTime? changed; String? changedBy; - RoleData( - {this.id, - this.name, - this.created, - this.createdBy, - this.changed, - this.changedBy}); + RoleData({ + this.id, this.name, this.created, this.createdBy, this.changed, this.changedBy}); RoleData.createFromMap(DataMap map) { fromMap(map); } @override void fromMap(DataMap map) { - id = map.containsKey('role_id') - ? valueOf(DataType.reference, map['role_id']) - : null; - name = map.containsKey('role_name') - ? valueOf(DataType.string, map['role_name']) - : null; - created = map.containsKey('role_created') - ? valueOf(DataType.datetime, map['role_created']) - : null; - createdBy = map.containsKey('role_createdby') - ? valueOf(DataType.string, map['role_createdby']) - : null; - changed = map.containsKey('role_changed') - ? valueOf(DataType.datetime, map['role_changed']) - : null; - changedBy = map.containsKey('role_changedby') - ? valueOf(DataType.string, map['role_changedby']) - : null; + id = map.containsKey('role_id') ? fromString(map['role_id'], dataType: DataType.reference) : null; + name = map.containsKey('role_name') ? fromString(map['role_name'], dataType: DataType.string) : null; + created = map.containsKey('role_created') ? fromString(map['role_created'], dataType: DataType.datetime) : null; + createdBy = map.containsKey('role_createdby') ? fromString(map['role_createdby'], dataType: DataType.string) : null; + changed = map.containsKey('role_changed') ? fromString(map['role_changed'], dataType: DataType.datetime) : null; + changedBy = map.containsKey('role_changedby') ? fromString(map['role_changedby'], dataType: DataType.string) : null; } - @override int keyOf() { return id ?? 0; } - @override - String nameOfKey() { + String nameOfKey(){ return 'role_id'; } - static DataType? dataTypeOf(String name) { DataType? rc; - switch (name) { - case 'id': - rc = DataType.reference; - break; - case 'name': - rc = DataType.string; - break; - case 'created': - rc = DataType.datetime; - break; - case 'createdBy': - rc = DataType.string; - break; - case 'changed': - rc = DataType.datetime; - break; - case 'changedBy': - rc = DataType.string; - break; - default: - break; + switch(name){ + case 'id': + rc = DataType.reference; + break; + case 'name': + rc = DataType.string; + break; + case 'created': + rc = DataType.datetime; + break; + case 'createdBy': + rc = DataType.string; + break; + case 'changed': + rc = DataType.datetime; + break; + case 'changedBy': + rc = DataType.string; + break; + default: + break; } return rc; } - @override DataMap toMap({DataMap? map, bool clear = true}) { map ??= DataMap(); diff --git a/lib/page/structures/create_structure_custom.dart b/lib/page/structures/create_structure_custom.dart index 1132463..c86d7af 100644 --- a/lib/page/structures/create_structure_custom.dart +++ b/lib/page/structures/create_structure_custom.dart @@ -2,30 +2,102 @@ // It will never overridden by the meta_tool. import 'package:flutter/material.dart'; +import '../../base/defines.dart'; +import '../../base/helper.dart'; import '../../base/i18n.dart'; +import '../../base/validators.dart'; +import '../../services/global_widget.dart'; import '../../setting/global_data.dart'; import '../../widget/attended_page.dart'; +import '../../widget/message_line.dart'; import '../../widget/widget_form.dart'; import 'create_structure_page.dart'; final i18n = I18N(); -class CreateStructureCustom extends State { +class CreateStructureCustom extends State with MessageLine { final globalData = GlobalData(); AttendedPage? attendedPage; - + final _fieldData = _FieldData(); + final GlobalKey _formKey = + GlobalKey(debugLabel: 'CreateStructure'); + final scopeController = TextEditingController(); + final nameController = TextEditingController(); + final valueController = TextEditingController(); + final positionController = TextEditingController(); CreateStructureCustom(); @override Widget build(BuildContext context) { final padding = GlobalThemeData.padding; + scopeController.text = _fieldData.scope; + nameController.text = _fieldData.name; + valueController.text = _fieldData.value; + positionController.text = asString(_fieldData.position); + final formItems = [ + FormItem( + TextFormField( + controller: scopeController, + decoration: InputDecoration(labelText: i18n.tr('Scope')), + validator: (input) => notEmpty(input), + onSaved: (value) => _fieldData.scope = value ?? '' + ), + weight: 6), + FormItem( + TextFormField( + controller: nameController, + decoration: InputDecoration(labelText: i18n.tr('Name')), + validator: (input) => notEmpty(input), + onSaved: (value) => _fieldData.name = value ?? '' + ), + weight: 6), + FormItem( + TextFormField( + controller: valueController, + decoration: InputDecoration(labelText: i18n.tr('Value')), + validator: (input) => notEmpty(input), + onSaved: (value) => _fieldData.value = value ?? '' + ), + weight: 6), + FormItem( + TextFormField( + controller: positionController, + decoration: InputDecoration(labelText: i18n.tr('Position')), + onSaved: (value) => _fieldData.position = fromString(value ?? '', dataType: DataType.int) + ), + weight: 6), + FormItem( + ElevatedButton( + onPressed: () => verifyAndStore(), + child: Text(i18n.tr('Save'))), + weight: 8, + gapAbove: 2 * padding), + FormItem( + ElevatedButton( + onPressed: () { + attendedPage!.pageStates.dbDataState.clear(); + globalData.navigate(context, '/Structures/list'); + }, + child: Text(i18n.tr('Cancel')), + ), + weight: 4) + ]; final rc = Scaffold( - appBar: globalData.appBarBuilder(i18n.tr('Change Structure data')), + appBar: globalData.appBarBuilder(i18n.tr('New Structure')), drawer: globalData.drawerBuilder(context), body: SafeArea( - child: WidgetForm.flexibleGridAttended( - attendedPage!.attendedWidgets(), - screenWidth: attendedPage!.pageStates.screenWidth, - padding: padding))); + child: Form( + key: _formKey, + child: Card( + margin: EdgeInsets.symmetric( + vertical: padding, horizontal: padding), + child: Padding( + padding: EdgeInsets.symmetric( + vertical: padding, horizontal: padding), + child: WidgetForm.flexibleGrid( + formItems, + screenWidth: attendedPage!.pageStates.screenWidth, + padding: padding, + )))))); return rc; } @@ -33,4 +105,58 @@ class CreateStructureCustom extends State { void initState() { super.initState(); } + + void store() { + final parameters = { + 'module': 'Structures', + 'sql': 'insert', + }; + _fieldData.toMap(parameters); + globalData.restPersistence! + .store(what: 'store', map: parameters) + .then((answer) { + if (answer.startsWith('id:')) { + final id = int.tryParse(answer.substring(3)); + if (id == null || id == 0) { + setError(i18n.tr('Saving data failed: $answer')); + setState(() => 1); + } else { + attendedPage!.pageStates.dbDataState.clear(); + globalData.navigate(context, '/Structures/edit;$id'); + } + } + }); + } + + void verifyAndStore() { + if (_formKey.currentState!.validate()) { + _formKey.currentState!.save(); + store(); + } + } + + @override + void dispose() { + scopeController.dispose(); + nameController.dispose(); + valueController.dispose(); + positionController.dispose(); + super.dispose(); + } +} + +class _FieldData { + String scope = ''; + String name = ''; + String value = ''; + int position = 0; + + + void toMap(Map map) { + map[':scope'] = scope; + map[':name'] = name; + map[':value'] = value; + map[':position'] = asString(position); + map[':createdBy'] = GlobalData.loginUserName; + } } diff --git a/lib/page/structures/create_structure_page.dart b/lib/page/structures/create_structure_page.dart index e27c01e..88aa0fb 100644 --- a/lib/page/structures/create_structure_page.dart +++ b/lib/page/structures/create_structure_page.dart @@ -12,15 +12,15 @@ class CreateStructurePage extends StatefulWidget { @override _CreateStructurePageState createState() { final rc = _CreateStructurePageState(); - rc.attendedPage = AttendedPage( - this, rc, GlobalData(), StructureMeta.instance, pageStates); + rc.attendedPage = + AttendedPage(this, rc, GlobalData(), StructureMeta.instance, pageStates); pageStates.attendedPage = rc.attendedPage; return rc; } } class _CreateStructurePageState extends CreateStructureCustom { - _CreateStructurePageState() : super(); + _CreateStructurePageState(): super(); @override void didChangeDependencies() { final size = MediaQuery.of(context).size; diff --git a/lib/page/structures/delete_structure_custom.dart b/lib/page/structures/delete_structure_custom.dart index d1dcfb2..fc775c3 100644 --- a/lib/page/structures/delete_structure_custom.dart +++ b/lib/page/structures/delete_structure_custom.dart @@ -2,31 +2,108 @@ // It will never overridden by the meta_tool. import 'package:flutter/material.dart'; +import '../../base/defines.dart'; +import '../../base/helper.dart'; import '../../base/i18n.dart'; +import '../../base/validators.dart'; +import '../../services/global_widget.dart'; import '../../setting/global_data.dart'; import '../../widget/attended_page.dart'; +import '../../widget/message_line.dart'; import '../../widget/widget_form.dart'; import 'delete_structure_page.dart'; final i18n = I18N(); -class DeleteStructureCustom extends State { +class DeleteStructureCustom extends State with MessageLine { final int primaryKey; final globalData = GlobalData(); AttendedPage? attendedPage; - + final _fieldData = _FieldData(); + final GlobalKey _formKey = + GlobalKey(debugLabel: 'DeleteStructure'); + final scopeController = TextEditingController(); + final nameController = TextEditingController(); + final valueController = TextEditingController(); + final positionController = TextEditingController(); DeleteStructureCustom(this.primaryKey); @override Widget build(BuildContext context) { final padding = GlobalThemeData.padding; + attendedPage?.loadRecord( + name: 'record', + reload: () => setState(() => 1), + onDone: (record) => _fieldData.fromMap(record), + parameters: {'module': 'Structures', 'sql': 'byId', ':id': primaryKey}); + scopeController.text = _fieldData.scope; + nameController.text = _fieldData.name; + valueController.text = _fieldData.value; + positionController.text = asString(_fieldData.position); + final formItems = [ + FormItem( + TextFormField( + controller: scopeController, + decoration: InputDecoration(labelText: i18n.tr('Scope')), + validator: (input) => notEmpty(input), + onSaved: (value) => _fieldData.scope = value ?? '' + ), + weight: 6), + FormItem( + TextFormField( + controller: nameController, + decoration: InputDecoration(labelText: i18n.tr('Name')), + validator: (input) => notEmpty(input), + onSaved: (value) => _fieldData.name = value ?? '' + ), + weight: 6), + FormItem( + TextFormField( + controller: valueController, + decoration: InputDecoration(labelText: i18n.tr('Value')), + validator: (input) => notEmpty(input), + onSaved: (value) => _fieldData.value = value ?? '' + ), + weight: 6), + FormItem( + TextFormField( + controller: positionController, + decoration: InputDecoration(labelText: i18n.tr('Position')), + onSaved: (value) => _fieldData.position = fromString(value ?? '', dataType: DataType.int) + ), + weight: 6), + FormItem( + ElevatedButton( + onPressed: () => verifyAndDelete(), + child: Text(i18n.tr('Delete'))), + weight: 8, + gapAbove: 2 * padding), + FormItem( + ElevatedButton( + onPressed: () { + attendedPage!.pageStates.dbDataState.clear(); + globalData.navigate(context, '/Structures/list'); + }, + child: Text(i18n.tr('Cancel')), + ), + weight: 4) + ]; final rc = Scaffold( - appBar: globalData.appBarBuilder(i18n.tr('Change Structure data')), + appBar: globalData.appBarBuilder(i18n.tr('Delete Structure')), drawer: globalData.drawerBuilder(context), body: SafeArea( - child: WidgetForm.flexibleGridAttended( - attendedPage!.attendedWidgets(), - screenWidth: attendedPage!.pageStates.screenWidth, - padding: padding))); + child: Form( + key: _formKey, + child: Card( + margin: EdgeInsets.symmetric( + vertical: padding, horizontal: padding), + child: Padding( + padding: EdgeInsets.symmetric( + vertical: padding, horizontal: padding), + child: WidgetForm.flexibleGrid( + formItems, + screenWidth: attendedPage!.pageStates.screenWidth, + padding: padding, + )))))); return rc; } @@ -34,4 +111,47 @@ class DeleteStructureCustom extends State { void initState() { super.initState(); } + + void delete() { + final parameters = { + 'module': 'Structures', + 'sql': 'delete', + }; + parameters[':id'] = primaryKey; + globalData.restPersistence! + .store(what: 'store', map: parameters) + .then((answer) { + globalData.navigate(context, '/Structures/list'); + }); + } + + void verifyAndDelete() { + if (_formKey.currentState!.validate()) { + _formKey.currentState!.save(); + delete(); + } + } + + @override + void dispose() { + scopeController.dispose(); + nameController.dispose(); + valueController.dispose(); + positionController.dispose(); + super.dispose(); + } +} + +class _FieldData { + String scope = ''; + String name = ''; + String value = ''; + int position = 0; + + void fromMap(Map map) { + scope = map['structure_scope']; + name = map['structure_name']; + value = map['structure_value']; + position = map['structure_position']; + } } diff --git a/lib/page/structures/delete_structure_page.dart b/lib/page/structures/delete_structure_page.dart index cc888a8..2bdedf3 100644 --- a/lib/page/structures/delete_structure_page.dart +++ b/lib/page/structures/delete_structure_page.dart @@ -13,15 +13,15 @@ class DeleteStructurePage extends StatefulWidget { @override _DeleteStructurePageState createState() { final rc = _DeleteStructurePageState(this.primaryKey); - rc.attendedPage = AttendedPage( - this, rc, GlobalData(), StructureMeta.instance, pageStates); + rc.attendedPage = + AttendedPage(this, rc, GlobalData(), StructureMeta.instance, pageStates); pageStates.attendedPage = rc.attendedPage; return rc; } } class _DeleteStructurePageState extends DeleteStructureCustom { - _DeleteStructurePageState(int primaryKey) : super(primaryKey); + _DeleteStructurePageState(int primaryKey): super(primaryKey); @override void didChangeDependencies() { final size = MediaQuery.of(context).size; diff --git a/lib/page/structures/edit_structure_custom.dart b/lib/page/structures/edit_structure_custom.dart index b331083..58fe2a8 100644 --- a/lib/page/structures/edit_structure_custom.dart +++ b/lib/page/structures/edit_structure_custom.dart @@ -2,31 +2,108 @@ // It will never overridden by the meta_tool. import 'package:flutter/material.dart'; +import '../../base/defines.dart'; +import '../../base/helper.dart'; import '../../base/i18n.dart'; +import '../../base/validators.dart'; +import '../../services/global_widget.dart'; import '../../setting/global_data.dart'; import '../../widget/attended_page.dart'; +import '../../widget/message_line.dart'; import '../../widget/widget_form.dart'; import 'edit_structure_page.dart'; final i18n = I18N(); -class EditStructureCustom extends State { +class EditStructureCustom extends State with MessageLine { final int primaryKey; final globalData = GlobalData(); AttendedPage? attendedPage; - + final _fieldData = _FieldData(); + final GlobalKey _formKey = + GlobalKey(debugLabel: 'EditStructure'); + final scopeController = TextEditingController(); + final nameController = TextEditingController(); + final valueController = TextEditingController(); + final positionController = TextEditingController(); EditStructureCustom(this.primaryKey); @override Widget build(BuildContext context) { final padding = GlobalThemeData.padding; + attendedPage?.loadRecord( + name: 'record', + reload: () => setState(() => 1), + onDone: (record) => _fieldData.fromMap(record), + parameters: {'module': 'Structures', 'sql': 'byId', ':id': primaryKey}); + scopeController.text = _fieldData.scope; + nameController.text = _fieldData.name; + valueController.text = _fieldData.value; + positionController.text = asString(_fieldData.position); + final formItems = [ + FormItem( + TextFormField( + controller: scopeController, + decoration: InputDecoration(labelText: i18n.tr('Scope')), + validator: (input) => notEmpty(input), + onSaved: (value) => _fieldData.scope = value ?? '' + ), + weight: 6), + FormItem( + TextFormField( + controller: nameController, + decoration: InputDecoration(labelText: i18n.tr('Name')), + validator: (input) => notEmpty(input), + onSaved: (value) => _fieldData.name = value ?? '' + ), + weight: 6), + FormItem( + TextFormField( + controller: valueController, + decoration: InputDecoration(labelText: i18n.tr('Value')), + validator: (input) => notEmpty(input), + onSaved: (value) => _fieldData.value = value ?? '' + ), + weight: 6), + FormItem( + TextFormField( + controller: positionController, + decoration: InputDecoration(labelText: i18n.tr('Position')), + onSaved: (value) => _fieldData.position = fromString(value ?? '', dataType: DataType.int) + ), + weight: 6), + FormItem( + ElevatedButton( + onPressed: () => verifyAndStore(), + child: Text(i18n.tr('Save'))), + weight: 8, + gapAbove: 2 * padding), + FormItem( + ElevatedButton( + onPressed: () { + attendedPage!.pageStates.dbDataState.clear(); + globalData.navigate(context, '/Structures/list'); + }, + child: Text(i18n.tr('Cancel')), + ), + weight: 4) + ]; final rc = Scaffold( - appBar: globalData.appBarBuilder(i18n.tr('Change Structure data')), + appBar: globalData.appBarBuilder(i18n.tr('Change Structure')), drawer: globalData.drawerBuilder(context), body: SafeArea( - child: WidgetForm.flexibleGridAttended( - attendedPage!.attendedWidgets(), - screenWidth: attendedPage!.pageStates.screenWidth, - padding: padding))); + child: Form( + key: _formKey, + child: Card( + margin: EdgeInsets.symmetric( + vertical: padding, horizontal: padding), + child: Padding( + padding: EdgeInsets.symmetric( + vertical: padding, horizontal: padding), + child: WidgetForm.flexibleGrid( + formItems, + screenWidth: attendedPage!.pageStates.screenWidth, + padding: padding, + )))))); return rc; } @@ -34,4 +111,55 @@ class EditStructureCustom extends State { void initState() { super.initState(); } + + void store() { + final parameters = { + 'module': 'Structures', + 'sql': 'update', + }; + parameters[':id'] = primaryKey; + _fieldData.toMap(parameters); + globalData.restPersistence! + .store(what: 'store', map: parameters) + .then((answer) {}); + } + + void verifyAndStore() { + if (_formKey.currentState!.validate()) { + _formKey.currentState!.save(); + store(); + } + } + + @override + void dispose() { + scopeController.dispose(); + nameController.dispose(); + valueController.dispose(); + positionController.dispose(); + super.dispose(); + } +} + +class _FieldData { + String scope = ''; + String name = ''; + String value = ''; + int position = 0; + + void fromMap(Map map) { + scope = map['structure_scope']; + name = map['structure_name']; + value = map['structure_value']; + position = map['structure_position']; + } + + void toMap(Map map) { + // please set outside: map[':id'] = primaryKey; + map[':scope'] = scope; + map[':name'] = name; + map[':value'] = value; + map[':position'] = asString(position); + map[':changedBy'] = GlobalData.loginUserName; + } } diff --git a/lib/page/structures/edit_structure_page.dart b/lib/page/structures/edit_structure_page.dart index a689d34..c151f66 100644 --- a/lib/page/structures/edit_structure_page.dart +++ b/lib/page/structures/edit_structure_page.dart @@ -13,15 +13,15 @@ class EditStructurePage extends StatefulWidget { @override _EditStructurePageState createState() { final rc = _EditStructurePageState(this.primaryKey); - rc.attendedPage = AttendedPage( - this, rc, GlobalData(), StructureMeta.instance, pageStates); + rc.attendedPage = + AttendedPage(this, rc, GlobalData(), StructureMeta.instance, pageStates); pageStates.attendedPage = rc.attendedPage; return rc; } } class _EditStructurePageState extends EditStructureCustom { - _EditStructurePageState(int primaryKey) : super(primaryKey); + _EditStructurePageState(int primaryKey): super(primaryKey); @override void didChangeDependencies() { final size = MediaQuery.of(context).size; diff --git a/lib/page/structures/list_structure_custom.dart b/lib/page/structures/list_structure_custom.dart index eb54b7d..28c0a64 100644 --- a/lib/page/structures/list_structure_custom.dart +++ b/lib/page/structures/list_structure_custom.dart @@ -2,7 +2,9 @@ // It will never overridden by the meta_tool. import 'package:flutter/material.dart'; +import '../../base/helper.dart'; import '../../base/i18n.dart'; +import '../../services/global_widget.dart'; import '../../setting/global_data.dart'; import '../../widget/attended_page.dart'; import '../../widget/widget_form.dart'; @@ -13,24 +15,103 @@ final i18n = I18N(); class ListStructureCustom extends State { final globalData = GlobalData(); AttendedPage? attendedPage; - + final _fieldData = _FieldData(); + final GlobalKey _formKey = + GlobalKey(debugLabel: 'CreateStructure'); + final textController = TextEditingController(); ListStructureCustom(); @override Widget build(BuildContext context) { final padding = GlobalThemeData.padding; + final formItems = [ + FormItem( + TextFormField( + controller: textController, + decoration: InputDecoration(labelText: i18n.tr('Text')), + onSaved: (value) => _fieldData.text = value ?? '' + ), + weight: 6), + FormItem( + ElevatedButton( + onPressed: () => search(), child: Text(i18n.tr('Search'))), + weight: 12, + gapAbove: padding), + ]; + final form = Form( + key: _formKey, + child: Card( + color: GlobalThemeData.formBackgroundColor, + elevation: GlobalThemeData.formElevation, + margin: + EdgeInsets.symmetric(vertical: padding, horizontal: padding), + child: Padding( + padding: EdgeInsets.symmetric( + vertical: padding, horizontal: padding), + child: WidgetForm.flexibleGrid(formItems, + screenWidth: attendedPage!.pageStates.screenWidth, + padding: padding)))); + final rows = attendedPage!.getRows( + columnList: 'structure_id;structure_scope;structure_name;structure_value;structure_position', + what: 'query', + parameters: { + 'module': 'Structures', + 'sql': 'list', + 'offset': '0', + 'size': '10', + ':text': _fieldData.text, + }, + onDone: () => setState(() => 1), + routeEdit: '/Structures/edit', + context: context); + final table = DataTable( + columns: [ + DataColumn( + label: Text(i18n.tr('d;Scope;Name;Value;Position')), + ), + ], + rows: rows, + ); + final frameWidget = Column(children: [ + form, + SizedBox(height: padding), + SizedBox(width: double.infinity, child: table), + ]); final rc = Scaffold( - appBar: globalData.appBarBuilder(i18n.tr('Change Structure data')), + appBar: globalData.appBarBuilder(i18n.tr('Overview structures')), drawer: globalData.drawerBuilder(context), - body: SafeArea( - child: WidgetForm.flexibleGridAttended( - attendedPage!.attendedWidgets(), - screenWidth: attendedPage!.pageStates.screenWidth, - padding: padding))); + floatingActionButton: FloatingActionButton( + onPressed: () { + globalData.navigate(context, '/Structures/create'); + }, + child: const Icon(Icons.add), + //backgroundColor: Colors.green, + ), + body: SafeArea(child: frameWidget)); return rc; } + @override + void dispose() { + helperDummyUsage(); + globalWidgetDummyUsage(); + textController.dispose(); + super.dispose(); + } + @override void initState() { super.initState(); } + + void search() { + attendedPage!.pageStates.dbDataState.clear(); + if (_formKey.currentState!.validate()) { + _formKey.currentState!.save(); + setState(() => 1); + } + } +} + +class _FieldData { + String text = ''; } diff --git a/lib/page/structures/list_structure_page.dart b/lib/page/structures/list_structure_page.dart index 55c901c..e286fbc 100644 --- a/lib/page/structures/list_structure_page.dart +++ b/lib/page/structures/list_structure_page.dart @@ -12,15 +12,15 @@ class ListStructurePage extends StatefulWidget { @override _ListStructurePageState createState() { final rc = _ListStructurePageState(); - rc.attendedPage = AttendedPage( - this, rc, GlobalData(), StructureMeta.instance, pageStates); + rc.attendedPage = + AttendedPage(this, rc, GlobalData(), StructureMeta.instance, pageStates); pageStates.attendedPage = rc.attendedPage; return rc; } } class _ListStructurePageState extends ListStructureCustom { - _ListStructurePageState() : super(); + _ListStructurePageState(): super(); @override void didChangeDependencies() { final size = MediaQuery.of(context).size; diff --git a/lib/page/structures/structure_data.dart b/lib/page/structures/structure_data.dart new file mode 100644 index 0000000..85285ec --- /dev/null +++ b/lib/page/structures/structure_data.dart @@ -0,0 +1,92 @@ +// DO NOT CHANGE. This file is created by the meta_tool +import '../../base/defines.dart'; +import '../../base/helper.dart'; +import '../../persistence/data_record.dart'; +class StructureData extends DataRecord{ + int? id; + String? scope; + String? name; + String? value; + int? position; + DateTime? created; + String? createdBy; + DateTime? changed; + String? changedBy; + StructureData({ + this.id, this.scope, this.name, this.value, this.position, this.created, this.createdBy, this.changed, this.changedBy}); + StructureData.createFromMap(DataMap map) { + fromMap(map); + } + @override + void fromMap(DataMap map) { + id = map.containsKey('structure_id') ? fromString(map['structure_id'], dataType: DataType.reference) : null; + scope = map.containsKey('structure_scope') ? fromString(map['structure_scope'], dataType: DataType.string) : null; + name = map.containsKey('structure_name') ? fromString(map['structure_name'], dataType: DataType.string) : null; + value = map.containsKey('structure_value') ? fromString(map['structure_value'], dataType: DataType.string) : null; + position = map.containsKey('structure_position') ? fromString(map['structure_position'], dataType: DataType.int) : null; + created = map.containsKey('structure_created') ? fromString(map['structure_created'], dataType: DataType.datetime) : null; + createdBy = map.containsKey('structure_createdby') ? fromString(map['structure_createdby'], dataType: DataType.string) : null; + changed = map.containsKey('structure_changed') ? fromString(map['structure_changed'], dataType: DataType.datetime) : null; + changedBy = map.containsKey('structure_changedby') ? fromString(map['structure_changedby'], dataType: DataType.string) : null; + } + @override + int keyOf() { + return id ?? 0; + } + @override + String nameOfKey(){ + return 'structure_id'; + } + static DataType? dataTypeOf(String name) { + DataType? rc; + switch(name){ + case 'id': + rc = DataType.reference; + break; + case 'scope': + rc = DataType.string; + break; + case 'name': + rc = DataType.string; + break; + case 'value': + rc = DataType.string; + break; + case 'position': + rc = DataType.int; + break; + case 'created': + rc = DataType.datetime; + break; + case 'createdBy': + rc = DataType.string; + break; + case 'changed': + rc = DataType.datetime; + break; + case 'changedBy': + rc = DataType.string; + break; + default: + break; + } + return rc; + } + @override + DataMap toMap({DataMap? map, bool clear = true}) { + map ??= DataMap(); + if (clear) { + map.clear(); + } + map['structure_id'] = id; + map['structure_scope'] = scope; + map['structure_name'] = name; + map['structure_value'] = value; + map['structure_position'] = position; + map['structure_created'] = created; + map['structure_createdby'] = createdBy; + map['structure_changed'] = changed; + map['structure_changedby'] = changedBy; + return map; + } +} diff --git a/lib/page/users/create_user_custom.dart b/lib/page/users/create_user_custom.dart index c0da66b..615970d 100644 --- a/lib/page/users/create_user_custom.dart +++ b/lib/page/users/create_user_custom.dart @@ -2,6 +2,8 @@ // It will never overridden by the meta_tool. import 'package:flutter/material.dart'; +import '../../base/defines.dart'; +import '../../base/helper.dart'; import '../../base/i18n.dart'; import '../../base/validators.dart'; import '../../services/global_widget.dart'; @@ -39,7 +41,7 @@ class CreateUserCustom extends State with MessageLine { controller: nameController, decoration: InputDecoration(labelText: i18n.tr('Name')), validator: (input) => notEmpty(input), - onSaved: (value) => _fieldData.name = value ?? '', + onSaved: (value) => _fieldData.name = value ?? '' ), weight: 6), FormItem( @@ -47,7 +49,7 @@ class CreateUserCustom extends State with MessageLine { controller: displayNameController, decoration: InputDecoration(labelText: i18n.tr('Display name')), validator: (input) => notEmpty(input), - onSaved: (value) => _fieldData.displayName = value ?? '', + onSaved: (value) => _fieldData.displayName = value ?? '' ), weight: 6), FormItem( @@ -55,7 +57,7 @@ class CreateUserCustom extends State with MessageLine { controller: emailController, decoration: InputDecoration(labelText: i18n.tr('EMail')), validator: (input) => notEmpty(input), - onSaved: (value) => _fieldData.email = value ?? '', + onSaved: (value) => _fieldData.email = value ?? '' ), weight: 6), FormItem( @@ -69,7 +71,8 @@ class CreateUserCustom extends State with MessageLine { weight: 6), FormItem( ElevatedButton( - onPressed: () => verifyAndStore(), child: Text(i18n.tr('Save'))), + onPressed: () => verifyAndStore(), + child: Text(i18n.tr('Save'))), weight: 8, gapAbove: 2 * padding), FormItem( @@ -151,11 +154,12 @@ class _FieldData { String email = ''; int role = 0; + void toMap(Map map) { map[':name'] = name; map[':displayName'] = displayName; map[':email'] = email; - map[':role'] = role; + map[':role'] = asString(role); map[':createdBy'] = GlobalData.loginUserName; } } diff --git a/lib/page/users/create_user_page.dart b/lib/page/users/create_user_page.dart index 71a2c05..14e69e2 100644 --- a/lib/page/users/create_user_page.dart +++ b/lib/page/users/create_user_page.dart @@ -20,7 +20,7 @@ class CreateUserPage extends StatefulWidget { } class _CreateUserPageState extends CreateUserCustom { - _CreateUserPageState() : super(); + _CreateUserPageState(): super(); @override void didChangeDependencies() { final size = MediaQuery.of(context).size; diff --git a/lib/page/users/delete_user_custom.dart b/lib/page/users/delete_user_custom.dart index 65cfc7a..64f531d 100644 --- a/lib/page/users/delete_user_custom.dart +++ b/lib/page/users/delete_user_custom.dart @@ -2,6 +2,8 @@ // It will never overridden by the meta_tool. import 'package:flutter/material.dart'; +import '../../base/defines.dart'; +import '../../base/helper.dart'; import '../../base/i18n.dart'; import '../../base/validators.dart'; import '../../services/global_widget.dart'; @@ -45,7 +47,7 @@ class DeleteUserCustom extends State with MessageLine { controller: nameController, decoration: InputDecoration(labelText: i18n.tr('Name')), validator: (input) => notEmpty(input), - onSaved: (value) => _fieldData.name = value ?? '', + onSaved: (value) => _fieldData.name = value ?? '' ), weight: 6), FormItem( @@ -53,7 +55,7 @@ class DeleteUserCustom extends State with MessageLine { controller: displayNameController, decoration: InputDecoration(labelText: i18n.tr('Display name')), validator: (input) => notEmpty(input), - onSaved: (value) => _fieldData.displayName = value ?? '', + onSaved: (value) => _fieldData.displayName = value ?? '' ), weight: 6), FormItem( @@ -61,7 +63,7 @@ class DeleteUserCustom extends State with MessageLine { controller: emailController, decoration: InputDecoration(labelText: i18n.tr('EMail')), validator: (input) => notEmpty(input), - onSaved: (value) => _fieldData.email = value ?? '', + onSaved: (value) => _fieldData.email = value ?? '' ), weight: 6), FormItem( diff --git a/lib/page/users/delete_user_page.dart b/lib/page/users/delete_user_page.dart index 8bbef4c..85cbfc9 100644 --- a/lib/page/users/delete_user_page.dart +++ b/lib/page/users/delete_user_page.dart @@ -21,7 +21,7 @@ class DeleteUserPage extends StatefulWidget { } class _DeleteUserPageState extends DeleteUserCustom { - _DeleteUserPageState(int primaryKey) : super(primaryKey); + _DeleteUserPageState(int primaryKey): super(primaryKey); @override void didChangeDependencies() { final size = MediaQuery.of(context).size; diff --git a/lib/page/users/edit_user_custom.dart b/lib/page/users/edit_user_custom.dart index 81685c3..70a9f50 100644 --- a/lib/page/users/edit_user_custom.dart +++ b/lib/page/users/edit_user_custom.dart @@ -2,6 +2,8 @@ // It will never overridden by the meta_tool. import 'package:flutter/material.dart'; +import '../../base/defines.dart'; +import '../../base/helper.dart'; import '../../base/i18n.dart'; import '../../base/validators.dart'; import '../../services/global_widget.dart'; @@ -45,7 +47,7 @@ class EditUserCustom extends State with MessageLine { controller: nameController, decoration: InputDecoration(labelText: i18n.tr('Name')), validator: (input) => notEmpty(input), - onSaved: (value) => _fieldData.name = value ?? '', + onSaved: (value) => _fieldData.name = value ?? '' ), weight: 6), FormItem( @@ -53,7 +55,7 @@ class EditUserCustom extends State with MessageLine { controller: displayNameController, decoration: InputDecoration(labelText: i18n.tr('Display name')), validator: (input) => notEmpty(input), - onSaved: (value) => _fieldData.displayName = value ?? '', + onSaved: (value) => _fieldData.displayName = value ?? '' ), weight: 6), FormItem( @@ -61,7 +63,7 @@ class EditUserCustom extends State with MessageLine { controller: emailController, decoration: InputDecoration(labelText: i18n.tr('EMail')), validator: (input) => notEmpty(input), - onSaved: (value) => _fieldData.email = value ?? '', + onSaved: (value) => _fieldData.email = value ?? '' ), weight: 6), FormItem( @@ -75,7 +77,8 @@ class EditUserCustom extends State with MessageLine { weight: 6), FormItem( ElevatedButton( - onPressed: () => verifyAndStore(), child: Text(i18n.tr('Save'))), + onPressed: () => verifyAndStore(), + child: Text(i18n.tr('Save'))), weight: 8, gapAbove: 2 * padding), FormItem( @@ -159,7 +162,7 @@ class _FieldData { map[':name'] = name; map[':displayName'] = displayName; map[':email'] = email; - map[':role'] = role; + map[':role'] = asString(role); map[':changedBy'] = GlobalData.loginUserName; } } diff --git a/lib/page/users/edit_user_page.dart b/lib/page/users/edit_user_page.dart index 4b2e75f..1179663 100644 --- a/lib/page/users/edit_user_page.dart +++ b/lib/page/users/edit_user_page.dart @@ -21,7 +21,7 @@ class EditUserPage extends StatefulWidget { } class _EditUserPageState extends EditUserCustom { - _EditUserPageState(int primaryKey) : super(primaryKey); + _EditUserPageState(int primaryKey): super(primaryKey); @override void didChangeDependencies() { final size = MediaQuery.of(context).size; diff --git a/lib/page/users/list_user_custom.dart b/lib/page/users/list_user_custom.dart index 4a62b31..b6b8727 100644 --- a/lib/page/users/list_user_custom.dart +++ b/lib/page/users/list_user_custom.dart @@ -32,7 +32,7 @@ class ListUserCustom extends State { TextFormField( controller: textController, decoration: InputDecoration(labelText: i18n.tr('Text')), - onSaved: (value) => _fieldData.text = value ?? '', + onSaved: (value) => _fieldData.text = value ?? '' ), weight: 6), FormItem( @@ -118,6 +118,8 @@ class ListUserCustom extends State { @override void dispose() { + helperDummyUsage(); + globalWidgetDummyUsage(); textController.dispose(); super.dispose(); } diff --git a/lib/page/users/list_user_page.dart b/lib/page/users/list_user_page.dart index 2723f48..1938d3d 100644 --- a/lib/page/users/list_user_page.dart +++ b/lib/page/users/list_user_page.dart @@ -20,7 +20,7 @@ class ListUserPage extends StatefulWidget { } class _ListUserPageState extends ListUserCustom { - _ListUserPageState() : super(); + _ListUserPageState(): super(); @override void didChangeDependencies() { final size = MediaQuery.of(context).size; diff --git a/lib/page/users/user_data.dart b/lib/page/users/user_data.dart index 5562cfd..d27593e 100644 --- a/lib/page/users/user_data.dart +++ b/lib/page/users/user_data.dart @@ -2,8 +2,7 @@ import '../../base/defines.dart'; import '../../base/helper.dart'; import '../../persistence/data_record.dart'; - -class UserData extends DataRecord { +class UserData extends DataRecord{ int? id; String? name; String? displayName; @@ -13,96 +12,66 @@ class UserData extends DataRecord { String? createdBy; DateTime? changed; String? changedBy; - UserData( - {this.id, - this.name, - this.displayName, - this.email, - this.role, - this.created, - this.createdBy, - this.changed, - this.changedBy}); + UserData({ + this.id, this.name, this.displayName, this.email, this.role, this.created, this.createdBy, this.changed, this.changedBy}); UserData.createFromMap(DataMap map) { fromMap(map); } @override void fromMap(DataMap map) { - id = map.containsKey('user_id') - ? valueOf(DataType.reference, map['user_id']) - : null; - name = map.containsKey('user_name') - ? valueOf(DataType.string, map['user_name']) - : null; - displayName = map.containsKey('user_displayname') - ? valueOf(DataType.string, map['user_displayname']) - : null; - email = map.containsKey('user_email') - ? valueOf(DataType.string, map['user_email']) - : null; - role = map.containsKey('user_role') - ? valueOf(DataType.reference, map['user_role']) - : null; - created = map.containsKey('user_created') - ? valueOf(DataType.datetime, map['user_created']) - : null; - createdBy = map.containsKey('user_createdby') - ? valueOf(DataType.string, map['user_createdby']) - : null; - changed = map.containsKey('user_changed') - ? valueOf(DataType.datetime, map['user_changed']) - : null; - changedBy = map.containsKey('user_changedby') - ? valueOf(DataType.string, map['user_changedby']) - : null; + id = map.containsKey('user_id') ? fromString(map['user_id'], dataType: DataType.reference) : null; + name = map.containsKey('user_name') ? fromString(map['user_name'], dataType: DataType.string) : null; + displayName = map.containsKey('user_displayname') ? fromString(map['user_displayname'], dataType: DataType.string) : null; + email = map.containsKey('user_email') ? fromString(map['user_email'], dataType: DataType.string) : null; + role = map.containsKey('user_role') ? fromString(map['user_role'], dataType: DataType.reference) : null; + created = map.containsKey('user_created') ? fromString(map['user_created'], dataType: DataType.datetime) : null; + createdBy = map.containsKey('user_createdby') ? fromString(map['user_createdby'], dataType: DataType.string) : null; + changed = map.containsKey('user_changed') ? fromString(map['user_changed'], dataType: DataType.datetime) : null; + changedBy = map.containsKey('user_changedby') ? fromString(map['user_changedby'], dataType: DataType.string) : null; } - @override int keyOf() { return id ?? 0; } - @override - String nameOfKey() { + String nameOfKey(){ return 'user_id'; } - static DataType? dataTypeOf(String name) { DataType? rc; - switch (name) { - case 'id': - rc = DataType.reference; - break; - case 'name': - rc = DataType.string; - break; - case 'displayName': - rc = DataType.string; - break; - case 'email': - rc = DataType.string; - break; - case 'role': - rc = DataType.reference; - break; - case 'created': - rc = DataType.datetime; - break; - case 'createdBy': - rc = DataType.string; - break; - case 'changed': - rc = DataType.datetime; - break; - case 'changedBy': - rc = DataType.string; - break; - default: - break; + switch(name){ + case 'id': + rc = DataType.reference; + break; + case 'name': + rc = DataType.string; + break; + case 'displayName': + rc = DataType.string; + break; + case 'email': + rc = DataType.string; + break; + case 'role': + rc = DataType.reference; + break; + case 'created': + rc = DataType.datetime; + break; + case 'createdBy': + rc = DataType.string; + break; + case 'changed': + rc = DataType.datetime; + break; + case 'changedBy': + rc = DataType.string; + break; + default: + break; } return rc; } - @override DataMap toMap({DataMap? map, bool clear = true}) { map ??= DataMap(); diff --git a/lib/services/global_widget.dart b/lib/services/global_widget.dart index c826b27..b3261a3 100644 --- a/lib/services/global_widget.dart +++ b/lib/services/global_widget.dart @@ -32,6 +32,12 @@ void comboRolesFromBackend( {'module': 'global', 'sql': 'comboRoles'}, onDone); } +/// This function is only used to avoid compiler warning "unused import" +/// for generated code. +void globalWidgetDummyUsage() { + // nothing to do +} + List>? _combo(String name, String columnValue, String columnText, String? textUndefined, AttendedPage attendedPage) { final records = attendedPage.pageStates.dbDataState.listResponse(name); diff --git a/metatool/bin/generator.dart b/metatool/bin/generator.dart index fa0bb51..4da9320 100644 --- a/metatool/bin/generator.dart +++ b/metatool/bin/generator.dart @@ -54,8 +54,8 @@ class Generator extends PageGenerator { final type = item.dataType.toString(); //id = data.containsKey('id') ? int.tryParse(data['id']) : null; buffer.writeln( - " ${item.name} = map.containsKey('$name') ? valueOf($type, " - "map['$name']) : null;"); + " ${item.name} = map.containsKey('$name') ? " + "fromString(map['$name'], dataType: $type) : null;"); } buffer.writeln(' }'); final name = primary == null ? 'id' : primary.name; @@ -184,7 +184,7 @@ List moduleNames(){ GeneratorBase.classToFilename(module.moduleNameSingular) + '_data.dart'; final directory = name.toLowerCase(); - writeFile('../../lib/page/$directory/$filename', + writeFile('../lib/page/$directory/$filename', generator.createModuleData(module)); } } diff --git a/metatool/bin/generator_base.dart b/metatool/bin/generator_base.dart index fc5fb42..e829ed4 100644 --- a/metatool/bin/generator_base.dart +++ b/metatool/bin/generator_base.dart @@ -36,11 +36,6 @@ class GeneratorBase { logger.log(line); } - String toCamelCase(String name) { - final rc = name.isEmpty ? '' : (name[0].toUpperCase() + name.substring(1)); - return rc; - } - /// Writes a given [contents] into a file named [filename]; void writeFile(String filename, String contents) { logger.log('creating $filename ...'); diff --git a/metatool/bin/page_generator.dart b/metatool/bin/page_generator.dart index 79bc43e..d9ddf20 100644 --- a/metatool/bin/page_generator.dart +++ b/metatool/bin/page_generator.dart @@ -3,6 +3,7 @@ import 'dart:io'; import 'package:dart_bones/dart_bones.dart'; import '../lib/base/defines.dart'; +import '../lib/base/helper.dart'; import '../lib/meta/module_meta_data.dart'; import '../lib/meta/modules.dart'; import 'generator.dart'; @@ -132,6 +133,8 @@ class ListUserCustom extends State { @override void dispose() { + helperDummyUsage(); + globalWidgetDummyUsage(); #DISPOSE_CONTROLLER super.dispose(); } @@ -158,6 +161,8 @@ class _FieldData { // It will never overridden by the meta_tool. import 'package:flutter/material.dart'; +import '../../base/defines.dart'; +import '../../base/helper.dart'; import '../../base/i18n.dart'; import '../../base/validators.dart'; import '../../services/global_widget.dart'; @@ -248,8 +253,7 @@ class _FieldData { #DEF_FIELD #FROM_MAP#TO_MAP} '''; - static final templateStorageDoneCreate = - ''' + static final templateStorageDoneCreate = ''' if (answer.startsWith('id:')) { final id = int.tryParse(answer.substring(3)); @@ -350,8 +354,11 @@ StatefulWidget? customPageByRoute(String route) { for (var field in page.fields) { if (field.widgetType == WidgetType.property && (field as PropertyMetaData).displayType == DisplayType.text) { - buffer.writeln( - ' ${field.name}Controller.text = _fieldData.${field.name};'); + var value = '_fieldData.${field.name}'; + if (field.dataType != DataType.string) { + value = 'asString($value)'; + } + buffer.writeln(' ${field.name}Controller.text = $value;'); } } return buffer.toString(); @@ -415,12 +422,9 @@ StatefulWidget? customPageByRoute(String route) { value = '0'; break; case DataType.date: - type = 'Date'; - value = 'Date()'; - break; case DataType.datetime: - type = 'DateTime'; - value = 'DateTime()'; + type = 'DateTime?'; + value = 'null'; break; case DataType.string: type = 'String'; @@ -432,7 +436,11 @@ StatefulWidget? customPageByRoute(String route) { break; // throw FormatException('buildDefinitionFields(): missing ${field2.dataType}'); } - buffer.writeln(" $type $name = $value;"); + if (value == 'null') { + buffer.writeln(" $type $name;"); + } else { + buffer.writeln(" $type $name = $value;"); + } } return buffer.toString(); } @@ -477,9 +485,14 @@ StatefulWidget? customPageByRoute(String route) { } validator += ' ]),\n'; } + final value = field.dataType == DataType.string + ? "value ?? ''" + : (field.dataType == DataType.date + ? "fromString(value ?? '', dataType: DataType.date)" + : "fromString(value ?? '', dataType: ${field.dataType})"); rc = '''^TextFormField( #CONTR^ decoration: InputDecoration(labelText: i18n.tr('${field.label}')), -#VALIDATOR^ onSaved: (value) => _fieldData.$name = value ?? '', +#VALIDATOR^ onSaved: (value) => _fieldData.$name = $value ^)''' .replaceFirst('#CONTR', withController ? '^ controller: ${name}Controller,\n' : '') @@ -597,7 +610,7 @@ StatefulWidget? customPageByRoute(String route) { ? '.toString()' : ''; var value = '_fieldData.$name$suffix'; - if (field is PropertyMetaData && field.hasOption(':pattern')){ + if (field is PropertyMetaData && field.hasOption(':pattern')) { value = 'asPattern($value)'; } buffer.writeln(" ':$name': $value,"); @@ -626,7 +639,8 @@ StatefulWidget? customPageByRoute(String route) { String buildToMap(PageMetaData page) { String? rc; if (page.pageType == PageType.edit || page.pageType == PageType.create) { - final buffer = StringBuffer('\n void toMap(Map map) {\n'); + final buffer = + StringBuffer('\n void toMap(Map map) {\n'); if (page.pageType == PageType.edit) { buffer.writeln(" // please set outside: map[':id'] = primaryKey;"); } @@ -635,7 +649,9 @@ StatefulWidget? customPageByRoute(String route) { continue; } final name = field.name; - buffer.writeln(" map[':$name'] = $name;"); + final value = + field.dataType == DataType.string ? name : 'asString($name)'; + buffer.writeln(" map[':$name'] = $value;"); } buffer.writeln(" map[':#'] = GlobalData.loginUserName;".replaceFirst( '#', page.pageType == PageType.edit ? 'changedBy' : 'createdBy')); diff --git a/metatool/bin/sql_generator.dart b/metatool/bin/sql_generator.dart index 208f2fc..1eb0926 100644 --- a/metatool/bin/sql_generator.dart +++ b/metatool/bin/sql_generator.dart @@ -9,6 +9,8 @@ import 'generator_base.dart'; /// Handles the SQL generation part of the generator. class SqlGenerator extends GeneratorBase { + static final regExprParameters = RegExp(r'(:\w+)'); + SqlGenerator(BaseLogger logger) : super(logger); /// Returns a DDL statement creating the database table of the [module]. @@ -49,8 +51,9 @@ class SqlGenerator extends GeneratorBase { for (var page in listPages) { if (page is ListPageMetaData) { var whereCondition = page.whereCondition; - if (whereCondition.endsWith('\n')){ - whereCondition = whereCondition.substring(0, whereCondition.length - 1); + if (whereCondition.endsWith('\n')) { + whereCondition = + whereCondition.substring(0, whereCondition.length - 1); } String selectItems2 = ''; var selectItems = @@ -74,10 +77,15 @@ class SqlGenerator extends GeneratorBase { buffer.writeln(''' type: list parameters: [$parameters] order: "$order" - sql: "SELECT -$selectItems t0.*$selectItems2 - FROM $tableName t0 -$joins$whereCondition ;"'''); + sql: | + SELECT'''); + if (selectItems.isNotEmpty) { + addToBuffer(selectItems, maxLength: 80, buffer: buffer, indent: 6); + } + addToBuffer(' t0.*$selectItems2', + maxLength: 80, buffer: buffer, indent: 6); + buffer.writeln(' FROM $tableName t0'); + buffer.write('$joins$whereCondition'); } } } @@ -111,9 +119,8 @@ update: buffer.write(sqlText); var items = module.standardColumns('changedBy'); var parameters = addToBuffer(' parameters: [', maxLength: 80); - var assignments = addToBuffer(' ', maxLength: 80); + var assignments = StringBuffer(); var firstParameter = true; - var firstAssignment = true; for (var item in items) { if (!item.hasOption('hidden')) { addToBuffer('":${item.name}"', @@ -121,32 +128,32 @@ update: separator: firstParameter ? null : ',', indent: 4, buffer: parameters); - firstParameter = false; if (!item.hasOption('primary')) { - addToBuffer('${item.columnName}=:${item.name}', - maxLength: 80, - separator: firstAssignment ? null : ',', - indent: 4, - buffer: assignments); - firstAssignment = false; + assignments.writeln(' ${item.columnName}=:${item.name},'); } + firstParameter = false; } } parameters.write(']'); var item = module.properties['changed']!; - addToBuffer('${item.columnName}=NOW()', - maxLength: 80, separator: ',', indent: 4, buffer: assignments); + assignments.write(' ${item.columnName}=NOW()'); // parameters: [":id", ":name", ":displayname", ":email", ":changedby"] buffer.writeln(parameters); - buffer.write(' sql: "UPDATE $tableName SET\n'); + buffer.write(' sql: |\n'); + buffer.write(' UPDATE $tableName SET\n'); buffer.writeln(assignments); //user_name=:name, user_displayname=:displayname, user_email=:email, user_changed=NOW(), user_changedby=:changedby - buffer.write(' WHERE ${list[0].columnName}=:${list[0].name};"\n'); + buffer.write(' WHERE ${list[0].columnName}=:${list[0].name};\n'); items = module.standardColumns('createdBy'); parameters = addToBuffer(' parameters: [', maxLength: 80); - final sql1 = addToBuffer(' sql: "INSERT INTO $tableName(', maxLength: 80); - final sql2 = addToBuffer(' VALUES(', maxLength: 80); + final sql1 = StringBuffer(' sql: |\n'); + addToBuffer(' INSERT INTO $tableName(', + maxLength: 80, buffer: sql1, indent: 4); + final sql2 = addToBuffer( + ' VALUES(', + maxLength: 80, + ); var first = true; for (var item in items) { if (!item.hasOption('primary')) { @@ -172,7 +179,7 @@ update: item = module.properties['created']!; addToBuffer('${item.columnName})', maxLength: 80, separator: ',', indent: 4, buffer: sql1); - addToBuffer('NOW());"', + addToBuffer('NOW());', maxLength: 80, separator: ',', indent: 4, buffer: sql2); // parameters: [":name", ":displayname", ":email", ":changedby"] buffer.write('''insert: @@ -183,13 +190,15 @@ update: buffer.writeln(sql2); return buffer.toString(); } - static final regExprParameters = RegExp(r'(:\w+)'); + /// Searches the parameters in the [whereCondition] and checks it against /// the [fields]. String findParameters(String whereCondition, List fields) { - final names = regExprParameters.allMatches(whereCondition) + final names = regExprParameters + .allMatches(whereCondition) .map((element) => element.group(1)) - .toSet().toList(); + .toSet() + .toList(); return '"' + names.join('","') + '"'; } diff --git a/metatool/local.properties b/metatool/local.properties new file mode 100644 index 0000000..77df14c --- /dev/null +++ b/metatool/local.properties @@ -0,0 +1,8 @@ +## This file must *NOT* be checked into Version Control Systems, +# as it contains information specific to your local configuration. +# +# Location of the SDK. This is only used by Gradle. +# For customization when using a Version Control System, please read the +# header note. +#Sat Oct 16 12:51:13 CEST 2021 +sdk.dir=/opt/android diff --git a/metatool/pubspec.yaml b/metatool/pubspec.yaml index 224883d..0d8234a 100644 --- a/metatool/pubspec.yaml +++ b/metatool/pubspec.yaml @@ -1,16 +1,18 @@ -name: meta-tool +name: meta_tool description: A generator of programming code for building Flutter apps. version: 1.0.0 homepage: https://github.com/hamatoma/exhibition environment: - sdk: ">=2.12.0 <3.0.0" +# sdk: ">=2.15.0 <3.0.0" + sdk: ">=2.15.0-163.0.dev <3.0.0" dependencies: meta: ^1.7.0 sprintf: ^6.0.0 yaml: ^3.1.0 path: ^1.8.0 + dart_bones: ^1.2.2 dev_dependencies: pedantic: ^1.11.1 diff --git a/metatool/test/helper_test.dart b/metatool/test/helper_test.dart new file mode 100644 index 0000000..f01c0e8 --- /dev/null +++ b/metatool/test/helper_test.dart @@ -0,0 +1,197 @@ +import 'package:dart_bones/dart_bones.dart'; +import 'package:test/test.dart'; +//import 'package:path/path.dart'; + +import '../lib/base/defines.dart'; +import '../lib/base/helper.dart'; +import '../lib/base/i18n.dart'; + +final i18n = I18N(); + +void main() { + final logger = MemoryLogger(LEVEL_FINE); + I18N.internal(logger); + FileSync.initialize(logger); + //final fileSync = FileSync(); + //final baseDir = init(logger); + //final targetDir = join(baseDir, nodeTarget); + //fileSync.ensureDirectory(targetDir); + group('fromString', () { + test('bool', () { + expect(fromString('T', dataType: DataType.bool, defaultValue: false), isTrue); + expect(fromString('F', dataType: DataType.bool, defaultValue: true), isFalse); + expect(fromString(i18n.tr('Yes'), dataType: DataType.bool, defaultValue: false), isTrue); + expect(fromString(i18n.tr('No'), dataType: DataType.bool, defaultValue: true), isFalse); + expect(fromString('', dataType: DataType.bool, defaultValue: false), isFalse); + expect(fromString('', dataType: DataType.bool, defaultValue: true), isTrue); + }); + test('int', () + { + expect(fromString('123', dataType: DataType.int, defaultValue: -1), + 123); + expect(fromString('-1234', dataType: DataType.int, defaultValue: -1), + -1234); + expect(fromString('', dataType: DataType.int, defaultValue: -1), + -1); + expect(fromString('a15', dataType: DataType.int, defaultValue: -1), + -1); + }); + test('nat', () + { + expect(fromString('123', dataType: DataType.nat, defaultValue: -1), + 123); + expect(fromString('-1234', dataType: DataType.nat, defaultValue: -1), + -1); + expect(fromString('', dataType: DataType.nat, defaultValue: -1), + -1); + expect(fromString('a15', dataType: DataType.nat, defaultValue: -1), + -1); + }); + test('reference', () + { + expect(fromString('123', dataType: DataType.reference, defaultValue: -1), + 123); + expect(fromString('-1234', dataType: DataType.reference, defaultValue: -1), + -1234); + expect(fromString('', dataType: DataType.reference, defaultValue: -1), + -1); + expect(fromString('a15', dataType: DataType.reference, defaultValue: -1), + -1); + }); + test('float', () + { + expect(fromString('123.76', dataType: DataType.float, defaultValue: -1), + 123.76); + expect(fromString('-4123.76', dataType: DataType.float, defaultValue: -1), + -4123.76); + expect(fromString('', dataType: DataType.float, defaultValue: -99999999), + -99999999); + expect(fromString('Nothing', dataType: DataType.float, defaultValue: -99999999), + -99999999); + }); + test('currency', () + { + expect(fromString('123.76', dataType: DataType.currency, defaultValue: -1), + 123.76); + expect(fromString('-4123.76', dataType: DataType.currency, defaultValue: -1), + -4123.76); + expect(fromString('', dataType: DataType.currency, defaultValue: -99999999), + -99999999); + expect(fromString('Nothing', dataType: DataType.currency, defaultValue: -99999999), + -99999999); + }); + test('date', () + { + expect(fromString('7.3.1987', dataType: DataType.date), + DateTime(1987, 3, 7)); + expect(fromString('17.12.2035', dataType: DataType.date), + DateTime(2035, 12, 17)); + expect(fromString('2012.6.2', dataType: DataType.date), + DateTime(2012, 6, 2)); + expect(fromString('1923.10.31', dataType: DataType.date), + DateTime(1923, 10, 31)); + expect(fromString('17.12.21', dataType: DataType.date), + isNull); + }); + test('datetime', () + { + expect(fromString('17.12.2035', dataType: DataType.datetime), + DateTime(2035, 12, 17)); + expect(fromString('7.3.1987', dataType: DataType.datetime), + DateTime(1987, 3, 7)); + expect(fromString('2012.6.2', dataType: DataType.datetime), + DateTime(2012, 6, 2)); + expect(fromString('1923.10.31', dataType: DataType.datetime), + DateTime(1923, 10, 31)); + expect(fromString('17.12.21', dataType: DataType.datetime), + isNull); + expect(fromString('7.3.1987T2:44', dataType: DataType.datetime), + DateTime(1987, 3, 7, 2, 44)); + expect(fromString('17.12.2035 13:59:22', dataType: DataType.datetime), + DateTime(2035, 12, 17, 13, 59, 22)); + expect(fromString('2012.6.2/23:59:59', dataType: DataType.datetime), + DateTime(2012, 6, 2, 23, 59, 59)); + expect(fromString('1923.10.31-3:4', dataType: DataType.datetime), + DateTime(1923, 10, 31, 3, 4)); + }); + }); + group('asPattern', () { + test('unchanged', () { + expect(asPattern('A test!123'), 'A test!123%'); + }); + test('with *', () { + expect(asPattern('*Wu*ff'), '%Wu%ff%'); + }); + test('empty', () { + expect(asPattern(''), '%'); + }); + test('with ?', () { + expect(asPattern('M??r'), 'M__r%'); + }); + test('mixed', () { + expect(asPattern('*M?i*r'), '%M_i%r%'); + }); + }); + group('asString', () { + test('bool', () { + expect(asString(true), i18n.tr('Yes')); + expect(asString(false), i18n.tr('No')); + expect(asString(true, dbFormat: true), 'T'); + expect(asString(false, dbFormat: true), 'F'); + }); + test('int', () { + expect(asString(12345), '12345'); + expect(asString(-33), '-33'); + expect(asString(-33, dbFormat: true), '-33'); + expect(asString(884433, dbFormat: true), '884433'); + }); + test('double', () { + expect(asString(7733.0), '7733.00'); + expect(asString(-123.77), '-123.77'); + expect(asString(1E-99), '.00'); + expect(asString(7733.0, dbFormat: true), '7733.00'); + expect(asString(-123.77, dbFormat: true), '-123.77'); + }); + test('Date', () { + expect(asString(DateTime(2021, 10, 3), dateOnly: true), '03.10.2021'); + expect( + asString(DateTime(2021, 10, 3, 9, 33), dateOnly: true), '03.10.2021'); + expect(asString(DateTime(2021, 10, 3, 9, 33), dateOnly: false), + '03.10.2021 09:33'); + expect(asString(DateTime(2021, 10, 3, 9, 33, 14), dateOnly: false), + '03.10.2021 09:33'); + expect( + asString(DateTime(2021, 10, 3, 9, 33, 14), + dateOnly: false, withSeconds: true), + '03.10.2021 09:33:14'); + expect(asString(DateTime(2021, 7, 3), dbFormat: true, dateOnly: true), + '2021-07-03'); + expect( + asString(DateTime(2021, 10, 3, 9, 33), + dbFormat: true, dateOnly: true), + '2021-10-03'); + expect( + asString(DateTime(2021, 7, 3, 9, 33), + dbFormat: true, dateOnly: false), + '2021-07-03 09:33:00'); + expect( + asString(DateTime(2021, 10, 3, 9, 33, 14), + dbFormat: true, dateOnly: false), + '2021-10-03 09:33:14'); + expect( + asString(DateTime(2021, 10, 3, 9, 33, 14), + dbFormat: true, dateOnly: false, withSeconds: true), + '2021-10-03 09:33:14'); + }); + test('string', () { + expect(asString('A test!123'), 'A test!123'); + expect(asString('A test!123', dbFormat: true), 'A test!123'); + }); + test('string', () { + expect(asString('A test!123'), 'A test!123'); + }); + test('string', () { + expect(asString('A test!123'), 'A test!123'); + }); + }); +} diff --git a/rest_server/data/sql/benchmarks.sql.yaml b/rest_server/data/sql/benchmarks.sql.yaml new file mode 100644 index 0000000..1214dba --- /dev/null +++ b/rest_server/data/sql/benchmarks.sql.yaml @@ -0,0 +1,48 @@ +--- +# DO NOT CHANGE. This file is created by the meta_tool +# SQL statements of the module "Benchmarks": + +module: Benchmarks +list: + type: list + parameters: [":text"] + order: "benchmark_id" + sql: | + SELECT + t0.* FROM benchmarks t0 + WHERE + (:text='' OR benchmark_lastname like :text + OR benchmark_firstname like :text) +byId: + type: record + parameters: [ ":id" ] + sql: "SELECT * FROM benchmarks WHERE benchmark_id=:id;" +delete: + type: delete + parameters: [ ":id" ] + sql: "DELETE * FROM benchmarks WHERE benchmark_id=:id;" +update: + type: update + parameters: [":id",":lastName",":firstName",":email",":birthday",":active", + ":weight",":income"] + sql: | + UPDATE benchmarks SET + benchmark_lastname=:lastName, + benchmark_firstname=:firstName, + benchmark_email=:email, + benchmark_birthday=:birthday, + benchmark_active=:active, + benchmark_weight=:weight, + benchmark_income=:income, + benchmark_changed=NOW() + WHERE benchmark_id=:id; +insert: + type: insert + parameters: [":lastName",":firstName",":email",":birthday",":active",":weight", + ":income",":createdBy"] + sql: | + INSERT INTO benchmarks(benchmark_lastname,benchmark_firstname, + benchmark_email,benchmark_birthday,benchmark_active,benchmark_weight, + benchmark_income,benchmark_createdby,benchmark_created) + VALUES(:lastName,:firstName,:email,:birthday,:active,:weight,:income, + :createdBy,NOW()); diff --git a/rest_server/data/sql/roles.sql.yaml b/rest_server/data/sql/roles.sql.yaml index 1eded90..901ab64 100644 --- a/rest_server/data/sql/roles.sql.yaml +++ b/rest_server/data/sql/roles.sql.yaml @@ -7,10 +7,9 @@ list: type: list parameters: [] order: "role_id" - sql: "SELECT - t0.* - FROM roles t0 - ;" + sql: | + SELECT + t0.* FROM roles t0 byId: type: record parameters: [ ":id" ] @@ -22,11 +21,14 @@ delete: update: type: update parameters: [":id",":name"] - sql: "UPDATE roles SET - role_name=:name,role_changed=NOW() - WHERE role_id=:id;" + sql: | + UPDATE roles SET + role_name=:name, + role_changed=NOW() + WHERE role_id=:id; insert: type: insert parameters: [":name",":createdBy"] - sql: "INSERT INTO roles(role_name,role_createdby,role_created) - VALUES(:name,:createdBy,NOW());" + sql: | + INSERT INTO roles(role_name,role_createdby,role_created) + VALUES(:name,:createdBy,NOW()); diff --git a/rest_server/data/sql/structures.sql.yaml b/rest_server/data/sql/structures.sql.yaml index 9595e1d..eb68f17 100644 --- a/rest_server/data/sql/structures.sql.yaml +++ b/rest_server/data/sql/structures.sql.yaml @@ -7,10 +7,9 @@ list: type: list parameters: [] order: "structure_id" - sql: "SELECT - t0.* - FROM structures t0 - ;" + sql: | + SELECT + t0.* FROM structures t0 byId: type: record parameters: [ ":id" ] @@ -22,13 +21,18 @@ delete: update: type: update parameters: [":id",":scope",":name",":value",":position"] - sql: "UPDATE structures SET - structure_scope=:scope,structure_name=:name,structure_value=:value, - structure_position=:position,structure_changed=NOW() - WHERE structure_id=:id;" + sql: | + UPDATE structures SET + structure_scope=:scope, + structure_name=:name, + structure_value=:value, + structure_position=:position, + structure_changed=NOW() + WHERE structure_id=:id; insert: type: insert parameters: [":scope",":name",":value",":position",":createdBy"] - sql: "INSERT INTO structures(structure_scope,structure_name,structure_value, + sql: | + INSERT INTO structures(structure_scope,structure_name,structure_value, structure_position,structure_createdby,structure_created) - VALUES(:scope,:name,:value,:position,:createdBy,NOW());" + VALUES(:scope,:name,:value,:position,:createdBy,NOW()); diff --git a/rest_server/data/sql/users.sql.yaml b/rest_server/data/sql/users.sql.yaml index 5102dfe..00a4637 100644 --- a/rest_server/data/sql/users.sql.yaml +++ b/rest_server/data/sql/users.sql.yaml @@ -7,15 +7,14 @@ list: type: list parameters: [":text",":role"] order: "user_id" - sql: "SELECT - t0.*,t1.role_name AS role - FROM users t0 + sql: | + SELECT + t0.*,t1.role_name AS role FROM users t0 JOIN roles t1 ON t1.role_id=t0.user_role WHERE (:text='' OR user_name like :text OR user_displayname like :text OR user_email like :text) AND (:role=0 OR :role=user_role) - ;" byId: type: record parameters: [ ":id" ] @@ -27,13 +26,18 @@ delete: update: type: update parameters: [":id",":name",":displayName",":email",":role"] - sql: "UPDATE users SET - user_name=:name,user_displayname=:displayName,user_email=:email, - user_role=:role,user_changed=NOW() - WHERE user_id=:id;" + sql: | + UPDATE users SET + user_name=:name, + user_displayname=:displayName, + user_email=:email, + user_role=:role, + user_changed=NOW() + WHERE user_id=:id; insert: type: insert parameters: [":name",":displayName",":email",":role",":createdBy"] - sql: "INSERT INTO users(user_name,user_displayname,user_email,user_role, + sql: | + INSERT INTO users(user_name,user_displayname,user_email,user_role, user_createdby,user_created) - VALUES(:name,:displayName,:email,:role,:createdBy,NOW());" + VALUES(:name,:displayName,:email,:role,:createdBy,NOW()); diff --git a/test/helper_test.dart b/test/helper_test.dart new file mode 100644 index 0000000..7d41733 --- /dev/null +++ b/test/helper_test.dart @@ -0,0 +1,3 @@ +/// The flutter test environment is not usable for helper.dart +/// See metadata/test/helper.dart for tests (with dart test environment) + diff --git a/tools/InitProject b/tools/InitProject index 0786b56..4ff2bfa 100755 --- a/tools/InitProject +++ b/tools/InitProject @@ -141,7 +141,7 @@ function Flutter(){ flutter config linux } function Finish(){ - pub upgrade + dart pub upgrade } if [ -z "$APP" ]; then Usage "missing PROJECT" -- 2.39.5