From bed48b4cb456297c79458253d1907c6840b7a920 Mon Sep 17 00:00:00 2001 From: mr Date: Wed, 5 Feb 2025 09:07:39 +0100 Subject: [PATCH] missing files --- lib/widgets/forms/processing_forms.dart | 147 ---------- lib/widgets/forms/resource_forms.dart | 91 ++++++ lib/widgets/forms/scheduler_forms.dart | 267 ++++++++++-------- lib/widgets/forms/storage_forms.dart | 18 -- .../forms/storage_processing_link_forms.dart | 154 ++++++++++ lib/widgets/forms/sub_add_forms.dart | 174 ++++++++++++ lib/widgets/forms/sub_expose_forms.dart | 9 +- lib/widgets/forms/sub_keys_forms.dart | 121 +++++--- lib/widgets/forms/sub_map_forms.dart | 115 -------- lib/widgets/forms/web_reference_forms.dart | 23 -- .../inputs/shallow_dropdown_input.dart | 4 +- lib/widgets/inputs/shallow_text_input.dart | 5 +- lib/widgets/inputs/sub_dropdown_input .dart | 9 +- lib/widgets/inputs/sub_text_input.dart | 5 +- lib/widgets/items/infos.dart | 24 ++ lib/widgets/items/item.dart | 22 +- lib/widgets/items/item_row.dart | 21 +- .../items/items_details/data_item.dart | 24 -- lib/widgets/sheduler_items/schedule.dart | 34 +-- .../sheduler_items/scheduler_calendar.dart | 10 +- .../sheduler_items/scheduler_item.dart | 14 +- library/flutter_flow_chart/.dart_tool/version | 2 +- .../lib/flutter_flow_chart.dart | 2 +- .../flutter_flow_chart/lib/src/dashboard.dart | 115 ++++---- .../lib/src/elements/connection_params.dart | 8 +- .../lib/src/elements/flow_element.dart | 8 + .../lib/src/flow_chart.dart | 70 ++--- .../lib/src/flow_chart_menu.dart | 31 +- .../lib/src/flow_chart_selected_menu.dart | 52 +++- .../lib/src/ui/draw_arrow.dart | 32 ++- .../lib/src/ui/element_widget.dart | 17 +- 31 files changed, 947 insertions(+), 681 deletions(-) delete mode 100644 lib/widgets/forms/processing_forms.dart create mode 100644 lib/widgets/forms/resource_forms.dart delete mode 100644 lib/widgets/forms/storage_forms.dart create mode 100644 lib/widgets/forms/storage_processing_link_forms.dart create mode 100644 lib/widgets/forms/sub_add_forms.dart delete mode 100644 lib/widgets/forms/sub_map_forms.dart delete mode 100644 lib/widgets/forms/web_reference_forms.dart create mode 100644 lib/widgets/items/infos.dart delete mode 100644 lib/widgets/items/items_details/data_item.dart diff --git a/lib/widgets/forms/processing_forms.dart b/lib/widgets/forms/processing_forms.dart deleted file mode 100644 index 65b9793..0000000 --- a/lib/widgets/forms/processing_forms.dart +++ /dev/null @@ -1,147 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_flow_chart/flutter_flow_chart.dart'; -import 'package:oc_front/core/services/perms_service.dart'; -import 'package:oc_front/main.dart'; -import 'package:oc_front/models/search.dart'; -import 'package:oc_front/models/workflow.dart'; -import 'package:oc_front/pages/workflow.dart'; -import 'package:oc_front/widgets/forms/sub_keys_forms.dart'; -import 'package:oc_front/widgets/forms/sub_expose_forms.dart'; -import 'package:oc_front/widgets/forms/sub_map_forms.dart'; -import 'package:oc_front/widgets/inputs/sub_text_input.dart'; - -Map> proxyWfItem = {}; -// ADD EXPOSE -class ProcessingFormsWidget extends StatefulWidget { - String elementID; - ProcessingItem item; - Dashboard dash; - ProcessingFormsWidget ({ super.key, required this.item, required this.dash, required this.elementID }); - @override ProcessingFormsWidgetState createState() => ProcessingFormsWidgetState(); -} -class ProcessingFormsWidgetState extends State { - Widget getInputAndOutputVariableForms(bool readOnly) { - var inList = widget.dash.GetArrowByElementID(widget.elementID, true); - var outList = widget.dash.GetArrowByElementID(widget.elementID, false); - List res = []; - List inItems = []; - List outItems = []; - for (var inItem in inList) { - var element = widget.dash.getElement(inItem.fromID.substring(0,36)); - if (element == null) { continue; } - var g = GraphItem(); - g.fromDashboard(element.serialize()); - inItems.add(g); - } - for (var outItem in outList) { - var element = widget.dash.getElement(outItem.toID.substring(0,36)); - if (element == null) { continue; } - var g = GraphItem(); - g.fromDashboard(element.serialize()); - outItems.add(g); - } - if (inItems.isNotEmpty) { - res.add(SubKeysMapFormsWidget(dash: widget.dash, isInput: true, item: widget.item, elementID: widget.elementID, - categoryKey: "container", varKey: "env", graphItems: inItems, readOnly: readOnly)); - } - if (outItems.isNotEmpty) { - res.add(SubKeysMapFormsWidget(dash: widget.dash, isInput: false, item: widget.item, elementID: widget.elementID, - categoryKey: "container", varKey: "env", graphItems: outItems, readOnly: readOnly)); - } - return Column( children: res ); - } - - @override Widget build(BuildContext context) { - bool readOnly = !PermsService.getPerm(Perms.WORKFLOW_EDIT); - List categories = []; - var l = widget.item.model?.model?.keys ?? []; - for (var child in l) { - var sub = widget.item.model!.model![child]!; - List children = []; - for (var st in sub.keys) { - if (sub[st]!.type?.contains("map") ?? false) { - children.add( - SubMapFormsWidget(dash: dash, empty: children.isEmpty, item: widget.item, - readOnly: readOnly, - elementID: widget.elementID, categoryKey: child, varKey: st) - ); - } else if (sub[st]!.type == "string") { - children.add(SubTextInputWidget(subkey: st, - readOnly: readOnly, - initialValue: widget.item.getVariable([child, st], widget.item.serialize()), - width: 180, empty: children.isEmpty, change: (value) { - widget.item.model ?? Model(); - Future.delayed(const Duration(seconds: 2), () { - if (widget.item.getVariable([child, st], widget.item.serialize()) == value) { - dash.saveDash(dash.id); - } - }); - var el = dash.getElement(widget.elementID); - widget.item = widget.item.deserialize(widget.item.setVariable([child, st], value, widget.item.serialize())) as dynamic; - el!.element = widget.item as dynamic; - }) - ); - } - } - categories.add(Container( - padding: const EdgeInsets.symmetric(vertical: 10), - width: 180, - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text("<${child.toUpperCase()}>", style: const TextStyle(fontSize: 13, fontWeight: FontWeight.bold), textAlign: TextAlign.center), - Padding(padding: const EdgeInsets.only(bottom: 10), child: SubTextInputWidget(subkey: "image", width: 180, empty: false, change: (value) {}, - initialValue: widget.item.container?.image, readOnly: true,)), - ...children, - getInputAndOutputVariableForms(readOnly), - ],) - )); - } - // EXPOSE - categories.add(Container( - padding: const EdgeInsets.symmetric(vertical: 10), - width: 180, - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - const Padding(padding: EdgeInsets.only(bottom: 5), child: Text("", - style: TextStyle(fontSize: 13, fontWeight: FontWeight.bold), textAlign: TextAlign.center)), - readOnly ? Container() : Row( children: [ - InkWell( onTap: () { - widget.item.expose.add(Expose()); - var el = dash.getElement(widget.elementID); - el!.element = widget.item as dynamic; - setState(() {}); - }, child: - Container( margin: const EdgeInsets.only(top: 5), - decoration: BoxDecoration(borderRadius: BorderRadius.circular(5), border: Border.all(color: Colors.grey, width: 1)), - width: 125, height: 30, - child: const Row( mainAxisAlignment: MainAxisAlignment.center, - children: [ Padding( padding: EdgeInsets.only(right: 5), child: Icon(Icons.add)), Text("add expose")]), - ) - ), - InkWell( onTap: () { - if (widget.item.expose.isEmpty) { return; } - widget.item.expose = widget.item.expose.sublist(0, widget.item.expose.length - 1); - var el = dash.getElement(widget.elementID); - el!.element = widget.item as dynamic; - setState(() {}); - }, child: - Container( margin: const EdgeInsets.only(left: 5, top: 5), - decoration: BoxDecoration(borderRadius: BorderRadius.circular(5), border: Border.all(color: Colors.grey, width: 1)), - width: 45, height: 30, - child: const Row( mainAxisAlignment: MainAxisAlignment.center, - children: [ Icon(Icons.delete, color: Colors.black) ]), - ) - ) - ]), - ],) - )); - for (var expose in widget.item.expose) { - categories.add(SubExposeFormsWidget( readOnly: readOnly, width: 180, dash: dash, empty: categories.isEmpty, - item: expose, elementID: widget.elementID)); - } - return SizedBox( height: getHeight(context) - 330, child: SingleChildScrollView( child: Column( - children: categories )) ); - } -} \ No newline at end of file diff --git a/lib/widgets/forms/resource_forms.dart b/lib/widgets/forms/resource_forms.dart new file mode 100644 index 0000000..0dc0a58 --- /dev/null +++ b/lib/widgets/forms/resource_forms.dart @@ -0,0 +1,91 @@ +import 'package:oc_front/main.dart'; +import 'package:flutter/material.dart'; +import 'package:oc_front/models/workflow.dart'; +import 'package:oc_front/models/resources/resources.dart'; +import 'package:oc_front/core/services/perms_service.dart'; +import 'package:oc_front/widgets/forms/sub_keys_forms.dart'; +import 'package:flutter_flow_chart/flutter_flow_chart.dart'; +import 'package:oc_front/widgets/inputs/sub_text_input.dart'; +import 'package:oc_front/widgets/forms/container_forms.dart'; +import 'package:oc_front/widgets/inputs/sub_dropdown_input%20.dart'; + +// ignore: must_be_immutable +class ResourceFormsWidget extends StatefulWidget { + int instanceID = 0; + AbstractItem item; + Dashboard dash; + String elementID; + ResourceFormsWidget ({ super.key, required this.item, required this.dash, required this.elementID }); + @override ResourceFormsWidgetState createState() => ResourceFormsWidgetState(); +} + +class ResourceFormsWidgetState extends State { + List getWidgets(Map infos) { + List widgets = []; + for (var key in infos.keys) { + if (infos[key] == null && infos[key] != 0) { continue; } + if (infos[key] is Map) { widgets.addAll(getWidgets(infos[key])); + } if (infos[key] is List) { + if (infos[key].isEmpty) { continue; } + widgets.add(SubTextInputWidget(subkey: key.replaceAll("_", " "), width: 180, empty: false, readOnly: true, + change: (value) {}, initialValue: (infos[key] as List).join(",") )); + } else if (infos[key] is Map) { + widgets.addAll(getWidgets(infos[key] as Map)); + } else { + widgets.add(SubTextInputWidget(subkey: key.replaceAll("_", " "), width: 180, empty: false, readOnly: true, + change: (value) {}, initialValue: infos[key] is List ? infos[key].join(",") : "${infos[key]}" )); + } + } + if (widgets.isNotEmpty) { + widgets.add(SizedBox( width: 200, height: 15) ); + } + return widgets; + } + + Widget getInputAndOutputVariableForms(bool readOnly) { + List res = []; + res.add(SubKeysMapFormsWidget(dash: widget.dash, type: SubMapFormsType.INPUT, item: widget.item, elementID: widget.elementID, + readOnly: readOnly)); + res.add(SubKeysMapFormsWidget(dash: widget.dash, type: SubMapFormsType.OUTPUT, item: widget.item, elementID: widget.elementID, + readOnly: readOnly)); + res.add(SubKeysMapFormsWidget(dash: widget.dash, type: SubMapFormsType.ENV, item: widget.item, elementID: widget.elementID, + readOnly: readOnly)); + return Column( children: res ); + } + + + @override Widget build(BuildContext context) { + List instancesCat = []; + List childrenReadOnly = getWidgets(widget.item.infos()); + List> dpItems = []; + for (var (i, instance) in widget.item.instances.indexed) { + dpItems.add(DropdownMenuItem(value: '$i', child: Text('${instance.name}', overflow: TextOverflow.ellipsis,))); + } + if (dpItems.isNotEmpty) { + childrenReadOnly.add(Padding( padding: EdgeInsets.only(top: 20), + child : Container( + width: 200, decoration: BoxDecoration( border: Border(bottom: BorderSide(color: Colors.grey))), + ))); + childrenReadOnly.add(Padding(padding: EdgeInsets.only(bottom: 15), child: + SubDropdownInputWidget( dropdownMenuEntries: dpItems, subkey: "", width: 180, empty: false, + initialValue: "${widget.instanceID}", change: (value) { + if (value != null) { setState(() { widget.instanceID = int.parse(value); }); } + }, + )) + ); + if (widget.item.instances.length > widget.instanceID) { + childrenReadOnly.addAll(getWidgets(widget.item.instances[widget.instanceID].infos())); + } + } + instancesCat.add(ContainerFormsWidget(dash: widget.dash, item: widget.item, elementID: widget.elementID)); + if (instancesCat.isNotEmpty) { + instancesCat.add(Container( + width: 200, decoration: BoxDecoration( border: Border(bottom: BorderSide(color: Colors.grey))), + )); + } + bool readOnly = !PermsService.getPerm(Perms.WORKFLOW_EDIT); + // missing env input and output variables + return SizedBox( height: getHeight(context) - 330, child: SingleChildScrollView( child: Column( + children: [ getInputAndOutputVariableForms(readOnly), ...childrenReadOnly, ...instancesCat, ]))); + } +} \ No newline at end of file diff --git a/lib/widgets/forms/scheduler_forms.dart b/lib/widgets/forms/scheduler_forms.dart index 8f69bd1..4d524be 100644 --- a/lib/widgets/forms/scheduler_forms.dart +++ b/lib/widgets/forms/scheduler_forms.dart @@ -1,72 +1,117 @@ -import 'package:alert_banner/exports.dart'; + import 'package:cron/cron.dart'; -import 'package:intl/intl.dart' as intl; -import 'package:flutter/material.dart'; -import 'package:flutter_flow_chart/flutter_flow_chart.dart'; -import 'package:datetime_picker_formfield/datetime_picker_formfield.dart'; -import 'package:oc_front/core/models/shared_workspace_local.dart'; -import 'package:oc_front/core/services/perms_service.dart'; -import 'package:oc_front/core/services/specialized_services/workflow_service.dart'; -import 'package:oc_front/core/services/specialized_services/check_service.dart'; +import 'package:oc_front/core/services/specialized_services/workflow_execution_service.dart'; import 'package:oc_front/main.dart'; +import 'package:flutter/material.dart'; +import 'package:intl/intl.dart' as intl; +import 'package:alert_banner/exports.dart'; +import 'package:oc_front/models/resources/compute.dart'; +import 'package:oc_front/models/resources/processing.dart'; +import 'package:oc_front/models/workflow.dart'; import 'package:oc_front/pages/shared.dart'; import 'package:oc_front/pages/workflow.dart'; import 'package:oc_front/widgets/dialog/alert.dart'; import 'package:oc_front/widgets/dialog/confirm_box.dart'; +import 'package:oc_front/core/services/perms_service.dart'; +import 'package:flutter_flow_chart/flutter_flow_chart.dart'; import 'package:oc_front/widgets/inputs/shallow_text_input.dart'; +import 'package:oc_front/core/models/shared_workspace_local.dart'; +import 'package:datetime_picker_formfield/datetime_picker_formfield.dart'; +import 'package:oc_front/core/services/specialized_services/check_service.dart'; +import 'package:oc_front/core/services/specialized_services/workflow_service.dart'; +// ignore: must_be_immutable class SchedulerFormsWidget extends StatefulWidget { + Scheduler schedule = Scheduler(); Dashboard item; - String purpose = ""; bool? booking; + bool valid = false; + bool shouldSearch = true; + int scheduleFutureCount = 0; + int scheduleBeforeCount = 0; String? error; String? errorEndDate; String? errorCron; Function validate = () {}; + final WorkflowExecutionService _service = WorkflowExecutionService(); SchedulerFormsWidget ({ super.key, required this.item, }); @override SchedulerFormsWidgetState createState() => SchedulerFormsWidgetState(); } class SchedulerFormsWidgetState extends State { CheckService check = CheckService(); void save(List> formKeys) { - dash.scheduleActive = !dash.scheduleActive; widget.error = null; widget.errorEndDate = null; widget.errorCron = null; + if (dash.elements.isEmpty || dash.elements.where((element) => element.element is ProcessingItem).isEmpty) { + dash.error = "You need at least one processing element"; + } + var processings = dash.elements.where((element) => element.element is ProcessingItem); + var computes = dash.elements.where((element) => element.element is ComputeItem); + for (var p in processings) { + var links = dash.arrows.where((element) => element.fromID.contains(p.id) || element.toID.contains(p.id)); + try { + List c = []; + for (var link in links) { + c.addAll(computes.where( (e) => link.toID.contains(e.id) || link.fromID.contains(e.id)).map( (e) => e.element as ComputeItem)); + } + if (c.isEmpty) { throw Exception("no compute element linked"); } + } catch (e) { + dash.error = "You need to link each processing element to a compute element"; + } + } + if (dash.error != null) { + showAlertBanner( context, () {}, AlertAlertBannerChild(text: dash.error.toString()),// <-- Put any widget here you want! + alertBannerLocation: AlertBannerLocation.bottom,); + setState(() {}); + return; + } for (var k in formKeys) { if (k.currentState != null) { - if (!k.currentState!.validate() && dash.scheduleActive) { - dash.scheduleActive = !dash.scheduleActive; + if (!k.currentState!.validate()) { return; } else { k.currentState!.save();} } } DateTime now = DateTime.now().add(const Duration(minutes: 1)); - if (dash.scheduler["start"] == null || DateTime.parse(dash.scheduler["start"]!).isBefore(now)) { - dash.scheduler["start"] = now.toUtc().toIso8601String(); - if (dash.scheduler["end"] != null) { - dash.scheduler["end"] = now.add(const Duration(minutes: 1)).toUtc().toIso8601String(); + if (widget.schedule.start == null || widget.schedule.start!.isBefore(now)) { + widget.schedule.start = now.toUtc(); + if (widget.schedule.end != null) { + widget.schedule.end = now.add(const Duration(minutes: 1)).toUtc(); } } - widget.item.saveDash(widget.item.id); + Duration durationBefore = widget.schedule.start!.difference(DateTime.now().toUtc()) + Duration(seconds: 5); + widget._service.schedule(context, widget.item.id ?? "", widget.schedule.serialize(), {}).then((value) { + setState(() { widget.valid = true; }); + Future.delayed(durationBefore, () { + try { + setState(() {}); + } catch (e) { /* */ } + }); + Future.delayed(const Duration(seconds: 10), () { + try { + setState(() { widget.valid = false; }); + } catch (e) { /* */ } + }); + }); } void checkBooking(List> formKeys, void Function(List> )? f){ - if (widget.item.scheduler["start"] == null) { + if (widget.schedule.start == null) { DateTime now = DateTime.now().add(const Duration(minutes: 5)); - widget.item.scheduler["start"] = now.toUtc().toIso8601String(); + widget.schedule.start = now.toUtc(); } - var s = DateTime.parse(widget.item.scheduler["start"]).toUtc().toIso8601String(); + var s = widget.schedule.start!.toUtc().toIso8601String(); var e = ""; - if (widget.item.scheduler["end"] == null) { - e = DateTime.parse(widget.item.scheduler["start"]).add(const Duration(seconds: 5)).toUtc().toIso8601String(); + if (widget.schedule.end == null) { + e = widget.schedule.start!.add(const Duration(seconds: 5)).toUtc().toIso8601String(); } else { - e = DateTime.parse(widget.item.scheduler["end"]).toUtc().toIso8601String(); + e = widget.schedule.end!.toUtc().toIso8601String(); } check.search(context, [widget.item.id ?? "", s.substring(0, 19), e.substring(0, 19)], {}).then( (v) { if (v.data == null) { return; } - widget.booking = v.data!.is_available; - if (v.data!.is_available) { + widget.booking = v.data!.isAvailable; + if (v.data!.isAvailable) { if (f != null) { f(formKeys); } else { showAlertBanner( context, () {}, @@ -84,6 +129,31 @@ class SchedulerFormsWidgetState extends State { } @override Widget build(BuildContext context) { + if (widget.shouldSearch && widget.item.name != "") { + widget.shouldSearch = false; + widget._service.search(null, [widget.item.name], {}).then((value) { + if (value.data != null) { + try { + setState(() { + widget.scheduleFutureCount = 0; + widget.scheduleBeforeCount = 0; + for (var exec in value.data!.executions) { + if (exec.startDate != null && DateTime.parse(exec.startDate!).isAfter(DateTime.now().toUtc())) { + widget.scheduleFutureCount++; + } else { + widget.scheduleBeforeCount++; + } + } + }); + } catch (e) { /* */ } + + } + }); + } else { + Future.delayed(const Duration(milliseconds: 100), () { + widget.shouldSearch = true; + }); + } bool isService = true; try { widget.item.elements.firstWhere((element) => (element.element?.serialize()["is_service"] ?? false) == true); @@ -95,22 +165,22 @@ class SchedulerFormsWidgetState extends State { DateTime? end; Duration delayed = const Duration(minutes: 5); - if (widget.item.scheduler["start"] != null) { - start = DateTime.parse(widget.item.scheduler["start"]!); - if (start.isBefore(DateTime.now()) && !dash.scheduleActive) { + if (widget.schedule.start != null) { + start = widget.schedule.start!; + if (start.isBefore(DateTime.now())) { start = DateTime.now().add(const Duration(minutes: 5)); - widget.item.scheduler["start"] = start.toUtc().toIso8601String(); + widget.schedule.start = start.toUtc(); } if (start.isBefore(DateTime.now())) { // get difference between now and start delayed = start.difference(DateTime.now()); } } - if (widget.item.scheduler["end"] != null) { - end = DateTime.parse(widget.item.scheduler["end"]!); - if (end.isBefore(DateTime.now()) && !dash.scheduleActive) { + if (widget.schedule.end != null) { + end = widget.schedule.end!; + if (end.isBefore(DateTime.now())) { end = DateTime.now().add(const Duration(minutes: 5)); - widget.item.scheduler["end"] = end.toUtc().toIso8601String(); + widget.schedule.end = end.toUtc(); } if (end.isBefore(DateTime.now())) { // get difference between now and start @@ -164,51 +234,11 @@ class SchedulerFormsWidgetState extends State { child: shallow ), const SizedBox(height: 20, width: 200 ), isService ? Text("Warning a processing is a service, if no end execution it will run forever.") : Container(), - Tooltip( message: "executions name", - child: Container( height: 40, margin: const EdgeInsets.only(top: 5), - padding: const EdgeInsets.symmetric(vertical: 5, horizontal: 10), - child: TextFormField( key: formKeys[0], readOnly: readOnly, - initialValue: "${widget.item.scheduler["name"] ?? "${widget.item.name}_executions"}", - enabled: !dash.scheduleActive && !readOnly, - onChanged: (value) { - Future.delayed(const Duration(seconds: 100), () { - if (widget.item.scheduler["name"] == value) { - widget.item.saveDash(widget.item.id); - } - }); - widget.item.scheduler["name"] = value; - }, - onSaved: (value) { - widget.item.scheduler["name"] = value ?? "${widget.item.scheduler["name"] ?? "${widget.item.name}_executions"}"; - }, - validator: (value) { - if (value == null || value.isEmpty) { - setState(() { widget.error = 'missing name'; }); - } - return value == null || value.isEmpty ? "not empty" : null; - }, - style: const TextStyle(fontSize: 12), - decoration: InputDecoration( - floatingLabelBehavior: FloatingLabelBehavior.always, - fillColor: Colors.white, - filled: true, - hintText: "enter executions name...", - labelText: "executions name*", - hintStyle: TextStyle(fontSize: 10), - labelStyle: TextStyle(fontSize: 10), - focusedErrorBorder: OutlineInputBorder(borderSide: BorderSide(color: widget.item.error != null || 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.item.error != null || widget.error != null ? Colors.red : Colors.black)), - enabledBorder: OutlineInputBorder(borderSide: BorderSide(color: widget.item.error != null || 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), - ), - ))), Tooltip( message: "start executions", child: Container( height: 40, margin: const EdgeInsets.only(top: 5), padding: const EdgeInsets.symmetric(vertical: 5, horizontal: 10), child: DateTimeField( key: formKeys[1], - enabled: !dash.scheduleActive && !readOnly, + enabled: !readOnly, resetIcon: null, onShowPicker: (context, currentValue) async { var date = await showDatePicker( @@ -228,7 +258,7 @@ class SchedulerFormsWidgetState extends State { return w; }, context: context, - firstDate: dash.scheduleActive ? DateTime(1900) : DateTime.now().add(const Duration(minutes: 5)), + firstDate: DateTime.now().add(const Duration(minutes: 5)), initialDate: DateTime.parse( start?.toLocal().toIso8601String() ?? currentValue?.toIso8601String() ?? DateTime.now().add(const Duration(minutes: 5)).toUtc().toIso8601String()).toLocal(), @@ -265,9 +295,9 @@ class SchedulerFormsWidgetState extends State { if (time == null) { return DateTime.now().add( const Duration(minutes: 1)); } count++; date = DateTime(date.year, date.month, date.day, time.hour, time.minute); - widget.item.scheduler["start"] = date.toUtc().toIso8601String(); + widget.schedule.start = date.toUtc(); } - widget.item.saveDash(widget.item.id); + widget.item.saveDash(widget.item.id, context); } return date; }, @@ -296,18 +326,18 @@ class SchedulerFormsWidgetState extends State { child: Container( height: 40, margin: const EdgeInsets.only(top: 5), padding: const EdgeInsets.symmetric(vertical: 5, horizontal: 10), child: DateTimeField( key: formKeys[2], - enabled: !dash.scheduleActive && !readOnly, + enabled: !readOnly, validator: (value) { - if (value == null && widget.item.scheduler["cron"] != null && widget.item.scheduler["cron"].isNotEmpty) { + if (value == null && widget.schedule.cron != null && widget.schedule.cron!.isNotEmpty) { setState(() { widget.errorEndDate = 'missing start date'; }); } - return value == null && widget.item.scheduler["cron"] != null && widget.item.scheduler["cron"].isNotEmpty ? "not empty" : null; + return value == null && widget.schedule.cron != null && widget.schedule.cron!.isNotEmpty ? "not empty" : null; }, onChanged: (value) { if (value == null) { - widget.item.scheduler.remove("end"); + widget.schedule.end = null; } }, resetIcon: const Icon(Icons.close, size: 15), @@ -329,7 +359,7 @@ class SchedulerFormsWidgetState extends State { return w; }, context: context, - firstDate: dash.scheduleActive ? DateTime(1900) : DateTime.now().add(const Duration(minutes: 5)), + firstDate: DateTime.now().add(const Duration(minutes: 5)), initialDate: DateTime.parse( end?.toLocal().toIso8601String() ?? currentValue?.toIso8601String() ?? DateTime.now().add(const Duration(minutes: 5)).toUtc().toIso8601String()).toLocal(), @@ -342,7 +372,7 @@ class SchedulerFormsWidgetState extends State { var count = 0; while(date!.microsecondsSinceEpoch <= (DateTime.now().microsecondsSinceEpoch) || time == null - || (date.microsecondsSinceEpoch) <= (DateTime.parse(widget.item.scheduler["start"] ?? DateTime.now().toIso8601String()).microsecondsSinceEpoch)) { + || (date.microsecondsSinceEpoch) <= (widget.schedule.start ?? DateTime.now()).microsecondsSinceEpoch) { if (count > 0) { showAlertBanner( context, () {}, // ignore: use_build_context_synchronously const AlertAlertBannerChild(text: "must be at least 1 minute from now to let system check info && upper starting date"),// <-- Put any widget here you want! @@ -370,9 +400,9 @@ class SchedulerFormsWidgetState extends State { if (time == null) { return null; } count++; date = DateTime(date.year, date.month, date.day, time.hour, time.minute); - widget.item.scheduler["end"] = date.toUtc().toIso8601String(); + widget.schedule.end = date.toUtc(); } - widget.item.saveDash(widget.item.id); + widget.item.saveDash(widget.item.id, context); } return date; }, @@ -400,19 +430,19 @@ class SchedulerFormsWidgetState extends State { child: Container( height: 40, margin: const EdgeInsets.only(top: 5), padding: const EdgeInsets.symmetric(vertical: 5, horizontal: 10), child: TextFormField( key: formKeys[3], - enabled: !dash.scheduleActive && !readOnly, - initialValue: widget.item.scheduler["cron"], + enabled: !readOnly, + initialValue: widget.schedule.cron, onChanged: (value) { Future.delayed(const Duration(seconds: 100), () { - if (widget.item.scheduler["cron"] == value) { - widget.item.saveDash(widget.item.id); + if (widget.schedule.cron == value) { + widget.item.saveDash(widget.item.id, context); } }); - widget.item.scheduler["cron"] = value; + widget.schedule.cron = value; }, onSaved: (value) { if (value != null) { - widget.item.scheduler["cron"] = value; + widget.schedule.cron = value; } }, validator: (value) { @@ -456,49 +486,58 @@ class SchedulerFormsWidgetState extends State { width: 200, height: 10, ), - Tooltip( message: "check booking", - child: InkWell( mouseCursor: SystemMouseCursors.click, - onTap: () { - PermsService.getPerm(Perms.WORKFLOW_BOOKING) ? checkBooking(formKeys, null) : null; - }, child: Container( margin: const EdgeInsets.only(bottom: 5, left: 10, right: 10), - decoration: BoxDecoration(borderRadius: BorderRadius.circular(5), - border: Border.all(color: widget.booking == null && !dash.scheduleActive ? ( + Tooltip( message: "check booking", child: InkWell( mouseCursor: SystemMouseCursors.click, + onTap: () { PermsService.getPerm(Perms.WORKFLOW_BOOKING) ? checkBooking(formKeys, null) : null; + }, child: Container( margin: const EdgeInsets.only(bottom: 5, left: 10, right: 10), + decoration: BoxDecoration(borderRadius: BorderRadius.circular(5), + border: Border.all(color: widget.booking == null ? ( PermsService.getPerm(Perms.WORKFLOW_BOOKING) && PermsService.getPerm(Perms.WORKFLOW_EDIT) ? Colors.black : Colors.grey) : ( - widget.booking == true || dash.scheduleActive ? Colors.green : redColor), width: 1)), + widget.booking == true ? Colors.green : redColor), width: 1)), width: 200, height: 30, - child: Icon( - Icons.verified_outlined, - color: widget.booking == null && !dash.scheduleActive ? Colors.black : (widget.booking == true || dash.scheduleActive ? Colors.green : redColor)), + child: Icon( Icons.verified_outlined, + color: widget.booking == null ? Colors.black : (widget.booking == true ? Colors.green : redColor)), )) ), - Tooltip( message: dash.scheduleActive ? "unbook" : "book", - child: InkWell( mouseCursor: SystemMouseCursors.click, + Tooltip( message: "book", child: InkWell( mouseCursor: SystemMouseCursors.click, onTap: () { - PermsService.getPerm(Perms.WORKFLOW_BOOKING) && PermsService.getPerm(Perms.WORKFLOW_EDIT) ? (dash.scheduleActive ? setState(() { save(formKeys); }) : checkBooking(formKeys, save)) : null; - }, child: Container( margin: const EdgeInsets.symmetric(vertical: 5, horizontal: 10), + PermsService.getPerm(Perms.WORKFLOW_BOOKING) && PermsService.getPerm(Perms.WORKFLOW_EDIT) ? setState(() { save(formKeys); }) : null; + }, child: Container( margin: const EdgeInsets.only(top: 5, bottom: 10, left: 10, right: 10), decoration: BoxDecoration(borderRadius: BorderRadius.circular(5), - border: Border.all(color: dash.scheduleActive ? Colors.green : ( PermsService.getPerm(Perms.WORKFLOW_BOOKING) ?Colors.black : Colors.grey ))), + border: Border.all(color: dash.error != null ? Colors.red : ( PermsService.getPerm(Perms.WORKFLOW_BOOKING) ?(widget.valid ? Colors.green : Colors.black) : Colors.grey ))), width: 200, height: 30, - child: Icon( - dash.scheduleActive ? Icons.cancel_schedule_send : Icons.schedule_send, color: dash.scheduleActive ? Colors.green : Colors.black), + child: Icon(Icons.schedule_send, color: dash.error != null ? Colors.red : (widget.valid ? Colors.green : Colors.black)), )) ), + Column( children: [ + Container( + height: 15, width: 200, + decoration: const BoxDecoration(border: Border(top: BorderSide(color: Colors.grey))), + ), + Container( alignment: Alignment.center, padding: const EdgeInsets.symmetric(horizontal: 10), + child:Text( textAlign: TextAlign.center, overflow: TextOverflow.ellipsis, + style: const TextStyle(fontSize: 13, color: Colors.grey ), + "Was booked ${widget.scheduleBeforeCount} times.")), + Container( alignment: Alignment.center, padding: const EdgeInsets.only(left: 10, right: 10, bottom: 15), + child:Text( textAlign: TextAlign.center, overflow: TextOverflow.ellipsis, + style: const TextStyle(fontSize: 13, color: Colors.grey ), + "Is booked ${widget.scheduleFutureCount} times.")), + ]), widget.item.info["shared"] != null && (widget.item.info["shared"] as List).isNotEmpty ? Column( children: [ Container( height: 30, width: 200, decoration: const BoxDecoration(border: Border(top: BorderSide(color: Colors.grey))), ), - Container( alignment: Alignment.center, padding: const EdgeInsets.symmetric(horizontal: 10), - child:Text( textAlign: TextAlign.center, overflow: TextOverflow.ellipsis, + Container( alignment: Alignment.center, + child:Text( overflow: TextOverflow.ellipsis, style: const TextStyle(fontSize: 14, color: Colors.black, fontWeight: FontWeight.bold), - "Workflow is shared in ${(widget.item.info["shared"] as List).length} workspace(s)")), + "Is shared ${(widget.item.info["shared"] as List).length} time(s).")), ...(widget.item.info["shared"] as List).where( (e) => CollaborativeAreaLocal.getCollaborativeArea(e) != null ).map((e) { var sw = CollaborativeAreaLocal.getCollaborativeArea(e); return Container( alignment: Alignment.center, padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 5), child: Row( children: [ - const Padding(padding: EdgeInsets.only(right: 10), child: Icon(Icons.work, color: Colors.grey, size: 15)), + const Padding(padding: EdgeInsets.only( left: 10, right: 10), child: Icon(Icons.work, color: Colors.grey, size: 15)), Text(style: const TextStyle(fontSize: 12, color: Colors.grey), "Workspace: ${sw != null && sw.name != null ? "${sw.name!.substring(0, sw.name!.length > 15 ? 12 : sw.name!.length)}${sw.name!.length > 15 ? "..." : ""}" : ""}") ])); diff --git a/lib/widgets/forms/storage_forms.dart b/lib/widgets/forms/storage_forms.dart deleted file mode 100644 index 3fee6e6..0000000 --- a/lib/widgets/forms/storage_forms.dart +++ /dev/null @@ -1,18 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:oc_front/models/search.dart'; -import 'package:oc_front/widgets/forms/web_reference_forms.dart'; - -class StorageFormsWidget extends StatefulWidget { - StorageItem item; - String purpose = ""; - Function validate = () {}; - StorageFormsWidget ({ super.key, required this.item }); - @override StorageFormsWidgetState createState() => StorageFormsWidgetState(); -} -class StorageFormsWidgetState extends State { - @override Widget build(BuildContext context) { - return Column( children: [ - WebReferenceFormsWidget(item: widget.item), - ]); - } -} \ No newline at end of file diff --git a/lib/widgets/forms/storage_processing_link_forms.dart b/lib/widgets/forms/storage_processing_link_forms.dart new file mode 100644 index 0000000..34c9bcf --- /dev/null +++ b/lib/widgets/forms/storage_processing_link_forms.dart @@ -0,0 +1,154 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_advanced_switch/flutter_advanced_switch.dart'; +import 'package:oc_front/main.dart'; +import 'package:oc_front/models/resources/resources.dart'; +import 'package:flutter_flow_chart/flutter_flow_chart.dart'; +import 'package:oc_front/models/workflow.dart'; +import 'package:oc_front/widgets/inputs/sub_text_input.dart'; + +// ignore: must_be_immutable +class StorageProcessingLinkFormsWidget extends StatefulWidget { + Dashboard dash; + ArrowPainter item; + bool readOnly = false; + StorageProcessingLinkFormsWidget ({ super.key, required this.dash, required this.item, this.readOnly = false }); + @override StorageProcessingLinkFormsWidgetState createState() => StorageProcessingLinkFormsWidgetState(); +} + +class StorageProcessingLinkFormsWidgetState extends State { + + List getParams(String fromID, String toID) { + List arr = []; + var els = widget.dash.elements.where( (e) => fromID.contains(e.id) || toID.contains(e.id)); + for (var element in els) { + var g = GraphItem(); + g.fromDashboard(element.serialize()); + var e = g.getElement(); + if (e == null) { continue; } + if (e.getSelectedInstance() != null) { + for (var env in e.getSelectedInstance()!.env) { + if (env.name?.contains("LINK") ?? true) { continue; } + arr.add(env); + } + } + } + return arr.where( (e) => e.name != null && e.value != null).toList(); + } + + + @override Widget build(BuildContext context) { + List children = [ + Padding( padding: const EdgeInsets.only(top: 10), + child: Text("", + style: const TextStyle(fontSize: 13, fontWeight: FontWeight.bold), textAlign: TextAlign.center)), + ]; + var params = getParams(widget.item.fromID, widget.item.toID); + widget.item.env = params.map( (e) => e.serialize()).toList(); + for (var param in params) { + children.add(SubTextInputWidget(subkey: param.name ?? "", width: 180, empty: false, readOnly: true, + change: (value) {}, initialValue: param.value ?? "", copyLabel: true)); + } + children.add(Container(width: 200, padding: const EdgeInsets.only(top: 10, bottom: 10), + decoration: const BoxDecoration(border: Border(bottom: BorderSide(color: Colors.grey, width: 1))))); + List inf = []; + int count = 0; + for(var info in widget.item.infos) { + count++; + inf.add(Padding( padding: EdgeInsets.only(top: 10, bottom: 5), + child : Row( crossAxisAlignment: CrossAxisAlignment.center, children: [ + Padding(padding: EdgeInsets.only(left: 10, right: 10), child: Text("N°$count")), + Container(width: 140, decoration: const BoxDecoration(border: Border(bottom: BorderSide(color: Colors.grey, width: 1)))) + ]))); + for (var key in (info as Map).keys) { + if (info[key] is bool) { + inf.add(AdvancedSwitch( + width: 150.0, + height: 25.0, + initialValue: info[key] as bool? ?? false, + enabled: !widget.readOnly, + activeChild: Text(key, style: const TextStyle(color: Colors.white)), + inactiveChild: Text(key == "write" ? "read" : "no $key", style: const TextStyle(color: Colors.white)), + activeColor: Colors.green, + inactiveColor: redColor, + onChanged: (v) { + try { + info[key] = v; + Future.delayed(const Duration(seconds: 1), () { + for (var a in widget.dash.arrows) { + if (a.fromID == widget.item.fromID && a.toID == widget.item.toID) { + a.infos = widget.item.infos; + } + } + widget.dash.saveDash(widget.dash.id, context); + }); + } catch (e) { /* */ } + + }, + )); + } else if (info[key] is String?) { + inf.add(SubTextInputWidget(subkey: key, width: 180, empty: false, change: (v) { + try { + info[key] = v; + Future.delayed(const Duration(seconds: 1), () { + if (info[key] != v) { return; } + for (var a in widget.dash.arrows) { + if (a.fromID == widget.item.fromID && a.toID == widget.item.toID) { + a.infos = widget.item.infos; + } + } + widget.dash.saveDash(widget.dash.id, context); + }); + } catch (e) { + print(e); + } + + }, initialValue: "${info[key] ?? ""}", readOnly: false, noLabel: false)); + } + + + } + } + return SizedBox( height: getHeight(context) - 230, child: SingleChildScrollView( child: Column(children: [ + ...children, + Row( mainAxisAlignment: MainAxisAlignment.center, children: [ + InkWell( onTap: () { + widget.item.infos.add({ + "write": false, + "source": null, + "destination": null, + "filename": null, + }); + setState(() { + widget.dash.saveDash(widget.dash.id, context); + }); + }, child: Container( margin: const EdgeInsets.only(top: 10), + decoration: BoxDecoration(borderRadius: BorderRadius.circular(5), + border: Border.all(color: Colors.grey, width: 1)), + width: 125, height: 30, + child: Row( mainAxisAlignment: MainAxisAlignment.center, + children: [ Padding( padding: EdgeInsets.only(right: 5), child: Icon(Icons.add, color: Colors.black,)), + Text("link infos", + style: TextStyle( color: Colors.black))]), + ), + ), + InkWell( onTap: () { + if (widget.item.infos.isEmpty) { return; } + setState(() { + widget.item.infos.removeLast(); + widget.dash.saveDash(widget.dash.id, context); + }); + }, child: + Container( margin: const EdgeInsets.only(left: 5, top: 10), + decoration: BoxDecoration(borderRadius: BorderRadius.circular(5), + border: Border.all(color: widget.item.infos.isEmpty ? Colors.grey : Colors.black , width: 1)), + width: 50, height: 30, + child: Row( mainAxisAlignment: MainAxisAlignment.center, + children: [ Icon( Icons.delete, size: 18, + color: widget.item.infos.isEmpty ? Colors.grey : Colors.black ) ]), + ) + ), + ]), + ...inf + ] ) )); + } +} \ No newline at end of file diff --git a/lib/widgets/forms/sub_add_forms.dart b/lib/widgets/forms/sub_add_forms.dart new file mode 100644 index 0000000..47dbfcd --- /dev/null +++ b/lib/widgets/forms/sub_add_forms.dart @@ -0,0 +1,174 @@ + +import 'package:flutter/material.dart'; +import 'package:flutter_flow_chart/flutter_flow_chart.dart'; +import 'package:oc_front/models/resources/resources.dart'; +import 'package:oc_front/widgets/forms/sub_keys_forms.dart'; +import 'package:oc_front/widgets/inputs/sub_text_input.dart'; + +// ignore: must_be_immutable +class SubAddFormsWidget extends StatefulWidget { + bool readOnly; + SubMapFormsType type; + String elementID = ""; + AbstractItem item; + Dashboard dash; + bool empty = false; + List forms = []; + SubAddFormsWidget ({ super.key, required this.dash, this.readOnly = false, + this.empty = false, required this.item, required this.elementID, + required this.type }); + @override SubAddFormsWidgetState createState() => SubAddFormsWidgetState(); +} +class SubAddFormsWidgetState extends State { + Param? addedparam; + @override Widget build(BuildContext context) { + AbstractInstance instance = widget.item.getSelectedInstance()!; + var f = (widget.type == SubMapFormsType.INPUT ? instance.inputs : ( + widget.type == SubMapFormsType.OUTPUT ? instance.outputs : instance.env)).where( (e) => !e.readOnly).toList(); + widget.forms = f; + if (addedparam != null) { + widget.forms.add(addedparam!); + } + List children = []; + for (var param in widget.forms) { + children.add(Row( mainAxisAlignment: MainAxisAlignment.center, children: [ + SubTextInputWidget(subkey: "key", readOnly: widget.readOnly, + initialValue: param.name, width: 81, empty: widget.empty, + change: (value) { + setState(() { + param.name = value; + param.attr = value; + if (addedparam?.value != null && addedparam?.name != null) { + addedparam = null; + } + var sel = widget.item.getSelectedInstance(); + if (sel != null) { + if (widget.type == SubMapFormsType.INPUT) { sel.inputs = [ + ...sel.inputs.where( (e) => e.readOnly), + ...widget.forms.where((e) => e.name != null && e.value != null) + ]; + } else if (widget.type == SubMapFormsType.OUTPUT) { + sel.outputs = [ + ...sel.outputs.where( (e) => e.readOnly), + ...widget.forms.where((e) => e.name != null && e.value != null) + ]; + } else { + sel.env = [ + ...sel.env.where( (e) => e.readOnly), + ...widget.forms.where((e) => e.name != null && e.value != null) + ]; + } + } + Future.delayed(const Duration(milliseconds: 100), () { + if (param.name == value) { + widget.dash.saveDash(widget.dash.id, context); + } + }); + var el = widget.dash.getElement(widget.elementID); + el!.element = widget.item as dynamic; + setState(() {}); + }); + }), + const Padding(padding: EdgeInsets.only(left: 5, right: 5, top: 15), child: Text("=", textAlign: TextAlign.center,)), + SubTextInputWidget(subkey: "value", initialValue: param.value, width: 81, empty: widget.empty, + readOnly: widget.readOnly, change: (value) { + param.value = value; + if (addedparam?.value != null && addedparam?.name != null) { + addedparam = null; + } + var sel = widget.item.getSelectedInstance(); + if (sel != null) { + if (widget.type == SubMapFormsType.INPUT) { sel.inputs = [ + ...sel.inputs.where( (e) => e.readOnly), + ...widget.forms.where((e) => e.name != null && e.value != null) + ]; + } else if (widget.type == SubMapFormsType.OUTPUT) { + sel.outputs = [ + ...sel.outputs.where( (e) => e.readOnly), + ...widget.forms.where((e) => e.name != null && e.value != null) + ]; + } else { + sel.env = [ + ...sel.env.where( (e) => e.readOnly ), + ...widget.forms.where((e) => e.name != null && e.value != null) + ]; + } + } + var el = widget.dash.getElement(widget.elementID); + el!.element = widget.item as dynamic; + setState(() {}); + Future.delayed(const Duration(milliseconds: 100), () { + if (param.value == value) { + widget.dash.saveDash(widget.dash.id, context); + } + }); + }), + ])); + } + return Column( crossAxisAlignment: CrossAxisAlignment.center, children : [ + widget.readOnly ? Container() : Row( mainAxisAlignment: MainAxisAlignment.center, children: [ + InkWell( onTap: () { + if (widget.forms.isNotEmpty && (widget.forms[widget.forms.length - 1].name == null + || widget.forms[widget.forms.length - 1].value == null)) { return;} + widget.forms.add(Param(readOnly: false)); + addedparam = widget.forms.last; + var el = widget.dash.getElement(widget.elementID); + el!.element = widget.item as dynamic; + setState(() {}); + }, child: Container( margin: const EdgeInsets.only(top: 10), + decoration: BoxDecoration(borderRadius: BorderRadius.circular(5), + border: Border.all(color: widget.forms.isNotEmpty && (widget.forms[widget.forms.length - 1].name == null + || widget.forms[widget.forms.length - 1].value == null) ? Colors.grey : Colors.grey, width: 1)), + width: 125, height: 30, + child: Row( mainAxisAlignment: MainAxisAlignment.center, + children: [ Padding( padding: EdgeInsets.only(right: 5), child: Icon(Icons.add, color: widget.forms.isNotEmpty && (widget.forms[widget.forms.length - 1].name == null + || widget.forms[widget.forms.length - 1].value == null) ? Colors.grey : Colors.black,)), + Text(widget.type == SubMapFormsType.ENV ? "env" : (widget.type == SubMapFormsType.INPUT ? "input" : "output"), + style: TextStyle( color: widget.forms.isNotEmpty && (widget.forms[widget.forms.length - 1].name == null + || widget.forms[widget.forms.length - 1].value == null) ? Colors.grey : Colors.black))]), + ), + ), + InkWell( onTap: () { + if (addedparam != null) { + addedparam = null; + return setState(() {}); + } + if (widget.forms.isEmpty) { return; } + widget.forms.sublist(0, widget.forms.length - 1); + var el = widget.dash.getElement(widget.elementID); + var sel = widget.item.getSelectedInstance(); + if (sel != null) { + widget.forms.removeLast(); + if (widget.type == SubMapFormsType.INPUT) { sel.inputs = [ + ...sel.inputs.where( (e) => e.readOnly), + ...widget.forms.where((e) => e.name != null && e.value != null) + ]; + } else if (widget.type == SubMapFormsType.OUTPUT) { + sel.outputs = [ + ...sel.outputs.where( (e) => e.readOnly), + ...widget.forms.where((e) => e.name != null && e.value != null) + ]; + } else { + sel.env = [ + ...sel.env.where( (e) => e.readOnly), + ...widget.forms.where((e) => e.name != null && e.value != null) + ]; + } + } + el!.element = widget.item as dynamic; + setState(() { widget.dash.saveDash(widget.dash.id, context); }); + }, child: + Container( margin: const EdgeInsets.only(left: 5, top: 10), + decoration: BoxDecoration(borderRadius: BorderRadius.circular(5), + border: Border.all(color: widget.forms.isEmpty ? Colors.grey : Colors.black , width: 1)), + width: 50, height: 30, + child: Row( mainAxisAlignment: MainAxisAlignment.center, + children: [ Icon( Icons.delete, size: 18, + color: widget.forms.isEmpty ? Colors.grey : Colors.black ) ]), + ) + ), + ]), + ...children + ]); + } +} \ No newline at end of file diff --git a/lib/widgets/forms/sub_expose_forms.dart b/lib/widgets/forms/sub_expose_forms.dart index 19cffb4..d82b45a 100644 --- a/lib/widgets/forms/sub_expose_forms.dart +++ b/lib/widgets/forms/sub_expose_forms.dart @@ -1,9 +1,10 @@ import 'package:flutter/material.dart'; +import 'package:oc_front/models/resources/processing.dart'; import 'package:flutter_flow_chart/flutter_flow_chart.dart'; -import 'package:oc_front/models/search.dart'; import 'package:oc_front/widgets/inputs/sub_text_input.dart'; +// ignore: must_be_immutable class SubExposeFormsWidget extends StatefulWidget { bool readOnly; Expose item; @@ -29,7 +30,7 @@ class SubExposeFormsWidgetState extends State { widget.item.port = int.parse(value); Future.delayed(const Duration(seconds: 2), () { if (widget.item.port == int.parse(value) && int.parse(value) != 0) { - widget.dash.saveDash(widget.dash.id); + widget.dash.saveDash(widget.dash.id, context); } }); } catch (e) { widget.item.port = null; } @@ -44,7 +45,7 @@ class SubExposeFormsWidgetState extends State { widget.item.PAT = int.parse(value); Future.delayed(const Duration(seconds: 2), () { if (widget.item.PAT == int.parse(value) && int.parse(value) != 0) { - widget.dash.saveDash(widget.dash.id); + widget.dash.saveDash(widget.dash.id, context); } }); } catch (e) { widget.item.PAT = null; } @@ -57,7 +58,7 @@ class SubExposeFormsWidgetState extends State { try { widget.item.path = value; Future.delayed(const Duration(seconds: 2), () { - if (widget.item.path == value) { widget.dash.saveDash(widget.dash.id); } + if (widget.item.path == value) { widget.dash.saveDash(widget.dash.id, context); } }); } catch (e) { widget.item.path = null; } var el = widget.dash.getElement(widget.elementID); diff --git a/lib/widgets/forms/sub_keys_forms.dart b/lib/widgets/forms/sub_keys_forms.dart index 20e7ab2..ffb935d 100644 --- a/lib/widgets/forms/sub_keys_forms.dart +++ b/lib/widgets/forms/sub_keys_forms.dart @@ -1,62 +1,97 @@ import 'package:flutter/material.dart'; +import 'package:flutter_advanced_switch/flutter_advanced_switch.dart'; import 'package:flutter_flow_chart/flutter_flow_chart.dart'; +import 'package:oc_front/main.dart'; +import 'package:oc_front/models/resources/resources.dart'; import 'package:oc_front/models/workflow.dart'; +import 'package:oc_front/widgets/forms/sub_add_forms.dart'; import 'package:oc_front/widgets/inputs/sub_text_input.dart'; - +enum SubMapFormsType { + ENV, + INPUT, + OUTPUT +} +// ignore: must_be_immutable class SubKeysMapFormsWidget extends StatefulWidget { bool readOnly = false; - FlowData item; + AbstractItem item; Dashboard dash; - String varKey = ""; bool empty = false; - bool isInput = true; + SubMapFormsType type; String elementID = ""; - String categoryKey = ""; - List graphItems = []; - SubKeysMapFormsWidget({ super.key, required this.dash, required this.isInput, this.readOnly = false, - this.empty = false, required this.item, required this.elementID, required this.graphItems, - required this.categoryKey, required this.varKey }); + SubKeysMapFormsWidget({ super.key, required this.dash, required this.type, this.readOnly = false, + this.empty = false, required this.item, required this.elementID }); @override SubKeysMapFormsWidgetState createState() => SubKeysMapFormsWidgetState(); } class SubKeysMapFormsWidgetState extends State { + bool _save = false; + + List getParams(String fromID, String toID) { + List arr = []; + var els = widget.dash.elements.where( (e) => fromID.contains(e.id) || toID.contains(e.id)); + for (var element in els) { + var g = GraphItem(); + g.fromDashboard(element.serialize()); + var e = g.getElement(); + if (e != null && e.getSelectedInstance() != null) { + arr = [...arr, ...e.getSelectedInstance()!.env]; + } + } + return arr; + } + List getInstanceInOutput(AbstractItem? item, SubMapFormsType type) { + List children = []; + if (item == null || item.getSelectedInstance() == null) { + return []; + } + AbstractInstance instance = item.getSelectedInstance()!; + List params = widget.type == SubMapFormsType.INPUT ? instance.inputs : ( widget.type == SubMapFormsType.OUTPUT ? instance.outputs : instance.env); + for ( var param in params) { + if (!param.readOnly) { continue; } + dynamic env; + if (param.value == null && param.attr != null) { + var s = item.serialize(); + s.addAll(item.getSelectedInstance()?.serialize() ?? {}); + env = s[param.attr!]; + } else { env = param.value; } + _save = true; + if (env is bool) { + var ctrl = ValueNotifier(env); + children.add(AdvancedSwitch( + width: 150.0, + height: 25.0, + controller: ctrl, + enabled: false, + activeChild: Text(param.name!, style: const TextStyle(color: Colors.white)), + inactiveChild: Text("no ${param.name!}", style: const TextStyle(color: Colors.white)), + activeColor: Colors.green, + inactiveColor: redColor, + onChanged: (value) {}, + )); + } else { + children.add(SubTextInputWidget( subkey: param.name!, width: 180, empty: false, change: (value) { }, + initialValue: env, readOnly: true, noLabel: false, copyLabel: true )); + } + } + return children; + } @override Widget build(BuildContext context) { List children = []; - - bool save = false; - for (var graphItem in widget.graphItems) { - int count = 0; - var el = graphItem.getElement(); - if (el == null || el.model == null) { continue; } - for ( var r in el.model!.refs.keys) { - var env = widget.item.getVariable(["container", "env"], widget.item.serialize()); - if (env == null || env is Map) { continue; } - var n = "${el.topic.toUpperCase()}_${el.getName().toUpperCase().replaceAll(" ", "_")}_${r.toUpperCase()}_$count"; - if (env[n] == null) { - save = true; - } - env[n]= "{{ ${ widget.isInput ? "in" : "out" }_${graphItem.id}_$r }}"; - widget.item.setVariable(["container", "env"], env, el.serialize()); - children.add( Padding(padding: const EdgeInsets.only(bottom: 10), - child: SubTextInputWidget(subkey: n, width: 180, empty: false, change: (value) {}, - initialValue: n, readOnly: true, noLabel: true))); - count++; - } + var newwidget = getInstanceInOutput(widget.item, widget.type); + children.add(Column( children : [ + Padding( padding: const EdgeInsets.only(top: 10), + child: Text("<${widget.type == SubMapFormsType.INPUT ? "INPUT" : (widget.type == SubMapFormsType.OUTPUT ? "OUTPUT" : "")} ENV VARIABLES>", + style: const TextStyle(fontSize: 13, fontWeight: FontWeight.bold), textAlign: TextAlign.center)), + ...newwidget, + SubAddFormsWidget(dash: widget.dash, item: widget.item, elementID: widget.elementID, type: widget.type), + Container(width: 200, padding: const EdgeInsets.only(top: 10, bottom: 10), + decoration: const BoxDecoration(border: Border(bottom: BorderSide(color: Colors.grey, width: 1)))), + ])); + if (_save) { + widget.dash.saveDash(widget.dash.id, context); } - if (save) { - widget.dash.saveDash(widget.dash.id); - } - if (children.isEmpty) { - return Container(); - } - return Column( children : [ - Container(width: 200, padding: const EdgeInsets.only(top: 10, bottom: 10), - decoration: const BoxDecoration(border: Border(bottom: BorderSide(color: Colors.grey, width: 1)))), - Padding( padding: const EdgeInsets.only(top: 10), - child: Text("<${widget.isInput ? "INPUT ENV VARIABLE" : "OUTPUT ENV VARIABLE"}>", style: const TextStyle(fontSize: 13, fontWeight: FontWeight.bold), - textAlign: TextAlign.center)), - Column( children: children), - ]); + return Column( children : children ); } } \ No newline at end of file diff --git a/lib/widgets/forms/sub_map_forms.dart b/lib/widgets/forms/sub_map_forms.dart deleted file mode 100644 index 134e345..0000000 --- a/lib/widgets/forms/sub_map_forms.dart +++ /dev/null @@ -1,115 +0,0 @@ - -import 'package:flutter/material.dart'; -import 'package:flutter_flow_chart/flutter_flow_chart.dart'; -import 'package:oc_front/widgets/inputs/sub_text_input.dart'; - -class MapForm { - String key = ""; - String value = ""; - MapForm({ required this.key, required this.value }); -} - -class SubMapFormsWidget extends StatefulWidget { - bool readOnly; - String categoryKey = ""; - String varKey = ""; - String elementID = ""; - FlowData item; - Dashboard dash; - bool empty = false; - List forms = []; - SubMapFormsWidget ({ super.key, required this.dash, this.readOnly = false, - this.empty = false, required this.item, required this.elementID, - required this.categoryKey, required this.varKey }); - @override SubMapFormsWidgetState createState() => SubMapFormsWidgetState(); -} -class SubMapFormsWidgetState extends State { - - Map toMap() { - Map m = {}; - for (var form in widget.forms) { - m[form.key] = form.value; - } - return m; - } - - @override Widget build(BuildContext context) { - Map? m = widget.item.getVariable([widget.categoryKey, widget.varKey], widget.item.serialize()); - var l = [widget.categoryKey, widget.varKey]; - List children = []; - List empty = []; - widget.forms = []; - var i = 0; - for (var key in (m?.keys.toList() ?? empty)) { - if (((m![key] as String?)?.contains('{{') ?? false)) { - continue; - } - widget.forms.add(MapForm(key: key, value: m[key])); - children.add(Row( children: [ - SubTextInputWidget(subkey: "key", readOnly: widget.readOnly, - initialValue: key, width: 77.5, empty: widget.empty, - change: (value) { - setState(() { - widget.forms[i].key = value; - Future.delayed(const Duration(seconds: 2), () { - widget.dash.saveDash(widget.dash.id); - }); - var el = widget.dash.getElement(widget.elementID); - widget.item = widget.item.deserialize(widget.item.setVariable(l, toMap(), widget.item.serialize())) as dynamic; - el!.element = widget.item as dynamic; - }); - }), - const Padding(padding: EdgeInsets.only(left: 5, right: 5, top: 15), child: Text("=", textAlign: TextAlign.center,)), - SubTextInputWidget(subkey: "value", initialValue: widget.forms[i].value, width: 77.5, empty: widget.empty, - readOnly: widget.readOnly, change: (value) { - Future.delayed(const Duration(seconds: 2), () { - widget.dash.saveDash(widget.dash.id); - }); - widget.forms[i].value = value; - var el = widget.dash.getElement(widget.elementID); - widget.item = widget.item.deserialize( - widget.item.setVariable(l, toMap(), widget.item.serialize())) as dynamic; - el!.element = widget.item as dynamic; - }), - ])); - i++; - } - return Column( children : [ - Container(width: 200, padding: const EdgeInsets.only(top: 10), - decoration: const BoxDecoration(border: Border(bottom: BorderSide(color: Colors.grey, width: 1))),), - widget.readOnly ? Container() : Row( children: [ - InkWell( onTap: () { - widget.forms.add(MapForm(key: "", value: "")); - var el = widget.dash.getElement(widget.elementID); - widget.item = widget.item.deserialize( - widget.item.setVariable(l, toMap(), widget.item.serialize())) as dynamic; - el!.element = widget.item as dynamic; - setState(() {}); - }, child: Container( margin: const EdgeInsets.only(top: 10), - decoration: BoxDecoration(borderRadius: BorderRadius.circular(5), border: Border.all(color: Colors.grey, width: 1)), - width: 125, height: 30, - child: Row( mainAxisAlignment: MainAxisAlignment.center, - children: [ const Padding( padding: EdgeInsets.only(right: 5), child: Icon(Icons.add)), Text("add ${widget.varKey} vars")]), - ), - ), - InkWell( onTap: () { - if (widget.forms.isEmpty) { return;} - widget.forms.sublist(0, widget.forms.length - 1); - widget.item = widget.item.deserialize( - widget.item.setVariable(l, toMap(), widget.item.serialize())) as dynamic; - var el = widget.dash.getElement(widget.elementID); - el!.element = widget.item as dynamic; - setState(() { widget.dash.saveDash(widget.dash.id); }); - }, child: - Container( margin: const EdgeInsets.only(left: 5, top: 10), - decoration: BoxDecoration(borderRadius: BorderRadius.circular(5), border: Border.all(color: Colors.grey, width: 1)), - width: 45, height: 30, - child: const Row( mainAxisAlignment: MainAxisAlignment.center, - children: [ Icon( Icons.delete, color: Colors.black ) ]), - ) - ), - ]), - ...children - ]); - } -} \ No newline at end of file diff --git a/lib/widgets/forms/web_reference_forms.dart b/lib/widgets/forms/web_reference_forms.dart deleted file mode 100644 index 6c2dfab..0000000 --- a/lib/widgets/forms/web_reference_forms.dart +++ /dev/null @@ -1,23 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:oc_front/widgets/inputs/sub_text_input.dart'; - -class WebReferenceFormsWidget extends StatefulWidget { - dynamic item; - WebReferenceFormsWidget ({ super.key, required this.item }); - @override WebReferenceFormsWidgetState createState() => WebReferenceFormsWidgetState(); -} -class WebReferenceFormsWidgetState extends State { - @override Widget build(BuildContext context) { - return Column( children: [ - SubTextInputWidget(subkey: "path", width: 180, empty: false, change: (value) { - widget.item.path = value.split(","); - }, initialValue: widget.item.path, readOnly: true,), - SubTextInputWidget(subkey: "protocol", width: 180, empty: false, change: (value) { - widget.item.protocol = value.split(","); - }, initialValue: widget.item.protocol, readOnly: true,), - SubTextInputWidget(subkey: "type", width: 180, empty: false, change: (value) { - widget.item.type = value.split(","); - }, initialValue: widget.item.type, readOnly: true,), - ]); - } -} \ No newline at end of file diff --git a/lib/widgets/inputs/shallow_dropdown_input.dart b/lib/widgets/inputs/shallow_dropdown_input.dart index 8b37ef6..4cbcf3c 100644 --- a/lib/widgets/inputs/shallow_dropdown_input.dart +++ b/lib/widgets/inputs/shallow_dropdown_input.dart @@ -94,7 +94,9 @@ class ShallowDropdownInputWidgetState extends State child:InkWell( mouseCursor: SystemMouseCursors.click, onTap: () async { - if (widget.canLoad == null || !widget.canLoad!(widget.current) || widget.load == null || widget.current == null) { + print("load ${widget.current}"); + if (widget.canLoad == null || !widget.canLoad!(widget.current) + || widget.load == null || widget.current == null) { return; } await widget.load!(widget.current!); diff --git a/lib/widgets/inputs/shallow_text_input.dart b/lib/widgets/inputs/shallow_text_input.dart index c5f712d..a5fc360 100644 --- a/lib/widgets/inputs/shallow_text_input.dart +++ b/lib/widgets/inputs/shallow_text_input.dart @@ -54,6 +54,8 @@ class ShallowTextInputWidget extends StatefulWidget { } } class ShallowTextInputWidgetState extends State { + TextEditingController ctrl = TextEditingController(); + bool validForms() { for (var form in widget.forms) { if (!form.validate()) { @@ -65,6 +67,7 @@ class ShallowTextInputWidgetState extends State { @override Widget build(BuildContext context) { var t = widget.type == CollaborativeAreaType.workspace ? "workspace" : (widget.type == CollaborativeAreaType.workflow ? "workflow" : "peer"); + ctrl.text = widget.current ?? ""; return Row( mainAxisAlignment: widget.alignment, children: [ Tooltip( message: widget.hint ?? "current $t", child: Theme( @@ -83,7 +86,7 @@ class ShallowTextInputWidgetState extends State { } }); }, - initialValue: widget.current, + controller: ctrl, style: TextStyle(color: widget.color ?? Colors.black, fontSize: 15), decoration: InputDecoration( filled: true, diff --git a/lib/widgets/inputs/sub_dropdown_input .dart b/lib/widgets/inputs/sub_dropdown_input .dart index 6b7b73b..df46433 100644 --- a/lib/widgets/inputs/sub_dropdown_input .dart +++ b/lib/widgets/inputs/sub_dropdown_input .dart @@ -4,10 +4,11 @@ class SubDropdownInputWidget extends StatefulWidget { String subkey; double width; bool empty; + String? initialValue; List> dropdownMenuEntries = []; void Function(String?)? change = (value) {}; - SubDropdownInputWidget ({ Key? key, required this.dropdownMenuEntries, - required this.subkey, required this.width, required this.empty, required this.change }): super(key: key); + SubDropdownInputWidget ({ super.key, required this.dropdownMenuEntries, this.initialValue, + required this.subkey, required this.width, required this.empty, required this.change }); @override SubDropdownInputWidgetState createState() => SubDropdownInputWidgetState(); } class SubDropdownInputWidgetState extends State { @@ -17,9 +18,11 @@ class SubDropdownInputWidgetState extends State { child: Container( margin: EdgeInsets.only(top: widget.empty ? 0 : 15), width: widget.width, height: 30, child: DropdownButtonFormField( + isExpanded: true, items: widget.dropdownMenuEntries, + value: widget.initialValue, onChanged: widget.change, - style: const TextStyle(fontSize: 12), + style: const TextStyle(fontSize: 12,color: Colors.black, overflow: TextOverflow.ellipsis), decoration: InputDecoration( hintText: "select ${widget.subkey}...", fillColor: Colors.white, diff --git a/lib/widgets/inputs/sub_text_input.dart b/lib/widgets/inputs/sub_text_input.dart index fc325aa..994b2a9 100644 --- a/lib/widgets/inputs/sub_text_input.dart +++ b/lib/widgets/inputs/sub_text_input.dart @@ -10,9 +10,10 @@ class SubTextInputWidget extends StatefulWidget { bool empty; bool noLabel; bool readOnly = false; + bool copyLabel = false; void Function(String) change = (value) {}; SubTextInputWidget ({ Key? key, - required this.subkey, this.readOnly = false, this.noLabel = false, + required this.subkey, this.readOnly = false, this.noLabel = false, this.copyLabel = false, this.initialValue, required this.width, required this.empty, required this.change }): super(key: key); @override SubTextInputWidgetState createState() => SubTextInputWidgetState(); @@ -47,7 +48,7 @@ class SubTextInputWidgetState extends State { ), ))), widget.readOnly ? InkWell( onTap: () { - Clipboard.setData(ClipboardData(text: widget.initialValue!)); + Clipboard.setData(ClipboardData(text: widget.copyLabel ? "\$${widget.subkey}" : widget.initialValue!)); showAlertBanner(context, () {}, const InfoAlertBannerChild(text: "successfully add to clipboard"), // <-- Put any widget here you want! alertBannerLocation: AlertBannerLocation.bottom,); }, child: Container( margin: EdgeInsets.only(left: 5, top: widget.empty ? 0 : 15), diff --git a/lib/widgets/items/infos.dart b/lib/widgets/items/infos.dart new file mode 100644 index 0000000..d9906d9 --- /dev/null +++ b/lib/widgets/items/infos.dart @@ -0,0 +1,24 @@ + +import 'package:flutter/material.dart'; +import 'package:oc_front/models/resources/resources.dart'; + +// ignore: must_be_immutable +class InfosWidget extends StatefulWidget { + AbstractItem item; + InfosWidget ({ super.key, required this.item }); + @override InfosWidgetState createState() => InfosWidgetState(); +} +class InfosWidgetState extends State { + @override Widget build(BuildContext context) { + List children = []; + var obj = widget.item.infos(); + for (var key in obj.keys) { + children.add( + Padding(padding: const EdgeInsets.symmetric(vertical: 20, horizontal: 100), + child: Text("$key : ${obj[key] ?? "no $key"}", + style: const TextStyle(fontSize: 15, fontWeight: FontWeight.w600))), + ); + } + return Wrap( children: children); + } +} \ No newline at end of file diff --git a/lib/widgets/items/item.dart b/lib/widgets/items/item.dart index 49f6bd8..ffbcdf0 100644 --- a/lib/widgets/items/item.dart +++ b/lib/widgets/items/item.dart @@ -1,9 +1,8 @@ - -import 'package:flutter/material.dart'; import 'package:oc_front/main.dart'; -import 'package:oc_front/models/search.dart'; -import 'package:oc_front/widgets/items/items_details/data_item.dart'; +import 'package:flutter/material.dart'; +import 'package:oc_front/models/resources/resources.dart'; +// ignore: must_be_immutable class ItemWidget extends StatefulWidget { AbstractItem item; ItemWidget ({ super.key, required this.item }); @@ -12,15 +11,10 @@ class ItemWidget extends StatefulWidget { class ItemWidgetState extends State { @override Widget build(BuildContext context) { Widget w = Container(); - /* if (isData(widget.item.topic)) { w = DataItemWidget(item: widget.item as DataItem); } - else if (isComputing(widget.item.topic)) { w = DataItemWidget(item: widget.item as DataItem); } - else if (isCompute(widget.item.topic)) { w = DataItemWidget(item: widget.item as DataItem); } - else if (isStorage(widget.item.topic)) { w = DataItemWidget(item: widget.item as DataItem); } */ - - return Container( + return SizedBox( height: getHeight(context) - 300, child: SingleChildScrollView( - child: Column( children: [ + child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ widget.item.description == null ? Container() : Container( width: getMainWidth(context), alignment: Alignment.center, @@ -29,10 +23,8 @@ class ItemWidgetState extends State { child: Text(widget.item.description!, style: TextStyle(fontSize: 15, color: Colors.grey, fontWeight: FontWeight.w500))), Container(padding: const EdgeInsets.all(30), - color: midColor, - width: getMainWidth(context) / 2, - child: w - ) + alignment: Alignment.topLeft, + color: midColor, width: getMainWidth(context) / 2, child: w) ] ) ) diff --git a/lib/widgets/items/item_row.dart b/lib/widgets/items/item_row.dart index 95984cd..dee40f2 100644 --- a/lib/widgets/items/item_row.dart +++ b/lib/widgets/items/item_row.dart @@ -1,9 +1,8 @@ -import 'dart:convert'; -import 'package:flutter/material.dart'; import 'package:oc_front/main.dart'; -import 'package:oc_front/models/search.dart'; -import 'package:oc_front/core/models/workspace_local.dart'; +import 'package:flutter/material.dart'; import 'package:oc_front/core/services/router.dart'; +import 'package:oc_front/models/resources/resources.dart'; +import 'package:oc_front/core/models/workspace_local.dart'; const List> _empty = []; // ignore: must_be_immutable @@ -38,7 +37,7 @@ class ItemRowWidgetState extends State { constraints: BoxConstraints(maxWidth: imageSize, minWidth: imageSize), child: image ?? Image.network('https://get-picto.com/wp-content/uploads/2024/01/logo-instagram-png.webp', height: imageSize, width: imageSize)), - Container( + SizedBox( width: widget.low ? widget.contextWidth - 20 : widget.contextWidth - (imageSize + 20) - endWidth, child: Padding(padding: widget.contextWidth != getMainWidth(context) ? const EdgeInsets.symmetric(horizontal: 10) : const EdgeInsets.symmetric(horizontal: 20), @@ -48,10 +47,7 @@ class ItemRowWidgetState extends State { widget.low ? Container() : Container(padding: const EdgeInsets.symmetric(vertical: 5, horizontal: 10), margin: const EdgeInsets.only(right: 20), decoration: BoxDecoration( - color: isData(widget.item.topic) ? Colors.blue : - isComputing(widget.item.topic) ? Colors.green : - isCompute(widget.item.topic) ? Colors.orange : - isStorage(widget.item.topic) ? redColor : Colors.grey, + color: getColor(widget.item.topic), borderRadius: BorderRadius.circular(4), ), child: Text( getMainWidth(context) < 600 ? "" : widget.item.topic.toString(), @@ -61,13 +57,13 @@ class ItemRowWidgetState extends State { style: TextStyle(fontSize: widget.low ? 14 : 20, overflow: TextOverflow.ellipsis, fontWeight: FontWeight.w600, color: Color(0xFFF67C0B9))), ) ]), - Text( "From ${widget.item.owner ?? "unknown owner"}", + widget.item.owners.isEmpty ? Container() : Text( "From ${widget.item.owners.map( (e) => e.name).join(", ")}", style: const TextStyle(fontSize: 14, color: Colors.grey, overflow: TextOverflow.ellipsis)), Text(widget.item.shortDescription ?? "", style: const TextStyle(fontSize: 12, overflow: TextOverflow.ellipsis)), ],) ) ), - widget.low ? Container() : Container( + widget.low ? Container() : SizedBox( width: endWidth, child: Row( mainAxisAlignment: MainAxisAlignment.center, @@ -91,7 +87,8 @@ class ItemRowWidgetState extends State { borderRadius: BorderRadius.circular(4), ), child: Icon(WorkspaceLocal.hasItem(widget.item) ? Icons.remove_shopping_cart : Icons.add_shopping_cart, - color: Colors.white, size: 20 )) + color: Colors.white, size: 20 ) + ) ), ...(ratio > 1 ? [Padding( padding: const EdgeInsets.only(left: 20), child: InkWell( diff --git a/lib/widgets/items/items_details/data_item.dart b/lib/widgets/items/items_details/data_item.dart deleted file mode 100644 index 762531f..0000000 --- a/lib/widgets/items/items_details/data_item.dart +++ /dev/null @@ -1,24 +0,0 @@ - -import 'package:flutter/material.dart'; -import 'package:oc_front/models/search.dart'; - -class DataItemWidget extends StatefulWidget { - DataItem item; - DataItemWidget ({ super.key, required this.item }); - @override DataItemWidgetState createState() => DataItemWidgetState(); -} -class DataItemWidgetState extends State { - @override Widget build(BuildContext context) { - return Wrap( children: [ - Padding(padding: const EdgeInsets.symmetric(vertical: 20, horizontal: 100), - child: Text("type : ${widget.item.type ?? "unknown type"}", - style: const TextStyle(fontSize: 15, fontWeight: FontWeight.w600))), - Padding(padding: const EdgeInsets.symmetric(horizontal: 100, vertical: 20), - child: Text("protocol : ${widget.item.protocols.isEmpty ? "no protocol founded" : widget.item.protocols.join(",")}", - style: const TextStyle(fontSize: 15, fontWeight: FontWeight.w600))), - Padding(padding: const EdgeInsets.symmetric(horizontal: 100, vertical: 20), - child: Text("ex : ${widget.item.exemple ?? "no example"}", - style: const TextStyle(fontSize: 15, fontWeight: FontWeight.w600))), - ]); - } -} \ No newline at end of file diff --git a/lib/widgets/sheduler_items/schedule.dart b/lib/widgets/sheduler_items/schedule.dart index 4f15d27..5bb311b 100644 --- a/lib/widgets/sheduler_items/schedule.dart +++ b/lib/widgets/sheduler_items/schedule.dart @@ -1,14 +1,14 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_box_transform/flutter_box_transform.dart'; -import 'package:oc_front/core/services/specialized_services/abstract_service.dart'; -import 'package:oc_front/core/services/specialized_services/booking_service.dart'; import 'package:oc_front/main.dart'; -import 'package:oc_front/models/workflow.dart'; +import 'package:flutter/material.dart'; import 'package:oc_front/widgets/logs.dart'; +import 'package:oc_front/models/workflow.dart'; import 'package:flutter_spinkit/flutter_spinkit.dart'; +import 'package:flutter_box_transform/flutter_box_transform.dart'; import 'package:oc_front/widgets/lib/tranformablebox.dart' as fork; -import 'package:oc_front/widgets/sheduler_items/scheduler_calendar.dart'; import 'package:oc_front/widgets/sheduler_items/scheduler_item.dart'; +import 'package:oc_front/widgets/sheduler_items/scheduler_calendar.dart'; +import 'package:oc_front/core/services/specialized_services/abstract_service.dart'; +import 'package:oc_front/core/services/specialized_services/workflow_execution_service.dart'; double menuSize = 300; // ignore: must_be_immutable @@ -19,8 +19,8 @@ class ScheduleWidget extends StatefulWidget { bool loading = true; bool isList = true; bool isBox = true; - AbstractService service; - ScheduleWidget ({ super.key, required this.start, required this.end, required this.service, + AbstractService service = WorkflowExecutionService(); + ScheduleWidget ({ super.key, required this.start, required this.end, this.isBox =true, this.isList = true, this.loading = false}); @override ScheduleWidgetState createState() => ScheduleWidgetState(); } @@ -43,19 +43,16 @@ class ScheduleWidgetState extends State { "${widget.start.year}-${widget.start.month > 9 ? widget.start.month : "0${widget.start.month}"}-${widget.start.day > 9 ? widget.start.day : "0${widget.start.day}"}", "${widget.end.year}-${widget.end.month > 9 ? widget.end.month : "0${widget.end.month}"}-${widget.end.day > 9 ? widget.end.day : "0${widget.end.day}"}"], {}), builder: (ctx, as) { - Future.delayed(const Duration(minutes: 1), () { - setState(() {}); - }); Map> data = {}; if (as.hasData && as.data!.data != null) { for (var element in as.data!.data!.executions) { - if (element.executionData == null) { continue; } - DateTime dateTime = DateTime.parse(element.executionData!); + if (element.startDate == null) { continue; } + DateTime dateTime = DateTime.parse(element.startDate!); DateTime date = DateTime(dateTime.year, dateTime.month, dateTime.day); var str = "${date.toIso8601String()}Z"; if (data[str] == null) { data[str] = []; } data[str]!.add(element); - data[str]!.sort((a, b) => DateTime.parse(a.executionData!).compareTo(DateTime.parse(b.executionData!))); + data[str]!.sort((a, b) => DateTime.parse(a.startDate!).compareTo(DateTime.parse(b.startDate!))); } } bool isInfo = getMainWidth(context) <= 600 && selected != null && widget.isBox; @@ -63,12 +60,12 @@ class ScheduleWidgetState extends State { List children = []; if (selected != null) { for (var wf in data[selected!] ?? ([])) { - DateTime d2 = DateTime.parse(wf.executionData!).toLocal(); + DateTime d2 = DateTime.parse(wf.startDate!).toLocal(); children.add( InkWell( - onTap: () => setState(() { selectedReal = wf.executionData; }), + onTap: () => setState(() { selectedReal = wf.startDate; }), child: Container( margin: const EdgeInsets.all(10), decoration: BoxDecoration( - border: Border.all(color: selectedReal != null && selectedReal == wf.executionData ? lightColor : Colors.transparent, width: 2), + border: Border.all(color: selectedReal != null && selectedReal == wf.startDate ? lightColor : Colors.transparent, width: 2), borderRadius: BorderRadius.circular(4), color: Colors.white ), child: Container( @@ -96,13 +93,12 @@ class ScheduleWidgetState extends State { )) )); } - } String? selectedID; WorkflowExecution? sel; if (selectedReal != null) { try { - sel = data[selected!]!.firstWhere((element) => element.executionData == selectedReal); + sel = data[selected!]!.firstWhere((element) => element.startDate == selectedReal); selectedID = sel.id; } catch(e) { /* */ } } diff --git a/lib/widgets/sheduler_items/scheduler_calendar.dart b/lib/widgets/sheduler_items/scheduler_calendar.dart index 79865c3..b4964cc 100644 --- a/lib/widgets/sheduler_items/scheduler_calendar.dart +++ b/lib/widgets/sheduler_items/scheduler_calendar.dart @@ -70,7 +70,7 @@ class SchedulerCalendarWidgetState extends State { } children.add(InkWell( onTap: () => widget.parent!.setState(() { selected = day.toIso8601String(); - selectedReal = ev.executionData; + selectedReal = ev.startDate; if (selectedReal == null) { widget.parent!.widget.isDayPlanner = true; } @@ -158,9 +158,9 @@ class SchedulerCalendarWidgetState extends State { shouldFillViewport: true, eventLoader: (day) { return widget.data[day.toIso8601String()] != null ? widget.data[day.toIso8601String()]!.map((e) { - DateTime dateTime = DateTime.parse(e.executionData!); + DateTime dateTime = DateTime.parse(e.startDate!); return Event("[${dateTime.hour > 9 ? dateTime.hour : "0${dateTime.hour}"}:${dateTime.minute > 9 ? dateTime.minute : "0${dateTime.minute}"}:${dateTime.second > 9 ? dateTime.second : "0${dateTime.second}"}] ${e.name}", - colors[(e.status ?? 1) - 1], e.executionData ); + colors[(e.status ?? 1) - 1], e.startDate ); }).toList() : []; }, )); @@ -169,10 +169,10 @@ class SchedulerCalendarWidgetState extends State { class Event { final String title; - String? executionData; + String? startDate; Color color; - Event(this.title, this.color, this.executionData); + Event(this.title, this.color, this.startDate); @override String toString() => title; diff --git a/lib/widgets/sheduler_items/scheduler_item.dart b/lib/widgets/sheduler_items/scheduler_item.dart index 4052515..2ec92d0 100644 --- a/lib/widgets/sheduler_items/scheduler_item.dart +++ b/lib/widgets/sheduler_items/scheduler_item.dart @@ -26,23 +26,23 @@ class SchedulerItemWidgetState extends State { for (var element in widget.data.keys.toList()..sort((a, b) => DateTime.parse(a).compareTo(DateTime.parse(b)))) { List widgets = []; for (var ev in widget.data[element] ?? ([] as List)) { - widget.keys[ev.executionData!] = GlobalKey(); - var d2 = DateTime.parse(ev.executionData!).toLocal(); + widget.keys[ev.startDate!] = GlobalKey(); + var d2 = DateTime.parse(ev.startDate!).toLocal(); DateTime? d3; try { d3 = DateTime.parse(ev.endDate!).toLocal(); } catch (e) { /* */ } widgets.add(InkWell( onTap: () => widget.parent?.setState(() { - selected = selected != element || ev.executionData != selectedReal ? element : null; - selectedReal = selected == null ? null : ev.executionData; + selected = selected != element || ev.startDate != selectedReal ? element : null; + selectedReal = selected == null ? null : ev.startDate; if (selectedReal == null) { widget.parent!.widget.isDayPlanner = true; } }), - child: Container( key: widget.keys[ev.executionData!], + child: Container( key: widget.keys[ev.startDate!], padding: const EdgeInsets.symmetric(vertical: 20, horizontal: 50), decoration: BoxDecoration( - border: selectedReal == ev.executionData ? + border: selectedReal == ev.startDate ? Border.all(color: lightColor, width: 2) : Border(top: BorderSide(color: midColor)), ), child: Row(children: [ @@ -59,7 +59,7 @@ class SchedulerItemWidgetState extends State { SizedBox( width: (widget.width - 330) / 2, child: Padding( padding: const EdgeInsets.only(left: 20), - child: Text(ev.name?.toUpperCase() ?? "", overflow: TextOverflow.ellipsis, + child: Text("${ev.name?.toUpperCase().split("EXECUTION")[0].replaceAll("_", "") ?? ""} EXECUTION", overflow: TextOverflow.ellipsis, style: const TextStyle(color: Colors.black, fontWeight: FontWeight.w500)), )), SizedBox( width: (widget.width - 340) / 2, diff --git a/library/flutter_flow_chart/.dart_tool/version b/library/flutter_flow_chart/.dart_tool/version index ff6984e..ffba2c8 100644 --- a/library/flutter_flow_chart/.dart_tool/version +++ b/library/flutter_flow_chart/.dart_tool/version @@ -1 +1 @@ -3.19.6 \ No newline at end of file +3.24.3 \ No newline at end of file diff --git a/library/flutter_flow_chart/lib/flutter_flow_chart.dart b/library/flutter_flow_chart/lib/flutter_flow_chart.dart index 181fe31..e9fa498 100755 --- a/library/flutter_flow_chart/lib/flutter_flow_chart.dart +++ b/library/flutter_flow_chart/lib/flutter_flow_chart.dart @@ -5,5 +5,5 @@ export 'src/dashboard.dart'; export 'src/elements/connection_params.dart'; export 'src/elements/flow_element.dart'; export 'src/flow_chart.dart'; -export 'src/ui/draw_arrow.dart' show ArrowParams, ArrowStyle, ArrowDirection; +export 'src/ui/draw_arrow.dart' show ArrowParams, ArrowStyle, ArrowDirection, ArrowPainter; export 'src/ui/grid_background.dart' show GridBackgroundParams; diff --git a/library/flutter_flow_chart/lib/src/dashboard.dart b/library/flutter_flow_chart/lib/src/dashboard.dart index 5279fb4..5cdc3b4 100755 --- a/library/flutter_flow_chart/lib/src/dashboard.dart +++ b/library/flutter_flow_chart/lib/src/dashboard.dart @@ -28,13 +28,11 @@ class Dashboard extends ChangeNotifier { GlobalKey chartMenuKey = GlobalKey(); GlobalKey chartKey = GlobalKey(); GlobalKey flutterChartKey = GlobalKey(); - + bool inDialog = false; List> tempHistory = []; List> history = []; - Map scheduler = {}; Map info = {}; - bool scheduleActive = false; String? id; String name = ""; bool isMenu = true; @@ -47,8 +45,9 @@ class Dashboard extends ChangeNotifier { double defaultDashWidth = 0; double defaultBackWidth = 10; double defaultForwardWidth = 10; - Future Function(String? id)? save; + Future Function(String? id, BuildContext? context)? save; List Function(FlowData? obj, String id)? infoItemWidget; + Widget Function(ArrowPainter item)? infoLinkWidget; List Function()? infoWidget; FlowData? Function(Map json)? transformToData; bool addChange = false; @@ -74,7 +73,6 @@ class Dashboard extends ChangeNotifier { this.save, this.dashColor = Colors.grey, this.midDashColor = Colors.blueGrey, - this.scheduler = const {}, Offset? handlerFeedbackOffset, this.isMenu = true, this.defaultDashSpace = 0, @@ -93,7 +91,7 @@ class Dashboard extends ChangeNotifier { // This is a workaround to set the handlerFeedbackOffset // to improve the user experience on devices with touch screens // This will prevent the handler being covered by user's finger - if (loadedGraph != null) { deserialize(loadedGraph!); } + if (loadedGraph != null) { deserialize(loadedGraph!, false); } if (handlerFeedbackOffset != null) { this.handlerFeedbackOffset = handlerFeedbackOffset; } else { @@ -110,18 +108,15 @@ class Dashboard extends ChangeNotifier { tempHistory = []; history = []; } - Future saveDash(String? id) async { - shouldSave = true; + Future saveDash(String? id, BuildContext? context) async { for (var element in saveRules) { - if (element(this)) { - shouldSave = true; - } else { + if (!element(this)) { shouldSave = false; break; } } if (save != null && shouldSave) { - save!(id); + save!(id, context); } } Future Function(String cat)? load; @@ -131,14 +126,12 @@ class Dashboard extends ChangeNotifier { final d = Dashboard( name: map['name'] as String, isMenu: map['isMenu'] as bool, - scheduler: map['schedule'] as Map? ?? {}, defaultDashSpace: map['defaultDashSpace'] as double? ?? 0, defaultDashWidth: map['defaultDashWidth'] as double? ?? 0, defaultArrowDirection: ArrowDirection.values[ map['defaultArrowDirection'] as int? ?? 0], defaultArrowStyle: ArrowStyle.values[map['arrowStyle'] as int? ?? 0], ); - d..scheduleActive = map['schedule_active'] as bool? ?? false; d..arrows = List.from( (map['arrows'] as List).map( (x) => ArrowPainter.fromMap(x as Map), @@ -170,15 +163,14 @@ class Dashboard extends ChangeNotifier { } void copyFromMap(Map map) { - scheduleActive = map['schedule_active'] as bool? ?? false; - scheduler = map['schedule'] as Map? ?? {}; + debugPrintStack(stackTrace: StackTrace.current, label: 'my_label', maxFrames: 5); defaultArrowStyle = ArrowStyle.values[map['arrowStyle'] as int? ?? 0]; defaultDashSpace = map['defaultDashSpace'] as double? ?? 0; defaultDashWidth = map['defaultDashWidth'] as double? ?? 0; defaultArrowDirection = ArrowDirection.values[ map['defaultArrowDirection'] as int? ?? 0]; arrows = List.from( - (map['arrows'] as List).map( + (map['arrows'] as List).map( (x) => ArrowPainter.fromMap(x as Map), ), ); @@ -257,26 +249,25 @@ class Dashboard extends ChangeNotifier { d["id"]=id; d["name"]=name; d["graph"]=graph; - d["schedule"]=scheduler; - d["schedule_active"]=scheduleActive; return d; } - void deserialize(Map graph) { + void deserialize(Map graph, bool noHistory) { elements = []; arrows = []; info["shared"] = graph["shared"] ?? []; - scheduler = graph['schedule'] ?? {}; - scheduleActive = graph['schedule_active'] ?? false; setZoomFactor(graph["graph"]?["zoom"] ?? 1.0); for(var el in graph['graph']?['elements'] ?? []) { List nexts = []; var flow = FlowElement.deserialize(this, el); for(var ar in graph['graph']['arrows']) { + if (ar['from']['id'] != flow.id) { continue; } nexts.add(ConnectionParams( srcElementId: ar['from']['id'], destElementId: ar['to']['id'], + infos: ar['infos'], + env: ar['env'], arrowParams: ArrowParams.fromMap(ar["params"]), pivots: [ Pivot(Offset(ar['from']['x'], (ar['from']['y']))), @@ -291,16 +282,35 @@ class Dashboard extends ChangeNotifier { arr.add(build); } } - try { - FlowData data = arr.firstWhere((element) => element.getID() == flow.element?.getID()); + if (flow.element != null) { flow.kind = ElementKind.widget; - flow.widget = chartKey.currentState?.widget.flowChart.widget.itemWidget(data); - } catch (e) { print(e); } + flow.widget = chartKey.currentState?.widget.flowChart.widget.itemWidget(flow.element!); + } elements.add(flow); } selectedMenuKey.currentState?.setState(() { }); chartMenuKey.currentState?.setState(() { }); - addToHistory(); + if (!noHistory) { + addToHistory(); + } + } + + + void applyInfos(Map> elInfos, Map graph) { + for(var id in elInfos.keys) { + try { + var element = elements.firstWhere((element) => element.id == id); + element.element?.addEnv(elInfos[id] ?? []); + } catch (e) { print("THERE ??? ${id} ${e}"); } + } + for(var ar in graph['graph']['arrows']) { + var arr = arrows.where((a) => a.fromID == ar['from']['id'] && a.toID == ar['to']['id']).toList(); + for (var a in arr) { + a.infos = ar['infos']; + a.env = ar['env']; + } + } + selectedLeftMenuKey.currentState?.setState(() { }); } /// add listener called when a new connection is created @@ -325,30 +335,31 @@ class Dashboard extends ChangeNotifier { handlerFeedbackOffset = offset; } - List GetArrowByElementID(String id, bool isinput) { - return arrows.where((element) => (isinput && element.toID.contains(id)) || (!isinput && element.fromID.contains(id))).toList(); + List getArrowByElementID(String id, bool isinput) { + return arrows.where((element) => + (isinput && element.toID.contains(id)) || (!isinput && element.fromID.contains(id))).toList(); } - void addArrows(ArrowPainter f) { + void addArrows(ArrowPainter f, BuildContext? context) { arrows.add(f); for (var f in arrowStyleRules) { arrows = f(this); } addChange = true; - saveDash(id); + saveDash(id, context); } - void removeArrows(bool Function(ArrowPainter) f) { + void removeArrows(bool Function(ArrowPainter) f, BuildContext? context) { arrows.removeWhere((element) => f(element)); for (var f in arrowStyleRules) { arrows = f(this); } - saveDash(id); + saveDash(id, context); } - void removeElements(bool Function(FlowElement) f) { + void removeElements(bool Function(FlowElement) f, BuildContext? context) { elements.removeWhere((element) => f(element)); - saveDash(id); + saveDash(id, context); } void clear() { @@ -356,9 +367,7 @@ class Dashboard extends ChangeNotifier { arrows.clear(); tempHistory = []; history = []; - scheduler = {}; info = {}; - scheduleActive = false; notifyListeners(); } bool noHistory = false; @@ -375,14 +384,13 @@ class Dashboard extends ChangeNotifier { Future.delayed(Duration(seconds: 1), () { chartMenuKey.currentState?.setState(() { }); }); - ; } bool isBack = false; void back() { if (canBack()) { noHistory = true; tempHistory.removeLast(); - if (tempHistory.length > 0) { + if (tempHistory.isNotEmpty) { copyFromMap(tempHistory.last); } chartKey.currentState?.setState(() { }); @@ -413,28 +421,29 @@ class Dashboard extends ChangeNotifier { FlowElement element, bool resizable, { bool notify = true, + BuildContext? context }) { element.isResizing = resizable; - saveDash(id); + saveDash(id, context); if (notify) notifyListeners(); } FlowElement? getElement(String id, {bool notify = true}) { try { return elements.firstWhere((element) { - return element.id == id; + return id.contains(element.id); }); } catch (e) { return null; } } /// add a [FlowElement] to the dashboard - void addElement(FlowElement element, {bool notify = true}) { + void addElement(FlowElement element, BuildContext? context, {bool notify = true}) { if (element.id.isEmpty) { element.id = const Uuid().v4(); } element.setScale(1, gridBackgroundParams.scale); elements.add(element); addChange = true; - saveDash(id); + saveDash(id, context); if (notify) { notifyListeners(); } @@ -554,16 +563,16 @@ class Dashboard extends ChangeNotifier { } /// remove all elements - void removeAllElements({bool notify = true}) { + void removeAllElements(BuildContext? context, {bool notify = true}) { elements.clear(); if (notify) notifyListeners(); - saveDash(id); + saveDash(id, context); } /// remove the [handler] connection of [element] void removeElementConnection( FlowElement element, - Handler handler, { + Handler handler, BuildContext? context, { bool notify = true, }) { Alignment alignment; @@ -600,7 +609,7 @@ class Dashboard extends ChangeNotifier { } } if (notify) notifyListeners(); - saveDash(id); + saveDash(id, context); } /// dissect an element connection @@ -690,14 +699,14 @@ class Dashboard extends ChangeNotifier { } /// remove all the connection from the [element] - void removeElementConnections(FlowElement element, {bool notify = true}) { + void removeElementConnections(FlowElement element, BuildContext? context, {bool notify = true}) { element.next.clear(); if (notify) notifyListeners(); - saveDash(id); + saveDash(id, context); } /// remove all the elements with [id] from the dashboard - void removeElementById(String id, {bool notify = true}) { + void removeElementById(String id, BuildContext? context, {bool notify = true}) { // remove the element var elementId = ''; elements.removeWhere((element) { @@ -714,12 +723,12 @@ class Dashboard extends ChangeNotifier { }); } if (notify) notifyListeners(); - saveDash(id); + saveDash(id, context); } /// remove element /// return true if it has been removed - bool removeElement(FlowElement element, {bool notify = true}) { + bool removeElement(FlowElement element, BuildContext? context, {bool notify = true}) { // remove the element var found = false; final elementId = element.id; @@ -735,7 +744,7 @@ class Dashboard extends ChangeNotifier { ); } if (notify) notifyListeners(); - saveDash(id); + saveDash(id, context); return found; } diff --git a/library/flutter_flow_chart/lib/src/elements/connection_params.dart b/library/flutter_flow_chart/lib/src/elements/connection_params.dart index 976c1c5..6808bc2 100755 --- a/library/flutter_flow_chart/lib/src/elements/connection_params.dart +++ b/library/flutter_flow_chart/lib/src/elements/connection_params.dart @@ -11,14 +11,19 @@ class ConnectionParams { required this.srcElementId, required this.destElementId, required this.arrowParams, + this.env = const [], + this.infos = const [], List? pivots, }) : pivots = pivots ?? []; - + List env = []; + List infos = []; /// factory ConnectionParams.fromMap(Map map) { return ConnectionParams( srcElementId: map['srcElementId'] as String, destElementId: map['destElementId'] as String, + infos: map['infos'] as List? ?? [], + env: map['env'] as List? ?? [], arrowParams: ArrowParams.fromMap(map['arrowParams'] as Map), pivots: (map['pivots'] as List?) ?.map( @@ -37,7 +42,6 @@ class ConnectionParams { final String destElementId; final String srcElementId; - /// Arrow parameters. final ArrowParams arrowParams; diff --git a/library/flutter_flow_chart/lib/src/elements/flow_element.dart b/library/flutter_flow_chart/lib/src/elements/flow_element.dart index d8e5d28..642e134 100755 --- a/library/flutter_flow_chart/lib/src/elements/flow_element.dart +++ b/library/flutter_flow_chart/lib/src/elements/flow_element.dart @@ -374,6 +374,7 @@ class FlowElement extends ChangeNotifier { graphElement['width'] = size.width; graphElement['height'] = size.height; graphElement['element']=element?.serialize(); + graphElement['next'] = next.map((x) => x.toMap()).toList(); return graphElement; } @@ -385,6 +386,13 @@ class FlowElement extends ChangeNotifier { position: Offset(double.parse("${map['x']}"), double.parse("${map['y']}")), size: Size(double.parse("${map['width']}"), double.parse("${map['height']}")), element: (dashboard.transformToData != null ? dashboard.transformToData!(map['element'] ?? {}) : null) as T?, + /*next: map['next'] != null && (map['next'] as List).isNotEmpty + ? List.from( + (map['next'] as List).map( + (x) => ConnectionParams.fromMap(x as Map), + ), + ) + : []*/ ); } } diff --git a/library/flutter_flow_chart/lib/src/flow_chart.dart b/library/flutter_flow_chart/lib/src/flow_chart.dart index 6931776..c3b2ca0 100755 --- a/library/flutter_flow_chart/lib/src/flow_chart.dart +++ b/library/flutter_flow_chart/lib/src/flow_chart.dart @@ -1,29 +1,27 @@ // ignore: directives_ordering -import 'dart:developer'; - +import 'package:uuid/uuid.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter/foundation.dart'; -import 'package:flutter_flow_chart/flutter_flow_chart.dart'; -import 'package:flutter_flow_chart/src/flow_chart_left_menu.dart'; -import 'package:flutter_flow_chart/src/flow_chart_menu.dart'; -import 'package:flutter_flow_chart/src/flow_chart_selected_menu.dart'; import 'package:flutter_flow_chart/src/ui/draw_arrow.dart'; +import 'package:flutter_flow_chart/flutter_flow_chart.dart'; +import 'package:flutter_flow_chart/src/flow_chart_menu.dart'; import 'package:flutter_flow_chart/src/ui/element_widget.dart'; import 'package:flutter_flow_chart/src/ui/grid_background.dart'; import 'package:flutter_flow_chart/src/ui/segment_handler.dart'; -import 'package:uuid/uuid.dart'; +import 'package:flutter_flow_chart/src/flow_chart_left_menu.dart'; +import 'package:flutter_flow_chart/src/flow_chart_selected_menu.dart'; + /// Main flow chart Widget. /// It displays the background grid, all the elements and connection lines abstract class FlowData { String getID(); String getName(); + String getType(); double? getWidth(); double? getHeight(); - - Map setVariable(List keys, dynamic value, Map map); - dynamic getVariable(List keys, Map map); + void addEnv(List infos); Map serialize(); FlowData deserialize(Map data); } @@ -321,17 +319,21 @@ class FlowChartState extends State { Future.delayed(Duration(milliseconds: 100), () => widget.dashboard.load!(widget.dashboard.id!) ); } else { Future.delayed(Duration(milliseconds: 100), () { - showDialog( - barrierDismissible: false, - context: context, builder: (context) { - return AlertDialog( - titlePadding: EdgeInsets.zero, - insetPadding: EdgeInsets.zero, - backgroundColor: Colors.white, - shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(0)), - title: widget.onDashboardAlertOpened!(context, widget.dashboard)); - - }); }); + if (!widget.dashboard.inDialog) { + widget.dashboard.inDialog = true; + showDialog( + barrierDismissible: false, + context: context, builder: (context) { + return AlertDialog( + titlePadding: EdgeInsets.zero, + insetPadding: EdgeInsets.zero, + backgroundColor: Colors.white, + shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(0)), + title: widget.onDashboardAlertOpened!(context, widget.dashboard)); + + }); + } + }); } } else { widget.dashboard.isOpened = true; @@ -357,14 +359,14 @@ class FlowChartState extends State { onKeyEvent: (event) { bool change = false; if (event.logicalKey == LogicalKeyboardKey.controlLeft) { - isCtrl = event is KeyDownEvent || event is KeyRepeatEvent; + isCtrl = event is KeyDownEvent || event is KeyRepeatEvent; } - if (event is KeyDownEvent || event.logicalKey == LogicalKeyboardKey.keyZ && isCtrl) { + /*if ((event is KeyDownEvent || event.logicalKey == LogicalKeyboardKey.keyZ) && isCtrl) { widget.dashboard.back(); } - if (event is KeyDownEvent || event.logicalKey == LogicalKeyboardKey.keyY && isCtrl) { + if ((event is KeyDownEvent || event.logicalKey == LogicalKeyboardKey.keyY) && isCtrl) { widget.dashboard.forward(); - } + }*/ if (event is KeyDownEvent && event.logicalKey == LogicalKeyboardKey.add) { change = true; for (var el in widget.dashboard.elementSelected) { @@ -379,18 +381,18 @@ class FlowChartState extends State { kind: el.kind, handlers: el.handlers, handlerSize: el.handlerSize, - )); + ), context); } } if (event is KeyDownEvent && event.logicalKey == LogicalKeyboardKey.delete) { change = true; - widget.dashboard.removeElements( (el) => el.isSelected ); + widget.dashboard.removeElements( (el) => el.isSelected, context ); for (var arrow in widget.dashboard.arrowsSelected) { for (var el in widget.dashboard.elements.where((element) => element.id == arrow.fromID.split("_")[0])) { el.next.removeAt(int.parse(arrow.fromID.split("_")[1])); } } - widget.dashboard.removeArrows( (el) => el.isSelected ); + widget.dashboard.removeArrows( (el) => el.isSelected, context ); } if (change) { DrawingArrow.instance.notifyListeners(); @@ -459,7 +461,7 @@ class FlowChartState extends State { Handler.rightCenter, ], ); - widget.dashboard.addElement(el); + widget.dashboard.addElement(el, context); }, ))] ), @@ -495,8 +497,8 @@ class FlowChartState extends State { onDragEnd: (d) => node.requestFocus(), childWhenDragging: Opacity(opacity: .5, child: Padding( padding: const EdgeInsets.all(10), - child: Container( child: widget.itemWidget(e), alignment: Alignment.center, - constraints: BoxConstraints(maxHeight: realSize - 10, maxWidth: realSize - 10), ))), + child: Container( alignment: Alignment.center, + constraints: BoxConstraints(maxHeight: realSize - 10, maxWidth: realSize - 10), child: widget.itemWidget(e), ))), feedback: Container( alignment: Alignment.center, constraints: BoxConstraints(maxHeight: realSize, maxWidth: realSize), child: widget.itemWidget(e) ), child: InkWell( mouseCursor: SystemMouseCursors.grab, child: Padding( padding: const EdgeInsets.all(10), @@ -548,6 +550,8 @@ class _DrawingArrowWidgetState extends State { painter: ArrowPainter( fromID: DrawingArrow.instance.fromID, toID: "", + env: DrawingArrow.instance.env, + infos: DrawingArrow.instance.infos, params: DrawingArrow.instance.params, from: DrawingArrow.instance.from, to: DrawingArrow.instance.to, @@ -878,9 +882,7 @@ class ChartWidgetState extends State { ), // Draw arrows for (int i = 0; i < widget.dashboard.elements.length; i++) - for (int n = 0; n < widget.dashboard.elements[i].next.length; n++) - DrawArrow( flow: this, key: UniqueKey(), @@ -889,6 +891,8 @@ class ChartWidgetState extends State { destElement: widget.dashboard.elements[widget.dashboard.findElementIndexById( widget.dashboard.elements[i].next[n].destElementId, )], + env: widget.dashboard.elements[i].next[n].env, + infos: widget.dashboard.elements[i].next[n].infos, arrowParams: widget.dashboard.elements[i].next[n].arrowParams, pivots: widget.dashboard.elements[i].next[n].pivots, ), diff --git a/library/flutter_flow_chart/lib/src/flow_chart_menu.dart b/library/flutter_flow_chart/lib/src/flow_chart_menu.dart index 2563f86..fa8418c 100644 --- a/library/flutter_flow_chart/lib/src/flow_chart_menu.dart +++ b/library/flutter_flow_chart/lib/src/flow_chart_menu.dart @@ -37,17 +37,20 @@ class FlowChartMenuState extends State { onTap: () { widget.dashboard.name = "graph_${DateTime.now().toString().replaceAll(" ", "_").substring(0, DateTime.now().toString().length - 7)}"; widget.dashboard.isOpened = true; - showDialog( - barrierDismissible: false, - context: context, builder: (context) { - return AlertDialog( - titlePadding: EdgeInsets.zero, - insetPadding: EdgeInsets.zero, - backgroundColor: Colors.white, - shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(0)), - title: widget.chart.widget.flowChart.widget.onDashboardAlertOpened!( - context, widget.dashboard)); - }); + if (!widget.dashboard.inDialog) { + widget.dashboard.inDialog = true; + showDialog( + barrierDismissible: false, + context: context, builder: (context) { + return AlertDialog( + titlePadding: EdgeInsets.zero, + insetPadding: EdgeInsets.zero, + backgroundColor: Colors.white, + shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(0)), + title: widget.chart.widget.flowChart.widget.onDashboardAlertOpened!( + context, widget.dashboard)); + }); + } }, child: Icon(Icons.folder, color: Colors.white))))), ])), @@ -57,8 +60,6 @@ class FlowChartMenuState extends State { ), child: Padding( padding: EdgeInsets.symmetric(horizontal: 10), child: PopupMenuButton( - child: - Row( children: [ Icon(Icons.fullscreen, color: Colors.white), Icon(Icons.arrow_drop_down, size: 10, color: Colors.white) ]), initialValue: null, onSelected: (DisplayEnum value) { if (value == DisplayEnum.MENU) { widget.dashboard.isMenu = !widget.dashboard.isMenu; } @@ -83,7 +84,9 @@ class FlowChartMenuState extends State { child: Text(widget.dashboard.isInfo ? 'hide info' : 'show info', textAlign: TextAlign.center,)) ]), ), - ] + ], + child: + Row( children: [ Icon(Icons.fullscreen, color: Colors.white), Icon(Icons.arrow_drop_down, size: 10, color: Colors.white) ]) ),) ) ), diff --git a/library/flutter_flow_chart/lib/src/flow_chart_selected_menu.dart b/library/flutter_flow_chart/lib/src/flow_chart_selected_menu.dart index c77edd0..ea57a60 100644 --- a/library/flutter_flow_chart/lib/src/flow_chart_selected_menu.dart +++ b/library/flutter_flow_chart/lib/src/flow_chart_selected_menu.dart @@ -36,10 +36,10 @@ class FlowChartSelectedMenuState extends State { widget.dashboard.elements[element.elementIndex!].next.removeAt(element.connIndex!); } return element.isSelected; - }); - widget.dashboard.removeElements((element) => element.isSelected); + }, context); + widget.dashboard.removeElements((element) => element.isSelected, context); Future.delayed(Duration(milliseconds: 100), () { - widget.dashboard.chartKey.currentState?.setState(() { }); + widget.dashboard.flutterChartKey.currentState?.setState(() { }); }); }, child: Container( margin: EdgeInsets.all(10), decoration: BoxDecoration(borderRadius: BorderRadius.circular(5), border: Border.all(color: Colors.black, width: 1)), @@ -51,7 +51,7 @@ class FlowChartSelectedMenuState extends State { child: InkWell( mouseCursor: SystemMouseCursors.click, onTap: () { for (var sel in widget.dashboard.elementSelected) { - widget.dashboard.addElement(FlowElement.fromMap(widget.dashboard, sel.toMap())); + widget.dashboard.addElement(FlowElement.fromMap(widget.dashboard, sel.toMap()), context); widget.dashboard.elements.last.position += Offset(50, 50); } Future.delayed(Duration(milliseconds: 100), () { @@ -67,6 +67,42 @@ class FlowChartSelectedMenuState extends State { ) : Container() ]) )); + } else if (widget.isDashboardInfo && widget.dashboard.arrowsSelected.length == 1) { + w = Container( + width: 200, + height: widget.height, + color: widget.dashboard.midDashColor, + child: SingleChildScrollView( child: Column( children: [ + widget.dashboard.infoItemWidget != null ? + widget.dashboard.infoLinkWidget!(widget.dashboard.arrowsSelected.first) : Container(), + widget.dashboard.arrowsSelected.isNotEmpty || widget.dashboard.elementSelected.isNotEmpty ? Container( + width: 200, + margin: EdgeInsets.only(top: 15), + decoration: BoxDecoration(border: Border( + top: BorderSide(color: Colors.grey, width: 1))), + child: Column(crossAxisAlignment: CrossAxisAlignment.center, children: [ + Tooltip( message: "remove", + child: InkWell( mouseCursor: SystemMouseCursors.click, + onTap: () { + widget.dashboard.removeArrows((element) { + if (element.isSelected && element.elementIndex != null && element.connIndex != null) { + widget.dashboard.elements[element.elementIndex!].next.removeAt(element.connIndex!); + } + return element.isSelected; + }, context); + Future.delayed(Duration(milliseconds: 100), () { + widget.dashboard.flutterChartKey.currentState?.setState(() { }); + }); + }, child: Container( margin: EdgeInsets.all(10), + decoration: BoxDecoration(borderRadius: BorderRadius.circular(5), border: Border.all(color: Colors.black, width: 1)), + width: 200, height: 30, + child: Icon(Icons.delete_outline, color: Colors.black), + )) + ), + ]) + ) : Container() + ]) + )); } else if (widget.isDashboardInfo && widget.dashboard.infoWidget != null) { w = Container( width: 200, @@ -520,10 +556,10 @@ class FlowChartSelectedMenuState extends State { widget.dashboard.elements[element.elementIndex!].next.removeAt(element.connIndex!); } return element.isSelected; - }); - widget.dashboard.removeElements((element) => element.isSelected); + }, context); + widget.dashboard.removeElements((element) => element.isSelected, context); Future.delayed(Duration(milliseconds: 100), () { - widget.dashboard.chartKey.currentState?.setState(() { }); + widget.dashboard.flutterChartKey.currentState?.setState(() { }); }); }, child: Container( margin: EdgeInsets.all(10), decoration: BoxDecoration(borderRadius: BorderRadius.circular(5), border: Border.all(color: Colors.black, width: 1)), @@ -535,7 +571,7 @@ class FlowChartSelectedMenuState extends State { child: InkWell( mouseCursor: SystemMouseCursors.click, onTap: () { for (var sel in widget.dashboard.elementSelected) { - widget.dashboard.addElement(FlowElement.fromMap(widget.dashboard, sel.toMap())); + widget.dashboard.addElement(FlowElement.fromMap(widget.dashboard, sel.toMap()), context); widget.dashboard.elements.last.position += Offset(50, 50); } Future.delayed(Duration(milliseconds: 100), () { diff --git a/library/flutter_flow_chart/lib/src/ui/draw_arrow.dart b/library/flutter_flow_chart/lib/src/ui/draw_arrow.dart index 22aea97..f7d73c5 100755 --- a/library/flutter_flow_chart/lib/src/ui/draw_arrow.dart +++ b/library/flutter_flow_chart/lib/src/ui/draw_arrow.dart @@ -211,6 +211,8 @@ class DrawingArrow extends ChangeNotifier { /// Arrow parameters. ArrowParams params = ArrowParams(); + List env = []; + List infos = []; String fromID = ""; String toID = ""; @@ -264,13 +266,16 @@ class DrawArrow extends StatefulWidget { required this.srcElement, required this.destElement, required List pivots, + this.infos = const [], + this.env = const [], super.key, ArrowParams? arrowParams, }) : arrowParams = arrowParams ?? ArrowParams(), pivots = PivotsNotifier(pivots); final int index; - + List env = []; + List infos = []; /// final ArrowParams arrowParams; @@ -340,6 +345,8 @@ class DrawArrowState extends State { builder: (context) { var painter = ArrowPainter( connIndex: widget.index, + infos: widget.infos, + env: widget.env, elementIndex: widget.flow.widget.dashboard.elements.indexOf(widget.srcElement), fromID: "${widget.srcElement.id}_${widget.index}", toID: "${widget.destElement.id}_${widget.index}", @@ -351,8 +358,8 @@ class DrawArrowState extends State { ); if ( widget.flow.widget.dashboard.arrows.where( (element) => element.fromID == "${widget.srcElement.id}_${widget.index}").isEmpty) { - widget.flow.widget.dashboard.addArrows(painter); - widget.flow.widget.dashboard.saveDash(widget.flow.widget.dashboard.id); + widget.flow.widget.dashboard.addArrows(painter, context); + widget.flow.widget.dashboard.saveDash(widget.flow.widget.dashboard.id, context); } else { var i = widget.flow.widget.dashboard.arrows.indexWhere( (element) => element.fromID == "${widget.srcElement.id}_${widget.index}"); @@ -390,7 +397,7 @@ class GraphParamsWidgetState extends State { child: Row(children: [ IconButton(onPressed: () { widget.comp.setState(() { - widget.comp.widget.dashboard.removeArrows((el) => el.fromID == "${widget.element.id}${widget.index}"); + widget.comp.widget.dashboard.removeArrows((el) => el.fromID == "${widget.element.id}${widget.index}", context); widget.element.next.removeAt(widget.index); }); }, icon: Icon(Icons.delete)) @@ -421,13 +428,13 @@ class ArrowInfoWidgetState extends State { /// [ArrowParams.startArrowPosition] and /// [ArrowParams.endArrowPosition] alignment. class ArrowPainter extends CustomPainter { - - /// ArrowPainter({ this.elementIndex, this.connIndex, this.toID = "", this.fromID = "", + this.infos = const [], + this.env = const [], this.isSelected = false, required this.params, this.from = Offset.zero, @@ -435,9 +442,9 @@ class ArrowPainter extends CustomPainter { List? pivots, }) : pivots = pivots ?? []; - /// + List env; + List infos; ArrowParams params; - /// String toID; String fromID; Offset to; @@ -462,6 +469,8 @@ class ArrowPainter extends CustomPainter { final arrowAngle= 25 * math.pi / 180; ArrowPainter deserialize(Map map) { + infos = map['infos']; + env = map['env']; params = ArrowParams.fromMap(map['params']); fromID = map['from']['id']; toID = map['to']['id']; @@ -469,9 +478,10 @@ class ArrowPainter extends CustomPainter { to = Offset(map['to']['x'], map['to']['y']); return this; } - Map serialize() { Map graphElement = {}; + graphElement['infos'] = infos; + graphElement['env'] = env; graphElement['from'] = { "id" : fromID.split("_")[0], "x" : from.dx, "y" : from.dy }; graphElement['to'] = { "id" : toID.split("_")[0], "x" : to.dx, "y" : to.dy }; graphElement['params'] = params.toMap(); @@ -484,6 +494,8 @@ class ArrowPainter extends CustomPainter { elementIndex: map['elementIndex'] as int, toID: map['toID'] != null ? map['toID'] as String : "", fromID: map['fromID'] as String, + infos: map['infos'] as List, + env: map['env'] as List, isSelected: map['isSelected'] != null ? map['isSelected'] as bool : false, params: ArrowParams.fromMap(map['params']), from: Offset( @@ -511,6 +523,8 @@ class ArrowPainter extends CustomPainter { "fromDy" : from.dy, "toDx" : to.dx, "toDy" : to.dy, + "infos" : infos, + "env" : env, 'pivots': pivots.map((e) => e.toMap()).toList(), }; } diff --git a/library/flutter_flow_chart/lib/src/ui/element_widget.dart b/library/flutter_flow_chart/lib/src/ui/element_widget.dart index adc3d63..718e348 100755 --- a/library/flutter_flow_chart/lib/src/ui/element_widget.dart +++ b/library/flutter_flow_chart/lib/src/ui/element_widget.dart @@ -151,12 +151,15 @@ class ElementWidgetState extends State { for (var element in widget.dashboard.elements) { element.isSelected = false; element.dashboard.chartKey.currentState?. setState(() { }); + widget.dashboard.selectedMenuKey.currentState?. setState(() { }); } } - widget.element.isSelected = !widget.element.isSelected; - for (var sel in widget.dashboard.arrows) { sel.isSelected = false; } - widget.dashboard.selectedMenuKey.currentState?. setState(() { }); - Future.delayed(Duration(seconds: 1), () { DrawingArrow.instance.notifyListeners(); }); + Future.delayed(Duration(milliseconds: 100), () { + DrawingArrow.instance.notifyListeners(); + widget.element.isSelected = !widget.element.isSelected; + for (var sel in widget.dashboard.arrows) { sel.isSelected = false; } + widget.dashboard.selectedMenuKey.currentState?. setState(() { }); + }); }); widget.onElementPressed?.call(context, tapLocation); }, @@ -234,7 +237,7 @@ class ElementWidgetState extends State { sel.changePosition(sel.position + diff); } } - widget.dashboard.save!(widget.dashboard.id); + widget.dashboard.saveDash(widget.dashboard.id, context); }, ), ), @@ -263,7 +266,7 @@ class ElementWidgetState extends State { child: Row( mainAxisAlignment: MainAxisAlignment.center, children: (!widget.isHovered ? [] : [ IconButton(tooltip: "remove element", onPressed: () { - widget.dashboard.removeElement(widget.element); + widget.dashboard.removeElement(widget.element, context); }, icon: Icon(Icons.delete_outline)), IconButton(tooltip: "copy element", onPressed: () { FlowElement newElement = FlowElement( @@ -274,7 +277,7 @@ class ElementWidgetState extends State { size: widget.element.size, widget: widget.element.widget, ); - widget.dashboard.addElement(newElement); + widget.dashboard.addElement(newElement, context); }, icon: Icon(Icons.copy, size: 20)), ])) ),