text,
}
-class DummyModule extends ModuleMetaData {
- DummyModule() : super('', [], []);
-}
-
/// Describes a field of the page.
class FieldMetaData extends WidgetMetaData {
DataType dataType;
: super(name, WidgetType.field);
}
+/// Describes the list page, that displays an overview over all records of the
+/// related table.
class ListPageMetaData extends PageMetaData {
final String tableHeaders;
final String tableColumns;
name: name, fields: fields, globalComboBoxes: globalComboBoxes);
}
+/// Describes a mapping page, that allows assignments of many table entries
+/// of the member table to one entry of a common table.
+///
+/// Example: Common table is roles, member table is starters. Than the page
+/// allows to assign some starters (menu items) to a role.
+class MappingPageMetaData extends PageMetaData {
+ ModuleMetaData? commonModule;
+ ModuleMetaData? memberModule;
+ PropertyMetaData? commonProperty;
+ PropertyMetaData? memberProperty;
+
+ /// Constructor.
+ ///
+ /// [name] is the page name. It must be unique over all pages in the module.
+ /// Default is a name derived from the page type.
+ ///
+ /// [commonModuleName]: the name of the module containing the common entries
+ /// of the relation.
+ ///
+ /// [memberModuleName]: the name of the module containing the member entries
+ /// that belongs to exactly one entry in the common module.
+ ///
+ /// [commonPropertyName]: the name of the property representing the common module.
+ ///
+ /// [memberPropertyName]: the name of the property representing the member module.
+ ///
+ /// Don't forget to initialize the [commonModule], [memberModule],
+ /// [commonProperty] and [memberProperty] in the overridden method [onInitialized].
+ MappingPageMetaData(String label, {String name = ''})
+ : super(label, PageType.mapping, name: name, fields: []);
+}
+
class MetaException extends FormatException {}
/// Stores the meta data of a module.
return rc;
}
- /// Returns the meta data of a property given by its [name] or null if missing.
- PropertyMetaData? propertyByName(String name) {
- final rc = propertyList.singleWhere((element) => element.name == name,
- orElse: null);
- return rc;
- }
-
/// Returns a property given by the [columnName].
PropertyMetaData? propertyByColumnName(String columnName) {
PropertyMetaData? rc;
return rc;
}
+ /// Returns the meta data of a property given by its [name] or null if missing.
+ PropertyMetaData? propertyByName(String name) {
+ final rc = propertyList.singleWhere((element) => element.name == name,
+ orElse: null);
+ return rc;
+ }
+
/// Returns the properties that are not in [metaColumns].
/// : if the name of the property is [included] the property is always part of
/// the result.
String name = '';
final String label;
final PageType pageType;
- ModuleMetaData module = DummyModule();
+ late ModuleMetaData module;
final List<WidgetMetaData> fields;
final String globalComboBoxes;
PageMetaData(this.label, this.pageType,
}
}
-enum PageType { create, custom, delete, edit, list }
+enum PageType { create, custom, delete, edit, list, mapping }
/// Stores the meta data of a module property stored as column in a database.
class PropertyMetaData extends WidgetMetaData {
- ModuleMetaData module = DummyModule();
+ late ModuleMetaData module;
final String label;
/// Relative width of the field in a 12 column form: 1 <= width <= 12
}
}
+class ReferenceProperty extends WidgetMetaData {
+ /// This attribute gets is real value after the construcctor of the module.
+ PropertyMetaData child = PropertyMetaData('dummy', '', DataType.bool, '');
+ final String nameChild;
+ ReferenceProperty({required this.nameChild})
+ : super(nameChild + 'Ref', WidgetType.referenceProperty);
+}
+
/// Describes a widget used in the page.
/// Base class of all other widgets.
class WidgetMetaData {
WidgetMetaData(this.name, this.widgetType);
}
-enum WidgetType { button, field, dbField, property }
+enum WidgetType { button, field, dbField, property, referenceProperty }
import 'module_meta_data.dart';
import 'benchmarks_meta.dart';
import 'roles_meta.dart';
+import 'rolestarter_meta.dart';
import 'starters_meta.dart';
import 'structures_meta.dart';
import 'users_meta.dart';
case 'Roles':
rc = RolesMeta();
break;
+ case 'Rolestarter':
+ rc = RoleStarterMeta();
+ break;
case 'Starters':
rc = StartersMeta();
break;
return [
'Benchmarks',
'Roles',
+ 'Rolestarter',
'Starters',
'Structures',
'Users',
--- /dev/null
+import '../base/defines.dart';
+import '../base/i18n.dart';
+import 'module_meta_data.dart';
+import 'roles_meta.dart';
+import 'starters_meta.dart';
+
+final i18n = I18N();
+final M = i18n.module("RoleStarter");
+
+class RoleStarterMeta extends ModuleMetaData {
+ static RoleStarterMeta instance = RoleStarterMeta.internal();
+ factory RoleStarterMeta() {
+ return instance;
+ }
+ RoleStarterMeta.internal()
+ : super('RoleStarter', [
+ PropertyMetaData('id', i18n.tr('Id'), DataType.reference, ':primary:',
+ displayType: DisplayType.combobox),
+ PropertyMetaData(
+ 'role', i18n.tr('Role'), DataType.reference, ':notnull:',
+ displayType: DisplayType.combobox,
+ foreignKey: 'roles.role_id;role_name;role'),
+ PropertyMetaData(
+ 'starter', i18n.tr('Starter'), DataType.reference, ':notnull:',
+ displayType: DisplayType.combobox,
+ foreignKey: 'starters.starter_id;starter_name;starter'),
+ PropertyMetaData('createdAt', i18n.tr('Created at'),
+ DataType.datetime, ':hidden:'),
+ PropertyMetaData(
+ 'createdBy', i18n.tr('Created by'), DataType.string, ':hidden:',
+ size: 32),
+ PropertyMetaData('changedAt', i18n.tr('Changed at'),
+ DataType.datetime, ':hidden:'),
+ PropertyMetaData(
+ 'changedBy', i18n.tr('Changed by'), DataType.string, ':hidden:',
+ size: 32),
+ ], [
+ MappingPageMetaData(
+ i18n.tr('Role-Starter Assignment'),
+ ),
+ ]);
+ @override
+ void onInitialized() {
+ super.onInitialized();
+ final page = pageByName('mapping') as MappingPageMetaData;
+ page.commonModule = RolesMeta();
+ page.memberModule = StartersMeta();
+ page.commonProperty = propertyByName('role');
+ page.memberProperty = propertyByName('starter');
+ }
+}
import 'roles/create_role_page.dart';
import 'roles/edit_role_page.dart';
import 'roles/list_role_page.dart';
+import 'rolestarter/mapping_rolestarter_page.dart';
import 'starters/create_starter_page.dart';
import 'starters/edit_starter_page.dart';
import 'starters/delete_starter_page.dart';
case '/Roles/list':
rc = ListRolePage();
break;
+ case '/RoleStarter/mapping':
+ rc = MappingRoleStarterPage();
+ break;
case '/Starters/create':
rc = CreateStarterPage();
break;
typedef FooterBuilder = FooterInterface? Function();
-class DummyFooter implements FooterInterface {
- @override
- Widget widget(PageControllerExhibition controller) {
- return const Text('');
- }
-
- /// Returns a method creating a footer.
- static DummyFooter? builder() => DummyFooter();
-}
-
abstract class FooterInterface {
Widget widget(PageControllerExhibition controller);
}
final FooterBuilder footerBuilder;
final BaseConfiguration configuration;
final RestPersistence? restPersistence;
- HomeDirectories homeDirectories = HomeDirectories.dummy();
+ late HomeDirectories homeDirectories;
final navigatorStack = NavigatorStack();
factory GlobalData() => _instance ?? GlobalData();
- GlobalData.dummy()
- : this.internal(BaseConfiguration({}, globalLogger), (input) => '',
- (input) => '', DummyFooter.builder, null, globalLogger);
-
/// [configuration]: general settings.
/// [appBarBuilder]: a factory to create the Hamburger menu.
/// [footerBuilder]: a factory to create a footer area.
throw FormatException('HomeDirectory.getHomePath(): unknown platform');
}
}
- HomeDirectories.dummy();
}
/// Manages the call stack of the navigator.
}
}
+class _FieldData {
+ int thePageSize = 10;
+ int theOffset = 0;
+#DEF_FIELDS}
+''';
+
+ static final templateMappingCustom =
+ '''// 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 '../../services/global_widget.dart';
+import '../../setting/global_data.dart';
+import '../../widget/attended_page.dart';
+import '../../widget/widget_form.dart';
+import '../../persistence/persistence.dart';
+import 'list_user_page.dart';
+
+final i18n = I18N();
+
+class MappingUserCustom extends State<MappingUserPage> {
+ final globalData = GlobalData();
+ late Future<DbData> _futureDbData;
+ AttendedPage? attendedPage;
+ final _fieldData = _FieldData();
+ final GlobalKey<FormState> _formKey =
+ GlobalKey<FormState>(debugLabel: 'CreateUser');
+#DEF_CONTROLLERS MappingUserCustom();
+ @override
+ Widget build(BuildContext context) {
+ final rc = Scaffold(
+ appBar: globalData.appBarBuilder(i18n.tr('Overview users')),
+ drawer: globalData.drawerBuilder(context),
+ floatingActionButton: FloatingActionButton(
+ onPressed: () {
+ globalData.navigate(context, '/Users/create');
+ },
+ child: const Icon(Icons.add),
+ tooltip: #TIP_ADD
+ ),
+ body: SafeArea(
+ child: FutureBuilder<DbData>(
+ future: _futureDbData,
+ builder: (context, snapshot) {
+ Widget rc;
+ if (snapshot.connectionState != ConnectionState.done) {
+ rc = const CircularProgressIndicator();
+ } else {
+ if (snapshot.hasData) {
+ final rows = attendedPage!.getRows(dbData: snapshot.data!,
+ columnList: '#ROW_COLUMNS',
+ onDone: () => setState(() => 1),
+ route#EDIT1: '/Users/#EDIT2',
+ context: context);
+ rc = buildFrame(totalCount: snapshot.data?.count ?? rows.length,
+ rows: rows);
+ } else if (snapshot.hasError) {
+ rc = Text('Backend problem: \${snapshot.error}');
+ } else {
+ rc = const CircularProgressIndicator();
+ }
+ }
+ return rc;
+ },
+ )),
+ );
+ return rc;
+ }
+
+ Widget buildFrame({required JsonList rows, required int totalCount}){
+ final padding = GlobalThemeData.padding;
+#INIT_COMBOS final formItems = <FormItem>[
+#FORM_ITEMS 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 table = DataTable(
+ columns: <DataColumn>[
+#TABLE_HEADER ],
+ rows: rows as List<DataRow>,
+ );
+ Widget? tabBar = attendedPage!.buildChipBar(
+ totalCount: totalCount,
+ offset: _fieldData.theOffset,
+ pageSize: _fieldData.thePageSize,
+ onTap: (offset) {
+ _fieldData.theOffset = offset;
+ requestRecords();
+ setState(() => 1);
+ });
+ final frameWidget = ListView(children: [
+ form,
+ if (tabBar != null) tabBar,
+ SizedBox(height: padding),
+ SizedBox(width: double.infinity, child: table),
+ ]);
+ return frameWidget;
+ }
+
+ @override
+ void didChangeDependencies() {
+ super.didChangeDependencies();
+ requestRecords();
+ }
+
+ @override
+ void dispose() {
+ helperDummyUsage(DataType.string);
+ globalWidgetDummyUsage();
+ super.dispose();
+ }
+
+ @override
+ void initState() {
+ super.initState();
+ }
+
+ void requestRecords() => _futureDbData = globalData.restPersistence!.query(
+ what: 'query', data: {
+ 'module': 'Users',
+ 'sql': 'list',
+ 'offset': _fieldData.theOffset,
+ 'size': _fieldData.thePageSize,
+#PARAM_DEF });
+
+ void search() {
+ attendedPage!.pageStates.dbDataState.clear();
+ if (_formKey.currentState!.validate()) {
+ _formKey.currentState!.save();
+ requestRecords();
+ setState(() => 1);
+ }
+ }
+}
+
class _FieldData {
int thePageSize = 10;
int theOffset = 0;
case PageType.custom:
rc = createRecordCustomized(page);
break;
+ case PageType.mapping:
+ rc = createMappingCustomized(page as MappingPageMetaData);
+ break;
}
return rc;
}
return rc;
}
+ /// Creates the customozed part of the [page] that is PageType.mapping.
+ String createMappingCustomized(MappingPageMetaData page) {
+ var rc = replaceVariables(templateMappingCustom, page)
+ .replaceFirst('#DEF_CONTROLLERS', buildDefinitionControllers(page))
+ .replaceFirst('#INIT_COMBOS', buildInitializeComboBoxes(page))
+ .replaceFirst('#FORM_ITEMS', buildFormItems(page, withController: true))
+ .replaceFirst('#PARAM_DEF', buildParamDefinitions(page));
+ return rc;
+ }
+
/// Returns a Dart class definition of the [page] that should not be modified.
String createPage(PageMetaData page) {
var rc = replaceVariables(templatePage, page);
hasPrimary = true;
break;
case PageType.custom:
- break;
case PageType.list:
+ case PageType.mapping:
break;
}
var rc = replaceVariables(templateRecordCustom, page)