From 685badc59abe9c70703d5944431b77796b3fb3f8 Mon Sep 17 00:00:00 2001 From: mr Date: Tue, 15 Oct 2024 11:28:29 +0200 Subject: [PATCH] New local front deployment + new args --- Dockerfile | 16 +- lib/core/sections/end_drawer.dart | 1 + lib/core/services/api_service.dart | 2 + .../specialized_services/check_service.dart | 4 +- .../specialized_services/peer_service.dart | 4 +- .../resource_service.dart | 4 +- .../specialized_services/shared_service.dart | 4 +- .../workflow_execution_service.dart | 6 +- .../workflow_service.dart | 4 +- .../workspace_service.dart | 4 +- lib/models/search.dart | 269 ++++++++++++++++-- lib/models/workflow.dart | 21 +- lib/pages/workflow.dart | 37 ++- lib/widgets/forms/data_forms.dart | 60 +--- lib/widgets/forms/processing_forms.dart | 242 ++++++++-------- lib/widgets/forms/scheduler_forms.dart | 104 ++++--- lib/widgets/forms/storage_forms.dart | 18 ++ lib/widgets/forms/sub_expose_forms.dart | 63 ++++ lib/widgets/forms/sub_keys_forms.dart | 61 ++++ lib/widgets/forms/sub_map_forms.dart | 113 ++++++++ lib/widgets/forms/web_reference_forms.dart | 23 ++ lib/widgets/inputs/sub_dropdown_input .dart | 40 +++ lib/widgets/inputs/sub_text_input.dart | 62 ++++ .../items/items_details/data_item.dart | 14 +- lib/widgets/sheduler_items/schedule.dart | 4 +- .../sheduler_items/scheduler_calendar.dart | 15 +- .../sheduler_items/scheduler_item.dart | 10 +- .../flutter_flow_chart/lib/src/dashboard.dart | 25 +- .../lib/src/flow_chart.dart | 6 +- .../lib/src/flow_chart_selected_menu.dart | 15 +- .../lib/src/ui/draw_arrow.dart | 15 +- local_run.sh | 11 + 32 files changed, 952 insertions(+), 325 deletions(-) create mode 100644 lib/widgets/forms/storage_forms.dart create mode 100644 lib/widgets/forms/sub_expose_forms.dart create mode 100644 lib/widgets/forms/sub_keys_forms.dart create mode 100644 lib/widgets/forms/sub_map_forms.dart create mode 100644 lib/widgets/forms/web_reference_forms.dart create mode 100644 lib/widgets/inputs/sub_dropdown_input .dart create mode 100644 lib/widgets/inputs/sub_text_input.dart create mode 100755 local_run.sh diff --git a/Dockerfile b/Dockerfile index b857c1a..6f902f1 100644 --- a/Dockerfile +++ b/Dockerfile @@ -5,12 +5,13 @@ FROM debian:latest AS build-env RUN apt-get update RUN apt-get install -y curl git unzip -ARG WORKSPACE_HOST="https://localhost:8089" -ARG WORKFLOW_HOST="https://localhost:8088" -ARG SEARCH_HOST="https://localhost:49618" -ARG ITEM_HOST="https://localhost:8087" -ARG SCHEDULER_HOST="http://localhost:8090" +ARG WORKSPACE_HOST="http://localhost:8089/oc" +ARG WORKFLOW_HOST="http://localhost:8088/oc" +ARG ITEM_HOST="http://localhost:8087/oc" +ARG SCHEDULER_HOST="http://localhost:8090/oc" ARG LOGS_HOST="http://localhost:3100" +ARG PEER_HOST="http://localhost:8091/oc" +ARG COLLABORATIVE_AREA_HOST="http://localhost:8094/oc" # define variables ARG FLUTTER_SDK=/usr/local/flutter @@ -42,7 +43,10 @@ RUN flutter pub get RUN flutter build web \ --dart-define=WORKSPACE_HOST=$WORKSPACE_HOST \ --dart-define=WORKFLOW_HOST=$WORKFLOW_HOST \ - --dart-define=SEARCH_HOST=$SEARCH_HOST \ + --dart-define=PEER_HOST=$PEER_HOST \ + --dart-define=COLLABORATIVE_AREA_HOST=$COLLABORATIVE_AREA_HOST \ + --dart-define=SCHEDULER_HOST=$SCHEDULER_HOST \ + --dart-define=LOGS_HOST=$LOGS_HOST \ --dart-define=ITEM_HOST=$ITEM_HOST # once heare the app will be compiled and ready to deploy diff --git a/lib/core/sections/end_drawer.dart b/lib/core/sections/end_drawer.dart index 65960d9..6449c70 100644 --- a/lib/core/sections/end_drawer.dart +++ b/lib/core/sections/end_drawer.dart @@ -41,6 +41,7 @@ class EndDrawerWidgetState extends State { ), ShallowDropdownInputWidget( current: WorkspaceLocal.current, + filled: Colors.grey.shade200, width: 400, all: () async => WorkspaceLocal.getWorkspacesShallow(), canRemove: (p0) => p0 != null, diff --git a/lib/core/services/api_service.dart b/lib/core/services/api_service.dart index 8d88e2f..b23daef 100644 --- a/lib/core/services/api_service.dart +++ b/lib/core/services/api_service.dart @@ -20,6 +20,7 @@ class APIService { )..interceptors.add(LogInterceptor( requestHeader: true, ),); APIService({ required String baseURL }) { + print("BASE URL " + baseURL); _dio = Dio( BaseOptions( baseUrl: baseURL, // you can keep this blank @@ -77,6 +78,7 @@ class APIService { try { _dio.options.headers["authorization"] = auth; _dio.interceptors.clear(); + print(url); var response = await _request(url, method, body, options); if (response.statusCode != null && response.statusCode! < 400) { if (method == "delete") { cache.remove(url); return APIResponse(); } diff --git a/lib/core/services/specialized_services/check_service.dart b/lib/core/services/specialized_services/check_service.dart index d82f9fe..eb8c7aa 100644 --- a/lib/core/services/specialized_services/check_service.dart +++ b/lib/core/services/specialized_services/check_service.dart @@ -6,9 +6,9 @@ import 'package:oc_front/models/workflow.dart'; class CheckService extends AbstractService { @override APIService service = APIService( - baseURL: const String.fromEnvironment('WORKFLOW_HOST', defaultValue: 'http://localhost:8088') + baseURL: const String.fromEnvironment('WORKFLOW_HOST', defaultValue: 'http://localhost:8080/workflow') ); - @override String subPath = "/oc/workflow/check/"; + @override String subPath = "/check/"; Future> search(BuildContext? context, List words, Map params) { return service.get("$subPath${words.join("/")}", true, context); diff --git a/lib/core/services/specialized_services/peer_service.dart b/lib/core/services/specialized_services/peer_service.dart index 2548f02..d15e77d 100644 --- a/lib/core/services/specialized_services/peer_service.dart +++ b/lib/core/services/specialized_services/peer_service.dart @@ -4,7 +4,7 @@ import 'package:oc_front/models/shared.dart'; class PeerService extends AbstractService { @override APIService service = APIService( - baseURL: const String.fromEnvironment('PEER_HOST', defaultValue: 'http://localhost:8093') + baseURL: const String.fromEnvironment('PEER_HOST', defaultValue: 'http://localhost:8080/peer') ); - @override String subPath = "/oc/peer/"; + @override String subPath = "/"; } \ No newline at end of file diff --git a/lib/core/services/specialized_services/resource_service.dart b/lib/core/services/specialized_services/resource_service.dart index 7fd274a..bd11e8b 100644 --- a/lib/core/services/specialized_services/resource_service.dart +++ b/lib/core/services/specialized_services/resource_service.dart @@ -6,9 +6,9 @@ import 'package:oc_front/models/search.dart'; class ResourceService extends AbstractService { @override APIService service = APIService( - baseURL: const String.fromEnvironment('ITEM_HOST', defaultValue: 'http://localhost:8087') + baseURL: const String.fromEnvironment('ITEM_HOST', defaultValue: 'http://localhost:8080/catalog') ); - @override String subPath = "/oc/resource/"; + @override String subPath = "/resource/"; @override Future> search(BuildContext? context, List words, Map params) { return service.get("${subPath}search/${words.join("/")}", false, context); diff --git a/lib/core/services/specialized_services/shared_service.dart b/lib/core/services/specialized_services/shared_service.dart index bd8b10c..9b9e5b7 100644 --- a/lib/core/services/specialized_services/shared_service.dart +++ b/lib/core/services/specialized_services/shared_service.dart @@ -6,9 +6,9 @@ import 'package:oc_front/models/shared.dart'; class SharedService extends AbstractService { @override APIService service = APIService( - baseURL: const String.fromEnvironment('SHAREDWORKSPACE_HOST', defaultValue: 'http://localhost:8091') + baseURL: const String.fromEnvironment('COLLABORATIVE_AREA_HOST', defaultValue: 'http://localhost:8080/shared') ); - @override String subPath = "/oc/shared/workspace/"; + @override String subPath = "/collaborative_area/"; Future> addWorkspace(BuildContext? context, String id, String id2) { return service.post("$subPath$id/workspace/$id2", {}, context); diff --git a/lib/core/services/specialized_services/workflow_execution_service.dart b/lib/core/services/specialized_services/workflow_execution_service.dart index 0fc53fa..9b7ef51 100644 --- a/lib/core/services/specialized_services/workflow_execution_service.dart +++ b/lib/core/services/specialized_services/workflow_execution_service.dart @@ -6,9 +6,9 @@ import 'package:oc_front/models/workflow.dart'; class WorkflowExecutionService extends AbstractService { @override APIService service = APIService( - baseURL: const String.fromEnvironment('SCHEDULER_HOST', defaultValue: 'http://localhost:8090') + baseURL: const String.fromEnvironment('SCHEDULER_HOST', defaultValue: 'http://localhost:8080/scheduler') ); - @override String subPath = "/oc/workflow_execution/"; + @override String subPath = "/"; @override Future> search(BuildContext? context, List words, Map params) { return service.get("${subPath}search/${words.join("/")}", false, context); @@ -20,4 +20,4 @@ class WorkflowExecutionService extends AbstractService { @override Future> put(BuildContext? context, String id, Map body, Map params) { return throw UnimplementedError(); } -} +} \ No newline at end of file diff --git a/lib/core/services/specialized_services/workflow_service.dart b/lib/core/services/specialized_services/workflow_service.dart index 4e59706..55afdb0 100644 --- a/lib/core/services/specialized_services/workflow_service.dart +++ b/lib/core/services/specialized_services/workflow_service.dart @@ -4,7 +4,7 @@ import 'package:oc_front/models/workflow.dart'; class WorflowService extends AbstractService { @override APIService service = APIService( - baseURL: const String.fromEnvironment('WORKFLOW_HOST', defaultValue: 'http://localhost:8088') + baseURL: const String.fromEnvironment('WORKFLOW_HOST', defaultValue: 'http://localhost:8080/workflow') ); - @override String subPath = "/oc/workflow/"; + @override String subPath = "/"; } \ No newline at end of file diff --git a/lib/core/services/specialized_services/workspace_service.dart b/lib/core/services/specialized_services/workspace_service.dart index e991097..92a20c4 100644 --- a/lib/core/services/specialized_services/workspace_service.dart +++ b/lib/core/services/specialized_services/workspace_service.dart @@ -4,7 +4,7 @@ import 'package:oc_front/models/workspace.dart'; class WorkspaceService extends AbstractService { @override APIService service = APIService( - baseURL: const String.fromEnvironment('WORKSPACE_HOST', defaultValue: 'http://localhost:8089') + baseURL: const String.fromEnvironment('WORKSPACE_HOST', defaultValue: 'http://localhost:8080/workspace') ); - @override String subPath = "/oc/workspace/"; + @override String subPath = "/"; } \ No newline at end of file diff --git a/lib/models/search.dart b/lib/models/search.dart index 8e8e675..48c879f 100644 --- a/lib/models/search.dart +++ b/lib/models/search.dart @@ -146,28 +146,53 @@ class Model extends SerializerDeserializer { class ResourceModel extends SerializerDeserializer { String? id; String? type; - Map? model; + Map refs; + Map>? model; ResourceModel({ this.id, this.type, + this.refs = const {}, this.model, }); @override deserialize(dynamic json) { try { json = json as Map; } catch (e) { return ResourceModel(); } - return ResourceModel( + var w = ResourceModel( id: json.containsKey("id") ? json["id"] : null, type: json.containsKey("type") ? json["type"] : null, - model: json.containsKey("model") ? fromMapJson(json["model"], Model()) : {}, + refs: json.containsKey("var_refs") ? json["var_refs"] : {}, ); + if (json.containsKey("model")) { + w.model = {}; + for (var key in (json["model"] as Map).keys) { + w.model![key] = {}; + for (var k2 in (json["model"][key] as Map).keys) { + w.model![key]![k2] = Model().deserialize(json["model"][key][k2]); + } + } + } + return w; + } + @override Map serialize() { + Map t = { + "id": id, + "type": type, + "var_refs": refs, + }; + t["model"] = {}; + if (model != null) { + for (var key in model!.keys) { + t["model"][key] = {}; + for (var k2 in model![key]!.keys) { + t["model"][key]![k2] = model![key]![k2]!.serialize(); + } + } + } + + return t; } - @override Map serialize() => { - "id": id, - "type": type, - "model": toMapJson(model ?? {}), - }; } Type? getTopicType(String topic) { @@ -195,6 +220,73 @@ bool isDataCenter(String topic) => topic == "datacenter"; bool isStorage(String topic) => topic == "storage"; bool isWorkflow(String topic) => topic == "workflow"; +class Expose extends SerializerDeserializer { + Expose({ + this.PAT, + this.port, + this.path, + }); + + int? port; + int? PAT; + String? path; + + @override deserialize(dynamic json) { + try { json = json as Map; + } catch (e) { return Expose(); } + return Expose( + port: json.containsKey("port") ? json["port"] : null, + PAT: json.containsKey("PAT") ? json["PAT"] : null, + path: json.containsKey("reverse") ? json["reverse"] : null, + ); + } + + @override Map serialize() => { + "port": port, + "PAT": PAT, + "reverse": path, + }; +} + +class Containered extends SerializerDeserializer { + Containered({ + this.image, + this.args, + this.command, + this.env, + this.volumes, + }); + + String? args; + String? image; + String? command; + Map? env; + Map? volumes; + + @override deserialize(dynamic json) { + try { json = json as Map; + } catch (e) { return Containered(); } + return Containered( + args: json.containsKey("args") ? json["args"] : null, + image: json.containsKey("image") ? json["image"] : null, + command: json.containsKey("command") ? json["command"] : null, + env: json.containsKey("env") ? json["env"] : null, + volumes: json.containsKey("volumes") ? json["volumes"] : null, + ); + } + + @override Map serialize() { + var w = { + "args": args, + "image": image, + "command": command, + "env": env, + "volumes": volumes, + }; + return w; + } +} + class ProcessingItem extends SerializerDeserializer implements AbstractItem { ProcessingItem({ this.id, @@ -217,7 +309,9 @@ class ProcessingItem extends SerializerDeserializer implements A this.parrallel = false, this.scallingModel, this.diskIO, - + + this.expose = const [], + this.container, this.model, }); @override ResourceModel? model; @@ -235,6 +329,8 @@ class ProcessingItem extends SerializerDeserializer implements A @override String? description; @override String? shortDescription; + Containered? container; + List expose = []; // Special Attributes List cpus = []; List gpus = []; @@ -261,6 +357,26 @@ class ProcessingItem extends SerializerDeserializer implements A double? getHeight() { return height; } + @override + Map setVariable(List keys, dynamic value, Map map) { + if (keys.isEmpty) { return map; } + var key = keys[0]; + if (keys.length > 1 && map[key] != null) { + map[key] = setVariable(keys.sublist(1), value, map[key]); + } else { + map[key] = value; + } + return map; + } + @override + dynamic getVariable(List keys, Map map) { + if (keys.isEmpty) { return null; } + var key = keys[0]; + if (keys.length > 1 && map[key] != null) { + return getVariable(keys.sublist(1), map[key]); + } + return map[key]; + } @override deserialize(dynamic json) { try { json = json as Map; @@ -278,7 +394,9 @@ class ProcessingItem extends SerializerDeserializer implements A inputs: json["inputs"] ?? [], outputs: json["outputs"] ?? [], source: json.containsKey("source") ? json["source"] : null, - + + expose: json.containsKey("expose") ? fromListJson(json["expose"], Expose()) : [], + container: json.containsKey("container") ? Containered().deserialize(json["container"]) : null, model: json.containsKey("resource_model") ? ResourceModel().deserialize(json["resource_model"]) : null, cpus: json.containsKey("cpus") ? fromListJson(json["cpus"], CPU()) : [], gpus: json.containsKey("gpus") ? fromListJson(json["gpus"], GPU()) : [], @@ -289,7 +407,6 @@ class ProcessingItem extends SerializerDeserializer implements A diskIO: json.containsKey("disk_io") ? json["disk_io"] : null, ); if (w.logo != null) { - // var image = Image.network(w.logo!); image.image .resolve(const ImageConfiguration()) @@ -302,7 +419,8 @@ class ProcessingItem extends SerializerDeserializer implements A } return w; } - @override Map serialize() => { + @override Map serialize() { + return { "id": id, "name": name, "logo": logo, @@ -323,7 +441,10 @@ class ProcessingItem extends SerializerDeserializer implements A "parrallel": parrallel, "scalling_model": scallingModel, "disk_io": diskIO, - }; + "" + "expose": toListJson(expose), + "container": container?.serialize(), + }; } } class WorkflowItem extends SerializerDeserializer implements AbstractItem { @@ -377,6 +498,27 @@ class WorkflowItem extends SerializerDeserializer implements Abstr @override String getName() { return name ?? ""; } + @override + Map setVariable(List keys, dynamic value, Map map) { + if (keys.isEmpty) { return map; } + var key = keys[0]; + if (keys.length > 1 && map[key] != null) { + map[key] = setVariable(keys.sublist(1), value, map[key]); + } else { + map[key] = value; + } + return map; + } + @override + dynamic getVariable(List keys, Map map) { + if (keys.isEmpty) { return null; } + var key = keys[0]; + if (keys.length > 1 && map[key] != null) { + return getVariable(keys.sublist(1), map[key]); + } + return map[key]; + } + @override deserialize(dynamic json) { try { json = json as Map; } catch (e) { return WorkflowItem(); } @@ -443,8 +585,10 @@ class DataItem extends SerializerDeserializer implements AbstractItem< this.inputs = _empty, this.outputs = _empty, this.model, + this.protocol, + this.path, this.protocols = const [], - this.dataType, + this.type, this.exemple, }); @override String? id; @@ -463,7 +607,9 @@ class DataItem extends SerializerDeserializer implements AbstractItem< @override ResourceModel? model; // Special Attributes List protocols = []; - String? dataType; + String? type; + String? protocol; + String? path; String? exemple; @override String getName() { return name ?? ""; @@ -482,6 +628,28 @@ class DataItem extends SerializerDeserializer implements AbstractItem< double? getHeight() { return height; } + + @override + Map setVariable(List keys, dynamic value, Map map) { + if (keys.isEmpty) { return map; } + var key = keys[0]; + if (keys.length > 1 && map[key] != null) { + map[key] = setVariable(keys.sublist(1), value, map[key]); + } else { + map[key] = value; + } + return map; + } + @override + dynamic getVariable(List keys, Map map) { + if (keys.isEmpty) { return null; } + var key = keys[0]; + if (keys.length > 1 && map[key] != null) { + return getVariable(keys.sublist(1), map[key]); + } + return map[key]; + } + @override deserialize(dynamic json) { try { json = json as Map; } catch (e) { return DataItem(); } @@ -500,7 +668,9 @@ class DataItem extends SerializerDeserializer implements AbstractItem< source: json.containsKey("source") ? json["source"] : null, model: json.containsKey("resource_model") ? ResourceModel().deserialize(json["resource_model"]) : null, protocols: json.containsKey("protocols") ? json["protocols"] : [], - dataType: json.containsKey("data_type") ? json["data_type"] : null, + type: json.containsKey("type") ? json["type"] : null, + protocol: json.containsKey("protocol") ? json["protocol"] : null, + path: json.containsKey("path") ? json["path"] : null, exemple: json.containsKey("exemple") ? json["exemple"] : null, ); if (w.logo != null) { @@ -517,6 +687,7 @@ class DataItem extends SerializerDeserializer implements AbstractItem< } return w; } + @override Map serialize() => { "id": id, "name": name, @@ -532,7 +703,9 @@ class DataItem extends SerializerDeserializer implements AbstractItem< "source": source, "resource_model": model?.serialize(), "protocols": protocols, - "data_type": dataType, + "type": type, + "protocol": protocol, + "path": path, "exemple": exemple, }; } @@ -626,6 +799,29 @@ class DataCenterItem extends SerializerDeserializer implements A } return w; } + + @override + Map setVariable(List keys, dynamic value, Map map) { + if (keys.isEmpty) { return map; } + var key = keys[0]; + if (keys.length > 1 && map[key] != null) { + map[key] = setVariable(keys.sublist(1), value, map[key]); + } else { + map[key] = value; + } + return map; + } + + @override + dynamic getVariable(List keys, Map map) { + if (keys.isEmpty) { return null; } + var key = keys[0]; + if (keys.length > 1 && map[key] != null) { + return getVariable(keys.sublist(1), map[key]); + } + return map[key]; + } + @override Map serialize() => { "id": id, "name": name, @@ -745,12 +941,15 @@ class StorageItem extends SerializerDeserializer implements Abstrac this.acronym, this.type, this.size, - this.url, + this.path, + this.protocol, this.encryption = false, this.redundancy, this.throughput, this.model, + this.local = false, }); + bool local = false; @override String? id; @override String? name; @override String? logo; @@ -768,8 +967,9 @@ class StorageItem extends SerializerDeserializer implements Abstrac // special attributes String? acronym; String? type; + String? path; + String? protocol; int? size; - String? url; bool encryption = false; String? redundancy; String? throughput; @@ -789,6 +989,29 @@ class StorageItem extends SerializerDeserializer implements Abstrac double? getHeight() { return height; } + + @override + dynamic getVariable(List keys, Map map) { + if (keys.isEmpty) { return null; } + var key = keys[0]; + if (keys.length > 1 && map[key] != null) { + return getVariable(keys.sublist(1), map[key]); + } + return map[key]; + } + + @override + Map setVariable(List keys, dynamic value, Map map) { + if (keys.isEmpty) { return map; } + var key = keys[0]; + if (keys.length > 1 && map[key] != null) { + map[key] = setVariable(keys.sublist(1), value, map[key]); + } else { + map[key] = value; + } + return map; + } + @override deserialize(dynamic json) { try { json = json as Map; } catch (e) { return StorageItem(); } @@ -802,6 +1025,7 @@ class StorageItem extends SerializerDeserializer implements Abstrac licence: json.containsKey("licence") ? json["licence"] : null, description: json.containsKey("description") ? json["description"] : null, shortDescription: json.containsKey("short_description") ? json["short_description"] : null, + local: json.containsKey("local") ? json["local"] : false, inputs: json["inputs"] ?? [], outputs: json["outputs"] ?? [], source: json.containsKey("source") ? json["source"] : null, @@ -809,7 +1033,8 @@ class StorageItem extends SerializerDeserializer implements Abstrac acronym: json.containsKey("acronym") ? json["acronym"] : null, type: json.containsKey("type") ? json["type"] : null, size: json.containsKey("size") ? json["size"] : null, - url: json.containsKey("url") ? json["url"] : null, + path: json.containsKey("path") ? json["path"] : null, + protocol: json.containsKey("protocol") ? json["protocol"] : null, encryption: json.containsKey("encryption") ? json["encryption"] : false, redundancy: json.containsKey("redundancy") ? json["redundancy"] : null, throughput: json.containsKey("throughput") ? json["throughput"] : null, @@ -835,6 +1060,7 @@ class StorageItem extends SerializerDeserializer implements Abstrac "owner": owner, "owner_logo": ownerLogo, "price": price, + "local": local, "licence": licence, "description": description, "short_description": shortDescription, @@ -845,7 +1071,8 @@ class StorageItem extends SerializerDeserializer implements Abstrac "acronym": acronym, "type": type, "size": size, - "url": url, + "path": path, + "protocol": protocol, "encryption": encryption, "redundancy": redundancy, "throughput": throughput, diff --git a/lib/models/workflow.dart b/lib/models/workflow.dart index d56d4f1..33b7391 100644 --- a/lib/models/workflow.dart +++ b/lib/models/workflow.dart @@ -76,8 +76,6 @@ class WorkflowExecution extends SerializerDeserializer { @override deserialize(dynamic json) { try { json = json as Map; } catch (e) { return WorkflowExecution(); } - print("qsdqdqssd"); - print(json); return WorkflowExecution( id: json.containsKey("id") ? json["id"] : "", endDate: json.containsKey("end_date") ? json["end_date"] : "", @@ -514,6 +512,15 @@ class GraphItem extends SerializerDeserializer { this.workflow, }); + AbstractItem? getElement() { + if (data != null) { return data!; } + if (processing != null) { return processing!; } + if (storage != null) { return storage!; } + if (datacenter != null) { return datacenter!; } + if (workflow != null) { return workflow!; } + return null; + } + void fromDashboard(Map j) { id = j["id"]; position = Position(x: j["x"], y: j["y"]); @@ -528,15 +535,19 @@ class GraphItem extends SerializerDeserializer { } else if (abs.topic == "processing") { processing = ProcessingItem().deserialize(abs.serialize()); processing!.model = ResourceModel().deserialize(j["element"]["resource_model"]); + if ((j["element"] as Map).containsKey("container")) { + processing!.container = Containered().deserialize(j["element"]["container"]); + processing!.container?.env?.removeWhere((key, value) => key == "" || value == ""); + processing!.container?.volumes?.removeWhere((key, value) => key == "" || value == ""); + processing!.expose.removeWhere((element) => element.port == null || element.port == 0 || (element.PAT == 0 && element.path == "")); + + } } else if (abs.topic == "datacenter") { datacenter = DataCenterItem().deserialize(abs.serialize()); - datacenter!.model = ResourceModel().deserialize(j["element"]["resource_model"]); } else if (abs.topic == "storage") { storage = StorageItem().deserialize(abs.serialize()); - storage!.model = ResourceModel().deserialize(j["element"]["resource_model"]); } else if (abs.topic == "workflow") { workflow = WorkflowItem().deserialize(abs.serialize()); - workflow!.model = ResourceModel().deserialize(j["element"]["resource_model"]); } else { datacenter = null; data = null; diff --git a/lib/pages/workflow.dart b/lib/pages/workflow.dart index 3e8d906..1b78b91 100644 --- a/lib/pages/workflow.dart +++ b/lib/pages/workflow.dart @@ -12,8 +12,10 @@ import 'package:oc_front/models/workflow.dart'; import 'package:oc_front/pages/abstract_page.dart'; import 'package:oc_front/pages/shared.dart'; import 'package:oc_front/widgets/dialog/shallow_creation.dart'; +import 'package:oc_front/widgets/forms/data_forms.dart'; import 'package:oc_front/widgets/forms/processing_forms.dart'; import 'package:oc_front/widgets/forms/scheduler_forms.dart'; +import 'package:oc_front/widgets/forms/storage_forms.dart'; import 'package:oc_front/widgets/items/item_row.dart'; import 'package:oc_front/widgets/inputs/shallow_dropdown_input.dart'; @@ -51,10 +53,28 @@ final WorflowService _service = WorflowService(); var e = item as AbstractItem; return Container(color: Colors.white, child: ItemRowWidget(low: true, contextWidth: 290, item: e)); } - List getForms(FlowData? obj) { - return obj == null ? [] : [ - ProcessingFormsWidget(item: obj as AbstractItem, dash: dash), - ]; + List getForms(FlowData? obj, String id) { + var objAbs = obj as AbstractItem?; + if (objAbs == null) { return []; } + List res = []; + if ( objAbs.topic == "processing") { + res = [ProcessingFormsWidget(item: objAbs as ProcessingItem, dash: dash, elementID: id)]; + } else if ( objAbs.topic == "data" ) { + res = [DataFormsWidget(item: objAbs as DataItem)]; + } else if ( objAbs.topic == "storage" ) { + res = [StorageFormsWidget(item: objAbs as StorageItem)]; + } + return [ Wrap( + alignment: WrapAlignment.center, + children: [ + Container( padding: const EdgeInsets.all(10), width: 250, height: 60, + decoration: const BoxDecoration(border: Border(bottom: BorderSide(color: Colors.grey, width: 1))), + child: const Column( mainAxisAlignment: MainAxisAlignment.center, children: [ + Text("ELEMENT INFO", style: TextStyle(fontSize: 15, fontWeight: FontWeight.bold), textAlign: TextAlign.center), + Text("", style: TextStyle(fontSize: 12), textAlign: TextAlign.center), + ])), + ...res + ]) ]; } List getDashInfoForms() { @@ -122,7 +142,6 @@ final WorflowService _service = WorflowService(); } } updateW.graph?.zoom = dash.getZoomFactor(); - print("SAVE DASH"); dash.addToHistory(); await _service.put(context, id, updateW.serialize(), {}).then( (e) { if (dash.addChange) { @@ -140,7 +159,13 @@ final WorflowService _service = WorflowService(); if (d.topic == "data") { return d as DataItem; } if (d.topic == "datacenter") { return d as DataCenterItem; } if (d.topic == "storage") { return d as StorageItem; } - if (d.topic == "processing") { return d as ProcessingItem; } + if (d.topic == "processing") { + d = d as ProcessingItem; + if (data.containsKey("container")) { + d.container = Containered().deserialize(data["container"]); + } + return d; + } if (d.topic == "workflows") { return d as WorkflowItem; } return null; } diff --git a/lib/widgets/forms/data_forms.dart b/lib/widgets/forms/data_forms.dart index e8ad985..3714bac 100644 --- a/lib/widgets/forms/data_forms.dart +++ b/lib/widgets/forms/data_forms.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; import 'package:oc_front/models/search.dart'; +import 'package:oc_front/widgets/forms/web_reference_forms.dart'; class DataFormsWidget extends StatefulWidget { DataItem item; @@ -10,64 +11,9 @@ class DataFormsWidget extends StatefulWidget { } class DataFormsWidgetState extends State { @override Widget build(BuildContext context) { + print(widget.item.serialize()); return Column( children: [ - Tooltip( message: "protocols", - child: Container( - margin: const EdgeInsets.only(left: 10), - width: 45, height: 25, - child: TextFormField( textAlign: TextAlign.center, - initialValue: widget.item.protocols.join(","), - onChanged: (value) { - widget.item.protocols = value.split(","); - }, - style: const TextStyle(fontSize: 12), - decoration: const InputDecoration( - fillColor: Colors.white, - filled: true, - labelText: "protocols", - labelStyle: TextStyle(fontSize: 10), - border: OutlineInputBorder(), - contentPadding: EdgeInsets.symmetric(horizontal: 10, vertical: 5), - ), - ))), - Tooltip( message: "datatype", - child: Container( - margin: const EdgeInsets.only(left: 10), - width: 45, height: 25, - child: TextFormField( textAlign: TextAlign.center, - initialValue: widget.item.dataType, - onChanged: (value) { - widget.item.dataType = value; - }, - style: const TextStyle(fontSize: 12), - decoration: const InputDecoration( - fillColor: Colors.white, - filled: true, - labelText: "datatype", - labelStyle: TextStyle(fontSize: 10), - border: OutlineInputBorder(), - contentPadding: EdgeInsets.symmetric(horizontal: 10, vertical: 5), - ), - ))), - Tooltip( message: "example", - child: Container( - margin: const EdgeInsets.only(left: 10), - width: 45, height: 25, - child: TextFormField( textAlign: TextAlign.center, - initialValue: widget.item.exemple, - onChanged: (value) { - widget.item.exemple = value; - }, - style: const TextStyle(fontSize: 12), - decoration: const InputDecoration( - fillColor: Colors.white, - filled: true, - labelText: "example", - labelStyle: TextStyle(fontSize: 10), - border: OutlineInputBorder(), - contentPadding: EdgeInsets.symmetric(horizontal: 10, vertical: 5), - ), - ))) + WebReferenceFormsWidget(item: widget.item), ]); } } \ No newline at end of file diff --git a/lib/widgets/forms/processing_forms.dart b/lib/widgets/forms/processing_forms.dart index 57b4c62..c0fc3a1 100644 --- a/lib/widgets/forms/processing_forms.dart +++ b/lib/widgets/forms/processing_forms.dart @@ -1,136 +1,142 @@ import 'package:flutter/material.dart'; -import 'package:flutter/services.dart'; import 'package:flutter_flow_chart/flutter_flow_chart.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 { - AbstractItem item; + String elementID; + ProcessingItem item; Dashboard dash; - ProcessingFormsWidget ({ super.key, required this.item, required this.dash }); + ProcessingFormsWidget ({ super.key, required this.item, required this.dash, required this.elementID }); @override ProcessingFormsWidgetState createState() => ProcessingFormsWidgetState(); } class ProcessingFormsWidgetState extends State { + Widget getInputAndOutputVariableForms() { + 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)); + } + if (outItems.isNotEmpty) { + res.add(SubKeysMapFormsWidget(dash: widget.dash, isInput: false, item: widget.item, elementID: widget.elementID, + categoryKey: "container", varKey: "env", graphItems: outItems)); + } + return Column( children: res ); + } + @override Widget build(BuildContext context) { - List children = []; + List categories = []; var l = widget.item.model?.model?.keys ?? []; for (var child in l) { - if (widget.item.model!.model![child]!.type != "string") { continue; } - children.add( - Tooltip( message: child, - child: Container( margin: EdgeInsets.only(top: children.isEmpty ? 0 : 15), - width: 200, height: 30, - child: TextFormField( textAlign: TextAlign.start, - initialValue: widget.item.model?.model?[child]?.value, - onChanged: (value) { - widget.item.model ?? Model(); - Future.delayed(const Duration(seconds: 2), () { - if (widget.item.model!.model?[child]?.value == value) { - dash.save!(dash.id); - } - }); - widget.item.model?.model?[child]?.value = value; - }, - style: const TextStyle(fontSize: 12), - decoration: InputDecoration( - hintText: "enter $child...", - fillColor: Colors.white, - filled: true, - labelText: child, - alignLabelWithHint: false, - errorStyle: const TextStyle(fontSize: 0), - hintStyle: const TextStyle(fontSize: 10), - labelStyle: const TextStyle(fontSize: 10), - floatingLabelBehavior: FloatingLabelBehavior.always, - enabledBorder: const OutlineInputBorder(borderSide: BorderSide(color: Colors.grey)), - border: const OutlineInputBorder(borderSide: BorderSide(color: Colors.grey)), - contentPadding: const EdgeInsets.symmetric(horizontal: 10, vertical: 5), - ), - ))) - ); + 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, + elementID: widget.elementID, categoryKey: child, varKey: st) + ); + } else if (sub[st]!.type == "string") { + children.add(SubTextInputWidget(subkey: st, initialValue: widget.item.getVariable([child, st], widget.item.serialize()), + width: 200, 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.save!(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.all(10), + width: 250, + 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: 200, empty: false, change: (value) {}, + initialValue: widget.item.container?.image, readOnly: true,)), + ...children, + getInputAndOutputVariableForms(), + ],) + )); } - if (widget.dash.scheduler["mode"] != null && widget.dash.scheduler["mode"] == 1) { - children.add( - Tooltip( message: "hostname", - child: Container( margin: EdgeInsets.only(top: children.isEmpty ? 0 : 15), - width: 200, height: 30, - child: TextFormField( textAlign: TextAlign.start, - onChanged: (value) { - widget.item.model ?? Model(); - Future.delayed(const Duration(seconds: 2), () { - if (widget.item.model!.model?["hostname"]?.value == value) { - dash.save!(dash.id); - } - }); - widget.item.model?.model?["hostname"]?.value = value; - }, - style: const TextStyle(fontSize: 12), - decoration: const InputDecoration( - hintText: "enter hostname...", - fillColor: Colors.white, - filled: true, - labelText: "hostname", - alignLabelWithHint: false, - errorStyle: TextStyle(fontSize: 0), - hintStyle: TextStyle(fontSize: 10), - labelStyle: TextStyle(fontSize: 10), - floatingLabelBehavior: FloatingLabelBehavior.always, - enabledBorder: OutlineInputBorder(borderSide: BorderSide(color: Colors.grey)), - border: OutlineInputBorder(borderSide: BorderSide(color: Colors.grey)), - contentPadding: EdgeInsets.symmetric(horizontal: 10, vertical: 5), - ), - ))) - ); - children.add( - Tooltip( message: "port", - child: Container( margin: EdgeInsets.only(top: children.isEmpty ? 0 : 15), - width: 200, height: 50, - child: TextFormField( textAlign: TextAlign.start, - onChanged: (value) { - widget.item.model ?? Model(); - Future.delayed(const Duration(seconds: 2), () { - if (widget.item.model!.model?["port"]?.value == value) { - dash.save!(dash.id); - } - }); - try { - widget.item.model?.model?["port"]?.value = int.parse(value); - } catch (e) { /**/ } - }, - keyboardType: TextInputType.number, - - inputFormatters: [ - FilteringTextInputFormatter.digitsOnly - ], // Only numbers can be entered - maxLength: 4, - style: const TextStyle(fontSize: 12), - decoration: const InputDecoration( - hintText: "enter port...", - fillColor: Colors.white, - filled: true, - labelText: "port", - alignLabelWithHint: false, - errorStyle: TextStyle(fontSize: 0), - hintStyle: TextStyle(fontSize: 10), - labelStyle: TextStyle(fontSize: 10), - floatingLabelBehavior: FloatingLabelBehavior.always, - enabledBorder: OutlineInputBorder(borderSide: BorderSide(color: Colors.grey)), - border: OutlineInputBorder(borderSide: BorderSide(color: Colors.grey)), - contentPadding: EdgeInsets.symmetric(horizontal: 10, vertical: 5), - ), - ))) - ); + // EXPOSE + categories.add(Container( + padding: const EdgeInsets.all(10), + width: 250, + decoration: const BoxDecoration(border: Border(top: BorderSide(color: Colors.grey, width: 1))), + 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)), + 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(left: 15, top: 5), + decoration: BoxDecoration(borderRadius: BorderRadius.circular(5), border: Border.all(color: Colors.grey, width: 1)), + width: 150, height: 30, + child: const Row( mainAxisAlignment: MainAxisAlignment.center, + children: [ Padding( padding: EdgeInsets.only(right: 5), child: Icon(Icons.add)), Text("add exposure")]), + ) + ), + 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, right: 10, 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( width: 200, dash: dash, empty: categories.isEmpty, + item: expose, elementID: widget.elementID)); } - return Column( children: [ - Container( padding: const EdgeInsets.all(10), width: 250, height: 60, margin: const EdgeInsets.only(bottom: 15), - decoration: const BoxDecoration(border: Border(bottom: BorderSide(color: Colors.grey, width: 1))), - child: const Column( mainAxisAlignment: MainAxisAlignment.center, children: [ - Text("ELEMENT INFO", style: TextStyle(fontSize: 15, fontWeight: FontWeight.bold), textAlign: TextAlign.center), - Text("", style: TextStyle(fontSize: 12), textAlign: TextAlign.center), - ])), - ...children - ]); + return SizedBox( height: MediaQuery.of(context).size.height - 330, child: SingleChildScrollView( child: Column( + children: categories )) ); } } \ No newline at end of file diff --git a/lib/widgets/forms/scheduler_forms.dart b/lib/widgets/forms/scheduler_forms.dart index 0e68c58..feff82c 100644 --- a/lib/widgets/forms/scheduler_forms.dart +++ b/lib/widgets/forms/scheduler_forms.dart @@ -24,6 +24,61 @@ class SchedulerFormsWidget extends StatefulWidget { } class SchedulerFormsWidgetState extends State { CheckService check = CheckService(); + void save(List> formKeys) { + dash.scheduleActive = !dash.scheduleActive; + for (var k in formKeys) { + if (k.currentState != null) { + if (!k.currentState!.validate()) { + dash.scheduleActive = !dash.scheduleActive; + 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(); + } + } + print(widget.item.id); + widget.item.save!(widget.item.id); + } + void checkBooking(List> formKeys, void Function(List> )? f){ + if (widget.item.scheduler["start"] == null) { + DateTime now = DateTime.now().add(const Duration(minutes: 5)); + widget.item.scheduler["start"] = now.toUtc().toIso8601String(); + } + var s = DateTime.parse(widget.item.scheduler["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(); + } else { + e = DateTime.parse(widget.item.scheduler["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; + print(v.data!.is_available); + if (v.data!.is_available) { + print(f); + if (f != null) { f(formKeys); + } else { + showAlertBanner( context, () {}, + const InfoAlertBannerChild(text: "no booking found at this date"),// <-- Put any widget here you want! + alertBannerLocation: AlertBannerLocation.bottom,); + } + } else { + showAlertBanner( context, () {}, + const AlertAlertBannerChild(text: "booking found at this date"),// <-- Put any widget here you want! + alertBannerLocation: AlertBannerLocation.bottom,); + } + setState(() {}); + } + ); + } + @override Widget build(BuildContext context) { try { if (widget.item.scheduler["mode"] == null) { widget.item.scheduler["mode"] = 1; } @@ -87,7 +142,7 @@ class SchedulerFormsWidgetState extends State { width: 140, initialValue: widget.item.scheduler["mode"] == 1, activeColor: Colors.green, inactiveColor: Colors.green, - activeChild: const Text("service", style: TextStyle(color: Colors.white)), + activeChild: const Text("simple task", style: TextStyle(color: Colors.white)), inactiveChild: const Text("cron task", style: TextStyle(color: Colors.white)), borderRadius: const BorderRadius.all(Radius.circular(15)), height: 30.0, disabledOpacity: 0.5, onChanged: (value) { @@ -372,34 +427,7 @@ class SchedulerFormsWidgetState extends State { Tooltip( message: "check booking", child: InkWell( mouseCursor: SystemMouseCursors.click, onTap: () { - if (dash.scheduleActive) { return; } - if (dash.scheduler["start"] == null ) { - DateTime now = DateTime.now().add(const Duration(minutes: 5)); - dash.scheduler["start"] = now.toUtc().toIso8601String(); - } - var s = DateTime.parse(dash.scheduler["start"]).toUtc().toIso8601String(); - var e = ""; - if (dash.scheduler["end"] == null) { - e = DateTime.parse(dash.scheduler["start"]).add(const Duration(seconds: 5)).toUtc().toIso8601String(); - } else { - e = DateTime.parse(dash.scheduler["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) { - showAlertBanner( context, () {}, - const InfoAlertBannerChild(text: "no booking found at this date"),// <-- Put any widget here you want! - alertBannerLocation: AlertBannerLocation.bottom,); - } else { - showAlertBanner( context, () {}, - const AlertAlertBannerChild(text: "booking found at this date"),// <-- Put any widget here you want! - alertBannerLocation: AlertBannerLocation.bottom,); - } - setState(() {}); - } - ); + checkBooking(formKeys, null); }, child: Container( margin: const EdgeInsets.only(bottom: 5), decoration: BoxDecoration(borderRadius: BorderRadius.circular(5), border: Border.all(color: widget.booking == null && !dash.scheduleActive ? Colors.black : (widget.booking == true || dash.scheduleActive ? Colors.green : Colors.red), width: 1)), @@ -412,23 +440,7 @@ class SchedulerFormsWidgetState extends State { Tooltip( message: dash.scheduleActive ? "unbook" : "book", child: InkWell( mouseCursor: SystemMouseCursors.click, onTap: () { - dash.scheduleActive = !dash.scheduleActive; - for (var k in formKeys) { - if (k.currentState != null) { - 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(); - } - } - widget.item.save!(widget.item.id); - setState(() { }); + dash.scheduleActive ? setState(() { save(formKeys); }) : checkBooking(formKeys, save); }, child: Container( margin: const EdgeInsets.symmetric(vertical: 5, horizontal: 10), decoration: BoxDecoration(borderRadius: BorderRadius.circular(5), border: Border.all(color: dash.scheduleActive ? Colors.green : Colors.black)), diff --git a/lib/widgets/forms/storage_forms.dart b/lib/widgets/forms/storage_forms.dart new file mode 100644 index 0000000..3fee6e6 --- /dev/null +++ b/lib/widgets/forms/storage_forms.dart @@ -0,0 +1,18 @@ +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/sub_expose_forms.dart b/lib/widgets/forms/sub_expose_forms.dart new file mode 100644 index 0000000..694d425 --- /dev/null +++ b/lib/widgets/forms/sub_expose_forms.dart @@ -0,0 +1,63 @@ + +import 'package:flutter/material.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'; + +class SubExposeFormsWidget extends StatefulWidget { + Expose item; + Dashboard dash; + String elementID = ""; + double width = 200; + bool empty = false; + SubExposeFormsWidget ({ super.key, required this.dash, + this.empty = false, required this.item, required this.elementID, required this.width }); + @override SubExposeFormsWidgetState createState() => SubExposeFormsWidgetState(); +} +class SubExposeFormsWidgetState extends State { + @override Widget build(BuildContext context) { + return Column( children : [ + Container( margin: const EdgeInsets.only(left: 10, right: 10, top: 5), + decoration: BoxDecoration(border: Border.all(color: Colors.grey, width: 1)), + width: 250 + ), + SubTextInputWidget(subkey: "reference port", initialValue: widget.item.port != null ? '${widget.item.port}' : null, + width: widget.width, empty: widget.empty, change: (value) { + try { + 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.save!(widget.dash.id); + } + }); + } catch (e) { widget.item.port = null; } + var el = widget.dash.getElement(widget.elementID); + el!.element = widget.item as dynamic; + }), + SubTextInputWidget(subkey: "PAT", initialValue: widget.item.PAT != null ? '${widget.item.PAT}' : null, + width: widget.width, empty: widget.empty, change: (value) { + try { + 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.save!(widget.dash.id); + } + }); + } catch (e) { widget.item.PAT = null; } + var el = widget.dash.getElement(widget.elementID); + el!.element = widget.item as dynamic; + }), + SubTextInputWidget(subkey: "reverse path", initialValue: widget.item.PAT != null ? '${widget.item.PAT}' : null, + width: widget.width, empty: widget.empty, change: (value) { + try { + widget.item.path = value; + Future.delayed(const Duration(seconds: 2), () { + if (widget.item.path == value) { widget.dash.save!(widget.dash.id); } + }); + } catch (e) { widget.item.path = null; } + var el = widget.dash.getElement(widget.elementID); + el!.element = widget.item as dynamic; + }), + ]); + } +} \ No newline at end of file diff --git a/lib/widgets/forms/sub_keys_forms.dart b/lib/widgets/forms/sub_keys_forms.dart new file mode 100644 index 0000000..89d033e --- /dev/null +++ b/lib/widgets/forms/sub_keys_forms.dart @@ -0,0 +1,61 @@ + +import 'package:flutter/material.dart'; +import 'package:flutter/widgets.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'; + +class SubKeysMapFormsWidget extends StatefulWidget { + FlowData item; + Dashboard dash; + String varKey = ""; + bool empty = false; + bool isInput = true; + String elementID = ""; + String categoryKey = ""; + List graphItems = []; + SubKeysMapFormsWidget({ super.key, required this.dash, required this.isInput, + this.empty = false, required this.item, required this.elementID, required this.graphItems, + required this.categoryKey, required this.varKey }); + @override SubKeysMapFormsWidgetState createState() => SubKeysMapFormsWidgetState(); +} +class SubKeysMapFormsWidgetState extends State { + + @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: 200, empty: false, change: (value) {}, initialValue: n, readOnly: true, noLabel: true))); + count++; + } + } + if (save) { + widget.dash.save!(widget.dash.id); + } + if (children.isEmpty) { + return Container(); + } + return Column( children : [ + Container(width: 250, 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), + ]); + } +} \ No newline at end of file diff --git a/lib/widgets/forms/sub_map_forms.dart b/lib/widgets/forms/sub_map_forms.dart new file mode 100644 index 0000000..e05fdf8 --- /dev/null +++ b/lib/widgets/forms/sub_map_forms.dart @@ -0,0 +1,113 @@ + +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 { + String categoryKey = ""; + String varKey = ""; + String elementID = ""; + FlowData item; + Dashboard dash; + bool empty = false; + List forms = []; + SubMapFormsWidget ({ super.key, required this.dash, + 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(Padding( padding: const EdgeInsets.symmetric(horizontal: 15), child: Row( children: [ + SubTextInputWidget(subkey: "key", initialValue: key, width: 91, empty: widget.empty, + change: (value) { + setState(() { + widget.forms[i].key = value; + Future.delayed(const Duration(seconds: 2), () { + widget.dash.save!(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: 90.8, empty: widget.empty, + change: (value) { + Future.delayed(const Duration(seconds: 2), () { + widget.dash.save!(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: 250, padding: const EdgeInsets.only(top: 10), + decoration: const BoxDecoration(border: Border(bottom: BorderSide(color: Colors.grey, width: 1))),), + 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(left: 15, top: 10), + decoration: BoxDecoration(borderRadius: BorderRadius.circular(5), border: Border.all(color: Colors.grey, width: 1)), + width: 150, 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.save!(widget.dash.id); }); + }, child: + Container( margin: const EdgeInsets.only(left: 5, right: 10, 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 new file mode 100644 index 0000000..66aff2b --- /dev/null +++ b/lib/widgets/forms/web_reference_forms.dart @@ -0,0 +1,23 @@ +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: 200, empty: false, change: (value) { + widget.item.protocols = value.split(","); + }, initialValue: widget.item.path, readOnly: true,), + SubTextInputWidget(subkey: "protocol", width: 200, empty: false, change: (value) { + widget.item.protocols = value.split(","); + }, initialValue: widget.item.protocol, readOnly: true,), + SubTextInputWidget(subkey: "type", width: 200, empty: false, change: (value) { + widget.item.protocols = value.split(","); + }, initialValue: widget.item.type, readOnly: true,), + ]); + } +} \ No newline at end of file diff --git a/lib/widgets/inputs/sub_dropdown_input .dart b/lib/widgets/inputs/sub_dropdown_input .dart new file mode 100644 index 0000000..6b7b73b --- /dev/null +++ b/lib/widgets/inputs/sub_dropdown_input .dart @@ -0,0 +1,40 @@ +import 'package:flutter/material.dart'; + +class SubDropdownInputWidget extends StatefulWidget { + String subkey; + double width; + bool empty; + 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); + @override SubDropdownInputWidgetState createState() => SubDropdownInputWidgetState(); +} +class SubDropdownInputWidgetState extends State { + + @override Widget build(BuildContext context) { + return Row( mainAxisAlignment: MainAxisAlignment.center, children: [ Tooltip( message: widget.subkey, + child: Container( margin: EdgeInsets.only(top: widget.empty ? 0 : 15), + width: widget.width, height: 30, + child: DropdownButtonFormField( + items: widget.dropdownMenuEntries, + onChanged: widget.change, + style: const TextStyle(fontSize: 12), + decoration: InputDecoration( + hintText: "select ${widget.subkey}...", + fillColor: Colors.white, + filled: true, + labelText: widget.subkey, + alignLabelWithHint: false, + errorStyle: const TextStyle(fontSize: 0), + hintStyle: const TextStyle(fontSize: 10), + labelStyle: const TextStyle(fontSize: 10), + floatingLabelBehavior: FloatingLabelBehavior.always, + enabledBorder: const OutlineInputBorder(borderSide: BorderSide(color: Colors.grey)), + border: const OutlineInputBorder(borderSide: BorderSide(color: Colors.grey)), + contentPadding: const EdgeInsets.symmetric(horizontal: 10, vertical: 5), + ), + ))), + ]); + } +} \ No newline at end of file diff --git a/lib/widgets/inputs/sub_text_input.dart b/lib/widgets/inputs/sub_text_input.dart new file mode 100644 index 0000000..b91e2fc --- /dev/null +++ b/lib/widgets/inputs/sub_text_input.dart @@ -0,0 +1,62 @@ +import 'package:alert_banner/exports.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:oc_front/widgets/dialog/alert.dart'; + +class SubTextInputWidget extends StatefulWidget { + String subkey; + String? initialValue; + double width; + bool empty; + bool noLabel; + bool readOnly = false; + void Function(String) change = (value) {}; + SubTextInputWidget ({ Key? key, + required this.subkey, this.readOnly = false, this.noLabel = false, + this.initialValue, required this.width, required this.empty, required this.change }): + super(key: key); + @override SubTextInputWidgetState createState() => SubTextInputWidgetState(); +} +class SubTextInputWidgetState extends State { + + @override Widget build(BuildContext context) { + if (widget.readOnly && widget.initialValue == null) { + return Container(); + } + return Row( mainAxisAlignment: MainAxisAlignment.center, children: [ Tooltip( message: widget.subkey, + child: Container( margin: EdgeInsets.only(top: widget.empty ? 0 : 15), + width: widget.width - (widget.readOnly ? 40 : 0), height: 30, + child: TextFormField( textAlign: TextAlign.start, + enabled: !widget.readOnly, + readOnly: widget.readOnly, + initialValue: widget.initialValue, + onChanged: widget.change, + style: const TextStyle(fontSize: 12), + decoration: InputDecoration( + hintText: "enter ${widget.subkey}...", + fillColor: Colors.white, + filled: true, + labelText: widget.noLabel ? "" : widget.subkey, + alignLabelWithHint: false, + errorStyle: const TextStyle(fontSize: 0), + hintStyle: const TextStyle(fontSize: 10), + labelStyle: const TextStyle(fontSize: 10), + floatingLabelBehavior: FloatingLabelBehavior.always, + enabledBorder: const OutlineInputBorder(borderSide: BorderSide(color: Colors.grey)), + border: const OutlineInputBorder(borderSide: BorderSide(color: Colors.grey)), + contentPadding: const EdgeInsets.symmetric(horizontal: 10, vertical: 5), + ), + ))), + widget.readOnly ? InkWell( onTap: () { + Clipboard.setData(ClipboardData(text: 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), + decoration: BoxDecoration(borderRadius: BorderRadius.circular(5), border: Border.all(color: Colors.grey, width: 1)), + width: 35, height: 30, + child: const Row( mainAxisAlignment: MainAxisAlignment.center, + children: [ Icon(Icons.copy, color: Colors.black, size: 15,) ]), + )) : Container() + ]); + } +} \ No newline at end of file diff --git a/lib/widgets/items/items_details/data_item.dart b/lib/widgets/items/items_details/data_item.dart index 03c3326..762531f 100644 --- a/lib/widgets/items/items_details/data_item.dart +++ b/lib/widgets/items/items_details/data_item.dart @@ -10,15 +10,15 @@ class DataItemWidget extends StatefulWidget { class DataItemWidgetState extends State { @override Widget build(BuildContext context) { return Wrap( children: [ - Padding(padding: EdgeInsets.symmetric(vertical: 20, horizontal: 100), - child: Text("type : ${widget.item.dataType ?? "unknown type"}", - style: TextStyle(fontSize: 15, fontWeight: FontWeight.w600))), - Padding(padding: EdgeInsets.symmetric(horizontal: 100, vertical: 20), + 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: TextStyle(fontSize: 15, fontWeight: FontWeight.w600))), - Padding(padding: EdgeInsets.symmetric(horizontal: 100, vertical: 20), + 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: TextStyle(fontSize: 15, fontWeight: FontWeight.w600))), + 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 308383f..241c01b 100644 --- a/lib/widgets/sheduler_items/schedule.dart +++ b/lib/widgets/sheduler_items/schedule.dart @@ -58,7 +58,7 @@ class ScheduleWidgetState extends State { borderRadius: BorderRadius.circular(4), ), ), - SizedBox( width: (menuSize - 140), + SizedBox( width: (menuSize - 160), child: Padding( padding: const EdgeInsets.only(left: 20), child: Text(wf.name?.toUpperCase() ?? "", overflow: TextOverflow.ellipsis, @@ -67,7 +67,7 @@ class ScheduleWidgetState extends State { SizedBox( child: Padding( padding: const EdgeInsets.only(left: 20), - child: Text("${d2.hour > 9 ? d2.hour : "0${d2.hour}"}:${d2.minute > 9 ? d2.minute : "0${d2.minute}"}", overflow: TextOverflow.ellipsis, + child: Text("${d2.hour > 9 ? d2.hour : "0${d2.hour}"}:${d2.minute > 9 ? d2.minute : "0${d2.minute}"}:${d2.second > 9 ? d2.second : "0${d2.second}"}", overflow: TextOverflow.ellipsis, style: const TextStyle(fontSize: 15, color: Colors.grey, fontWeight: FontWeight.w500)))) ]) diff --git a/lib/widgets/sheduler_items/scheduler_calendar.dart b/lib/widgets/sheduler_items/scheduler_calendar.dart index 3a3367c..ad6f0dc 100644 --- a/lib/widgets/sheduler_items/scheduler_calendar.dart +++ b/lib/widgets/sheduler_items/scheduler_calendar.dart @@ -40,7 +40,7 @@ class SchedulerCalendarWidgetState extends State { lastDay: widget.end, focusedDay: widget.focusedDay, calendarStyle: const CalendarStyle( - markersMaxCount: 3, + markersMaxCount: 2, markersAnchor: 0, markersAlignment: Alignment.topCenter ), @@ -75,7 +75,7 @@ class SchedulerCalendarWidgetState extends State { } }), child: Container( - margin: const EdgeInsets.only(bottom: 2.5, top: 25), + margin: const EdgeInsets.only(bottom: 2.5), padding: const EdgeInsets.symmetric(horizontal: 10.0, vertical: 2), decoration: BoxDecoration( borderRadius: BorderRadius.circular(4), @@ -87,7 +87,7 @@ class SchedulerCalendarWidgetState extends State { return Column(mainAxisAlignment: MainAxisAlignment.center, children: children); }, defaultBuilder: (context, date, events) => Container( - alignment: Alignment.center, + alignment: !isEvent(widget.data, date) ? Alignment.center : Alignment.topCenter, margin:const EdgeInsets.all(2.0), decoration: BoxDecoration( border: Border.all(color: Colors.grey.shade300), @@ -96,7 +96,8 @@ class SchedulerCalendarWidgetState extends State { child: !isEvent(widget.data, date) ? Text( date.day.toString(), style: const TextStyle(color: Colors.grey), - ) : Column( children: [ Container( padding: const EdgeInsets.symmetric(vertical: 5), child: Text( + ) : Column( + children: [ Container( padding: const EdgeInsets.symmetric(vertical: 5), child: Text( date.day.toString(), style: const TextStyle(color: Colors.grey), )) ]) @@ -115,7 +116,7 @@ class SchedulerCalendarWidgetState extends State { ), ), selectedBuilder: (context, date, events) => Container( - alignment: Alignment.center, + alignment: !isEvent(widget.data, date) ? Alignment.center : Alignment.topCenter, margin: const EdgeInsets.all(2.0), decoration: BoxDecoration( border: Border.all(color: const Color.fromRGBO(38, 166, 154, 1), width: 2), @@ -131,7 +132,7 @@ class SchedulerCalendarWidgetState extends State { ), todayBuilder: (context, date, events) => Container( margin: const EdgeInsets.all(2.0), - alignment: Alignment.center, + alignment: !isEvent(widget.data, date) ? Alignment.center : Alignment.topCenter, decoration: BoxDecoration( color: const Color.fromRGBO(38, 166, 154, .5), shape: BoxShape.rectangle, @@ -157,7 +158,7 @@ class SchedulerCalendarWidgetState extends State { eventLoader: (day) { return widget.data[day.toIso8601String()] != null ? widget.data[day.toIso8601String()]!.map((e) { DateTime dateTime = DateTime.parse(e.executionData!); - return Event("[${dateTime.hour > 9 ? dateTime.hour : "0${dateTime.hour}"}:${dateTime.minute > 9 ? dateTime.minute : "0${dateTime.minute}"}] ${e.name}", + 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 ); }).toList() : []; }, diff --git a/lib/widgets/sheduler_items/scheduler_item.dart b/lib/widgets/sheduler_items/scheduler_item.dart index 644f5b2..dd9884d 100644 --- a/lib/widgets/sheduler_items/scheduler_item.dart +++ b/lib/widgets/sheduler_items/scheduler_item.dart @@ -56,24 +56,24 @@ class SchedulerItemWidgetState extends State { overflow: TextOverflow.ellipsis, textAlign: TextAlign.center, style: const TextStyle( color: Colors.white)) ), - SizedBox( width: (widget.width - 312) / 2, + SizedBox( width: (widget.width - 330) / 2, child: Padding( padding: const EdgeInsets.only(left: 20), child: Text(ev.name?.toUpperCase() ?? "", overflow: TextOverflow.ellipsis, style: const TextStyle(color: Colors.black, fontWeight: FontWeight.w500)), )), - SizedBox( width: (widget.width - 312) / 2, + SizedBox( width: (widget.width - 340) / 2, child: Padding( padding: const EdgeInsets.only(left: 20), child: Container( padding: const EdgeInsets.symmetric(horizontal: 20), - child: Text(d3 != null ? "killed at ${d3.day}/${d3.month}/${d3.year} ${d3.hour}:${d3.minute}" + child: Text(d3 != null ? "killed at ${d3.day}/${d3.month}/${d3.year} ${d3.hour}:${d3.minute}:${d3.second}" : "infinite run till process end", overflow: TextOverflow.ellipsis, style: const TextStyle( fontSize: 12, color: Colors.grey, fontWeight: FontWeight.w500))), )), SizedBox( child: Padding( padding: const EdgeInsets.only(left: 20), - child: Text("${d2.hour > 9 ? d2.hour : "0${d2.hour}"}:${d2.minute > 9 ? d2.minute : "0${d2.minute}"}", overflow: TextOverflow.ellipsis, + child: Text("${d2.hour > 9 ? d2.hour : "0${d2.hour}"}:${d2.minute > 9 ? d2.minute : "0${d2.minute}"}:${d2.second > 9 ? d2.second : "0${d2.second}"}", overflow: TextOverflow.ellipsis, style: const TextStyle(fontSize: 25, color: Colors.grey, fontWeight: FontWeight.w500)))) ]) @@ -111,7 +111,7 @@ class SchedulerItemWidgetState extends State { }); return Container( alignment: children.isNotEmpty ? Alignment.topLeft : Alignment.center, - color: children.isNotEmpty ? Colors.transparent : Colors.grey.shade300, + color: children.isNotEmpty ? Colors.transparent : Colors.white, width: children.isNotEmpty ? MediaQuery.of(context).size.width : null, height: MediaQuery.of(context).size.height - HeaderConstants.height - 50, child: children.isNotEmpty ? SingleChildScrollView( child: Column( children: children)) : const Text("NO DATA FOUND", style: TextStyle(color: Colors.grey, fontSize: 30)) diff --git a/library/flutter_flow_chart/lib/src/dashboard.dart b/library/flutter_flow_chart/lib/src/dashboard.dart index 4a4a4e0..d75c958 100755 --- a/library/flutter_flow_chart/lib/src/dashboard.dart +++ b/library/flutter_flow_chart/lib/src/dashboard.dart @@ -23,7 +23,6 @@ typedef ConnectionListener = void Function( /// It notifies changes to [FlowChart] // class Dashboard extends ChangeNotifier { - bool shouldSave = true; GlobalKey selectedMenuKey = GlobalKey(); GlobalKey selectedLeftMenuKey = GlobalKey(); GlobalKey chartMenuKey = GlobalKey(); @@ -46,10 +45,11 @@ class Dashboard extends ChangeNotifier { double defaultBackWidth = 10; double defaultForwardWidth = 10; Future Function(String? id)? save; - List Function(FlowData? obj)? infoItemWidget; + List Function(FlowData? obj, String id)? infoItemWidget; List Function()? infoWidget; FlowData? Function(Map json)? transformToData; bool addChange = false; + bool shouldSave = true; /// Dashboard({ this.id, @@ -175,8 +175,7 @@ class Dashboard extends ChangeNotifier { /// The current elements in the dashboard List elements; - List get elementSelected => - elements.where((element) => element.isSelected).toList(); + List get elementSelected => elements.where((element) => element.isSelected).toList(); Offset _dashboardPosition; @@ -202,15 +201,11 @@ class Dashboard extends ChangeNotifier { /// bool blockDefaultZoomGestures; - - /// minimum zoom factor allowed - /// default is 0.25 - /// setting it to 1 will prevent zooming out - /// setting it to 0 will remove the limit double minimumZoomFactor; - final List _connectionListeners = []; + + Map serialize() { Map d = {}; Map graph = {}; @@ -264,7 +259,6 @@ class Dashboard extends ChangeNotifier { } catch (e) { print(e); } elements.add(flow); } - print("DASH " + name); selectedMenuKey.currentState?.setState(() { }); chartMenuKey.currentState?.setState(() { }); addToHistory(); @@ -292,6 +286,10 @@ 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(); + } + void addArrows(ArrowPainter f) { arrows.add(f); addChange = true; @@ -385,7 +383,10 @@ class Dashboard extends ChangeNotifier { } FlowElement? getElement(String id, {bool notify = true}) { - try { return elements.firstWhere((element) => element.id == id); } + try { return elements.firstWhere((element) { + print(element.id + " - " + id); + return element.id == id; + }); } catch (e) { return null; } } diff --git a/library/flutter_flow_chart/lib/src/flow_chart.dart b/library/flutter_flow_chart/lib/src/flow_chart.dart index a432d17..18f827d 100755 --- a/library/flutter_flow_chart/lib/src/flow_chart.dart +++ b/library/flutter_flow_chart/lib/src/flow_chart.dart @@ -22,6 +22,8 @@ abstract class FlowData { double? getWidth(); double? getHeight(); + Map setVariable(List keys, dynamic value, Map map); + dynamic getVariable(List keys, Map map); Map serialize(); FlowData deserialize(Map data); } @@ -344,7 +346,7 @@ class FlowChartState extends State { focusNode: node, onKeyEvent: (event) { bool change = false; - if ((event is KeyDownEvent || event is KeyRepeatEvent) && event.logicalKey == LogicalKeyboardKey.arrowUp) { + /*if ((event is KeyDownEvent || event is KeyRepeatEvent) && event.logicalKey == LogicalKeyboardKey.arrowUp) { change = true; for (var el in widget.dashboard.elements) { if (el.isSelected) { @@ -375,7 +377,7 @@ class FlowChartState extends State { el.position = Offset(el.position.dx + 10, el.position.dy); } } - } + }*/ if (event is KeyDownEvent && event.logicalKey == LogicalKeyboardKey.add) { change = true; 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 027e3fa..d21b1c1 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 @@ -20,14 +20,13 @@ class FlowChartSelectedMenuState extends State { width: 250, height: widget.height, color: Colors.grey.shade300, - child: SingleChildScrollView( child: Column( children: [ ...widget.dashboard.infoItemWidget != null ? - widget.dashboard.infoItemWidget!(widget.dashboard.elementSelected.first.element) : [], + child: Column( children: [ ...widget.dashboard.infoItemWidget != null ? + widget.dashboard.infoItemWidget!(widget.dashboard.elementSelected.first.element, widget.dashboard.elementSelected.first.id) : [], widget.dashboard.arrowsSelected.isNotEmpty || widget.dashboard.elementSelected.isNotEmpty ? Container( width: 250, margin: EdgeInsets.only(top: 15), decoration: BoxDecoration(border: Border( - top: BorderSide(color: Colors.grey, width: 1), - bottom: BorderSide(color: Colors.grey, width: 1))), + top: BorderSide(color: Colors.grey, width: 1))), child: Column(crossAxisAlignment: CrossAxisAlignment.center, children: [ Tooltip( message: "remove", child: InkWell( mouseCursor: SystemMouseCursors.click, @@ -67,7 +66,7 @@ class FlowChartSelectedMenuState extends State { ]) ) : Container() ]) - )); + ); } else if (widget.isDashboardInfo && widget.dashboard.infoWidget != null) { w = Container( width: 250, @@ -533,7 +532,7 @@ class FlowChartSelectedMenuState extends State { }); }, child: Container( margin: EdgeInsets.all(10), decoration: BoxDecoration(borderRadius: BorderRadius.circular(5), border: Border.all(color: Colors.black, width: 1)), - width: 140, height: 30, + width: 200, height: 30, child: Icon(Icons.delete_outline, color: Colors.black), )) ), @@ -547,9 +546,9 @@ class FlowChartSelectedMenuState extends State { Future.delayed(Duration(milliseconds: 100), () { widget.dashboard.chartKey.currentState?.setState(() { }); }); - }, child: Container( margin: EdgeInsets.all(10), + }, child: Container( margin: EdgeInsets.only(left: 10, right: 10, bottom: 10), decoration: BoxDecoration(borderRadius: BorderRadius.circular(5), border: Border.all(color: Colors.black, width: 1)), - width: 140, height: 30, + width: 200, height: 30, child: Icon(Icons.copy, color: Colors.black), )) ), 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 8cad41b..8baa579 100755 --- a/library/flutter_flow_chart/lib/src/ui/draw_arrow.dart +++ b/library/flutter_flow_chart/lib/src/ui/draw_arrow.dart @@ -420,9 +420,7 @@ class ArrowInfoWidgetState extends State { /// [ArrowParams.startArrowPosition] and /// [ArrowParams.endArrowPosition] alignment. class ArrowPainter extends CustomPainter { - String fromID; - String toID; - bool isSelected = false; + /// ArrowPainter({ this.elementIndex, @@ -439,12 +437,13 @@ class ArrowPainter extends CustomPainter { /// ArrowParams params; /// - Offset from; - int? elementIndex; - int? connIndex; - /// + String toID; + String fromID; Offset to; - + Offset from; + int? connIndex; + int? elementIndex; + bool isSelected = false; /// Path path = Path(); Path dashed = Path(); diff --git a/local_run.sh b/local_run.sh new file mode 100755 index 0000000..0ad8c1e --- /dev/null +++ b/local_run.sh @@ -0,0 +1,11 @@ +#!/bin/bash + +WORKSPACE_HOST='http://localhost:8089/oc' +WORKFLOW_HOST='http://localhost:8088/oc' +ITEM_HOST='http://localhost:8087/oc' +SCHEDULER_HOST='http://localhost:8090/oc' +LOGS_HOST='http://localhost:3100' +PEER_HOST='http://localhost:8091/oc' +COLLABORATIVE_AREA_HOST='http://localhost:8094/oc' + +flutter run -d linux --dart-define=WORKSPACE_HOST=$WORKSPACE_HOST --dart-define=WORKFLOW_HOST=$WORKFLOW_HOST --dart-define=PEER_HOST=$PEER_HOST --dart-define=COLLABORATIVE_AREA_HOST=$COLLABORATIVE_AREA_HOST --dart-define=SCHEDULER_HOST=$SCHEDULER_HOST --dart-define=LOGS_HOST=$LOGS_HOST --dart-define=ITEM_HOST=$ITEM_HOST \ No newline at end of file