Rules on dashboard + Permissions

This commit is contained in:
mr 2024-11-21 11:00:44 +01:00
parent 2ceab090fd
commit 7fea931b63
12 changed files with 317 additions and 289 deletions

View File

@ -42,51 +42,42 @@ Map<Perms, String> perms = {
class PermsService { class PermsService {
static final Map<Perms, bool> _perms = { static final Map<Perms, bool> _perms = {
Perms.SEARCH_INTERNAL: true, Perms.SEARCH_INTERNAL: false,
Perms.SEARCH_EXTERNAL: true, Perms.SEARCH_EXTERNAL: false,
Perms.WORKSPACE_SHARE: true, Perms.WORKSPACE_SHARE: false,
Perms.WORKSPACE_UNSHARE: true, Perms.WORKSPACE_UNSHARE: false,
Perms.WORKFLOW_CREATE: true, Perms.WORKFLOW_CREATE: false,
Perms.WORKFLOW_EDIT: true, Perms.WORKFLOW_EDIT: false,
Perms.WORKFLOW_DELETE: true, Perms.WORKFLOW_DELETE: false,
Perms.WORKFLOW_BOOKING: true, Perms.WORKFLOW_BOOKING: false,
Perms.WORKFLOW_SHARE: true, Perms.WORKFLOW_SHARE: false,
Perms.WORKFLOW_UNSHARE: true, Perms.WORKFLOW_UNSHARE: false,
Perms.PEER_SHARE: true, Perms.PEER_SHARE: false,
Perms.PEER_UNSHARE: true, Perms.PEER_UNSHARE: false,
Perms.COLLABORATIVE_AREA_CREATE: true, Perms.COLLABORATIVE_AREA_CREATE: false,
Perms.COLLABORATIVE_AREA_EDIT: true, Perms.COLLABORATIVE_AREA_EDIT: false,
Perms.COLLABORATIVE_AREA_DELETE: true, Perms.COLLABORATIVE_AREA_DELETE: false,
}; };
static final PermsService _instance = PermsService._internal(); static final PermsService _instance = PermsService._internal();
factory PermsService() => _instance; factory PermsService() => _instance;
PermsService._internal(); PermsService._internal();
/* should decode claims such as in oc-auth */ /* should decode claims such as in oc-auth */
static Future<void> init(String token ) async { static Future<void> init(String token ) async {
/* var claims = token.split(".").last; var claims = token.split(".").last;
var decoded = base64.decode(claims); var decoded = base64.decode(claims);
String foo = utf8.decode(decoded); String foo = utf8.decode(decoded);
var what = json.decode(foo);
try { try {
var what = json.decode(foo);
what = what["session"]["access_token"] as Map<String, dynamic>; what = what["session"]["access_token"] as Map<String, dynamic>;
for (var w in perms.values) { for (var w in perms.keys) {
if (what.keys.contains(perms[w])) {
if (what.keys.contains(w)) { _perms[w] = true;
print("CONTAINS");
} else { } else {
for (var y in what.keys) { _perms[w] = false;
print("${w}, ${y} ${what.keys.contains(w)}");
}
} }
} }
} catch (e) { } catch (e) {/**/}
print("THERE");
}*/
_perms.forEach((key, value) {
_perms[key] = true;
});
} }
static void clear() { static void clear() {

View File

@ -11,7 +11,6 @@ class WorkflowExecutionService extends AbstractService<WorkflowExecutions> {
@override String subPath = "/"; @override String subPath = "/";
@override Future<APIResponse<WorkflowExecutions>> search(BuildContext? context, List<String> words, Map<String, dynamic> params) { @override Future<APIResponse<WorkflowExecutions>> search(BuildContext? context, List<String> words, Map<String, dynamic> params) {
print("${subPath}search/${words.join("/")}");
return service.get("${subPath}search/${words.join("/")}", false, context); return service.get("${subPath}search/${words.join("/")}", false, context);
} }

View File

@ -26,9 +26,6 @@ class SchedulerPageWidget extends StatefulWidget {
static Widget factory() { return SchedulerPageWidget(); } static Widget factory() { return SchedulerPageWidget(); }
} }
class SchedulerPageWidgetState extends State<SchedulerPageWidget> { class SchedulerPageWidgetState extends State<SchedulerPageWidget> {
List<Color> colors = [Colors.blue, Colors.orange, redColor, Colors.green, redColor];
List<String> titles = ["SCHEDULED", "RUNNING", "FAILURE", "SUCCESS", "FORGOTTEN"];
@override Widget build(BuildContext context) { @override Widget build(BuildContext context) {
GlobalKey<ScheduleWidgetState> k = GlobalKey<ScheduleWidgetState>(); GlobalKey<ScheduleWidgetState> k = GlobalKey<ScheduleWidgetState>();
return Column( children: [ return Column( children: [

View File

@ -290,6 +290,38 @@ final WorflowService _service = WorflowService();
dash.infoItemWidget = getForms; dash.infoItemWidget = getForms;
dash.infoWidget = getDashInfoForms; dash.infoWidget = getDashInfoForms;
dash.widthOffset = 50; dash.widthOffset = 50;
dash.saveRules = [
(dash) {
dash.error = null;
if (dash.scheduleActive) {
if (dash.elements.isEmpty || dash.elements.where((element) => element.element is ProcessingItem).isEmpty) {
dash.error = "You need at least one processing element";
dash.scheduleActive = false;
}
var processings = dash.elements.where((element) => element.element is ProcessingItem).map((e) => e.element as ProcessingItem);
var computes = dash.elements.where((element) => element.element is ComputeItem).map((e) => e.element as ComputeItem);
if (processings.length != computes.length) {
dash.error = "You need the same number of processing and compute elements";
dash.scheduleActive = false;
}
for (var p in processings) {
var links = dash.arrows.where((element) => element.fromID.contains(p.getID()) || element.toID.contains(p.getID()));
try {
computes.firstWhere( (e) => links.first.toID.contains(e.getID()) || links.first.fromID.contains(e.getID()) );
} catch (e) {
dash.error = "You need to link each processing element to a compute element";
dash.scheduleActive = false;
}
}
if (dash.error != null) {
print(dash.error);
setState(() {});
}
return dash.scheduleActive;
}
return true;
}
];
return FlowChart<AbstractItem>( return FlowChart<AbstractItem>(
key: dash.flutterChartKey, key: dash.flutterChartKey,
itemLeftBottomBadges: getBottomLeftBadge, itemLeftBottomBadges: getBottomLeftBadge,

View File

@ -73,7 +73,7 @@ class ProcessingFormsWidgetState extends State<ProcessingFormsWidget> {
widget.item.model ?? Model(); widget.item.model ?? Model();
Future.delayed(const Duration(seconds: 2), () { Future.delayed(const Duration(seconds: 2), () {
if (widget.item.getVariable([child, st], widget.item.serialize()) == value) { if (widget.item.getVariable([child, st], widget.item.serialize()) == value) {
dash.save!(dash.id); dash.saveDash(dash.id);
} }
}); });
var el = dash.getElement(widget.elementID); var el = dash.getElement(widget.elementID);

View File

@ -48,7 +48,7 @@ class SchedulerFormsWidgetState extends State<SchedulerFormsWidget> {
dash.scheduler["end"] = now.add(const Duration(minutes: 1)).toUtc().toIso8601String(); dash.scheduler["end"] = now.add(const Duration(minutes: 1)).toUtc().toIso8601String();
} }
} }
widget.item.save!(widget.item.id); widget.item.saveDash(widget.item.id);
} }
void checkBooking(List<GlobalKey<FormFieldState>> formKeys, void Function(List<GlobalKey<FormFieldState>> )? f){ void checkBooking(List<GlobalKey<FormFieldState>> formKeys, void Function(List<GlobalKey<FormFieldState>> )? f){
if (widget.item.scheduler["start"] == null) { if (widget.item.scheduler["start"] == null) {
@ -93,12 +93,18 @@ class SchedulerFormsWidgetState extends State<SchedulerFormsWidget> {
bool readOnly = !PermsService.getPerm(Perms.WORKFLOW_EDIT); bool readOnly = !PermsService.getPerm(Perms.WORKFLOW_EDIT);
DateTime? start; DateTime? start;
DateTime? end; DateTime? end;
Duration delayed = const Duration(minutes: 5);
if (widget.item.scheduler["start"] != null) { if (widget.item.scheduler["start"] != null) {
start = DateTime.parse(widget.item.scheduler["start"]!); start = DateTime.parse(widget.item.scheduler["start"]!);
if (start.isBefore(DateTime.now()) && !dash.scheduleActive) { if (start.isBefore(DateTime.now()) && !dash.scheduleActive) {
start = DateTime.now().add(const Duration(minutes: 5)); start = DateTime.now().add(const Duration(minutes: 5));
widget.item.scheduler["start"] = start.toUtc().toIso8601String(); widget.item.scheduler["start"] = start.toUtc().toIso8601String();
} }
if (start.isBefore(DateTime.now())) {
// get difference between now and start
delayed = start.difference(DateTime.now());
}
} }
if (widget.item.scheduler["end"] != null) { if (widget.item.scheduler["end"] != null) {
end = DateTime.parse(widget.item.scheduler["end"]!); end = DateTime.parse(widget.item.scheduler["end"]!);
@ -106,6 +112,13 @@ class SchedulerFormsWidgetState extends State<SchedulerFormsWidget> {
end = DateTime.now().add(const Duration(minutes: 5)); end = DateTime.now().add(const Duration(minutes: 5));
widget.item.scheduler["end"] = end.toUtc().toIso8601String(); widget.item.scheduler["end"] = end.toUtc().toIso8601String();
} }
if (end.isBefore(DateTime.now())) {
// get difference between now and start
delayed = end.difference(DateTime.now());
}
Future.delayed(delayed, () {
WorkflowFactory.key.currentState?.setState(() { });
});
} }
List<GlobalKey<FormFieldState>> formKeys = [GlobalKey<FormFieldState>(), GlobalKey<FormFieldState>(), GlobalKey<FormFieldState>(), GlobalKey<FormFieldState>()]; List<GlobalKey<FormFieldState>> formKeys = [GlobalKey<FormFieldState>(), GlobalKey<FormFieldState>(), GlobalKey<FormFieldState>(), GlobalKey<FormFieldState>()];
var shallow = ShallowTextInputWidget( var shallow = ShallowTextInputWidget(
@ -160,7 +173,7 @@ class SchedulerFormsWidgetState extends State<SchedulerFormsWidget> {
onChanged: (value) { onChanged: (value) {
Future.delayed(const Duration(seconds: 100), () { Future.delayed(const Duration(seconds: 100), () {
if (widget.item.scheduler["name"] == value) { if (widget.item.scheduler["name"] == value) {
widget.item.save!(widget.item.id); widget.item.saveDash(widget.item.id);
} }
}); });
widget.item.scheduler["name"] = value; widget.item.scheduler["name"] = value;
@ -183,11 +196,11 @@ class SchedulerFormsWidgetState extends State<SchedulerFormsWidget> {
labelText: "executions name*", labelText: "executions name*",
hintStyle: TextStyle(fontSize: 10), hintStyle: TextStyle(fontSize: 10),
labelStyle: TextStyle(fontSize: 10), labelStyle: TextStyle(fontSize: 10),
focusedErrorBorder: OutlineInputBorder(borderSide: BorderSide(color: widget.error != null ? Colors.red : Colors.black)), focusedErrorBorder: OutlineInputBorder(borderSide: BorderSide(color: widget.item.error != null || widget.error != null ? Colors.red : Colors.black)),
errorBorder: OutlineInputBorder(borderSide: BorderSide(color: widget.error != null ? Colors.red : Colors.black)), errorBorder: OutlineInputBorder(borderSide: BorderSide(color: widget.item.error != null || widget.error != null ? Colors.red : Colors.black)),
focusedBorder: OutlineInputBorder(borderSide: BorderSide(color: widget.error != null ? Colors.red : Colors.black)), focusedBorder: OutlineInputBorder(borderSide: BorderSide(color: widget.item.error != null || widget.error != null ? Colors.red : Colors.black)),
enabledBorder: OutlineInputBorder(borderSide: BorderSide(color: widget.error != null ? Colors.red : Colors.grey)), enabledBorder: OutlineInputBorder(borderSide: BorderSide(color: widget.item.error != null || widget.error != null ? Colors.red : Colors.grey)),
border: OutlineInputBorder(borderSide: BorderSide(color: widget.error != null ? Colors.red : Colors.grey)), border: OutlineInputBorder(borderSide: BorderSide(color: widget.item.error != null || widget.error != null ? Colors.red : Colors.grey)),
contentPadding: EdgeInsets.symmetric(horizontal: 10, vertical: 5), contentPadding: EdgeInsets.symmetric(horizontal: 10, vertical: 5),
), ),
))), ))),
@ -254,7 +267,7 @@ class SchedulerFormsWidgetState extends State<SchedulerFormsWidget> {
date = DateTime(date.year, date.month, date.day, time.hour, time.minute); date = DateTime(date.year, date.month, date.day, time.hour, time.minute);
widget.item.scheduler["start"] = date.toUtc().toIso8601String(); widget.item.scheduler["start"] = date.toUtc().toIso8601String();
} }
widget.item.save!(widget.item.id); widget.item.saveDash(widget.item.id);
} }
return date; return date;
}, },
@ -359,7 +372,7 @@ class SchedulerFormsWidgetState extends State<SchedulerFormsWidget> {
date = DateTime(date.year, date.month, date.day, time.hour, time.minute); date = DateTime(date.year, date.month, date.day, time.hour, time.minute);
widget.item.scheduler["end"] = date.toUtc().toIso8601String(); widget.item.scheduler["end"] = date.toUtc().toIso8601String();
} }
widget.item.save!(widget.item.id); widget.item.saveDash(widget.item.id);
} }
return date; return date;
}, },
@ -392,7 +405,7 @@ class SchedulerFormsWidgetState extends State<SchedulerFormsWidget> {
onChanged: (value) { onChanged: (value) {
Future.delayed(const Duration(seconds: 100), () { Future.delayed(const Duration(seconds: 100), () {
if (widget.item.scheduler["cron"] == value) { if (widget.item.scheduler["cron"] == value) {
widget.item.save!(widget.item.id); widget.item.saveDash(widget.item.id);
} }
}); });
widget.item.scheduler["cron"] = value; widget.item.scheduler["cron"] = value;

View File

@ -29,7 +29,7 @@ class SubExposeFormsWidgetState extends State<SubExposeFormsWidget> {
widget.item.port = int.parse(value); widget.item.port = int.parse(value);
Future.delayed(const Duration(seconds: 2), () { Future.delayed(const Duration(seconds: 2), () {
if (widget.item.port == int.parse(value) && int.parse(value) != 0) { if (widget.item.port == int.parse(value) && int.parse(value) != 0) {
widget.dash.save!(widget.dash.id); widget.dash.saveDash(widget.dash.id);
} }
}); });
} catch (e) { widget.item.port = null; } } catch (e) { widget.item.port = null; }
@ -44,7 +44,7 @@ class SubExposeFormsWidgetState extends State<SubExposeFormsWidget> {
widget.item.PAT = int.parse(value); widget.item.PAT = int.parse(value);
Future.delayed(const Duration(seconds: 2), () { Future.delayed(const Duration(seconds: 2), () {
if (widget.item.PAT == int.parse(value) && int.parse(value) != 0) { if (widget.item.PAT == int.parse(value) && int.parse(value) != 0) {
widget.dash.save!(widget.dash.id); widget.dash.saveDash(widget.dash.id);
} }
}); });
} catch (e) { widget.item.PAT = null; } } catch (e) { widget.item.PAT = null; }
@ -57,7 +57,7 @@ class SubExposeFormsWidgetState extends State<SubExposeFormsWidget> {
try { try {
widget.item.path = value; widget.item.path = value;
Future.delayed(const Duration(seconds: 2), () { Future.delayed(const Duration(seconds: 2), () {
if (widget.item.path == value) { widget.dash.save!(widget.dash.id); } if (widget.item.path == value) { widget.dash.saveDash(widget.dash.id); }
}); });
} catch (e) { widget.item.path = null; } } catch (e) { widget.item.path = null; }
var el = widget.dash.getElement(widget.elementID); var el = widget.dash.getElement(widget.elementID);

View File

@ -1,6 +1,5 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter_flow_chart/flutter_flow_chart.dart'; import 'package:flutter_flow_chart/flutter_flow_chart.dart';
import 'package:oc_front/models/workflow.dart'; import 'package:oc_front/models/workflow.dart';
import 'package:oc_front/widgets/inputs/sub_text_input.dart'; import 'package:oc_front/widgets/inputs/sub_text_input.dart';
@ -46,7 +45,7 @@ class SubKeysMapFormsWidgetState extends State<SubKeysMapFormsWidget> {
} }
} }
if (save) { if (save) {
widget.dash.save!(widget.dash.id); widget.dash.saveDash(widget.dash.id);
} }
if (children.isEmpty) { if (children.isEmpty) {
return Container(); return Container();

View File

@ -52,7 +52,7 @@ class SubMapFormsWidgetState extends State<SubMapFormsWidget> {
setState(() { setState(() {
widget.forms[i].key = value; widget.forms[i].key = value;
Future.delayed(const Duration(seconds: 2), () { Future.delayed(const Duration(seconds: 2), () {
widget.dash.save!(widget.dash.id); widget.dash.saveDash(widget.dash.id);
}); });
var el = widget.dash.getElement(widget.elementID); var el = widget.dash.getElement(widget.elementID);
widget.item = widget.item.deserialize(widget.item.setVariable(l, toMap(), widget.item.serialize())) as dynamic; widget.item = widget.item.deserialize(widget.item.setVariable(l, toMap(), widget.item.serialize())) as dynamic;
@ -63,7 +63,7 @@ class SubMapFormsWidgetState extends State<SubMapFormsWidget> {
SubTextInputWidget(subkey: "value", initialValue: widget.forms[i].value, width: 77.5, empty: widget.empty, SubTextInputWidget(subkey: "value", initialValue: widget.forms[i].value, width: 77.5, empty: widget.empty,
readOnly: widget.readOnly, change: (value) { readOnly: widget.readOnly, change: (value) {
Future.delayed(const Duration(seconds: 2), () { Future.delayed(const Duration(seconds: 2), () {
widget.dash.save!(widget.dash.id); widget.dash.saveDash(widget.dash.id);
}); });
widget.forms[i].value = value; widget.forms[i].value = value;
var el = widget.dash.getElement(widget.elementID); var el = widget.dash.getElement(widget.elementID);
@ -99,7 +99,7 @@ class SubMapFormsWidgetState extends State<SubMapFormsWidget> {
widget.item.setVariable(l, toMap(), widget.item.serialize())) as dynamic; widget.item.setVariable(l, toMap(), widget.item.serialize())) as dynamic;
var el = widget.dash.getElement(widget.elementID); var el = widget.dash.getElement(widget.elementID);
el!.element = widget.item as dynamic; el!.element = widget.item as dynamic;
setState(() { widget.dash.save!(widget.dash.id); }); setState(() { widget.dash.saveDash(widget.dash.id); });
}, child: }, child:
Container( margin: const EdgeInsets.only(left: 5, top: 10), Container( margin: const EdgeInsets.only(left: 5, top: 10),
decoration: BoxDecoration(borderRadius: BorderRadius.circular(5), border: Border.all(color: Colors.grey, width: 1)), decoration: BoxDecoration(borderRadius: BorderRadius.circular(5), border: Border.all(color: Colors.grey, width: 1)),

View File

@ -31,7 +31,6 @@ class ScheduleWidgetState extends State<ScheduleWidget> {
String search = ""; String search = "";
String? level; String? level;
List<Color> colors = [Colors.blue, Colors.orange, redColor, Colors.green, redColor]; List<Color> colors = [Colors.blue, Colors.orange, redColor, Colors.green, redColor];
List<String> titles = ["SCHEDULED", "RUNNING", "FAILURE", "SUCCESS", "MISSED"];
DateTime getFocusedDay() { DateTime getFocusedDay() {
if (selected != null) { return DateTime.parse(selected!); } if (selected != null) { return DateTime.parse(selected!); }

View File

@ -28,8 +28,10 @@ class Dashboard extends ChangeNotifier {
GlobalKey<FlowChartMenuState> chartMenuKey = GlobalKey<FlowChartMenuState>(); GlobalKey<FlowChartMenuState> chartMenuKey = GlobalKey<FlowChartMenuState>();
GlobalKey<ChartWidgetState> chartKey = GlobalKey<ChartWidgetState>(); GlobalKey<ChartWidgetState> chartKey = GlobalKey<ChartWidgetState>();
GlobalKey<FlowChartState> flutterChartKey = GlobalKey<FlowChartState>(); GlobalKey<FlowChartState> flutterChartKey = GlobalKey<FlowChartState>();
List<Map<String, dynamic>> tempHistory = []; List<Map<String, dynamic>> tempHistory = [];
List<Map<String, dynamic>> history = []; List<Map<String, dynamic>> history = [];
Map<String, dynamic> scheduler = {}; Map<String, dynamic> scheduler = {};
Map<String, dynamic> info = {}; Map<String, dynamic> info = {};
bool scheduleActive = false; bool scheduleActive = false;
@ -58,7 +60,10 @@ class Dashboard extends ChangeNotifier {
/// This is used to move the dashboard on the screen /// This is used to move the dashboard on the screen
double widthOffset = 0; double widthOffset = 0;
double heightOffset = 0; double heightOffset = 0;
/// List<bool Function(Dashboard)> saveRules = [];
String? error;
Dashboard({ Dashboard({
this.id, this.id,
this.widthOffset = 0, this.widthOffset = 0,
@ -104,7 +109,20 @@ class Dashboard extends ChangeNotifier {
tempHistory = []; tempHistory = [];
history = []; history = [];
} }
Future<void> saveDash(String? id) async {
shouldSave = true;
for (var element in saveRules) {
if (element(this)) {
shouldSave = true;
} else {
shouldSave = false;
break;
}
}
if (save != null && shouldSave) {
save!(id);
}
}
Future<void> Function(String cat)? load; Future<void> Function(String cat)? load;
/// ///
@ -305,23 +323,17 @@ class Dashboard extends ChangeNotifier {
void addArrows(ArrowPainter f) { void addArrows(ArrowPainter f) {
arrows.add(f); arrows.add(f);
addChange = true; addChange = true;
if (save != null) { saveDash(id);
save!(id);
}
} }
void removeArrows(bool Function(ArrowPainter) f) { void removeArrows(bool Function(ArrowPainter) f) {
arrows.removeWhere((element) => f(element)); arrows.removeWhere((element) => f(element));
if (save != null) { saveDash(id);
save!(id);
}
} }
void removeElements(bool Function(FlowElement<FlowData>) f) { void removeElements(bool Function(FlowElement<FlowData>) f) {
elements.removeWhere((element) => f(element)); elements.removeWhere((element) => f(element));
if (save != null) { saveDash(id);
save!(id);
}
} }
void clear() { void clear() {
@ -388,9 +400,7 @@ class Dashboard extends ChangeNotifier {
bool notify = true, bool notify = true,
}) { }) {
element.isResizing = resizable; element.isResizing = resizable;
if (save != null) { saveDash(id);
save!(id);
}
if (notify) notifyListeners(); if (notify) notifyListeners();
} }
@ -409,9 +419,7 @@ class Dashboard extends ChangeNotifier {
element.setScale(1, gridBackgroundParams.scale); element.setScale(1, gridBackgroundParams.scale);
elements.add(element); elements.add(element);
addChange = true; addChange = true;
if (save != null) { saveDash(id);
save!(id);
}
if (notify) { if (notify) {
notifyListeners(); notifyListeners();
} }
@ -534,9 +542,7 @@ class Dashboard extends ChangeNotifier {
void removeAllElements({bool notify = true}) { void removeAllElements({bool notify = true}) {
elements.clear(); elements.clear();
if (notify) notifyListeners(); if (notify) notifyListeners();
if (save != null) { saveDash(id);
save!(id);
}
} }
/// remove the [handler] connection of [element] /// remove the [handler] connection of [element]
@ -579,9 +585,7 @@ class Dashboard extends ChangeNotifier {
} }
} }
if (notify) notifyListeners(); if (notify) notifyListeners();
if (save != null) { saveDash(id);
save!(id);
}
} }
/// dissect an element connection /// dissect an element connection
@ -674,9 +678,7 @@ class Dashboard extends ChangeNotifier {
void removeElementConnections(FlowElement element, {bool notify = true}) { void removeElementConnections(FlowElement element, {bool notify = true}) {
element.next.clear(); element.next.clear();
if (notify) notifyListeners(); if (notify) notifyListeners();
if (save != null) { saveDash(id);
save!(id);
}
} }
/// remove all the elements with [id] from the dashboard /// remove all the elements with [id] from the dashboard
@ -697,9 +699,7 @@ class Dashboard extends ChangeNotifier {
}); });
} }
if (notify) notifyListeners(); if (notify) notifyListeners();
if (save != null) { saveDash(id);
save!(id);
}
} }
/// remove element /// remove element
@ -720,9 +720,7 @@ class Dashboard extends ChangeNotifier {
); );
} }
if (notify) notifyListeners(); if (notify) notifyListeners();
if (save != null) { saveDash(id);
save!(id);
}
return found; return found;
} }

View File

@ -86,94 +86,89 @@ class FlowChartSelectedMenuState extends State<FlowChartSelectedMenu> {
Text("STYLE ${widget.dashboard.elementSelected.isNotEmpty ? "ELEMENT" : "ARROW"}", style: TextStyle(fontSize: 15, fontWeight: FontWeight.bold), textAlign: TextAlign.center), Text("STYLE ${widget.dashboard.elementSelected.isNotEmpty ? "ELEMENT" : "ARROW"}", style: TextStyle(fontSize: 15, fontWeight: FontWeight.bold), textAlign: TextAlign.center),
Text("<${widget.dashboard.arrowsSelected.isEmpty && widget.dashboard.elementSelected.isEmpty ? "general" : "selected"}>", style: TextStyle(fontSize: 12), textAlign: TextAlign.center), Text("<${widget.dashboard.arrowsSelected.isEmpty && widget.dashboard.elementSelected.isEmpty ? "general" : "selected"}>", style: TextStyle(fontSize: 12), textAlign: TextAlign.center),
])), ])),
Container( width: 200, height: widget.height - 60, child: SingleChildScrollView( child: Column( children: [ SizedBox( width: 200, height: widget.height - 60, child: SingleChildScrollView( child: Column( children: [
widget.dashboard.elementSelected.isNotEmpty ? Container() : Container( padding: EdgeInsets.symmetric(horizontal: 10, vertical: 20), widget.dashboard.elementSelected.isNotEmpty ? Container() : Container( padding: EdgeInsets.symmetric(horizontal: 10, vertical: 20),
decoration: BoxDecoration(border: Border(bottom: BorderSide(color: Colors.grey, width: 1))), decoration: BoxDecoration(border: Border(bottom: BorderSide(color: Colors.grey, width: 1))),
child: Column( children: [ child: Column( children: [
Row( children: [ Row( children: [
InkWell( mouseCursor: SystemMouseCursors.click, child: Container( InkWell( mouseCursor: SystemMouseCursors.click,
child: Padding( padding: EdgeInsets.only(left: 10, right: 10), child: Padding( padding: EdgeInsets.only(left: 10, right: 10),
child: PopupMenuButton<ArrowDash>( child: PopupMenuButton<ArrowDash>(
tooltip: "line defaults", tooltip: "line defaults",
constraints: BoxConstraints(maxWidth: 100), constraints: BoxConstraints(maxWidth: 100),
child: Row( children: [ initialValue: null,
MySeparator( onSelected: (ArrowDash value) {
width: 35, if (widget.dashboard.elementSelected.isEmpty) {
dashWidth: widget.dashboard.defaultDashWidth, for(var sel in widget.dashboard.arrowsSelected) {
dashSpace: widget.dashboard.defaultDashSpace, sel.params.dashSpace = spaceArrowDash(value);
color: Colors.black sel.params.dashWidth = widthArrowDash(value);
),
SizedBox(height: 25, width: 10),
Icon(Icons.arrow_drop_down, size: 10, color: Colors.black) ]),
initialValue: null,
onSelected: (ArrowDash value) {
if (widget.dashboard.elementSelected.isEmpty) {
for(var sel in widget.dashboard.arrowsSelected) {
sel.params.dashSpace = spaceArrowDash(value);
sel.params.dashWidth = widthArrowDash(value);
}
widget.dashboard.chartKey.currentState?.setState(() { });
} }
widget.dashboard.defaultDashSpace = spaceArrowDash(value); widget.dashboard.chartKey.currentState?.setState(() { });
widget.dashboard.defaultDashWidth = widthArrowDash(value); }
setState(() {}); widget.dashboard.defaultDashSpace = spaceArrowDash(value);
}, widget.dashboard.defaultDashWidth = widthArrowDash(value);
itemBuilder: (BuildContext context) => <PopupMenuEntry<ArrowDash>>[ setState(() {});
PopupMenuItem<ArrowDash>( },
value: ArrowDash.line, itemBuilder: (BuildContext context) => <PopupMenuEntry<ArrowDash>>[
child: Row( mainAxisAlignment: MainAxisAlignment.center, children: [ PopupMenuItem<ArrowDash>(
MySeparator(width: 25, dashWidth: widthArrowDash(ArrowDash.line), value: ArrowDash.line,
dashSpace: spaceArrowDash(ArrowDash.line),) child: Row( mainAxisAlignment: MainAxisAlignment.center, children: [
]), MySeparator(width: 25, dashWidth: widthArrowDash(ArrowDash.line),
), dashSpace: spaceArrowDash(ArrowDash.line),)
PopupMenuItem<ArrowDash>( ]),
value: ArrowDash.largeDash,
child: Row( mainAxisAlignment: MainAxisAlignment.center, children: [
MySeparator(width: 25, dashWidth: widthArrowDash(ArrowDash.largeDash), dashSpace: spaceArrowDash(ArrowDash.largeDash),)
]),
),
PopupMenuItem<ArrowDash>(
value: ArrowDash.mediumDash,
child: Row( mainAxisAlignment: MainAxisAlignment.center, children: [
MySeparator(width: 25, dashWidth: widthArrowDash(ArrowDash.mediumDash), dashSpace: spaceArrowDash(ArrowDash.mediumDash),)
]),
),
PopupMenuItem<ArrowDash>(
value: ArrowDash.smallDash,
child: Row( mainAxisAlignment: MainAxisAlignment.center, children: [
MySeparator(width: 25, dashWidth: widthArrowDash(ArrowDash.smallDash), dashSpace: spaceArrowDash(ArrowDash.smallDash),)
]),
),
PopupMenuItem<ArrowDash>(
value: ArrowDash.heavyDotted,
child: Row( mainAxisAlignment: MainAxisAlignment.center, children: [
MySeparator(width: 25, dashWidth: widthArrowDash(ArrowDash.heavyDotted), dashSpace: spaceArrowDash(ArrowDash.heavyDotted),)
]),
),
PopupMenuItem<ArrowDash>(
value: ArrowDash.mediumDotted,
child: Row( mainAxisAlignment: MainAxisAlignment.center, children: [
MySeparator(width: 25, dashWidth: widthArrowDash(ArrowDash.mediumDotted), dashSpace: spaceArrowDash(ArrowDash.mediumDotted),)
]),
),
PopupMenuItem<ArrowDash>(
value: ArrowDash.lightDotted,
child: Row( mainAxisAlignment: MainAxisAlignment.center, children: [
MySeparator(width: 25, dashWidth: widthArrowDash(ArrowDash.lightDotted), dashSpace: spaceArrowDash(ArrowDash.lightDotted),)
]),
),
]
), ),
) PopupMenuItem<ArrowDash>(
value: ArrowDash.largeDash,
child: Row( mainAxisAlignment: MainAxisAlignment.center, children: [
MySeparator(width: 25, dashWidth: widthArrowDash(ArrowDash.largeDash), dashSpace: spaceArrowDash(ArrowDash.largeDash),)
]),
),
PopupMenuItem<ArrowDash>(
value: ArrowDash.mediumDash,
child: Row( mainAxisAlignment: MainAxisAlignment.center, children: [
MySeparator(width: 25, dashWidth: widthArrowDash(ArrowDash.mediumDash), dashSpace: spaceArrowDash(ArrowDash.mediumDash),)
]),
),
PopupMenuItem<ArrowDash>(
value: ArrowDash.smallDash,
child: Row( mainAxisAlignment: MainAxisAlignment.center, children: [
MySeparator(width: 25, dashWidth: widthArrowDash(ArrowDash.smallDash), dashSpace: spaceArrowDash(ArrowDash.smallDash),)
]),
),
PopupMenuItem<ArrowDash>(
value: ArrowDash.heavyDotted,
child: Row( mainAxisAlignment: MainAxisAlignment.center, children: [
MySeparator(width: 25, dashWidth: widthArrowDash(ArrowDash.heavyDotted), dashSpace: spaceArrowDash(ArrowDash.heavyDotted),)
]),
),
PopupMenuItem<ArrowDash>(
value: ArrowDash.mediumDotted,
child: Row( mainAxisAlignment: MainAxisAlignment.center, children: [
MySeparator(width: 25, dashWidth: widthArrowDash(ArrowDash.mediumDotted), dashSpace: spaceArrowDash(ArrowDash.mediumDotted),)
]),
),
PopupMenuItem<ArrowDash>(
value: ArrowDash.lightDotted,
child: Row( mainAxisAlignment: MainAxisAlignment.center, children: [
MySeparator(width: 25, dashWidth: widthArrowDash(ArrowDash.lightDotted), dashSpace: spaceArrowDash(ArrowDash.lightDotted),)
]),
),
],
child: Row( children: [
MySeparator(
width: 35,
dashWidth: widget.dashboard.defaultDashWidth,
dashSpace: widget.dashboard.defaultDashSpace,
color: Colors.black
),
SizedBox(height: 25, width: 10),
Icon(Icons.arrow_drop_down, size: 10, color: Colors.black) ])
),
) )
), ),
PopupMenuButton<void>( PopupMenuButton<void>(
tooltip: "color picker", tooltip: "color picker",
constraints: BoxConstraints(maxWidth: 664), constraints: BoxConstraints(maxWidth: 664),
child: Row( children: [
Container(width: 15, height: 15, color: widget.dashboard.defaultColor),
Container(height: 25, width: 5),
Icon(Icons.arrow_drop_down, size: 10, color: Colors.black) ]),
initialValue: null, initialValue: null,
onSelected: (void value) {}, onSelected: (void value) {},
itemBuilder: (BuildContext context) => <PopupMenuEntry<void>>[ itemBuilder: (BuildContext context) => <PopupMenuEntry<void>>[
@ -186,7 +181,11 @@ class FlowChartSelectedMenuState extends State<FlowChartSelectedMenu> {
setState(() { widget.dashboard.defaultColor = value; }); setState(() { widget.dashboard.defaultColor = value; });
},), },),
), ),
] ],
child: Row( children: [
Container(width: 15, height: 15, color: widget.dashboard.defaultColor),
SizedBox(height: 25, width: 5),
Icon(Icons.arrow_drop_down, size: 10, color: Colors.black) ])
), ),
Tooltip( message: "stroke width", Tooltip( message: "stroke width",
child: Container( child: Container(
@ -228,50 +227,49 @@ class FlowChartSelectedMenuState extends State<FlowChartSelectedMenu> {
))) )))
]), ]),
Row(children: [ Row(children: [
InkWell( mouseCursor: SystemMouseCursors.click, child: Container( InkWell( mouseCursor: SystemMouseCursors.click, child: Padding(
child: Padding( padding: EdgeInsets.only(left: 10, top: 10, right: 10), padding: EdgeInsets.only(left: 10, top: 10, right: 10),
child: PopupMenuButton<ArrowStyle>( child: PopupMenuButton<ArrowStyle>(
child: initialValue: null,
Row( children: [ Icon(widget.dashboard.defaultArrowStyle == ArrowStyle.segmented ? Icons.turn_slight_left : widget.dashboard.defaultArrowStyle == ArrowStyle.curve ? Icons.roundabout_left : Icons.turn_sharp_left_outlined onSelected: (ArrowStyle value) {
, color: Colors.black), if (widget.dashboard.elementSelected.isEmpty) {
Icon(Icons.arrow_drop_down, size: 10, color: Colors.black) ]), for(var sel in widget.dashboard.arrowsSelected) { sel.params.style = value; }
initialValue: null, widget.dashboard.chartKey.currentState?.setState(() { });
onSelected: (ArrowStyle value) { }
if (widget.dashboard.elementSelected.isEmpty) { widget.dashboard.defaultArrowStyle = value;
for(var sel in widget.dashboard.arrowsSelected) { sel.params.style = value; } setState(() {});
widget.dashboard.chartKey.currentState?.setState(() { }); },
} tooltip: "line styles",
widget.dashboard.defaultArrowStyle = value; itemBuilder: (BuildContext context) => <PopupMenuEntry<ArrowStyle>>[
setState(() {}); PopupMenuItem<ArrowStyle>(
}, value: ArrowStyle.segmented,
tooltip: "line styles", child: Row( children: [
itemBuilder: (BuildContext context) => <PopupMenuEntry<ArrowStyle>>[ Icon(Icons.turn_slight_left),
PopupMenuItem<ArrowStyle>( Padding( padding: EdgeInsets.only(left: 10),
value: ArrowStyle.segmented, child: Text('straight', textAlign: TextAlign.center,))
child: Row( children: [ ]),
Icon(Icons.turn_slight_left), ),
Padding( padding: EdgeInsets.only(left: 10), PopupMenuItem<ArrowStyle>(
child: Text('straight', textAlign: TextAlign.center,)) value: ArrowStyle.curve,
]), child: Row( children: [
), Icon(Icons.roundabout_left),
PopupMenuItem<ArrowStyle>( Padding( padding: EdgeInsets.only(left: 10),
value: ArrowStyle.curve, child: Text('curved', textAlign: TextAlign.center,))
child: Row( children: [ ]),
Icon(Icons.roundabout_left), ),
Padding( padding: EdgeInsets.only(left: 10), PopupMenuItem<ArrowStyle>(
child: Text('curved', textAlign: TextAlign.center,)) value: ArrowStyle.rectangular,
]), child: Row( children: [
), Icon(Icons.turn_sharp_left_outlined),
PopupMenuItem<ArrowStyle>( Padding( padding: EdgeInsets.only(left: 10),
value: ArrowStyle.rectangular, child: Text('rectangular', textAlign: TextAlign.center,))
child: Row( children: [ ]),
Icon(Icons.turn_sharp_left_outlined), ),
Padding( padding: EdgeInsets.only(left: 10), ],
child: Text('rectangular', textAlign: TextAlign.center,)) child:
]), Row( children: [ Icon(widget.dashboard.defaultArrowStyle == ArrowStyle.segmented ? Icons.turn_slight_left : widget.dashboard.defaultArrowStyle == ArrowStyle.curve ? Icons.roundabout_left : Icons.turn_sharp_left_outlined
), , color: Colors.black),
] Icon(Icons.arrow_drop_down, size: 10, color: Colors.black) ])
)
) )
) )
), ),
@ -352,60 +350,57 @@ class FlowChartSelectedMenuState extends State<FlowChartSelectedMenu> {
))) )))
]), ]),
])), ])),
widget.dashboard.elementSelected.isNotEmpty && widget.dashboard.elementSelected.length == 1 ? Container( widget.dashboard.elementSelected.isNotEmpty ? Container() :
// TODO : TEST OMG Container( padding: EdgeInsets.only(left: 10, right: 10, bottom: 20, top: 15),
) : Container(),
widget.dashboard.elementSelected.isNotEmpty ? Container() : Container( padding: EdgeInsets.only(left: 10, right: 10, bottom: 20, top: 15),
decoration: BoxDecoration(border: Border(bottom: BorderSide(color: Colors.grey, width: 1))), decoration: BoxDecoration(border: Border(bottom: BorderSide(color: Colors.grey, width: 1))),
child: Column( children: [ child: Column( children: [
Row( mainAxisAlignment: MainAxisAlignment.center, children : [ Row( mainAxisAlignment: MainAxisAlignment.center, children : [
InkWell( mouseCursor: SystemMouseCursors.click, child: Container( InkWell( mouseCursor: SystemMouseCursors.click,
child: Padding( padding: EdgeInsets.symmetric(horizontal: 10), child: Padding( padding: EdgeInsets.symmetric(horizontal: 10),
child: PopupMenuButton<ArrowDirection>( child: PopupMenuButton<ArrowDirection>(
child: initialValue: null,
Row( children: [ onSelected: (ArrowDirection value) {
Icon(widget.dashboard.defaultArrowDirection == ArrowDirection.forward ? Icons.arrow_forward : widget.dashboard.defaultArrowDirection == ArrowDirection.backward ? Icons.arrow_back : Icons.sync_alt_outlined, color: Colors.black), if (widget.dashboard.elementSelected.isEmpty) {
Padding( padding: EdgeInsets.symmetric(horizontal: 10), for(var sel in widget.dashboard.arrowsSelected) { sel.params.direction = value; }
child: Text(widget.dashboard.defaultArrowDirection == ArrowDirection.forward ? 'forward' : widget.dashboard.defaultArrowDirection == ArrowDirection.backward ? 'backward' : 'bidirectionnal')), widget.dashboard.chartKey.currentState?.setState(() { });
Icon(Icons.arrow_drop_down, size: 10, color: Colors.black) ]), }
initialValue: null, widget.dashboard.defaultArrowDirection = value;
onSelected: (ArrowDirection value) { setState(() {});
if (widget.dashboard.elementSelected.isEmpty) { },
for(var sel in widget.dashboard.arrowsSelected) { sel.params.direction = value; } tooltip: widget.dashboard.defaultArrowDirection == ArrowDirection.forward ? 'forward' : widget.dashboard.defaultArrowDirection == ArrowDirection.backward ? 'backward' : 'bidirectionnal',
widget.dashboard.chartKey.currentState?.setState(() { }); itemBuilder: (BuildContext context) => <PopupMenuEntry<ArrowDirection>>[
} PopupMenuItem<ArrowDirection>(
widget.dashboard.defaultArrowDirection = value; value: ArrowDirection.forward,
setState(() {}); child: Row( children: [
}, Icon(Icons.arrow_forward),
tooltip: widget.dashboard.defaultArrowDirection == ArrowDirection.forward ? 'forward' : widget.dashboard.defaultArrowDirection == ArrowDirection.backward ? 'backward' : 'bidirectionnal', Padding( padding: EdgeInsets.only(left: 10),
itemBuilder: (BuildContext context) => <PopupMenuEntry<ArrowDirection>>[ child: Text('forward', textAlign: TextAlign.center,))
PopupMenuItem<ArrowDirection>( ]),
value: ArrowDirection.forward, ),
child: Row( children: [ PopupMenuItem<ArrowDirection>(
Icon(Icons.arrow_forward), value: ArrowDirection.backward,
Padding( padding: EdgeInsets.only(left: 10), child: Row( children: [
child: Text('forward', textAlign: TextAlign.center,)) Icon(Icons.arrow_back),
]), Padding( padding: EdgeInsets.only(left: 10),
), child: Text('curved', textAlign: TextAlign.center,))
PopupMenuItem<ArrowDirection>( ]),
value: ArrowDirection.backward, ),
child: Row( children: [ PopupMenuItem<ArrowDirection>(
Icon(Icons.arrow_back), value: ArrowDirection.bidirectionnal,
Padding( padding: EdgeInsets.only(left: 10), child: Row( children: [
child: Text('curved', textAlign: TextAlign.center,)) Icon(Icons.sync_alt_outlined),
]), Padding( padding: EdgeInsets.only(left: 10),
), child: Text('bidirectionnal', textAlign: TextAlign.center,))
PopupMenuItem<ArrowDirection>( ]),
value: ArrowDirection.bidirectionnal, ),
child: Row( children: [ ],
Icon(Icons.sync_alt_outlined), child:
Padding( padding: EdgeInsets.only(left: 10), Row( children: [
child: Text('bidirectionnal', textAlign: TextAlign.center,)) Icon(widget.dashboard.defaultArrowDirection == ArrowDirection.forward ? Icons.arrow_forward : widget.dashboard.defaultArrowDirection == ArrowDirection.backward ? Icons.arrow_back : Icons.sync_alt_outlined, color: Colors.black),
]), Padding( padding: EdgeInsets.symmetric(horizontal: 10),
), child: Text(widget.dashboard.defaultArrowDirection == ArrowDirection.forward ? 'forward' : widget.dashboard.defaultArrowDirection == ArrowDirection.backward ? 'backward' : 'bidirectionnal')),
] Icon(Icons.arrow_drop_down, size: 10, color: Colors.black) ])
),) ),)
)
), ),
]), ]),
Row(children: [ Row(children: [
@ -560,46 +555,51 @@ class FlowChartSelectedMenuState extends State<FlowChartSelectedMenu> {
} }
return Column( children: [ return Column( children: [
Container( // SHORTCUT Container( // SHORTCUT
width: 200, width: 200, height: 50,
height: 50, decoration: BoxDecoration(color: widget.dashboard.midDashColor,
decoration: BoxDecoration(color: widget.dashboard.midDashColor, border: Border(bottom: BorderSide(color: Colors.grey, width: 1))), border: Border(bottom: BorderSide(color: Colors.grey, width: 1))),
child: Row( children: [ child: Row( children: [
Tooltip( Tooltip( message: "dashboard information",
message: "dashboard information", child: InkWell( onTap: () => setState(() {widget.isDashboardInfo = true; }),
child: InkWell( onTap: () => setState(() {widget.isDashboardInfo = true; }), mouseCursor: SystemMouseCursors.click,
mouseCursor: SystemMouseCursors.click, child: Container( alignment: Alignment.center,
child: Container( alignment: Alignment.center, padding: EdgeInsets.symmetric(vertical: 10),
padding: EdgeInsets.symmetric(vertical: 10), color: widget.isDashboardInfo ? Colors.grey : widget.dashboard.midDashColor,
color: widget.isDashboardInfo ? Colors.grey : widget.dashboard.midDashColor, width: 200 / 2, child: Icon(Icons.info, color: Colors.white))
width: 200 / 2, child: Icon(Icons.info, color: Colors.white)) )
) ),
), Tooltip(
Tooltip( message: "element style",
message: "element style", child: InkWell( onTap: () => setState(() {widget.isDashboardInfo = false; }),
child: InkWell( onTap: () => setState(() {widget.isDashboardInfo = false; }), mouseCursor: SystemMouseCursors.click,
mouseCursor: SystemMouseCursors.click, child: Container( alignment: Alignment.center,
child: Container( alignment: Alignment.center, padding: EdgeInsets.symmetric(vertical: 10),
padding: EdgeInsets.symmetric(vertical: 10), color: !widget.isDashboardInfo ? Colors.grey : widget.dashboard.midDashColor,
color: !widget.isDashboardInfo ? Colors.grey : widget.dashboard.midDashColor, width: 200 / 2, child: Icon(Icons.format_paint, color: Colors.white)),
width: 200 / 2, child: Icon(Icons.format_paint, color: Colors.white)), )
)) )
])), ]
)
),
widget.dashboard.error != null ? Container( width: 200, color: Colors.red, padding: EdgeInsets.all(10),
child: Center( child: Text(widget.dashboard.error!,
style: TextStyle(color: Colors.white, fontSize: 15), textAlign: TextAlign.center))) : Container(),
w w
]); ]);
} }
} }
// ignore: must_be_immutable
class MySeparator extends StatelessWidget { class MySeparator extends StatelessWidget {
double width = 1; double dashWidth = 10; double dashSpace = 10; double width = 1; double dashWidth = 10; double dashSpace = 10;
MySeparator({Key? key, this.width = 1, this.dashSpace = 10, this.dashWidth = 10, MySeparator({super.key, this.width = 1, this.dashSpace = 10, this.dashWidth = 10,
this.height = 1, this.color = Colors.black}) this.height = 1, this.color = Colors.black});
: super(key: key);
final double height; final double height;
final Color color; final Color color;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Container( width: width, child: dashSpace == 0 ? return SizedBox( width: width, child: dashSpace == 0 ?
Divider( thickness: 2, color: color ) Divider( thickness: 2, color: color )
: DottedLine( : DottedLine(
dashLength: dashWidth, dashLength: dashWidth,