Revolution #1
3 changed files with 346 additions and 1 deletions
88
lib/models/table_column_definition.dart
Normal file
88
lib/models/table_column_definition.dart
Normal file
|
|
@ -0,0 +1,88 @@
|
||||||
|
abstract class TableColumnDefinition {
|
||||||
|
final String columnName;
|
||||||
|
final bool isUnique;
|
||||||
|
|
||||||
|
TableColumnDefinition({
|
||||||
|
required this.columnName,
|
||||||
|
required this.isUnique,
|
||||||
|
});
|
||||||
|
|
||||||
|
String get def => throw UnimplementedError("def getter not implemented");
|
||||||
|
}
|
||||||
|
|
||||||
|
class SerialPrimaryColumnDefinition extends TableColumnDefinition {
|
||||||
|
SerialPrimaryColumnDefinition({
|
||||||
|
required super.columnName,
|
||||||
|
}) : super(isUnique: true);
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get def => "$columnName:serial:primary";
|
||||||
|
}
|
||||||
|
|
||||||
|
class TextColumnDefinition extends TableColumnDefinition {
|
||||||
|
TextColumnDefinition({
|
||||||
|
required super.columnName,
|
||||||
|
required super.isUnique,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get def => "$columnName:str${isUnique ? ":unique" : ""}";
|
||||||
|
}
|
||||||
|
|
||||||
|
class BooleanColumnDefinition extends TableColumnDefinition {
|
||||||
|
BooleanColumnDefinition({
|
||||||
|
required super.columnName,
|
||||||
|
required super.isUnique,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get def => "$columnName:bool${isUnique ? ":unique" : ""}";
|
||||||
|
}
|
||||||
|
|
||||||
|
class TimestampColumnDefinition extends TableColumnDefinition {
|
||||||
|
TimestampColumnDefinition({
|
||||||
|
required super.columnName,
|
||||||
|
required super.isUnique,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get def => "$columnName:datetime${isUnique ? ":unique" : ""}";
|
||||||
|
}
|
||||||
|
|
||||||
|
class DoubleColumnDefinition extends TableColumnDefinition {
|
||||||
|
DoubleColumnDefinition({
|
||||||
|
required super.columnName,
|
||||||
|
required super.isUnique,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get def => "$columnName:float${isUnique ? ":unique" : ""}";
|
||||||
|
}
|
||||||
|
|
||||||
|
class IntegerColumnDefinition extends TableColumnDefinition {
|
||||||
|
IntegerColumnDefinition({
|
||||||
|
required super.columnName,
|
||||||
|
required super.isUnique,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get def => "$columnName:int${isUnique ? ":unique" : ""}";
|
||||||
|
}
|
||||||
|
|
||||||
|
class UserRefColumnDefinition extends TableColumnDefinition {
|
||||||
|
UserRefColumnDefinition({
|
||||||
|
required super.columnName,
|
||||||
|
}) : super(isUnique: false);
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get def => "$columnName:int-user";
|
||||||
|
}
|
||||||
|
|
||||||
|
class AssetRefColumnDefinition extends TableColumnDefinition {
|
||||||
|
AssetRefColumnDefinition({
|
||||||
|
required super.columnName,
|
||||||
|
}) : super(isUnique: false);
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get def => "$columnName:int-asset";
|
||||||
|
}
|
||||||
251
lib/pages/dialogs/create_table_dialog.dart
Normal file
251
lib/pages/dialogs/create_table_dialog.dart
Normal file
|
|
@ -0,0 +1,251 @@
|
||||||
|
import 'package:dio/dio.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_fast_forms/flutter_fast_forms.dart';
|
||||||
|
import 'package:get/get.dart';
|
||||||
|
import 'package:styled_widget/styled_widget.dart';
|
||||||
|
import 'package:tuuli_app/api_controller.dart';
|
||||||
|
import 'package:tuuli_app/models/table_column_definition.dart';
|
||||||
|
|
||||||
|
const typeToNameMatcher = {
|
||||||
|
SerialPrimaryColumnDefinition: "Serial ID",
|
||||||
|
TextColumnDefinition: "Text",
|
||||||
|
BooleanColumnDefinition: "Boolean",
|
||||||
|
TimestampColumnDefinition: "Date/Time",
|
||||||
|
DoubleColumnDefinition: "Double",
|
||||||
|
IntegerColumnDefinition: "Integer",
|
||||||
|
UserRefColumnDefinition: "User reference",
|
||||||
|
AssetRefColumnDefinition: "Asset reference",
|
||||||
|
};
|
||||||
|
|
||||||
|
class CreateTableController extends GetxController {
|
||||||
|
final _tableName = "".obs;
|
||||||
|
String get tableName => _tableName.value;
|
||||||
|
set tableName(String value) => _tableName.value = value;
|
||||||
|
|
||||||
|
final _columnsDefinition = <TableColumnDefinition>[].obs;
|
||||||
|
List<TableColumnDefinition> get columnsDefinition => _columnsDefinition;
|
||||||
|
|
||||||
|
Future<void> createTable() async {
|
||||||
|
try {
|
||||||
|
final resp = await ApiController.to.apiClient.createTable(
|
||||||
|
tableName: tableName,
|
||||||
|
columnsDefinition:
|
||||||
|
_columnsDefinition.map((e) => e.def).toList(growable: false),
|
||||||
|
);
|
||||||
|
|
||||||
|
final respData = resp.data;
|
||||||
|
if (respData == null) {
|
||||||
|
throw Exception("No data in response");
|
||||||
|
}
|
||||||
|
|
||||||
|
Get.back(result: true);
|
||||||
|
} on DioError catch (e) {
|
||||||
|
final respData = e.response?.data;
|
||||||
|
if (respData != null) {
|
||||||
|
Get.snackbar(
|
||||||
|
"Error trying to update tables access",
|
||||||
|
"${respData['error']}",
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
Get.snackbar(
|
||||||
|
"Error trying to update tables access",
|
||||||
|
"$e",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
Get.snackbar(
|
||||||
|
"Error trying to update tables access",
|
||||||
|
"$e",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> createNewColumn() async {
|
||||||
|
final columnName = "".obs;
|
||||||
|
final columnType = "".obs;
|
||||||
|
final columnIsUnique = false.obs;
|
||||||
|
|
||||||
|
final confirm = await Get.dialog<bool>(
|
||||||
|
AlertDialog(
|
||||||
|
title: const Text("Create new column"),
|
||||||
|
content: Wrap(
|
||||||
|
runSpacing: 16,
|
||||||
|
children: [
|
||||||
|
FastTextField(
|
||||||
|
name: "ColumnName",
|
||||||
|
decoration: const InputDecoration(
|
||||||
|
labelText: "Column name",
|
||||||
|
border: OutlineInputBorder(),
|
||||||
|
),
|
||||||
|
initialValue: columnName.value,
|
||||||
|
onChanged: (value) => columnName.value = value ?? "",
|
||||||
|
),
|
||||||
|
FastDropdown(
|
||||||
|
name: "ColumnTypes",
|
||||||
|
hint: const Text("Select column type"),
|
||||||
|
items: typeToNameMatcher.keys.toList(growable: false),
|
||||||
|
itemsBuilder: (items, field) => items
|
||||||
|
.map(
|
||||||
|
(e) => DropdownMenuItem(
|
||||||
|
value: e,
|
||||||
|
child: Text(typeToNameMatcher[e]!),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.toList(),
|
||||||
|
onChanged: (value) =>
|
||||||
|
columnType.value = typeToNameMatcher[value] ?? "",
|
||||||
|
),
|
||||||
|
FastCheckbox(
|
||||||
|
name: "ColumnIsUnique",
|
||||||
|
titleText: "Is Unique",
|
||||||
|
initialValue: false,
|
||||||
|
onChanged: (value) => columnIsUnique.value = value!,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
actions: [
|
||||||
|
TextButton(
|
||||||
|
onPressed: () {
|
||||||
|
Get.back(result: false);
|
||||||
|
},
|
||||||
|
child: const Text('Close'),
|
||||||
|
),
|
||||||
|
TextButton(
|
||||||
|
onPressed: () {
|
||||||
|
Get.back(result: true);
|
||||||
|
},
|
||||||
|
child: const Text('Create'),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
if (confirm != true) return;
|
||||||
|
|
||||||
|
TableColumnDefinition? ct;
|
||||||
|
switch (columnType.value) {
|
||||||
|
case "Serial ID":
|
||||||
|
ct = SerialPrimaryColumnDefinition(
|
||||||
|
columnName: columnName.value,
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
case "Text":
|
||||||
|
ct = TextColumnDefinition(
|
||||||
|
columnName: columnName.value,
|
||||||
|
isUnique: columnIsUnique.value,
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
case "Boolean":
|
||||||
|
ct = BooleanColumnDefinition(
|
||||||
|
columnName: columnName.value,
|
||||||
|
isUnique: columnIsUnique.value,
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
case "Date/Time":
|
||||||
|
ct = TimestampColumnDefinition(
|
||||||
|
columnName: columnName.value,
|
||||||
|
isUnique: columnIsUnique.value,
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
case "Double":
|
||||||
|
ct = DoubleColumnDefinition(
|
||||||
|
columnName: columnName.value,
|
||||||
|
isUnique: columnIsUnique.value,
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
case "Integer":
|
||||||
|
ct = IntegerColumnDefinition(
|
||||||
|
columnName: columnName.value,
|
||||||
|
isUnique: columnIsUnique.value,
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
case "User reference":
|
||||||
|
ct = UserRefColumnDefinition(
|
||||||
|
columnName: columnName.value,
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
case "Asset reference":
|
||||||
|
ct = AssetRefColumnDefinition(
|
||||||
|
columnName: columnName.value,
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (ct == null) return;
|
||||||
|
_columnsDefinition.add(ct);
|
||||||
|
}
|
||||||
|
|
||||||
|
void removeColumn(TableColumnDefinition e) {
|
||||||
|
_columnsDefinition.remove(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class CreateTableDialog extends GetView<CreateTableController> {
|
||||||
|
const CreateTableDialog({Key? key}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return AlertDialog(
|
||||||
|
title: const Text('Creating new table'),
|
||||||
|
content: Column(
|
||||||
|
children: [
|
||||||
|
TextField(
|
||||||
|
decoration: const InputDecoration(
|
||||||
|
labelText: "Table name",
|
||||||
|
border: OutlineInputBorder(),
|
||||||
|
),
|
||||||
|
onChanged: (value) => controller.tableName = value,
|
||||||
|
),
|
||||||
|
const Divider(),
|
||||||
|
Obx(
|
||||||
|
() => ListView(
|
||||||
|
children: controller.columnsDefinition
|
||||||
|
.map(
|
||||||
|
(e) => ListTile(
|
||||||
|
title: Text(e.columnName),
|
||||||
|
subtitle: Text(e.def),
|
||||||
|
trailing: IconButton(
|
||||||
|
onPressed: () => controller.removeColumn(e),
|
||||||
|
icon: const Icon(Icons.delete),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.toList(),
|
||||||
|
).expanded(),
|
||||||
|
),
|
||||||
|
const Divider(),
|
||||||
|
[
|
||||||
|
ElevatedButton(
|
||||||
|
onPressed: () => controller.createNewColumn(),
|
||||||
|
child: const Text("Create column"),
|
||||||
|
).expanded()
|
||||||
|
].toRow(),
|
||||||
|
],
|
||||||
|
).constrained(width: Get.width * 0.9, height: Get.height * 0.9),
|
||||||
|
actions: [
|
||||||
|
TextButton(
|
||||||
|
onPressed: () {
|
||||||
|
Get.back();
|
||||||
|
},
|
||||||
|
child: const Text('Close'),
|
||||||
|
),
|
||||||
|
Obx(
|
||||||
|
() => TextButton(
|
||||||
|
onPressed: controller.columnsDefinition.isEmpty
|
||||||
|
? null
|
||||||
|
: () => controller.createTable(),
|
||||||
|
child: const Text('Create'),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Future<bool?> show() async {
|
||||||
|
Get.lazyPut<CreateTableController>(() => CreateTableController());
|
||||||
|
|
||||||
|
return Get.dialog<bool>(
|
||||||
|
const CreateTableDialog(),
|
||||||
|
barrierDismissible: false,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -5,6 +5,7 @@ import 'package:tuuli_api/tuuli_api.dart';
|
||||||
import 'package:tuuli_app/api_controller.dart';
|
import 'package:tuuli_app/api_controller.dart';
|
||||||
import 'package:recase/recase.dart';
|
import 'package:recase/recase.dart';
|
||||||
import 'package:tuuli_app/models/db_column_definition.dart';
|
import 'package:tuuli_app/models/db_column_definition.dart';
|
||||||
|
import 'package:tuuli_app/pages/dialogs/create_table_dialog.dart';
|
||||||
|
|
||||||
class TablesListPanelController extends GetxController {
|
class TablesListPanelController extends GetxController {
|
||||||
@override
|
@override
|
||||||
|
|
@ -54,7 +55,12 @@ class TablesListPanelController extends GetxController {
|
||||||
_isLoading.value = false;
|
_isLoading.value = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> createNewTable() async {}
|
Future<void> createNewTable() async {
|
||||||
|
final created = await CreateTableDialog.show();
|
||||||
|
if (created == true) {
|
||||||
|
refreshData();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Future<void> openTable(TableDefinition table) async {}
|
Future<void> openTable(TableDefinition table) async {}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue