--- /dev/null
+---
+# configuration of the bones backend for configuration:
+created: 2020.11.11 11:47
+author: flutter_bones.module_model.exportSqlBackend()
+version: 1.0.0
+modules:
+ - module: configuration
+ sqlInfos:
+ - name: combobox_by_scope
+ type: list
+ sql: "SELECT configuration_id,configuration_property,configuration_value FROM configuration
+ WHERE configuration_scope=:scope
+ ORDER BY configuration_order;"
import 'package:flutter/material.dart';
import 'src/helper/settings.dart';
-import 'src/page/demo_page.dart';
import 'src/page/async_example_page.dart';
+import 'src/page/configuration/configuration_create_page.dart';
+import 'src/page/configuration/configuration_list_page.dart';
+import 'src/page/demo_page.dart';
+import 'src/page/menu/menu_create_page.dart';
+import 'src/page/menu/menu_list_page.dart';
import 'src/page/role/role_create_page.dart';
import 'src/page/role/role_list_page.dart';
import 'src/page/user/user_create_page.dart';
import 'src/page/user/user_list_page.dart';
import 'src/page/user/user_login_page.dart';
-import 'src/page/menu/menu_list_page.dart';
-import 'src/page/menu/menu_create_page.dart';
-import 'src/page/configuration/configuration_create_page.dart';
-import 'src/page/configuration/configuration_list_page.dart';
import 'src/private/bsettings.dart';
class BoneApp extends StatefulWidget {
page = ConfigurationCreatePage(BSettings.lastInstance.pageData);
break;
case '/menu/list':
- page = MenuCreatePage(BSettings.lastInstance.pageData);
+ page = MenuListPage(BSettings.lastInstance.pageData);
break;
case '/menu/create':
- page = MenuListPage(BSettings.lastInstance.pageData);
+ page = MenuCreatePage(BSettings.lastInstance.pageData);
break;
case '/user/login':
default:
///
/// Allows a model driven design of flutter apps:
/// The design of the screens is done by a yaml file (or a compatible map).
+export 'src/helper/helper_async.dart';
export 'src/helper/settings.dart';
export 'src/helper/string_helper.dart';
export 'src/helper/validators.dart';
-export 'src/helper/helper_async.dart';
export 'src/model/button_model.dart';
export 'src/model/checkbox_model.dart';
+export 'src/model/combo_base_model.dart';
export 'src/model/combobox_model.dart';
export 'src/model/empty_line_model.dart';
export 'src/model/field_model.dart';
export 'src/model/page_model.dart';
export 'src/model/section_model.dart';
export 'src/model/standard/configuration_model.dart';
+export 'src/model/standard/menu_model.dart';
export 'src/model/standard/role_model.dart';
export 'src/model/standard/standard_modules.dart';
export 'src/model/standard/user_model.dart';
-export 'src/model/standard/menu_model.dart';
export 'src/model/text_field_model.dart';
export 'src/model/text_model.dart';
export 'src/model/widget_model.dart';
-export 'src/page/login_page.dart.01';
export 'src/page/application_data.dart';
+export 'src/page/configuration/configuration_create_page.dart';
+export 'src/page/login_page.dart.01';
export 'src/page/role/role_create_page.dart';
export 'src/page/user/user_create_page.dart';
-export 'src/page/configuration/configuration_create_page.dart';
export 'src/page/user_page.dart';
export 'src/persistence/persistence.dart';
-export 'src/persistence/rest_persistence.dart';
export 'src/persistence/persistence_cache.dart';
+export 'src/persistence/rest_persistence.dart';
export 'src/widget/raised_button_bone.dart';
export 'src/widget/simple_form.dart';
export 'src/widget/text_form_field_bone.dart';
return rc;
}
+ /// Replaces all placeholders defined by [syntaxPlaceholder] or [regExpPlaceholder]
+ /// in [source] and return this result.
+ /// [syntaxPlaceholder] or [regExpPlaceholder] must contain a single group
+ /// identifying the name of the placeholder.
+ /// Example:
+ /// replacePlaceholders('Hi ~user~', { "user": "joe"}, syntaxPlaceholder: r'~(\w+)~')
+ /// returns "Hi Joe".
+ static String replacePlaceholders(
+ String source, Map<String, String> placeholders,
+ {String syntaxPlaceholder, RegExp regExpPlaceholder}) {
+ regExpPlaceholder ??= RegExp(syntaxPlaceholder);
+ final rc =
+ regExpPlaceholder.allMatches(source).fold(source, (string, match) {
+ final name = match.group(1);
+ final rc2 = placeholders.containsKey(name)
+ ? string.replaceFirst(match.group(0), placeholders[name])
+ : string;
+ return rc2;
+ });
+ return rc;
+ }
+
/// Splits a argument list into an [option] list and a true arguments list.
/// [args]: the argument list to split.
/// [options]: OUT: the options list
/// Describes a text widget without user interaction.
class AllDbFieldsModel extends WidgetModel {
static final regExprOptions = RegExp(r'^(unknown)$');
- List<String> options;
String text;
bool isRichText;
- final Map<String, dynamic> map;
AllDbFieldsModel(
- SectionModel section, PageModel page, this.map, BaseLogger logger)
- : super(section, page, WidgetModelType.allDbFields, logger);
+ SectionModel section, PageModel page, BaseLogger logger)
+ : super(section, page, WidgetModelType.allDbFields, null, logger);
/// Returns the name including the names of the parent
@override
return stringBuffer;
}
- /// Parses the map and stores the data in the instance.
- void parse() {
+ /// Parses the [map] and stores the data in the instance.
+ void parse(Map map) {
+ super.parse(map);
checkSuperfluousAttributes(map, 'options widgetType'.split(' '));
options = parseOptions('options', map);
addFieldsOfTable(page.module.mainTable());
- checkOptionsByRegExpr(options, regExprOptions);
+ checkOptionsByRegExpr(regExprOptions);
}
@override
String label;
String name;
String toolTip;
- final Map<String, dynamic> map;
- List<String> options;
ButtonModelType buttonModelType;
VoidCallbackBones onPressed;
/// Constructs an instance by parsing the map for some properties.
- ButtonModel(SectionModel section, PageModel page, this.map, BaseLogger logger)
- : super(section, page, WidgetModelType.button, logger);
+ ButtonModel(SectionModel section, PageModel page, BaseLogger logger)
+ : super(section, page, WidgetModelType.button, null, logger);
/// Constructs an instance with all properties given.
ButtonModel.direct(
String text,
ButtonModelType buttonModelType,
List<String> options,
- this.map,
BaseLogger logger)
- : super(section, page, WidgetModelType.button, logger) {
+ : super(section, page, WidgetModelType.button, options, logger) {
this.name = name;
this.label = text;
this.toolTip = toolTip;
@override
String fullName() => '${section?.name}.$name';
- /// Parses the map and stores the data in the instance.
- void parse() {
+ /// Parses the [map]and stores the data in the instance.
+ void parse(Map map) {
name = parseString('name', map, required: true);
+ super.parse(map);
checkSuperfluousAttributes(map,
'buttonType label name options text toolTip widgetType'.split(' '));
label = parseString('label', map, required: true);
parseEnum<ButtonModelType>('buttonType', map, ButtonModelType.values);
buttonModelType ??= ButtonModelType.custom;
options = parseOptions('options', map);
- checkOptionsByRegExpr(options, regExprOptions);
+ checkOptionsByRegExpr(regExprOptions);
}
@override
class CheckboxModel extends FieldModel {
static final regExprOptions = RegExp(r'^(readonly|disabled|required|undef)$');
- final Map<String, dynamic> map;
-
CheckboxModel(
- SectionModel section, PageModel page, this.map, BaseLogger logger)
- : super(section, page, map, WidgetModelType.checkbox, logger);
+ SectionModel section, PageModel page, BaseLogger logger)
+ : super(section, page, WidgetModelType.checkbox, logger);
- /// Parses the map and stores the data in the instance.
- void parse() {
- super.parse();
+ /// Parses the [map]and stores the data in the instance.
+ void parse(Map map) {
+ super.parse(map);
checkSuperfluousAttributes(
map, 'name label options toolTip widgetType'.split(' '));
- options = parseOptions('options', map);
- checkOptionsByRegExpr(options, regExprOptions);
+ checkOptionsByRegExpr(regExprOptions);
parseFinish();
}
String foreignKey;
/// A constructor used in the parser.
- ColumnModel(this.table, Map map, BaseLogger logger)
- : super(null, null, map, WidgetModelType.column, logger);
+ ColumnModel(this.table, BaseLogger logger)
+ : super(null, null, WidgetModelType.column, logger);
/// A constructor for columns created by the program.
ColumnModel.direct(
: super.direct(
section: null,
page: null,
- map: null,
name: name,
label: label,
toolTip: toolTip,
@override
String fullName() => '${table.name}.$name';
- /// Tests whether a given [option] is part of [options].
- bool hasOption(String option) {
- bool rc = options?.contains(option) ?? false;
- return rc;
- }
-
- /// Parses the map and stores the data in the instance.
- void parse() {
+ /// Parses the [map]and stores the data in the instance.
+ void parse(Map map) {
name = parseString('column', map, required: true);
+ super.parse(map);
checkSuperfluousAttributes(
map,
'column dataType defaultValue foreignKey label listOption listType options rows size texts tooTip validators validatorsText values widgetType'
.split(' '));
- super.parse();
dataType =
parseEnum<DataType>('dataType', map, DataType.values, required: true);
size = parseInt('size', map, required: dataType == DataType.string);
logger.error(
'invalid foreign key in ${fullName()}: $foreignKey expected: "<table>.<primary> <colName>" e.g. "role.role_id role_name"');
}
- checkOptionsByRegExpr(options, regExprOptions);
+ checkOptionsByRegExpr(regExprOptions);
if (options.contains('primary')) {
if (!options.contains('notnull')) {
options.add('notnull');
logger.error(
'curious item (position $no) in column list of ${table.fullName()}: ${StringUtils.limitString("$item", 80)}');
} else {
- final current = ColumnModel(table, item, logger);
- current.parse();
+ final current = ColumnModel(table, logger);
+ current.parse(item);
table.addColumn(current);
}
}
abstract class ComboBaseModel extends FieldModel {
static final regExprListDbOption =
RegExp(r'^\w+\.\w+\.\w+;\w+ \w+(?:;( ?:\w+=[^ ])*)?$');
- static final regExprListConfiguration = RegExp(r'^scope:\w+$');
+ static final regExprListConfiguration =
+ RegExp(r'^\w+\.scope.\w+;\w+ \w+(?:;( ?:\w+=[^ ])*)?$');
List<String> texts;
List values;
String listOption;
ComboboxListType listType;
ComboboxData data;
- ComboBaseModel(SectionModel section, PageModel page, Map map,
+ ComboBaseModel(SectionModel section, PageModel page,
WidgetModelType widgetType, BaseLogger logger)
- : super(section, page, map, widgetType, logger);
+ : super(section, page, widgetType, logger);
ComboBaseModel.direct(
{SectionModel section,
PageModel page,
- Map map,
String name,
String label,
String toolTip,
WidgetModelType widgetType,
dynamic defaultValue,
BaseLogger logger})
- : super.direct(section, page, map, widgetType, name, label, toolTip,
+ : super.direct(section, page, widgetType, name, label, toolTip,
dataType, options, defaultValue, logger);
/// Transfers the list data from [texts] and [values] to [data].
}
}
- /// Parses the map and stores the data in the instance.
- void parse() {
- super.parse();
+ /// Parses the [map]and stores the data in the instance.
+ void parse(Map map) {
+ super.parse(map);
texts = parseStringList('texts', map);
listType =
parseEnum<ComboboxListType>('listType', map, ComboboxListType.values);
}
}
+/// Stores the [texts] and [_values] of a combobox.
class ComboboxData {
final List<String> texts;
List _values;
WaitState waitState;
- ComboboxData(this.texts, this._values, [this.waitState = WaitState.undef]);
+ ComboboxData(this.texts, this._values, [this.waitState = WaitState.undef]){
+ this._values ??= this.texts;
+ }
/// Returns the length of [_values].
int get valuesLength => _values == null ? 0 : _values.length;
static final regExprOptions = RegExp(r'^(disabled|readonly|required|undef)$');
ComboboxModel(
- SectionModel section, PageModel page, Map map, BaseLogger logger)
- : super(section, page, map, WidgetModelType.combobox, logger);
+ SectionModel section, PageModel page, BaseLogger logger)
+ : super(section, page, WidgetModelType.combobox, logger);
/// Dumps the instance into a [StringBuffer]
StringBuffer dump(StringBuffer stringBuffer) {
return stringBuffer;
}
- /// Parses the map and stores the data in the instance.
- void parse() {
+ /// Parses the [map]and stores the data in the instance.
+ void parse(Map map) {
checkSuperfluousAttributes(
map,
'dataType defaultValue filterType label listOption listType name options texts toolTip values validators validatorsText widgetType'
.split(' '));
- super.parse();
- checkOptionsByRegExpr(options, regExprOptions);
+ super.parse(map);
+ checkOptionsByRegExpr(regExprOptions);
parseFinish();
}
}
var value;
ColumnModel column;
- /// A constructor fetching the properties by parsing the [map].
+ /// A constructor fetching the properties by parsing the map.
DbReferenceModel(
- SectionModel section, PageModel page, Map map, BaseLogger logger)
- : super(section, page, map, WidgetModelType.dbReference, logger);
+ SectionModel section, PageModel page, BaseLogger logger)
+ : super(section, page, WidgetModelType.dbReference, logger);
/// A constructor without map parsing.
DbReferenceModel.fromColumn(SectionModel section, PageModel page,
: super.direct(
section: section,
page: page,
- map: null,
widgetType: WidgetModelType.dbReference,
name: column.name,
label: column.label,
toolTip: column.toolTip,
dataType: column.dataType,
- options: column.options ?? <String>[],
+ options: <String>[],
texts: column.texts,
values: column.values,
listOption: column.listOption,
listType: column.listType,
logger: logger) {
+ options ??= [];
+ options.addAll(column.options ?? []);
this.column = column;
maxSize = column.size;
rows = column.rows;
return stringBuffer;
}
- /// Parses the map and stores the data in the instance.
- void parse() {
+ /// Parses the [map]and stores the data in the instance.
+ void parse(Map map) {
checkSuperfluousAttributes(
map,
'column filterType label maxSize listOption listType name options rows toolTip texts widgetType values'
.split(' '));
- super.parse();
+ super.parse(map);
final columnName = parseString('column', map, required: true);
column = page.module.getColumn(columnName, this);
maxSize = parseInt('maxSize', map, required: false);
values ??= column.values;
listOption ??= column.listOption;
listType ??= column.listType;
- checkOptionsByRegExpr(options, regExprOptions);
+ checkOptionsByRegExpr(regExprOptions);
options += column.options;
parseFinish();
}
/// Describes an empty line used as separator between two other widgets.
class EmptyLineModel extends WidgetModel {
static final regExprOptions = RegExp(r'^(unknown)$');
- List<String> options;
bool isRichText;
- final Map<String, dynamic> map;
EmptyLineModel(
- SectionModel section, PageModel page, this.map, BaseLogger logger)
- : super(section, page, WidgetModelType.emptyLine, logger);
+ SectionModel section, PageModel page, BaseLogger logger)
+ : super(section, page, WidgetModelType.emptyLine, null, logger);
/// Dumps the instance into a [StringBuffer]
StringBuffer dump(StringBuffer stringBuffer) {
@override
String fullName() => '${section.name}.${widgetName()}';
- /// Parses the map and stores the data in the instance.
- void parse() {
- options = parseOptions('options', map);
+ /// Parses the [map]and stores the data in the instance.
+ void parse(Map map) {
+ super.parse(map);
checkSuperfluousAttributes(map, 'options widgetType'.split(' '));
- checkOptionsByRegExpr(options, regExprOptions);
+ checkOptionsByRegExpr(regExprOptions);
}
@override
String label;
String toolTip;
DataType dataType;
- List<String> options;
FilterType filterType;
dynamic _value;
dynamic defaultValue;
/// key: validator name, e.g. 'regExpr'
/// value: the error message
final messageOfValidator = <String, String>{};
- final Map<String, dynamic> map;
- FieldModel(SectionModel section, PageModel page, this.map,
+ FieldModel(SectionModel section, PageModel page,
WidgetModelType fieldModelType, BaseLogger logger)
- : super(section, page, fieldModelType, logger);
+ : super(section, page, fieldModelType, null, logger);
FieldModel.direct(
SectionModel section,
PageModel page,
- this.map,
WidgetModelType widgetModelType,
this.name,
this.label,
this.toolTip,
this.dataType,
- this.options,
this.defaultValue,
+ List<String> options,
BaseLogger logger,
[this.filterType])
- : super(section, page, widgetModelType, logger);
+ : super(section, page, widgetModelType, options, logger);
get value => _value;
@override
String fullName() => '${page.name}.$name';
- /// Tests whether a given [option] is part of [options].
- bool hasOption(String option) {
- if (options == null) {
- return false;
- }
- bool rc = options.contains(option);
- return rc;
- }
-
- /// Parses the map and stores the data in the instance.
- void parse() {
+ /// Parses the [map]and stores the data in the instance.
+ void parse(Map map) {
name = parseString(
widgetModelType == WidgetModelType.column ? 'column' : 'name', map,
required: true);
+ super.parse(map);
label = parseString('label', map, required: false);
toolTip = parseString('toolTip', map, required: false);
filterType = parseEnum<FilterType>('filterType', map, FilterType.values);
/// Base class of all models.
abstract class ModelBase {
BaseLogger logger;
+ List<String> options;
- ModelBase(this.logger);
+ ModelBase(this.options, this.logger);
+
+ void parse(Map map) {
+ options = parseOptions('options', map);
+ }
/// Tests the validity of the entries in [options] comparing with an [regExpr].
/// Errors will be logged.
- bool checkOptionsByRegExpr(List<String> options, RegExp regExpr) {
+ bool checkOptionsByRegExpr(RegExp regExpr) {
bool rc = false;
- options.forEach((element) {
+ options?.forEach((element) {
if (regExpr.firstMatch(element) == null) {
logger.error('wrong option $element in ${fullName()}');
rc = true;
return rc;
}
+ /// Tests whether a given [option] is part of [options].
+ bool hasOption(String option) {
+ if (options == null) {
+ return false;
+ }
+ bool rc = options.contains(option);
+ return rc;
+ }
+
/// Tests a [map] for superfluous [keys].
/// Keys of the [map] that are not listed in [keys] will be logged as errors.
/// Keys that do not have the type String are logged as errors.
/// Fetches an entry from a map addressed by a [key].
/// An error is logged if [required] is true and the map does not contain the key.
List<String> parseOptions(String key, Map<String, dynamic> map) {
- List<String> rc = [];
+ List<String> rc;
if (map.containsKey(key)) {
final value = map[key];
if (value.runtimeType == String && value.isNotEmpty) {
'wrong datatype of options ${value.runtimeType} in ${fullName()}');
}
}
- return rc;
+ return rc ?? [];
}
/// Fetches an entry from a map addressed by a [key].
static final regExprOptions = RegExp(r'^(noPages)$');
final Map<String, dynamic> map;
String name;
- List<String> options;
@protected
final pages = <PageModel>[];
final tables = <TableModel>[];
- ModuleModel(this.map, BaseLogger logger) : super(logger);
+ ModuleModel(this.map, BaseLogger logger) : super(null, logger);
/// Adds the column [name] from [source] to [target] if that column is not member of [target].
void addColumnIfMissing(
return rc;
}
- /// Tests whether an options named 'name' is set.
- bool hasOption(String name) => options != null && options.contains(name);
-
/// Returns the main table of the module.
/// This is the first defined table.
TableModel mainTable() {
return found;
}
- /// Parses the map and stores the data in the instance.
- void parse() {
+ /// Parses the [map]and stores the data in the instance.
+ void parse([Map map]) {
+ map ??= this.map;
name = parseString('module', map, required: true);
+ super.parse(map);
checkSuperfluousAttributes(map, 'module options pages tables'.split(' '));
if (map.containsKey('tables')) {
TableModel.parseList(this, map['tables'], logger);
}
- options = parseOptions('options', map);
if (!hasOption('noPages')) {
if (!map.containsKey('pages')) {
logger.error('Module $name: missing pages');
}
}
}
- checkOptionsByRegExpr(options, regExprOptions);
+ checkOptionsByRegExpr(regExprOptions);
}
/// Returns a child table given by [name], null otherwise.
class PageModel extends ModelBase {
static final regExprOptions = RegExp(r'^(noAutoButton)$');
final ModuleModel module;
- final Map<String, dynamic> map;
String name;
final List<SectionModel> sections = [];
PageModelType pageModelType;
- List<String> options;
final fields = <FieldModel>[];
final buttons = <ButtonModel>[];
final widgets = <WidgetModel>[];
List<String> tableTitles;
List<String> tableColumns;
- PageModel(this.module, this.map, BaseLogger logger) : super(logger);
+ PageModel(this.module, BaseLogger logger) : super(null, logger);
/// Adds a [button] to the [this.buttons].
/// If already defined and error is logged.
return rc;
}
- /// Parses the map and stores the data in the instance.
- void parse() {
+ /// Parses the [map]and stores the data in the instance.
+ void parse(Map map) {
name = parseString('page', map, required: true);
checkSuperfluousAttributes(
map,
case PageModelType.list:
if (buttonByName('search', required: false) == null) {
addButton(ButtonModel.direct(section, this, 'search', 'Suchen',
- ButtonModelType.search, [], null, logger));
+ ButtonModelType.search, [], logger));
}
break;
case PageModelType.create:
case PageModelType.change:
if (buttonByName('cancel', required: false) == null) {
addButton(ButtonModel.direct(section, this, 'cancel', 'Abbruch',
- ButtonModelType.cancel, [], null, logger));
+ ButtonModelType.cancel, [], logger));
}
if (buttonByName('store', required: false) == null) {
addButton(ButtonModel.direct(section, this, 'store', 'Speichern',
- ButtonModelType.store, [], null, logger));
+ ButtonModelType.store, [], logger));
}
break;
default:
break;
}
}
- checkOptionsByRegExpr(options, regExprOptions);
+ checkOptionsByRegExpr(regExprOptions);
}
@override
module.logger.error(
'curious item in section list of ${module.fullName()}: ${StringUtils.limitString("$item", 80)}');
} else {
- final page = PageModel(module, item, logger);
+ final page = PageModel(module, logger);
// we need a name before adding to module
- page.parse();
+ page.parse(item);
module.addPage(page);
}
}
String name;
final children = <WidgetModel>[];
final buttons = <WidgetModel>[];
- List<String> options;
final int no;
- final Map<String, dynamic> map;
- SectionModel(this.no, PageModel page, SectionModel section, this.map,
+ SectionModel(this.no, PageModel page, SectionModel section,
BaseLogger logger)
- : super(section, page, WidgetModelType.section, logger);
+ : super(section, page, WidgetModelType.section, null, logger);
/// Dumps the internal structure into a [stringBuffer]
StringBuffer dump(StringBuffer stringBuffer) {
String fullName() =>
section == null ? '${page.name}.$name' : '${section.name}.$name';
- /// Parses the map and stores the data in the instance.
- void parse() {
+ /// Parses the [map]and stores the data in the instance.
+ void parse(Map map) {
sectionModelType = parseEnum<SectionModelType>(
'sectionType', map, SectionModelType.values);
name = parseString('name', map) ??
map, 'children fields name options sectionType widgetType'.split(' '));
options = parseOptions('options', map);
- checkOptionsByRegExpr(options, regExprOptions);
+ checkOptionsByRegExpr(regExprOptions);
if (!map.containsKey('children')) {
logger.error('missing children in ${fullName()}');
} else {
WidgetModel widget;
switch (widgetType) {
case WidgetModelType.allDbFields:
- widget = AllDbFieldsModel(this, page, child, logger);
+ widget = AllDbFieldsModel(this, page, logger);
break;
case WidgetModelType.checkbox:
- widget = CheckboxModel(this, page, child, logger);
+ widget = CheckboxModel(this, page, logger);
break;
case WidgetModelType.combobox:
- widget = ComboboxModel(this, page, child, logger);
+ widget = ComboboxModel(this, page, logger);
break;
case WidgetModelType.textField:
- widget = TextFieldModel(this, page, child, logger);
+ widget = TextFieldModel(this, page, logger);
break;
case WidgetModelType.button:
- widget = ButtonModel(this, page, child, logger);
+ widget = ButtonModel(this, page, logger);
break;
case WidgetModelType.text:
- widget = TextModel(this, page, child, logger);
+ widget = TextModel(this, page, logger);
break;
case WidgetModelType.emptyLine:
- widget = EmptyLineModel(this, page, child, logger);
+ widget = EmptyLineModel(this, page, logger);
break;
case WidgetModelType.dbReference:
- widget = DbReferenceModel(this, page, child, logger);
+ widget = DbReferenceModel(this, page, logger);
break;
default:
//@ToDo: nested section
}
if (widget != null) {
children.add(widget);
- widget.parse();
+ widget.parse(child);
page.widgets.add(widget);
switch (widget.widgetModelType) {
case WidgetModelType.button:
page.logger.error(
'curious item in section list of ${page.fullName()}: ${StringUtils.limitString("$item", 80)}');
} else {
- final current = SectionModel(no, page, null, item, logger);
- current.parse();
+ final current = SectionModel(no, page, null, logger);
+ current.parse(item);
if (section != null) {
section.children.add(current);
} else {
'label': 'Bereich',
'size': 64,
'options': 'notnull',
+ 'validators': r'required regExpr=i/^\w+$',
+ 'validatorsText': 'regExpr=Nur Buchstaben, Ziffern und Unterstrich erlaubt',
},
{
'column': 'configuration_property',
'dataType': 'string',
'size': 16,
'label': 'Datentyp',
+ 'listType': 'explicite',
+ 'texts': ';bool;date;float;int;string',
+ 'validators': 'required',
},
{
'column': 'configuration_value',
'column': 'menu_icon',
'dataType': 'reference',
'label': 'Bild',
- 'foreignKey':
- 'configuration.configuration_id configuration_property',
+ 'foreignKey': 'configuration.configuration_id configuration_value',
'listType': 'configuration',
- 'listOption': 'scope:icons',
+ 'listOption':
+ 'std.scope.icons;configuration_value configuration_id;',
},
]
},
'column': 'role_priority',
'dataType': 'int',
'label': 'Priorität',
+ 'validators': 'required minInt=1 maxInt=99',
},
{
'column': 'role_active',
{
"sectionType": "simpleForm",
"children": [
+ {
+ "widgetType": "text",
+ "text": "Ändern des Passworts von Benutzer ~user~",
+ "options": "placeholder"
+ },
{
"widgetType": "textField",
"name": "user_password",
class TableModel extends ModelBase {
static final regExprOptions = RegExp(r'^(unknown)$');
final ModuleModel module;
- final Map<String, dynamic> map;
String name;
- List<String> options;
final columns = <ColumnModel>[];
ColumnModel primary;
- TableModel(this.module, this.map, BaseLogger logger) : super(logger);
+ TableModel(this.module, BaseLogger logger) : super(null, logger);
/// Adds a [button] to the [this.buttons].
/// If already defined and error is logged.
@override
String fullName() => '${module.name}.$name';
- /// Parses the map and stores the data in the instance.
- void parse() {
+ /// Parses the [map]and stores the data in the instance.
+ void parse(Map map) {
name = parseString('table', map, required: true);
checkSuperfluousAttributes(map, 'columns options table'.split(' '));
options = parseOptions('options', map);
ColumnModel.parseColumns(this, item, logger);
}
}
- checkOptionsByRegExpr(options, regExprOptions);
+ checkOptionsByRegExpr(regExprOptions);
addIfMissing(
'${name}_createdat', 'Erzeugt', DataType.dateTime, ['hidden', 'null']);
addIfMissing(
module.logger.error(
'curious item in section list of ${module.fullName()}: ${StringUtils.limitString("$item", 80)}');
} else {
- final table = TableModel(module, item, logger);
- table.parse();
+ final table = TableModel(module, logger);
+ table.parse(item);
module.addTable(table);
}
}
var value;
TextFieldModel(
- SectionModel section, PageModel page, Map map, BaseLogger logger)
- : super(section, page, map, WidgetModelType.textField, logger);
+ SectionModel section, PageModel page, BaseLogger logger)
+ : super(section, page, WidgetModelType.textField, logger);
TextFieldModel.direct(
SectionModel section,
PageModel page,
- Map map,
String name,
String label,
String toolTip,
List<String> options,
dynamic defaultValue,
BaseLogger logger)
- : super.direct(section, page, null, WidgetModelType.textField, name,
+ : super.direct(section, page, WidgetModelType.textField, name,
label, toolTip, dataType, options, defaultValue, logger);
/// Dumps the internal structure into a [stringBuffer]
return stringBuffer;
}
- /// Parses the map and stores the data in the instance.
- void parse() {
- super.parse();
+ /// Parses the [map]and stores the data in the instance.
+ void parse(Map map) {
+ super.parse(map);
checkSuperfluousAttributes(
map,
'dataType filterType label maxSize name options rows toolTip validators validatorsText value widgetType'
break;
}
options = parseOptions('options', map);
- checkOptionsByRegExpr(options, regExprOptions);
+ checkOptionsByRegExpr(regExprOptions);
parseFinish();
}
}
/// Describes a text widget without user interaction.
class TextModel extends WidgetModel {
- static final regExprOptions = RegExp(r'^(rich)$');
- List<String> options;
+ static final regExprOptions = RegExp(r'^(richText|placeholder|h[1-5])$');
String text;
bool isRichText;
- final Map<String, dynamic> map;
- TextModel(SectionModel section, PageModel page, this.map, BaseLogger logger)
- : super(section, page, WidgetModelType.text, logger);
+ TextModel(SectionModel section, PageModel page, BaseLogger logger)
+ : super(section, page, WidgetModelType.text, null, logger);
/// Returns the name including the names of the parent
@override
return stringBuffer;
}
- /// Parses the map and stores the data in the instance.
- void parse() {
+ /// Parses the [map]and stores the data in the instance.
+ void parse(Map map) {
checkSuperfluousAttributes(map, 'options text widgetType'.split(' '));
text = parseString('text', map, required: true);
options = parseOptions('options', map);
- checkOptionsByRegExpr(options, regExprOptions);
- isRichText = options.contains('richtext');
+ checkOptionsByRegExpr(regExprOptions);
+ isRichText = options.contains('richText');
}
@override
final WidgetModelType widgetModelType;
int id;
- WidgetModel(this.section, this.page, this.widgetModelType, BaseLogger logger)
- : super(logger) {
+ WidgetModel(this.section, this.page, this.widgetModelType,
+ List<String> options, BaseLogger logger)
+ : super(options, logger) {
this.id = ++lastId;
}
/// Dumps the internal structure into a [stringBuffer]
StringBuffer dump(StringBuffer stringBuffer);
- void parse();
+ void parse(Map map){
+ super.parse(map);
+ }
String widgetName();
}
}
}
-class ConfigurationChangePageState extends State<ConfigurationChangePage> {
+class ConfigurationChangePageState extends State<ConfigurationChangePage> implements RedrawPage {
final ApplicationData applicationData;
final int primaryId;
final Map initialRow;
@override
Widget build(BuildContext context) {
- if (controller == null) {
- controller = ConfigurationController(
- _formKey, this, 'change', context, applicationData, redrawCallback:
- (RedrawReason reason,
- {String customString,
- RedrawCallbackFunctionSimple callback}) {
- switch (reason) {
- case RedrawReason.callback:
- callback(RedrawReason.custom, customString);
- setState(() {});
- break;
- default:
- setState(() {});
- break;
- }
- });
- controller.initialize();
- }
// controller.buildWidgetList() is called in editForm
return Scaffold(
appBar: applicationData.appBarBuilder('Konfiguration ändern'),
));
}
+ @override
+ void initState() {
+ super.initState();
+ controller = ConfigurationController(
+ _formKey, this, 'change', context, applicationData);
+ controller.initialize();
+ }
void dispose() {
controller.dispose();
super.dispose();
}
+
+ @override
+ void redraw(RedrawReason reason, {String customString, RedrawCallbackFunctionSimple callback}) {
+ setState( () {
+ controller.afterSetState(reason, customString: customString, callback: callback);
+ });
+ }
}
/// Controller for a page named [pageName].
ConfigurationController(
GlobalKey<FormState> formKey,
- State<StatefulWidget> parent,
+ RedrawPage parent,
String pageName,
BuildContext context,
ApplicationData applicationData,
import 'package:flutter/material.dart';
-
import '../../helper/settings.dart';
import '../../widget/edit_form.dart';
+import '../../widget/page_controller_bones.dart';
import '../application_data.dart';
import 'configuration_controller.dart';
}
}
-class ConfigurationCreatePageState extends State<ConfigurationCreatePage> {
+class ConfigurationCreatePageState extends State<ConfigurationCreatePage> implements RedrawPage {
final ApplicationData applicationData;
final GlobalKey<FormState> _formKey =
@override
Widget build(BuildContext context) {
- if (controller == null) {
- controller = ConfigurationController(
- _formKey, this, 'create', context, applicationData);
- controller.initialize();
- }
- controller.buildWidgetList();
+ controller.beginOfBuild(context);
return Scaffold(
appBar: applicationData.appBarBuilder('Neue Konfiguration'),
drawer: applicationData.drawerBuilder(context),
configuration: applicationData.configuration,
));
}
+
+ @override
+ void initState() {
+ super.initState();
+ controller = ConfigurationController(
+ _formKey, this, 'create', context, applicationData);
+ controller.initialize();
+ }
+ @override
+ void redraw(RedrawReason reason, {String customString, RedrawCallbackFunctionSimple callback}) {
+ setState( () {
+ controller.afterSetState(reason, customString: customString, callback: callback);
+ });
+ }
}
import 'package:flutter/material.dart';
-
+import '../../model/page_model.dart';
import '../../widget/list_form.dart';
import '../../widget/page_controller_bones.dart';
import '../application_data.dart';
}
}
-class ConfigurationListPageState extends State<ConfigurationListPage> {
+class ConfigurationListPageState extends State<ConfigurationListPage>
+ implements RedrawPage {
final ApplicationData applicationData;
final GlobalKey<FormState> _formKey =
ConfigurationListPageState(this.applicationData);
- @override
- void initState() {
- super.initState();
- controller = ConfigurationController(
- _formKey, this, 'list', context, applicationData, redrawCallback:
- (RedrawReason reason,
- {String customString, RedrawCallbackFunctionSimple callback}) {
- switch (reason) {
- case RedrawReason.fetchList:
- controller.buildRows();
- break;
- case RedrawReason.callback:
- callback(RedrawReason.custom, customString);
- setState(() {});
- break;
- default:
- setState(() {});
- break;
- }
- });
- controller.initialize();
- controller.buildWidgetList();
- controller.buildRows();
- controller.completeAsync();
- }
-
@override
Widget build(BuildContext context) {
- controller.buildHandler(context);
+ controller.beginOfBuild(context);
return Scaffold(
appBar: applicationData.appBarBuilder('Konfigurationen'),
drawer: applicationData.drawerBuilder(context),
RaisedButton(
child: Text('Neue Konfiguration'),
onPressed: () {
- Navigator.pushNamed(context, '/configuration/create');
-
- /// Force the redraw on return:
- controller.listRows = null;
+ controller.goTo(pageType: PageModelType.create);
},
),
]),
),
);
}
+
+ @override
+ void initState() {
+ super.initState();
+ controller = ConfigurationController(
+ _formKey, this, 'list', context, applicationData, redrawCallback:
+ (RedrawReason reason,
+ {String customString, RedrawCallbackFunctionSimple callback}) {
+ switch (reason) {
+ case RedrawReason.fetchList:
+ controller.buildRows();
+ break;
+ case RedrawReason.callback:
+ callback(RedrawReason.custom, customString: customString);
+ setState(() {});
+ break;
+ default:
+ setState(() {});
+ break;
+ }
+ });
+ controller.initialize();
+ }
+
+ @override
+ void redraw(RedrawReason reason,
+ {String customString, RedrawCallbackFunctionSimple callback}) {
+ setState(() {
+ controller.afterSetState(reason,
+ customString: customString, callback: callback);
+ });
+ }
}
}
}
-class MenuChangePageState extends State<MenuChangePage> {
+class MenuChangePageState extends State<MenuChangePage> implements RedrawPage {
final ApplicationData applicationData;
final int primaryId;
final Map initialRow;
@override
Widget build(BuildContext context) {
- if (controller == null) {
- controller =
- MenuController(_formKey, this, 'change', context, applicationData,
- redrawCallback: (RedrawReason reason,
- {String customString,
- RedrawCallbackFunctionSimple callback}) {
- switch (reason) {
- case RedrawReason.callback:
- callback(RedrawReason.custom, customString);
- setState(() {});
- break;
- default:
- setState(() {});
- break;
- }
- });
- controller.initialize();
- }
+ controller.beginOfBuild(context);
// controller.buildWidgetList() is called in editForm
return Scaffold(
appBar: applicationData.appBarBuilder('Startmenü ändern'),
controller.dispose();
super.dispose();
}
+
+ @override
+ void initState() {
+ super.initState();
+ controller = MenuController(
+ _formKey,
+ this,
+ 'change',
+ context,
+ applicationData,
+ );
+ controller.initialize();
+ }
+
+ @override
+ void redraw(RedrawReason reason,
+ {String customString, RedrawCallbackFunctionSimple callback}) {
+ setState(() {
+ controller.afterSetState(reason,
+ customString: customString, callback: callback);
+ });
+ }
}
class MenuController extends PageControllerBones {
/// Controller for a page named [pageName].
- MenuController(GlobalKey<FormState> formKey, State<StatefulWidget> parent,
+ MenuController(GlobalKey<FormState> formKey, RedrawPage parent,
String pageName, BuildContext context, ApplicationData applicationData,
{Function redrawCallback})
: super(formKey, parent, MenuModel(Settings().logger), pageName, context,
import '../../helper/settings.dart';
import '../../widget/edit_form.dart';
+import '../../widget/page_controller_bones.dart';
import '../application_data.dart';
import 'menu_controller.dart';
}
}
-class MenuCreatePageState extends State<MenuCreatePage> {
+class MenuCreatePageState extends State<MenuCreatePage> implements RedrawPage {
final ApplicationData applicationData;
final GlobalKey<FormState> _formKey =
@override
Widget build(BuildContext context) {
- if (controller == null) {
- controller =
- MenuController(_formKey, this, 'create', context, applicationData);
- controller.initialize();
- }
- controller.buildWidgetList();
+ controller.beginOfBuild(context);
return Scaffold(
appBar: applicationData.appBarBuilder('Neues Startmenü'),
drawer: applicationData.drawerBuilder(context),
configuration: applicationData.configuration,
));
}
+
+ @override
+ void initState() {
+ super.initState();
+ controller =
+ MenuController(_formKey, this, 'create', context, applicationData);
+ controller.initialize();
+ }
+
+ @override
+ void redraw(RedrawReason reason,
+ {String customString, RedrawCallbackFunctionSimple callback}) {
+ setState(() {
+ controller.afterSetState(reason,
+ customString: customString, callback: callback);
+ });
+ }
}
import 'package:flutter/material.dart';
-
+import '../../model/page_model.dart';
import '../../widget/list_form.dart';
import '../../widget/page_controller_bones.dart';
import '../application_data.dart';
}
}
-class MenuListPageState extends State<MenuListPage> {
+class MenuListPageState extends State<MenuListPage> implements RedrawPage {
final ApplicationData applicationData;
final GlobalKey<FormState> _formKey =
MenuListPageState(this.applicationData);
- @override
- void initState() {
- super.initState();
- controller =
- MenuController(_formKey, this, 'list', context, applicationData,
- redrawCallback: (RedrawReason reason,
- {String customString, RedrawCallbackFunctionSimple callback}) {
- switch (reason) {
- case RedrawReason.fetchList:
- controller.buildRows();
- break;
- case RedrawReason.callback:
- callback(RedrawReason.custom, customString);
- setState(() {});
- break;
- default:
- setState(() {});
- break;
- }
- });
- controller.initialize();
- controller.buildWidgetList();
- controller.buildRows();
- controller.completeAsync();
- }
-
@override
Widget build(BuildContext context) {
- controller.buildHandler(context);
+ controller.beginOfBuild(context);
return Scaffold(
appBar: applicationData.appBarBuilder('Startmenüs'),
drawer: applicationData.drawerBuilder(context),
RaisedButton(
child: Text('Neues Startmenü'),
onPressed: () {
- Navigator.pushNamed(context, '/menu/create');
-
- /// Force the redraw on return:
- controller.listRows = null;
+ controller.goTo(pageType: PageModelType.create);
},
),
]),
),
);
}
+
+ @override
+ void initState() {
+ super.initState();
+ controller =
+ MenuController(_formKey, this, 'list', context, applicationData);
+ controller.initialize();
+ }
+
+ @override
+ void redraw(RedrawReason reason,
+ {String customString, RedrawCallbackFunctionSimple callback}) {
+ setState(() {
+ controller.afterSetState(reason,
+ customString: customString, callback: callback);
+ });
+ }
}
import 'package:flutter/material.dart';
-
import '../../helper/settings.dart';
import '../../widget/edit_form.dart';
import '../../widget/page_controller_bones.dart';
}
}
-class RoleChangePageState extends State<RoleChangePage> {
+class RoleChangePageState extends State<RoleChangePage> implements RedrawPage{
final ApplicationData applicationData;
final int primaryId;
final Map initialRow;
@override
Widget build(BuildContext context) {
- if (controller == null) {
- controller =
- RoleController(_formKey, this, 'change', context, applicationData,
- redrawCallback: (RedrawReason reason,
- {String customString,
- RedrawCallbackFunctionSimple callback}) {
- switch (reason) {
- case RedrawReason.callback:
- callback(RedrawReason.custom, customString);
- setState(() {});
- break;
- default:
- setState(() {});
- break;
- }
- });
- controller.initialize();
- }
- // controller.buildWidgetList() is called in editForm
+ controller.beginOfBuild(context);
return Scaffold(
appBar: applicationData.appBarBuilder('Rolle ändern'),
drawer: applicationData.drawerBuilder(context),
initialRow: initialRow,
));
}
+ @override
+ void initState() {
+ super.initState();
+ controller = RoleController(
+ _formKey, this, 'change', context, applicationData);
+ controller.initialize();
+ }
+ @override
+ void redraw(RedrawReason reason,
+ {String customString, RedrawCallbackFunctionSimple callback}) {
+ setState(() {
+ controller.afterSetState(reason,
+ customString: customString, callback: callback);
+ });
+ }
void dispose() {
controller.dispose();
super.dispose();
class RoleController extends PageControllerBones {
/// Controller for a page named [pageName].
- RoleController(GlobalKey<FormState> formKey, State<StatefulWidget> parent,
+ RoleController(GlobalKey<FormState> formKey, RedrawPage parent,
String pageName, BuildContext context, ApplicationData applicationData,
{Function redrawCallback})
: super(formKey, parent, RoleModel(Settings().logger), pageName, context,
import '../../helper/settings.dart';
import '../../widget/edit_form.dart';
+import '../../widget/page_controller_bones.dart';
import '../application_data.dart';
import 'role_controller.dart';
}
}
-class RoleCreatePageState extends State<RoleCreatePage> {
+class RoleCreatePageState extends State<RoleCreatePage> implements RedrawPage{
final ApplicationData applicationData;
final GlobalKey<FormState> _formKey =
@override
Widget build(BuildContext context) {
- if (controller == null) {
- controller =
- RoleController(_formKey, this, 'create', context, applicationData);
- controller.initialize();
- }
- controller.buildWidgetList();
+ controller.beginOfBuild(context);
return Scaffold(
appBar: applicationData.appBarBuilder('Neue Rolle'),
drawer: applicationData.drawerBuilder(context),
configuration: applicationData.configuration,
));
}
+ @override
+ void initState() {
+ super.initState();
+ controller = RoleController(
+ _formKey, this, 'create', context, applicationData);
+ controller.initialize();
+ }
+
+ @override
+ void redraw(RedrawReason reason,
+ {String customString, RedrawCallbackFunctionSimple callback}) {
+ setState(() {
+ controller.afterSetState(reason,
+ customString: customString, callback: callback);
+ });
+ }
}
import 'package:flutter/material.dart';
-
+import '../../model/page_model.dart';
import '../../widget/list_form.dart';
import '../../widget/page_controller_bones.dart';
import '../application_data.dart';
}
}
-class RoleListPageState extends State<RoleListPage> {
+class RoleListPageState extends State<RoleListPage> implements RedrawPage{
final ApplicationData applicationData;
final GlobalKey<FormState> _formKey =
RoleListPageState(this.applicationData);
- @override
- void initState() {
- super.initState();
- controller =
- RoleController(_formKey, this, 'list', context, applicationData,
- redrawCallback: (RedrawReason reason,
- {String customString, RedrawCallbackFunctionSimple callback}) {
- switch (reason) {
- case RedrawReason.fetchList:
- controller.buildRows();
- break;
- case RedrawReason.callback:
- callback(RedrawReason.custom, customString);
- setState(() {});
- break;
- default:
- setState(() {});
- break;
- }
- });
- controller.initialize();
- controller.buildWidgetList();
- controller.buildRows();
- controller.completeAsync();
- }
-
@override
Widget build(BuildContext context) {
- controller.buildHandler(context);
+ controller.beginOfBuild(context);
return Scaffold(
appBar: applicationData.appBarBuilder('Rollen'),
drawer: applicationData.drawerBuilder(context),
RaisedButton(
child: Text('Neue Rolle'),
onPressed: () {
- Navigator.pushNamed(context, '/role/create');
-
- /// Force the redraw on return:
- controller.listRows = null;
+ controller.goTo(pageType: PageModelType.create);
},
),
]),
),
);
}
+
+ @override
+ void initState() {
+ super.initState();
+ controller =
+ RoleController(_formKey, this, 'list', context, applicationData);
+ controller.initialize();
+ }
+
+ @override
+ void redraw(RedrawReason reason,
+ {String customString, RedrawCallbackFunctionSimple callback}) {
+ setState(() {
+ controller.afterSetState(reason,
+ customString: customString, callback: callback);
+ });
+ }
}
import 'package:flutter/material.dart';
+
import '../../helper/settings.dart';
import '../../model/button_model.dart';
import '../../widget/edit_form.dart';
}
}
-class UserChangePageState extends State<UserChangePage> {
+class UserChangePageState extends State<UserChangePage> implements RedrawPage {
final ApplicationData applicationData;
final int primaryId;
final Map initialRow;
@override
Widget build(BuildContext context) {
- if (controller == null) {
- controller =
- UserController(_formKey, this, 'change', context, applicationData,
- redrawCallback: (RedrawReason reason,
- {String customString,
- RedrawCallbackFunctionSimple callback}) {
- switch (reason) {
- case RedrawReason.callback:
- callback(RedrawReason.custom, customString);
- setState(() {});
- break;
- default:
- setState(() {});
- break;
- }
- });
- controller.initialize();
- customize();
- }
- // controller.buildWidgetList() is called in editForm
+ controller.beginOfBuild(context);
return Scaffold(
appBar: applicationData.appBarBuilder('Benutzer ändern'),
drawer: applicationData.drawerBuilder(context),
controller.dispose();
super.dispose();
}
+
+ @override
+ void initState() {
+ super.initState();
+ controller =
+ UserController(_formKey, this, 'change', context, applicationData);
+ controller.initialize();
+ customize();
+ }
+
+ @override
+ void redraw(RedrawReason reason,
+ {String customString, RedrawCallbackFunctionSimple callback}) {
+ setState(() {
+ controller.afterSetState(reason,
+ customString: customString, callback: callback);
+ });
+ }
}
class UserController extends PageControllerBones {
/// Controller for a page named [pageName].
- UserController(GlobalKey<FormState> formKey, State<StatefulWidget> parent,
+ UserController(GlobalKey<FormState> formKey, RedrawPage parent,
String pageName, BuildContext context, ApplicationData applicationData,
{Function redrawCallback})
: super(formKey, parent, UserModel(Settings().logger), pageName, context,
MaterialPageRoute(
builder: (context) => UserChangePage(id, applicationData, row)));
}
+
}
import '../../helper/settings.dart';
import '../../widget/edit_form.dart';
+import '../../widget/page_controller_bones.dart';
import '../application_data.dart';
import 'user_controller.dart';
}
}
-class UserCreatePageState extends State<UserCreatePage> {
+class UserCreatePageState extends State<UserCreatePage> implements RedrawPage {
final ApplicationData applicationData;
final GlobalKey<FormState> _formKey =
@override
Widget build(BuildContext context) {
- if (controller == null) {
- controller =
- UserController(_formKey, this, 'create', context, applicationData);
- controller.initialize();
- }
- controller.buildWidgetList();
+ controller.beginOfBuild(context);
return Scaffold(
- appBar: applicationData.appBarBuilder('Neue Rolle'),
+ appBar: applicationData.appBarBuilder('Neuer Benutzer'),
drawer: applicationData.drawerBuilder(context),
body: EditForm.editForm(
key: _formKey,
configuration: applicationData.configuration,
));
}
+
+ @override
+ void initState() {
+ super.initState();
+ controller =
+ UserController(_formKey, this, 'create', context, applicationData);
+ controller.initialize();
+ }
+
+ @override
+ void redraw(RedrawReason reason,
+ {String customString, RedrawCallbackFunctionSimple callback}) {
+ setState(() {
+ controller.afterSetState(reason,
+ customString: customString, callback: callback);
+ });
+ }
}
import 'package:flutter/material.dart';
+import 'package:flutter_bones/flutter_bones.dart';
+import '../../model/page_model.dart';
import '../../widget/list_form.dart';
import '../../widget/page_controller_bones.dart';
import '../application_data.dart';
}
}
-class UserListPageState extends State<UserListPage> {
+class UserListPageState extends State<UserListPage> implements RedrawPage {
final ApplicationData applicationData;
final GlobalKey<FormState> _formKey =
UserListPageState(this.applicationData);
- @override
- void initState() {
- super.initState();
- controller =
- UserController(_formKey, this, 'list', context, applicationData,
- redrawCallback: (RedrawReason reason,
- {String customString, RedrawCallbackFunctionSimple callback}) {
- switch (reason) {
- case RedrawReason.fetchList:
- controller.buildRows();
- break;
- case RedrawReason.callback:
- callback(RedrawReason.custom, customString);
- setState(() {});
- break;
- default:
- setState(() {});
- break;
- }
- });
- controller.initialize();
- controller.buildWidgetList();
- controller.buildRows();
- controller.completeAsync();
- }
-
@override
Widget build(BuildContext context) {
- controller.buildHandler(context);
+ controller.beginOfBuild(context);
return Scaffold(
appBar: applicationData.appBarBuilder('Benutzer'),
drawer: applicationData.drawerBuilder(context),
RaisedButton(
child: Text('Neuer Benutzer'),
onPressed: () {
- Navigator.pushNamed(context, '/user/create');
-
- /// Force the redraw on return:
- controller.listRows = null;
+ controller.goTo(pageType: PageModelType.create);
},
),
]),
),
);
}
+
+ @override
+ void initState() {
+ super.initState();
+ controller =
+ UserController(_formKey, this, 'list', context, applicationData);
+ controller.initialize();
+ }
+
+ @override
+ void redraw(RedrawReason reason,
+ {String customString, RedrawCallbackFunctionSimple callback}) {
+ setState(() {
+ controller.afterSetState(reason,
+ customString: customString, callback: callback);
+ });
+ }
}
import '../../widget/edit_form.dart';
import '../../widget/page_controller_bones.dart';
import '../application_data.dart';
-import 'user_controller.dart';
import 'hash.dart';
+import 'user_controller.dart';
class UserLoginPage extends StatefulWidget {
final ApplicationData applicationData;
}
}
-class UserLoginPageState extends State<UserLoginPage> {
+class UserLoginPageState extends State<UserLoginPage> implements RedrawPage {
final ApplicationData applicationData;
final GlobalKey<FormState> _formKey =
GlobalKey<FormState>(debugLabel: 'user.login');
@override
Widget build(BuildContext context) {
- if (controller == null) {
- controller =
- UserController(_formKey, this, 'login', context, applicationData,
- redrawCallback: (RedrawReason reason,
- {String customString,
- RedrawCallbackFunctionSimple callback}) {
- switch (reason) {
- case RedrawReason.callback:
- callback(RedrawReason.custom, customString);
- setState(() {});
- break;
- default:
- setState(() {});
- break;
- }
- });
- controller.initialize();
- customize();
- }
- // controller.buildWidgetList() is called in editForm
+ controller.beginOfBuild(context);
return Scaffold(
- appBar: applicationData.appBarBuilder('Passwort ändern'),
+ appBar: applicationData.appBarBuilder('Anmelden'),
drawer: applicationData.drawerBuilder(context),
body: EditForm.editForm(
key: _formKey,
controller.dispose();
super.dispose();
}
+
+ @override
+ void initState() {
+ super.initState();
+ controller =
+ UserController(_formKey, this, 'login', context, applicationData);
+ controller.initialize();
+ customize();
+ }
+
+ @override
+ void redraw(RedrawReason reason,
+ {String customString, RedrawCallbackFunctionSimple callback}) {
+ setState(() {
+ controller.afterSetState(reason,
+ customString: customString, callback: callback);
+ });
+ }
}
import '../../widget/edit_form.dart';
import '../../widget/page_controller_bones.dart';
import '../application_data.dart';
-import 'user_controller.dart';
import 'hash.dart';
+import 'user_controller.dart';
class UserPasswordPage extends StatefulWidget {
final ApplicationData applicationData;
}
}
-class UserPasswordPageState extends State<UserPasswordPage> {
+class UserPasswordPageState extends State<UserPasswordPage> implements RedrawPage {
final ApplicationData applicationData;
final int primaryId;
final String userName;
@override
Widget build(BuildContext context) {
- if (controller == null) {
- controller =
- UserController(_formKey, this, 'password', context, applicationData,
- redrawCallback: (RedrawReason reason,
- {String customString,
- RedrawCallbackFunctionSimple callback}) {
- switch (reason) {
- case RedrawReason.callback:
- callback(RedrawReason.custom, customString);
- setState(() {});
- break;
- default:
- setState(() {});
- break;
- }
- });
- controller.initialize();
- customize();
- }
- // controller.buildWidgetList() is called in editForm
+ controller.beginOfBuild(context);
return Scaffold(
appBar: applicationData.appBarBuilder('Passwort ändern'),
drawer: applicationData.drawerBuilder(context),
}
void customize() {
+ controller.placeholders['user'] = userName;
ButtonModel button = controller.page.buttonByName('store');
button?.onPressed = () {
if (_formKey.currentState.validate()) {
controller.dispose();
super.dispose();
}
+
+ @override
+ void initState() {
+ super.initState();
+ controller =
+ UserController(_formKey, this, 'password', context, applicationData);
+ controller.initialize();
+ customize();
+ }
+
+ @override
+ void redraw(RedrawReason reason,
+ {String customString, RedrawCallbackFunctionSimple callback}) {
+ setState(() {
+ controller.afterSetState(reason,
+ customString: customString, callback: callback);
+ });
+ }
}
/// A cache for objects coming from a persistence layer.
/// Uses the least recently used algorithm to avoid overflow.
class PersistenceCache {
- static final regExpCombobox =
+ /// format: <nickname>.<sqlType>.<sqlName>;<col_text> <col_value>;<parameters>...
+ static final regExpComboboxDbColumn =
RegExp(r'^\w+\.\w+\.\w+;\w+ \w+;( ?:\w+=\S*)*$');
+
+ /// format: <nickname>.scope.<scope>;<col_text> <col_value>;<parameters>...
+ static final regExpComboboxConfiguration =
+ RegExp(r'^\w+\.scope\.\w+;\w+ \w+;( ?:\w+=\S*)*$');
static final regExpRecord = RegExp(r'^\w+\.\w+\.\w+;( ?:\w+=\S*)+$');
static int nextRecordNo = 0;
final leastReasentlyUsed = <CacheEntry>[];
/// The format of [key]:
/// "<id>.<module>.<sqlName>;<colText> <colValue>;<param1> <param2>..."
/// e.g. "x99.role.list;role_name role_id;:role_name=% :role_active=T"
+ /// or
+ /// "<id> scope=<scope>
+ /// e.g. "icons scope=icons"
/// If [hasUndef] is true the first combobox list entry is '-' with the value null.
/// If [oneTime] is true the result is only used one time, the LRU algoritm is
/// not used.
- Future<ComboboxData> comboboxAsync(String key,
+ Future<ComboboxData> comboboxAsync(ComboboxListType listType, String key,
{bool hasUndef = false, bool oneTime = false}) async {
ComboboxData rc;
- if (regExpCombobox.firstMatch(key) == null) {
- logger.error('wrong key syntax: $key');
+ String errorMessage;
+ switch (listType) {
+ case ComboboxListType.dbColumn:
+ if (regExpComboboxDbColumn.firstMatch(key) == null) {
+ errorMessage = 'wrong key syntax: $key';
+ }
+ break;
+ case ComboboxListType.configuration:
+ if (regExpComboboxConfiguration.firstMatch(key) == null) {
+ errorMessage = 'wrong key syntax: $key';
+ }
+ break;
+ default:
+ errorMessage = 'comboboxAsync(): unknown listType: $listType';
+ break;
+ }
+ if (errorMessage != null) {
+ logger.error(errorMessage);
} else if (map.containsKey(key)) {
final entry = updateLRU(key);
rc = entry.comboboxData;
});
final texts = hasUndef ? ['-'] : <String>[];
final values = hasUndef ? <dynamic>[null] : <dynamic>[];
-
+ if (listType == ComboboxListType.configuration) {
+ params2[':scope'] = idModuleName[2];
+ idModuleName[1] = 'configuration';
+ idModuleName[2] = 'combobox_by_scope';
+ }
final rows = await persistence.list(
module: idModuleName[1], sqlName: idModuleName[2], params: params2);
final entry = CacheEntry(key, CacheEntryType.combobox,
import 'package:flutter/material.dart';
+import '../page/application_data.dart';
import '../page/configuration/configuration_list_page.dart';
import '../page/demo_page.dart';
+import '../page/menu/menu_list_page.dart';
import '../page/role/role_list_page.dart';
import '../page/user/user_list_page.dart';
import '../page/user/user_login_page.dart';
-import '../page/application_data.dart';
import 'bsettings.dart';
class MenuItem {
rc = RoleListPage(applicationData);
break;
case 'configuration.list':
- rc = RoleListPage(applicationData);
+ rc = ConfigurationListPage(applicationData);
break;
case 'menu.list':
- rc = RoleListPage(applicationData);
+ rc = MenuListPage(applicationData);
break;
case 'demo':
rc = DemoPage(applicationData);
typedef RedrawCallbackFunction = Function(RedrawReason reason,
{String customString, RedrawCallbackFunctionSimple callback});
typedef RedrawCallbackFunctionSimple = Function(
- RedrawReason reason, String customString);
+ RedrawReason reason, {String customString});
class PageControllerBones implements ValidatorController {
final ModuleModel moduleModel;
final GlobalKey<FormState> globalKey;
final String pageName;
PageModel page;
+ ThemeData themeData;
Future<bool> waitForCompletion;
final ApplicationData applicationData;
- State parent;
+ RedrawPage parent;
final BuildContext context;
Iterable listRows;
final textControllers = <String, TextEditingController>{};
- final comboboxDataMap = <String, ComboboxData>{};
final asyncCompletedModels = <ComboBaseModel>[];
int refreshCounter = 0;
+ final placeholders = <String, String>{};
+
+ /// Opens another page.
+ /// Use exactly one of the parameter:
+ /// [pageType]: in this case the route will be constructed
+ /// [route]: the route of the new page, e.g. '/role/change'
+ void goTo({ PageModelType pageType, String route}) {
+ applicationData.pushCaller(this);
+ if (pageType != null){
+ route = '/${moduleModel.name}/${StringUtils.enumToString(pageType)}';
+ }
+ Navigator.pushNamed(context, route);
+ }
PageControllerBones(this.globalKey, this.parent, this.moduleModel,
this.pageName, this.context, this.applicationData,
[this.redrawCallback]);
+ void afterSetState(RedrawReason reason,
+ {String customString, RedrawCallbackFunctionSimple callback}) {
+ if (callback != null) {
+ callback(reason, customString: customString);
+ }
+ }
+
Future<ComboboxData> buildComboboxDataFromPersistence(
ComboBaseModel model) async {
- final rc = await applicationData.persistenceCache
- .comboboxAsync(model.listOption, hasUndef: model.hasOption('undef'));
+ final rc = await applicationData.persistenceCache.comboboxAsync(
+ model.listType, model.listOption,
+ hasUndef: model.hasOption('undef'));
return rc;
}
/// This method should be called in each stateful widget of a page in the
/// build() method.
- void buildHandler(BuildContext context) {
+ void beginOfBuild(BuildContext context) {
if (asyncCompletedModels.isNotEmpty && ++refreshCounter == 1) {
wait(millisec: 2000).then((any) => reload());
}
page.fields.forEach((element) => prepareModel(element));
}
- @deprecated
- ComboboxData comboboxData(String name) {
- ComboboxData rc = comboboxDataMap.containsKey(name)
- ? comboboxDataMap[name]
- : ComboboxData([], null);
- comboboxDataMap[name] = rc;
- if (rc.waitState == WaitState.undef) {
- ComboBaseModel model = page.fieldByName(name) as ComboBaseModel;
- if (model != null) {
- switch (model.listType) {
- case ComboboxListType.explicite:
- rc = ComboboxData(model.texts, model.values, WaitState.ready);
- comboboxDataMap[name] = rc;
- break;
- case ComboboxListType.undef:
- rc = ComboboxData([], [], WaitState.ready);
- comboboxDataMap[name] = rc;
- break;
- case ComboboxListType.dbColumn:
- comboboxDataDb(model, rc);
- break;
- case ComboboxListType.configuration:
- break;
- }
- }
- }
- return rc;
- }
-
- @deprecated
- void comboboxDataDb(ComboBaseModel model, ComboboxData data) {
- // example: xxx.role.list;role_displayname role_id;:role_name=% :excluded=0'
- final keyColumnsParams = model.listOption.split(';');
- final nameModuleSql = keyColumnsParams[0].split('.');
- final cols = keyColumnsParams[1].split(' ');
- final params = <String, dynamic>{};
- if (keyColumnsParams.length > 2 && keyColumnsParams[2].isNotEmpty) {
- keyColumnsParams[2].split(' ').forEach((element) {
- final keyValue = element.split('=');
- params[keyValue[0]] = keyValue[1];
- });
- }
- applicationData.persistence
- .list(
- module: nameModuleSql[1], sqlName: nameModuleSql[2], params: params)
- .then((rows) {
- rows.forEach((row) {
- data.texts.add(row[cols[0]]);
- var value = row[cols[1]];
- if (value is String) {
- value = StringHelper.fromString(value, model.dataType);
- }
- data.addValue(value);
- });
- if (model.hasOption('undef')) {
- data.texts.insert(0, '-');
- data.insertValue(0, null);
- }
- data.waitState = WaitState.ready;
- redraw(RedrawReason.redraw);
- });
- }
-
/// Completes the widgets asynchronously if needed.
void completeAsync() {
waitForCompletion = completeModelsAsync();
/// Completes models synchronously if possible or initializes the asynchronous
/// completion.
void completeModels(WidgetModel model) {
- if (model is ComboBaseModel && model.listOption != null) {
- model.data =
- applicationData.persistenceCache.comboboxFromCache(model.listOption);
+ if (model is ComboBaseModel && model.listType != null) {
+ if (model.listOption != null) {
+ model.data = applicationData.persistenceCache
+ .comboboxFromCache(model.listOption);
+ }
if (model.data == null) {
if (model.mustCompletedAsync) {
asyncCompletedModels.add(model);
Future.forEach(asyncCompletedModels, (ComboBaseModel model) async {
switch (model.listType) {
case ComboboxListType.dbColumn:
+ case ComboboxListType.configuration:
final data = await buildComboboxDataFromPersistence(model);
model.data = data;
break;
});
}
- /// Returns a [WidgetList] filled with widgets
- @deprecated
- WidgetList filterSet({@required String pageName}) {
- final rc = WidgetList('${page.fullName()}.widgets', moduleModel.logger);
- moduleModel
- .pageByName(pageName)
- .fields
- .where((element) => element.filterType != null)
- .forEach((element) {
- Widget widget = View().modelToWidget(element, this);
- if (element.widgetModelType == WidgetModelType.combobox) {
- rc.waitCandidates.add(element);
- }
- rc.addWidget(element.name, widget);
- });
- return rc;
- }
-
/// Returns the container for application specific information.
ApplicationData getApplicationData() {
return applicationData;
/// e.g. ModuleModel.parse() is called.
/// This method must be called early after the constructor.
void initialize() {
+ themeData = Theme.of(context);
page = moduleModel.pageByName(pageName);
widgetList = WidgetList('${page.fullName()}.widgets', moduleModel.logger);
+ buildWidgetList();
+ if (page?.pageModelType == PageModelType.list) {
+ buildRows();
+ }
+ completeAsync();
}
/// Copies the values of [initialRow] into the values of the fields.
/// [reason] and [customString] will be forwarded to the callback function.
void redraw(RedrawReason reason,
{String customString, RedrawCallbackFunctionSimple callback}) {
- if (redrawCallback == null) {
- moduleModel.logger.error(
- 'not overridden: fetchListRows() in ${moduleModel.widgetName()}.$pageName');
- } else {
- if (reason == RedrawReason.setError) {
- applicationData.setLastErrorMessage(page.fullName(), customString);
- }
- redrawCallback(reason, customString: customString, callback: callback);
+ switch(reason){
+ case RedrawReason.fetchList:
+ buildRows();
+ break;
+ default:
+ parent.redraw(reason, customString: customString, callback: callback);
+ break;
}
}
}
// This interface allows the generic handling of the edit form by a model driven module.
+/// An interface for enforcing the redraw of a page.
+abstract class RedrawPage {
+ /// Enforces a redraw (= setState()) of a page.
+ void redraw(RedrawReason reason,
+ {String customString, RedrawCallbackFunctionSimple callback});
+}
+
enum RedrawReason {
custom,
callback,
static View _instance;
Settings settings;
BaseConfiguration widgetConfiguration;
-
+ static final regExpPlaceholder = RegExp(r'~(\w~)~');
final BaseLogger logger;
factory View([BaseLogger logger]) {
Widget combobox(
ComboBaseModel model, PageControllerBones controller, initialValue) {
Widget rc;
- if (model.data != null && model.data.waitState == WaitState.ready) {
+ if (model != null && model.data?.waitState == WaitState.ready) {
rc = comboboxRaw(model, controller, initialValue);
} else {
rc = FutureBuilder<bool>(
if (snapshot.hasData) {
return comboboxRaw(model, controller, initialValue);
} else if (snapshot.hasError) {
- return errorMessage(snapshot.error);
+ return errorMessage(snapshot.error.toString());
} else {
return Container(
alignment: Alignment.topCenter,
if (comboboxData == null || comboboxData.texts.length == 0) {
items.add(DropdownMenuItem(
onTap: controller.getOnTap(model.name, controller),
- value: null,
+ value: initialValue,
child: Text('-')));
} else {
for (var ix = 0; ix < comboboxData.texts.length; ix++) {
rc = emptyLine(model);
break;
case WidgetModelType.text:
- rc = text(model);
+ rc = text(model, controller);
break;
case WidgetModelType.checkbox:
rc = checkbox(model, controller, initialValue);
}
/// Creates a text from the [model].
- Widget text(TextModel model) {
- final rc = Text(model.text);
+ Widget text(TextModel model, PageControllerBones controller) {
+ var text = model.text;
+ if (model.hasOption('placeholders')){
+ text = StringHelper.replacePlaceholders(text, controller.placeholders, regExpPlaceholder: regExpPlaceholder);
+ }
+ TextStyle style;
+ if (model.hasOption('h1')) {
+ style = controller.themeData.textTheme.headline1;
+ } else if (model.hasOption('h2')){
+ style = controller.themeData.textTheme.headline2;
+ } else if (model.hasOption('h3')){
+ style = controller.themeData.textTheme.headline3;
+ } else if (model.hasOption('h4')){
+ style = controller.themeData.textTheme.headline4;
+ } else if (model.hasOption('h5')){
+ style = controller.themeData.textTheme.headline5;
+ }
+ final rc = Text(model.text, style: style);
return rc;
}
--- /dev/null
+import 'package:http/http.dart' as http;
+
+class EMail {
+ static sendRegistrationNotification(String email) async {
+ Map<String, String> headers = new Map();
+ headers["Authorization"] = "Bearer SENDGRIDAPIKEY";
+ headers["Content-Type"] = "application/json";
+
+ var url = 'https://api.sendgrid.com/v3/mail/send';
+ var response = await http.post(url, headers: headers, body: '''{
+ \"personalizations\": [
+ {
+ \"to\": [
+ {
+ \"email\": \"jerrod@liftaixxx.com\"
+ },
+ {
+ \"email\": \"darran@gmailxxx.com\"
+ }
+ ]
+ }
+ ],
+ \"from\": {
+ \"email\": \"app@liftaixxx.com\"
+ },
+ \"subject\": \"New user registration\",
+ \"content\": [
+ {
+ \"type\": \"text\/plain\",
+ \"value\": \"New user register: $email\"
+ }
+ ]
+ }
+ ''');
+ print('Response status: ${response.statusCode}');
+ print('Response body: ${response.body}');
+ }
+}
expect(StringHelper.fromString('2020.1.2', null),
startsWith('<StringHelper.fromString(): unknown datatype'));
});
+ test('replacePlaceholders', () {
+ expect(
+ StringHelper.replacePlaceholders(
+ 'a: ~aa~ b: ~b c: ~c~ ~d~', {'aa': 'x', 'b': 'y', 'c': 'zz'},
+ syntaxPlaceholder: r'~(\w+)~'),
+ equals('a: x b: ~b c: zz ~d~'));
+ });
});
group('dateXToString', () {
test('dateToString', () {
equals('4.3.2020 09:33'));
});
test('asDatabaseString', () {
- expect(StringHelper.asDatabaseString('abc', DataType.string), equals('abc'));
+ expect(
+ StringHelper.asDatabaseString('abc', DataType.string), equals('abc'));
expect(StringHelper.asDatabaseString(345, DataType.int), equals('345'));
- expect(StringHelper.asDatabaseString(34.5, DataType.float), equals('34.5'));
+ expect(
+ StringHelper.asDatabaseString(34.5, DataType.float), equals('34.5'));
expect(StringHelper.asDatabaseString(true, DataType.bool), equals('T'));
expect(StringHelper.asDatabaseString(false, DataType.bool), equals('F'));
- expect(StringHelper.asDatabaseString(null, DataType.bool), equals('NULL'));
- expect(StringHelper.asDatabaseString(null, DataType.currency), equals('NULL'));
- expect(StringHelper.asDatabaseString(DateTime(2020, 3, 4, 9, 33, 44), DataType.dateTime),
+ expect(
+ StringHelper.asDatabaseString(null, DataType.bool), equals('NULL'));
+ expect(StringHelper.asDatabaseString(null, DataType.currency),
+ equals('NULL'));
+ expect(
+ StringHelper.asDatabaseString(
+ DateTime(2020, 3, 4, 9, 33, 44), DataType.dateTime),
equals('2020-03-04 09:33:44'));
- expect(StringHelper.asDatabaseString(DateTime(2020, 3, 4, 9, 33, 44), DataType.date),
+ expect(
+ StringHelper.asDatabaseString(
+ DateTime(2020, 3, 4, 9, 33, 44), DataType.date),
equals('2020-03-04'));
});
});
'b',
ButtonModelType.store,
[],
- null,
logger));
page.addButton(ButtonModel.direct(
null,
'b',
ButtonModelType.store,
[],
- null,
logger));
page.buttonByName('unknown');
page.addField(TextFieldModel.direct(
null,
page,
- null,
'x',
'y',
'z',
page.addField(TextFieldModel.direct(
null,
page,
- null,
'x',
'y',
'z',
final dump = module.dump(StringBuffer()).toString();
expect(dump, '''= module role: options:
== table role: options:
- column role_id: DataType.int "Id" options: primary notnull unique readonly
+ column role_id: DataType.int "Id" options: primary notnull unique
column role_name: DataType.string "Rolle" options: unique notnull
column role_priority: DataType.int "Priorität" options:
column role_active: DataType.bool "Aktiv" options:
- column role_createdat: DataType.dateTime "Erzeugt" options: hidden null
- column role_createdby: DataType.string "Erzeugt von" options: hidden
- column role_changedat: DataType.dateTime "Geändert" options: hidden null
- column role_changedby: DataType.string "Geändert von" options: hidden
+ column role_createdat: DataType.dateTime "Erzeugt" options: null
+ column role_createdby: DataType.string "Erzeugt von" options: null
+ column role_changedat: DataType.dateTime "Geändert" options: null
+ column role_changedby: DataType.string "Geändert von" options: null
== page create: PageModelType.create options:
= section simpleForm1: SectionModelType.simpleForm options: [
allDbFields 10 options:
] # create.simpleForm1
== page change: PageModelType.change options:
= section simpleForm1: SectionModelType.simpleForm options: [
- allDbFields 17 options:
+ allDbFields 21 options:
] # change.simpleForm1
== page list: PageModelType.list options:
= section filterPanel1: SectionModelType.filterPanel options: [
final dump = module.dump(StringBuffer()).toString();
expect(dump, equals('''= module user: options:
== table user: options:
- column user_id: DataType.int "Id" options: primary notnull unique readonly
+ column user_id: DataType.int "Id" options: primary notnull unique
column user_name: DataType.string "User" options: unique notnull
column user_displayname: DataType.string "Anzeigename" options: unique notnull
column user_email: DataType.string "EMail" options: unique notnull
column user_password: DataType.string "Passwort" options: password hidden
column user_role: DataType.reference "Rolle" options: undef
- column user_createdat: DataType.dateTime "Erzeugt" options: hidden null
- column user_createdby: DataType.string "Erzeugt von" options: hidden
- column user_changedat: DataType.dateTime "Geändert" options: hidden null
- column user_changedby: DataType.string "Geändert von" options: hidden
+ column user_createdat: DataType.dateTime "Erzeugt" options: null
+ column user_createdby: DataType.string "Erzeugt von" options: null
+ column user_changedat: DataType.dateTime "Geändert" options: null
+ column user_changedby: DataType.string "Geändert von" options: null
== page create: PageModelType.create options:
= section simpleForm1: SectionModelType.simpleForm options: [
allDbFields 12 options:
] # create.simpleForm1
== page change: PageModelType.change options:
= section simpleForm1: SectionModelType.simpleForm options: [
- allDbFields 20 options:
+ allDbFields 24 options:
button set_password: text: options: Passwort ändern
] # change.simpleForm1
== page password: PageModelType.change options:
= section simpleForm1: SectionModelType.simpleForm options: [
+ text 38 text: Ändern des Passworts von Benutzer ~user~: options: placeholder
textField user_password: options: password
textField repetition: options: password
] # password.simpleForm1
final dump = module.dump(StringBuffer()).toString();
expect(dump, equals('''= module configuration: options:
== table configuration: options:
- column configuration_id: DataType.int "Id" options: primary notnull unique readonly
+ column configuration_id: DataType.int "Id" options: primary notnull unique
column configuration_scope: DataType.string "Bereich" options: notnull
column configuration_property: DataType.string "Eigenschaft" options:
column configuration_order: DataType.int "Reihe" options:
column configuration_type: DataType.string "Datentyp" options:
column configuration_value: DataType.string "Wert" options:
column configuration_description: DataType.string "Beschreibung" options:
- column configuration_createdat: DataType.dateTime "Erzeugt" options: hidden null
- column configuration_createdby: DataType.string "Erzeugt von" options: hidden
- column configuration_changedat: DataType.dateTime "Geändert" options: hidden null
- column configuration_changedby: DataType.string "Geändert von" options: hidden
+ column configuration_createdat: DataType.dateTime "Erzeugt" options: null
+ column configuration_createdby: DataType.string "Erzeugt von" options: null
+ column configuration_changedat: DataType.dateTime "Geändert" options: null
+ column configuration_changedby: DataType.string "Geändert von" options: null
== page create: PageModelType.create options:
= section simpleForm1: SectionModelType.simpleForm options: [
allDbFields 13 options:
] # create.simpleForm1
== page change: PageModelType.change options:
= section simpleForm1: SectionModelType.simpleForm options: [
- allDbFields 23 options:
+ allDbFields 27 options:
] # change.simpleForm1
== page list: PageModelType.list options:
= section filterPanel1: SectionModelType.filterPanel options: [
final dump = module.dump(StringBuffer()).toString();
expect(dump, equals('''= module menu: options:
== table menu: options:
- column menu_id: DataType.int "Id" options: primary notnull unique readonly
+ column menu_id: DataType.int "Id" options: primary notnull unique
column menu_name: DataType.string "Name" options: unique notnull
column menu_icon: DataType.reference "Bild" options:
- column menu_createdat: DataType.dateTime "Erzeugt" options: hidden null
- column menu_createdby: DataType.string "Erzeugt von" options: hidden
- column menu_changedat: DataType.dateTime "Geändert" options: hidden null
- column menu_changedby: DataType.string "Geändert von" options: hidden
+ column menu_createdat: DataType.dateTime "Erzeugt" options: null
+ column menu_createdby: DataType.string "Erzeugt von" options: null
+ column menu_changedat: DataType.dateTime "Geändert" options: null
+ column menu_changedby: DataType.string "Geändert von" options: null
== page create: PageModelType.create options:
= section simpleForm1: SectionModelType.simpleForm options: [
allDbFields 9 options:
] # create.simpleForm1
== page change: PageModelType.change options:
= section simpleForm1: SectionModelType.simpleForm options: [
- allDbFields 15 options:
+ allDbFields 19 options:
] # change.simpleForm1
== page list: PageModelType.list options:
= section filterPanel1: SectionModelType.filterPanel options: [
cache = PersistenceCache(persistence, logger, maxEntries: 2);
});
group('basics', () {
- test('combobox', () async {
+ test('combobox-dbcolumn', () async {
logger.clear();
final cache2 = PersistenceCache(persistence, logger);
expect(cache2, isNotNull);
cache.clear();
const key = 'id1.role.list;role_name role_id;:role_name=%';
const key2 = 'id2.role.list;role_name role_id;:role_name=%';
- var data = await cache.comboboxAsync(key, hasUndef: true);
- var data2 = await cache.comboboxAsync(key2, hasUndef: false);
+ var data = await cache.comboboxAsync(ComboboxListType.dbColumn, key,
+ hasUndef: true);
+ var data2 = await cache.comboboxAsync(ComboboxListType.dbColumn, key2,
+ hasUndef: false);
expect(logger.errors.length, equals(0));
expect(data, isNotNull);
expect(data.texts.length, greaterThan(4));
expect(data.texts.length, equals(data2.valuesLength + 1));
expect(cache.leastReasentlyUsed.length, equals(2));
const key3 = 'id3.role.list;role_name role_id;:role_name=%';
- var data3 = await cache.comboboxAsync(key3, hasUndef: false);
+ var data3 = await cache.comboboxAsync(ComboboxListType.dbColumn, key3,
+ hasUndef: false);
expect(data3, isNotNull);
expect(cache.leastReasentlyUsed.length, equals(2));
expect(cache.map.containsKey(key), isFalse);
logger.clear();
cache.clear();
const key = 'id1.role.list;role_name+role_id;:role_name=%';
- final data = await cache.comboboxAsync(key);
+ final data = await cache.comboboxAsync(ComboboxListType.dbColumn, key);
expect(data, isNull);
expect(logger.errors.length, equals(1));
expect(
cache.clear();
expect(cache, isNotNull);
const key = 'id1.role.list;role_name role_id;:role_name=%';
- var data = await cache.comboboxAsync(key, hasUndef: true);
+ var data = await cache.comboboxAsync(
+ ComboboxListType.dbColumn, key, hasUndef: true);
final data2 = cache.comboboxFromCache(key);
expect(logger.errors.length, equals(0));
expect(data, isNotNull);
expect(data2, isNotNull);
expect(data2, equals(data));
});
+ test('combobox-configuration', () async {
+ logger.clear();
+ final cache2 = PersistenceCache(persistence, logger);
+ expect(cache2, isNotNull);
+ cache.clear();
+ const key = 'id1.scope.icons;configuration_value configuration_id;:role_name=%';
+ var data = await cache.comboboxAsync(
+ ComboboxListType.configuration, key, hasUndef: true);
+ expect(logger.errors.length, equals(0));
+ expect(data, isNotNull);
+ expect(data.texts.length, greaterThan(4));
+ expect(data.texts.length, equals(data.valuesLength));
+ expect(cache.leastReasentlyUsed.length, equals(1));
+ });
});
}
final table = module.tableByName('test');
expect(table, isNotNull);
var model = table.columnByName('test');
- final page = PageModel(module, null, logger);
+ final page = PageModel(module, logger);
page.addField(model);
model.page = page;
expect(model, isNotNull);