Latest Front with debug
This commit is contained in:
		| @@ -14,6 +14,7 @@ class WorkSpaceItem { | ||||
| } | ||||
|  | ||||
| class SharedWorkspaceLocal { | ||||
|   static String? current; | ||||
|   static Map<String, SharedWorkspace> workspaces = {}; | ||||
|   static final SharedService _service = SharedService(); | ||||
|  | ||||
| @@ -23,7 +24,6 @@ class SharedWorkspaceLocal { | ||||
|         var vals = value.data!.values; | ||||
|         for (var element in vals) { | ||||
|           var ws = SharedWorkspace().deserialize(element); | ||||
|           print(element); | ||||
|           if (ws.id == null) { continue; } | ||||
|           workspaces[ws.id!] = ws; | ||||
|         } | ||||
|   | ||||
| @@ -1,6 +1,7 @@ | ||||
| import 'package:flutter/material.dart'; | ||||
| import 'package:flutter_flow_chart/flutter_flow_chart.dart'; | ||||
| import 'package:oc_front/core/sections/end_drawer.dart'; | ||||
| import 'package:oc_front/models/response.dart'; | ||||
| import 'package:oc_front/models/search.dart'; | ||||
| import 'package:oc_front/models/workspace.dart'; | ||||
| import 'package:oc_front/core/services/specialized_services/workspace_service.dart'; | ||||
| @@ -34,14 +35,14 @@ class WorkspaceLocal { | ||||
|             _service.put(context, ws.id!, { "active" : true }, {}); | ||||
|           } | ||||
|           if (ws.active == true && changeCurrent) { | ||||
|             print(ws.serialize()); | ||||
|             current = ws.id; | ||||
|           } | ||||
|           fill();       | ||||
|         } | ||||
|       } else { | ||||
|         WorkspaceLocal.createWorkspace("main", context); | ||||
|         WorkspaceLocal.createWorkspace("main", null); | ||||
|       } | ||||
|       print("qsdqsd $current"); | ||||
|     }); | ||||
|   } | ||||
|  | ||||
| @@ -83,7 +84,7 @@ class WorkspaceLocal { | ||||
|  | ||||
|   static Future<void> createWorkspace(String name, BuildContext? context) async { | ||||
|     Workspace n = Workspace(name: name); | ||||
|     await _service.post(context, n.serialize(), {}).then((value) { | ||||
|     await _service.post(null, n.serialize(), {}).then((value) { | ||||
|       if (value.data != null) { | ||||
|         workspaces[value.data!.id!] = value.data!; | ||||
|         current = value.data!.id; | ||||
| @@ -97,11 +98,12 @@ class WorkspaceLocal { | ||||
|   } | ||||
|  | ||||
|   static void changeWorkspaceByName(String name) { | ||||
|     var id = workspaces.entries.firstWhere((element) => element.value.name == "${name}_workspace").key; | ||||
|     var id = workspaces.entries.firstWhere((element) => element.value.name == "${name}_workspace").key;   | ||||
|     changeWorkspace(id); | ||||
|   } | ||||
|  | ||||
|   static void changeWorkspace(String id) { | ||||
|     print("WORKSPACES ID $id"); | ||||
|     _service.put(null, id, { "active" : true }, {}); | ||||
|     current = id; | ||||
|     fill(); | ||||
| @@ -118,6 +120,25 @@ class WorkspaceLocal { | ||||
|     } | ||||
|     return res; | ||||
|   } | ||||
|  | ||||
|   static List<Shallow> getWorkspacesShallow() { | ||||
|     List<Shallow> res = []; | ||||
|     for (var element in workspaces.values) { | ||||
|       res.add(Shallow(id: element.id ?? "", name: element.name ?? "")); | ||||
|     } | ||||
|     return res; | ||||
|   } | ||||
|  | ||||
|   static List<AbstractItem> byWorkspace(String id) { | ||||
|     List<AbstractItem<FlowData>> d = []; | ||||
|     var w = workspaces[id]!; | ||||
|     d = [ ...d, ...w.datas.where((element) => !d.map( (d2) => d2.id).contains(element.id)) ]; | ||||
|     d = [ ...d, ...w.datacenters.where((element) => !d.map( (d2) => d2.id).contains(element.id)) ]; | ||||
|     d = [ ...d, ...w.processings.where((element) => !d.map( (d2) => d2.id).contains(element.id)) ]; | ||||
|     d = [ ...d, ...w.storages.where((element) => !d.map( (d2) => d2.id).contains(element.id)) ]; | ||||
|     d = [ ...d, ...w.workflows.where((element) => !d.map( (d2) => d2.id).contains(element.id)) ]; | ||||
|     return d; | ||||
|   } | ||||
|    | ||||
|   static List<AbstractItem> byTopic(String topic, bool all) { | ||||
|     if (all) { | ||||
|   | ||||
| @@ -1,11 +1,14 @@ | ||||
| import 'package:flutter/material.dart'; | ||||
| import 'package:oc_front/core/models/shared_workspace_local.dart'; | ||||
| import 'package:oc_front/core/services/specialized_services/shared_service.dart'; | ||||
| import 'package:oc_front/core/services/specialized_services/workspace_service.dart'; | ||||
| import 'package:oc_front/models/response.dart'; | ||||
| import 'package:oc_front/models/search.dart'; | ||||
| import 'package:oc_front/pages/catalog.dart'; | ||||
| import 'package:oc_front/core/models/workspace_local.dart'; | ||||
| import 'package:oc_front/pages/shared.dart'; | ||||
| import 'package:oc_front/widgets/items/item_row.dart'; | ||||
| import 'package:oc_front/widgets/menu_clipper/shared_workspace_menu.dart'; | ||||
| import 'package:oc_front/widgets/menu_clipper/workspace_menu.dart'; | ||||
| import 'package:oc_front/widgets/inputs/shallow_dropdown_input.dart'; | ||||
|  | ||||
| GlobalKey<EndDrawerWidgetState> endDrawerKey = GlobalKey<EndDrawerWidgetState>(); | ||||
| class EndDrawerWidget extends StatefulWidget { | ||||
| @@ -17,8 +20,6 @@ class EndDrawerWidgetState extends State<EndDrawerWidget> { | ||||
|   @override Widget build(BuildContext context) { | ||||
|     List<ItemRowWidget> itemRows = WorkspaceLocal.items.map( | ||||
|       (e) => ItemRowWidget(contextWidth: 400, item: e, keys: [endDrawerKey, CatalogFactory.key],)).toList(); | ||||
|     print(WorkspaceLocal.workspaces[WorkspaceLocal.current]!.shared); | ||||
|     print(SharedWorkspaceLocal.workspaces); | ||||
|     return Stack( children: [  | ||||
|       Container(  | ||||
|         color: Colors.white, | ||||
| @@ -38,7 +39,19 @@ class EndDrawerWidgetState extends State<EndDrawerWidget> { | ||||
|                  | ||||
|               ), | ||||
|             ), | ||||
|             MenuWorkspaceWidget(simpliest: true, width: 400), | ||||
|             ShallowDropdownInputWidget( | ||||
|                 current: WorkspaceLocal.current, | ||||
|                 width: 400, | ||||
|                 all: () async => WorkspaceLocal.getWorkspacesShallow(), | ||||
|                 canRemove: (p0) => p0 != null, | ||||
|                 remove: (p0) async { | ||||
|                   await WorkspaceService().delete(context, p0, {}).then( (e) => WorkspaceLocal.deleteWorkspace(p0)); | ||||
|                 }, | ||||
|                 type: SharedWorkspaceType.workspace, | ||||
|                 change: (String? change) { | ||||
|                   WorkspaceLocal.changeWorkspace(change.toString()); | ||||
|                 } | ||||
|             ), | ||||
|             Column( children: [ | ||||
|             itemRows.isEmpty ? Container( height: MediaQuery.of(context).size.height - 100,  | ||||
|               color: Colors.grey.shade300, | ||||
| @@ -51,12 +64,29 @@ class EndDrawerWidgetState extends State<EndDrawerWidget> { | ||||
|             ]) | ||||
|           ]) | ||||
|         ),  | ||||
|       Positioned( bottom: 0, left: 0,  | ||||
|         child: SharedMenuWorkspaceWidget( width: 400,  | ||||
|         excluded: const [], | ||||
|         before: WorkspaceLocal.workspaces[WorkspaceLocal.current]!.shared, | ||||
|         selected: WorkspaceLocal.workspaces[WorkspaceLocal.current]!.shared, | ||||
|         reverse: itemRows.isEmpty, contextID: WorkspaceLocal.current ?? "",) ) | ||||
|       itemRows.isEmpty ? Container() : Positioned( bottom: 0, left: 0,  | ||||
|         child: ShallowDropdownInputWidget( | ||||
|           type: SharedWorkspaceType.workspace, | ||||
|             all: () async => SharedWorkspaceLocal.workspaces.values.map(  | ||||
|               (e) => Shallow(id: e.id ?? "", name: e.name ?? "") ).toList(), | ||||
|             current: WorkspaceLocal.workspaces[WorkspaceLocal.current]?.shared, | ||||
|             width: 400, | ||||
|             filled:  Colors.grey.shade300, | ||||
|             hintColor: Colors.grey, | ||||
|             color: Colors.black, | ||||
|             canLoad: (String? change) => SharedWorkspaceLocal.workspaces[change] == null  | ||||
|               || !SharedWorkspaceLocal.workspaces[change]!.workspaces.map( (e) => e.id ).contains(WorkspaceLocal.current), | ||||
|             canRemove: (String? change) => SharedWorkspaceLocal.workspaces[change] == null  | ||||
|             || SharedWorkspaceLocal.workspaces[change]!.workspaces.map( (e) => e.id ).contains(WorkspaceLocal.current),  | ||||
|             load: (String val) async { | ||||
|               await SharedService().addWorkspace(context, val, WorkspaceLocal.current ?? ""); | ||||
|               SharedWorkspaceLocal.init(context, false); | ||||
|             }, | ||||
|             remove: (String val) async { | ||||
|               await SharedService().removeWorkspace(context, val, WorkspaceLocal.current ?? ""); | ||||
|               SharedWorkspaceLocal.init(context, false); | ||||
|             }) | ||||
|           ) | ||||
|       ] | ||||
|     ); | ||||
|   } | ||||
|   | ||||
| @@ -2,27 +2,40 @@ import 'package:flutter/material.dart'; | ||||
| import 'package:oc_front/core/sections/header/menu.dart'; | ||||
| import 'package:oc_front/core/sections/header/search.dart'; | ||||
| import 'package:oc_front/core/services/router.dart'; | ||||
| import 'package:oc_front/widgets/menu_clipper/clipper_menu.dart'; | ||||
| import 'package:oc_front/widgets/menus/clipper_menu.dart'; | ||||
|  | ||||
| class HeaderConstants { | ||||
|   static final List<RouterItem> noHeader = [ | ||||
|     AppRouter.workflowItem, | ||||
|     AppRouter.workflowIDItem, | ||||
|   ]; | ||||
|   static HeaderWidgetState? headerWidget; | ||||
|   static double height = 200; | ||||
|   static String? title; | ||||
|   static String? description; | ||||
|  | ||||
|   static setTitle(String? v) { | ||||
|     title = v; | ||||
|     HeaderConstants.headerWidget?.setState(() {}); | ||||
|   } | ||||
|  | ||||
|   static setDescription(String? v) { | ||||
|     description = v; | ||||
|     HeaderConstants.headerWidget?.setState(() {}); | ||||
|   } | ||||
|  | ||||
|   static bool isNoHeader(String route) { | ||||
|     return noHeader.where((element) => element.route == route).isNotEmpty; | ||||
|   } | ||||
| } | ||||
|  | ||||
| GlobalKey<HeaderWidgetState> headerWidgetKey = GlobalKey<HeaderWidgetState>(); | ||||
| class HeaderWidget extends StatefulWidget { | ||||
|   HeaderWidget () : super(key: headerWidgetKey); | ||||
|   HeaderWidget () : super(key: null); | ||||
|   @override HeaderWidgetState createState() => HeaderWidgetState(); | ||||
| } | ||||
| class HeaderWidgetState extends State<HeaderWidget> { | ||||
|   @override Widget build(BuildContext context) { | ||||
|     headerWidgetKey = GlobalKey<HeaderWidgetState>(); | ||||
|     HeaderConstants.headerWidget = this; | ||||
|     headerMenuKey.currentState?.closeMenu(); | ||||
|     HeaderConstants.height = HeaderConstants.isNoHeader(AppRouter.currentRoute.route) ? 50 : 200; | ||||
|     return Column( children: [ | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| import 'package:oc_front/main.dart'; | ||||
| import 'package:flutter/material.dart'; | ||||
| import 'package:oc_front/widgets/menu_clipper/clipper_menu.dart'; | ||||
| import 'package:oc_front/widgets/menus/clipper_menu.dart'; | ||||
| import 'package:oc_front/widgets/dialog/login.dart'; | ||||
|  | ||||
| class HeaderMenuWidget extends StatefulWidget{ | ||||
| @@ -17,8 +17,6 @@ class HeaderMenuWidgetState extends State<HeaderMenuWidget> { | ||||
|         ), | ||||
|         child: Padding(padding: const EdgeInsets.only(top: 5, bottom: 5, left: 50, right: 50),  | ||||
|           child: Stack(children: [ | ||||
|             /*...(searchWidgetKey.currentState == null ? [Positioned( left: -20, top: -5, | ||||
|               child: SvgPicture.asset("assets/images/icon.svg", height: 70, semanticsLabel: 'OpenCloud Logo'))] : []),*/ | ||||
|             Row(crossAxisAlignment: CrossAxisAlignment.stretch,  | ||||
|             mainAxisAlignment: MainAxisAlignment.end, | ||||
|             children: [ | ||||
|   | ||||
| @@ -1,6 +1,9 @@ | ||||
| import 'package:flutter/material.dart'; | ||||
| import 'package:flutter_svg/svg.dart'; | ||||
| import 'package:oc_front/core/sections/header/header.dart'; | ||||
| import 'package:oc_front/core/services/router.dart'; | ||||
| import 'package:oc_front/pages/shared.dart'; | ||||
| import 'package:oc_front/widgets/inputs/shallow_text_input.dart'; | ||||
|  | ||||
| class SearchConstants { | ||||
|   static final Map<String, String?> _searchHost = {}; | ||||
| @@ -34,21 +37,22 @@ class SearchWidgetState extends State<SearchWidget> { | ||||
|               ) | ||||
|             ) | ||||
|           )] : []), | ||||
|           AppRouter.currentRoute.description != null ?  | ||||
|           AppRouter.currentRoute.description != null  | ||||
|           || (AppRouter.currentRoute.route.contains("shared") && HeaderConstants.title != null) ?  | ||||
|             Column(  | ||||
|               crossAxisAlignment: CrossAxisAlignment.start, | ||||
|               mainAxisAlignment: MainAxisAlignment.center, | ||||
|               children: [ | ||||
|                 Text(AppRouter.currentRoute.description!, style: const TextStyle( | ||||
|                 Text(HeaderConstants.title ?? AppRouter.currentRoute.description!, style: const TextStyle( | ||||
|                   color: Color.fromRGBO(38, 166, 154, 1), | ||||
|                   fontSize: 24, | ||||
|                   fontWeight: FontWeight.w600 | ||||
|                 )), | ||||
|                 Row(children: [ | ||||
|                   ...(AppRouter.currentRoute.help == null || AppRouter.currentRoute.help!.isEmpty ? []  | ||||
|                   ...(HeaderConstants.description == null && (AppRouter.currentRoute.help == null || AppRouter.currentRoute.help!.isEmpty) ? []  | ||||
|                     : [ const Padding( padding: EdgeInsets.only(right: 10),  | ||||
|                       child: Icon(Icons.help_outline, color: Colors.grey, size: 20)), | ||||
|                     Text(AppRouter.currentRoute.help ?? "", style: const TextStyle( | ||||
|                     Text(HeaderConstants.description ?? AppRouter.currentRoute.help ?? "", style: const TextStyle( | ||||
|                       color: Colors.grey, | ||||
|                       fontSize: 14, | ||||
|                       fontWeight: FontWeight.w400 | ||||
| @@ -58,58 +62,25 @@ class SearchWidgetState extends State<SearchWidget> { | ||||
|               ], | ||||
|             ) | ||||
|           : Row(  | ||||
|           mainAxisAlignment: MainAxisAlignment.center, | ||||
|           children: [  | ||||
|             Container( | ||||
|               width: MediaQuery.of(context).size.width - 400 > 0 ? MediaQuery.of(context).size.width - 300 - 100 : 200, | ||||
|               height: 50, | ||||
|               color: Colors.white, | ||||
|               child: TextField( | ||||
|                 onChanged: (value) => SearchConstants.set(value), | ||||
|                 decoration: InputDecoration( | ||||
|                   hintText: "Search in ${AppRouter.currentRoute.route}...", | ||||
|                   contentPadding: const EdgeInsets.symmetric(horizontal: 30), | ||||
|                   hintStyle: const TextStyle( | ||||
|                     color: Colors.black, | ||||
|                     fontSize: 14, | ||||
|                     fontWeight: FontWeight.w300 | ||||
|                   ), | ||||
|                   border: InputBorder.none | ||||
|                 ) | ||||
|               ) | ||||
|             ), | ||||
|             Tooltip( | ||||
|               message: 'search', | ||||
|               child: InkWell(  | ||||
|                 onTap: () {  | ||||
|               mainAxisAlignment: MainAxisAlignment.center, | ||||
|               children: [ ShallowTextInputWidget( | ||||
|                 width: MediaQuery.of(context).size.width - 400 > 0 ? MediaQuery.of(context).size.width - 300 - 100 : 200, | ||||
|                 type: SharedWorkspaceType.workspace, | ||||
|                 hint: "search in resources...", | ||||
|                 iconLoad: Icons.search, | ||||
|                 iconRemove: Icons.screen_search_desktop_outlined, | ||||
|                 tooltipLoad: "search", | ||||
|                 tooltipRemove: "distributed search", | ||||
|                 canLoad: (String? str) => str != null && str.isNotEmpty, | ||||
|                 canRemove: (String? str) => str != null && str.isNotEmpty, | ||||
|                 change: (value) => SearchConstants.set(value), | ||||
|                 loadStr: (String val) async { | ||||
|                   AppRouter.currentRoute.factory.search(context);  | ||||
|                 }, | ||||
|                 child: Container( | ||||
|                   width: 50, | ||||
|                   height: 50, | ||||
|                   decoration: BoxDecoration( | ||||
|                     color: Colors.black, | ||||
|                     border: Border(right: BorderSide(color: Colors.white)), | ||||
|                   ),       | ||||
|                   child: const Icon(Icons.search, color: Colors.white) | ||||
|                 ) | ||||
|               ) | ||||
|             ), | ||||
|             Tooltip( | ||||
|               message: 'distributed search', | ||||
|               child: InkWell(  | ||||
|                 onTap: () {  | ||||
|                 remove: (String val) async { | ||||
|                   AppRouter.currentRoute.factory.search(context);  | ||||
|                 }, | ||||
|                 child: Container( | ||||
|                   width: 50, | ||||
|                   height: 50, | ||||
|                   color: Colors.black, | ||||
|                   child: const Icon(Icons.screen_search_desktop_outlined, color: Colors.white) | ||||
|                 ) | ||||
|               ) | ||||
|             ) | ||||
|           ]) | ||||
|           ) ]), | ||||
|         ]; | ||||
|     return Container( | ||||
|       width: MediaQuery.of(context).size.width, | ||||
|   | ||||
| @@ -1,3 +1,4 @@ | ||||
| import 'package:oc_front/core/sections/header/header.dart'; | ||||
| import 'package:oc_front/main.dart'; | ||||
| import 'package:oc_front/pages/abstract_page.dart'; | ||||
| import 'package:oc_front/pages/catalog.dart'; | ||||
| @@ -43,6 +44,10 @@ class RouterItem { | ||||
|     AppRouter.currentRoute = this; | ||||
|     var newPath = "$path"; | ||||
|     for (var arg in args) { newPath = newPath.replaceAll(":$arg", params[arg] ?? ""); } | ||||
|     Future.delayed( const Duration(seconds: 1), () { | ||||
|       HeaderConstants.setTitle(null); | ||||
|       HeaderConstants.setDescription(null); | ||||
|     }); | ||||
|     context.go(newPath);  | ||||
|   } | ||||
| } | ||||
| @@ -50,8 +55,8 @@ class RouterItem { | ||||
| class AppRouter {  | ||||
|   static const String home = "catalog"; | ||||
|   static final RouterItem workflowItem = RouterItem(icon: Icons.rebase_edit, label: "workflow manager", route: "workflow",  | ||||
|       description: "View to select & create new workflow.", help: "Workflow only access to your workspace datas. If a an element of your flow is missing, perhaps means it's missing in workspace.",  | ||||
|       factory: WorkflowFactory()); | ||||
|   static final RouterItem workflowIDItem = RouterItem(description: "", help: "", route: "workflow/:id", factory: WorkflowFactory(), args: ["id"]); | ||||
|   static final RouterItem catalogItem = RouterItem(description: "", help: "", route: "catalog/:id", factory: CatalogItemFactory(), args: ["id"]); | ||||
|   static final RouterItem catalog= RouterItem(icon: Icons.book_outlined, label: "catalog searcher", route: home, factory: CatalogFactory()); | ||||
|  | ||||
| @@ -64,6 +69,7 @@ class AppRouter { | ||||
|       factory: DatacenterFactory()), | ||||
|     RouterItem(icon: Icons.public_outlined, label: "localisations", route: "map", factory: MapFactory()), | ||||
|     RouterItem(icon: Icons.share_rounded, label: "shared spaces", route: "shared", factory: SharedFactory()), | ||||
|     workflowIDItem, | ||||
|     catalogItem, | ||||
|   ]; | ||||
|   static List<String> history = []; | ||||
|   | ||||
| @@ -15,6 +15,7 @@ abstract class AbstractService<T extends SerializerDeserializer> { | ||||
|     return service.get("$subPath$id", true, context); | ||||
|   } | ||||
|   Future<APIResponse<T>> post(BuildContext? context, Map<String, dynamic> body, Map<String, String> params) {  | ||||
|     print("Creating workspace $body"); | ||||
|     return service.post(subPath, body, context); | ||||
|   } | ||||
|   Future<APIResponse<T>> put(BuildContext? context, String id, Map<String, dynamic> body, Map<String, String> params) {  | ||||
|   | ||||
							
								
								
									
										10
									
								
								lib/core/services/specialized_services/peer_service.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								lib/core/services/specialized_services/peer_service.dart
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,10 @@ | ||||
| import 'package:oc_front/core/services/api_service.dart'; | ||||
| import 'package:oc_front/core/services/specialized_services/abstract_service.dart'; | ||||
| import 'package:oc_front/models/shared.dart'; | ||||
|  | ||||
| class PeerService extends AbstractService<Peer> { | ||||
|   @override APIService<Peer> service = APIService<Peer>( | ||||
|     baseURL: const String.fromEnvironment('PEER_HOST', defaultValue: 'http://localhost:8093') | ||||
|   ); | ||||
|   @override String subPath = "/oc/peer/"; | ||||
| } | ||||
| @@ -58,3 +58,17 @@ class RawData extends SerializerDeserializer<RawData> { | ||||
|   @override deserialize(dynamic json) { return RawData(values: json ?? []); } | ||||
|   @override Map<String, dynamic> serialize() => { }; | ||||
| } | ||||
|  | ||||
| abstract class ShallowData { | ||||
|   String getID(); | ||||
|   String getName(); | ||||
| } | ||||
|  | ||||
| class Shallow { | ||||
|   String id; | ||||
|   String name; | ||||
|   Shallow({ | ||||
|     this.id = "", | ||||
|     this.name = "", | ||||
|   }); | ||||
| } | ||||
| @@ -1,5 +1,5 @@ | ||||
| import 'package:flutter/material.dart'; | ||||
| import 'package:oc_front/models/abstract.dart'; | ||||
| import 'package:oc_front/models/response.dart'; | ||||
| import 'package:oc_front/models/workflow.dart'; | ||||
| import 'package:oc_front/models/workspace.dart'; | ||||
|  | ||||
| @@ -35,7 +35,7 @@ class SharedWorkspace extends SerializerDeserializer<SharedWorkspace> { | ||||
|       id: json.containsKey("id") ? json["id"] : null, | ||||
|       name: json.containsKey("name") ? json["name"] : null, | ||||
|       description: json.containsKey("description") ? json["description"] : null, | ||||
|       creatorID: json.containsKey("creator_id") ? json["creator_id"] : null, | ||||
|       creatorID: json.containsKey("peer_id") ? json["peer_id"] : null, | ||||
|       version: json.containsKey("version") ? json["version"] : null, | ||||
|       attributes: json.containsKey("attributes") ? json["attributes"] : {}, | ||||
|       workspaces: json.containsKey("shared_workspaces") ? fromListJson(json["shared_workspaces"], Workspace()) : [], | ||||
| @@ -87,13 +87,16 @@ class Rule extends SerializerDeserializer<Rule> { | ||||
|   }; | ||||
| } | ||||
|  | ||||
| class Peer extends SerializerDeserializer<Peer> { | ||||
| class Peer extends SerializerDeserializer<Peer> implements ShallowData { | ||||
|   String? id; | ||||
|   String? name; | ||||
|  | ||||
|   Peer( | ||||
|       {this.id, | ||||
|       this.name,}); | ||||
|    | ||||
|   @override String getID() => id ?? ""; | ||||
|   @override String getName() => name ?? ""; | ||||
|  | ||||
|   @override | ||||
|   deserialize(dynamic json) { | ||||
|   | ||||
| @@ -4,6 +4,7 @@ import 'package:flutter_flow_chart/flutter_flow_chart.dart'; | ||||
| import 'package:oc_front/core/models/workspace_local.dart'; | ||||
| import 'package:oc_front/models/abstract.dart'; | ||||
| import 'package:oc_front/models/logs.dart'; | ||||
| import 'package:oc_front/models/response.dart'; | ||||
| import 'package:oc_front/models/search.dart'; | ||||
|  | ||||
| class Check extends SerializerDeserializer<Check> { | ||||
| @@ -98,7 +99,7 @@ class WorkflowExecution extends SerializerDeserializer<WorkflowExecution> { | ||||
|  | ||||
| } | ||||
|  | ||||
| class Workflow extends SerializerDeserializer<Workflow> { | ||||
| class Workflow extends SerializerDeserializer<Workflow>  implements ShallowData { | ||||
|   String? id; | ||||
|   String? name; | ||||
|   List<dynamic> data; | ||||
| @@ -125,9 +126,9 @@ class Workflow extends SerializerDeserializer<Workflow> { | ||||
|     this.shared = const [], | ||||
|   }); | ||||
|  | ||||
|   String getID() { | ||||
|     return id ?? ""; | ||||
|   } | ||||
|   @override String getID() => id ?? ""; | ||||
|   @override String getName() => name ?? ""; | ||||
|   @override String getDescription() => ""; | ||||
|  | ||||
|   @override deserialize(dynamic json) { | ||||
|     try { json = json as Map<String, dynamic>; | ||||
| @@ -210,20 +211,24 @@ class Scheduler extends SerializerDeserializer<Scheduler> { | ||||
|     id = j["id"]; | ||||
|     name = j["name"]; | ||||
|     cron = j["cron"]; | ||||
|     mode =j["mode"]; | ||||
|     try { | ||||
|       start = DateTime.parse(j["start"]); | ||||
|       start = j["start"] != null ? DateTime.parse(j["start"]) : DateTime.now().add( const Duration(minutes: 1)).toUtc(); | ||||
|       if (start == DateTime.utc(0)) { | ||||
|         start = DateTime.now().add( const Duration(minutes: 1)).toUtc(); | ||||
|       } | ||||
|       if (j.containsKey("end") && j["end"] != null) { | ||||
|         end = DateTime.parse(j["end"]); | ||||
|       } | ||||
|        | ||||
|     } catch (e) {} | ||||
|     mode = int.parse(j["mode"].toString()); | ||||
|   } | ||||
|   Map<String, dynamic> toDashboard() { | ||||
|     return { | ||||
|       "id": id, | ||||
|       "name": name, | ||||
|       "cron": cron, | ||||
|       "mode": int.parse(mode.toString()), | ||||
|       "mode": mode ?? 1, | ||||
|       "start": start?.toIso8601String(), | ||||
|       "end": end?.toIso8601String(), | ||||
|     }; | ||||
| @@ -241,15 +246,28 @@ class Scheduler extends SerializerDeserializer<Scheduler> { | ||||
|       end: json.containsKey("end") && json["end"] != null ? DateTime.parse(json["end"]) : null, | ||||
|     ); | ||||
|   } | ||||
|   @override Map<String, dynamic> serialize() => { | ||||
|     "id": id, | ||||
|     "name": name, | ||||
|     "cron": cron ?? "", | ||||
|     "mode": int.parse(mode.toString()), | ||||
|     "start": start?.toIso8601String(), | ||||
|     "end": end?.toIso8601String(), | ||||
|   }; | ||||
|   @override Map<String, dynamic> serialize() { | ||||
|     try { | ||||
|       return { | ||||
|         "id": id, | ||||
|         "name": name, | ||||
|         "cron": cron ?? "", | ||||
|         "mode": mode ?? 1, | ||||
|         "start": start?.toIso8601String(), | ||||
|         "end": end?.toIso8601String(), | ||||
|       }; | ||||
|     } catch (e) { | ||||
|       return { | ||||
|         "id": id, | ||||
|         "name": name, | ||||
|         "cron": cron ?? "", | ||||
|         "start": start?.toIso8601String(), | ||||
|         "end": end?.toIso8601String(), | ||||
|       }; | ||||
|     } | ||||
|   } | ||||
| } | ||||
|  | ||||
| class Graph extends SerializerDeserializer<Graph> { | ||||
|   double zoom; | ||||
|   Map<String, GraphItem> items = {}; | ||||
| @@ -505,24 +523,32 @@ class GraphItem extends SerializerDeserializer<GraphItem> { | ||||
|       if (abs.topic == "data") {  | ||||
|         data = DataItem().deserialize(abs.serialize());  | ||||
|         data!.model = ResourceModel().deserialize(j["element"]["resource_model"]); | ||||
|       } | ||||
|       if (abs.topic == "processing") {  | ||||
|       } else if (abs.topic == "processing") {  | ||||
|         processing = ProcessingItem().deserialize(abs.serialize()); | ||||
|         processing!.model = ResourceModel().deserialize(j["element"]["resource_model"]); | ||||
|       } | ||||
|       if (abs.topic == "datacenter") {  | ||||
|       } else if (abs.topic == "datacenter") {  | ||||
|         datacenter = DataCenterItem().deserialize(abs.serialize());  | ||||
|         datacenter!.model = ResourceModel().deserialize(j["element"]["resource_model"]); | ||||
|       } | ||||
|       if (abs.topic == "storage") {  | ||||
|       } else if (abs.topic == "storage") {  | ||||
|         storage = StorageItem().deserialize(abs.serialize());  | ||||
|         storage!.model = ResourceModel().deserialize(j["element"]["resource_model"]); | ||||
|       } | ||||
|       if (abs.topic == "workflow") {  | ||||
|       } else if (abs.topic == "workflow") {  | ||||
|         workflow = WorkflowItem().deserialize(abs.serialize());  | ||||
|         workflow!.model = ResourceModel().deserialize(j["element"]["resource_model"]); | ||||
|       } else { | ||||
|         datacenter = null; | ||||
|         data = null; | ||||
|         processing = null; | ||||
|         storage = null; | ||||
|         workflow = null; | ||||
|       } | ||||
|     }  | ||||
|     } else { | ||||
|         datacenter = null; | ||||
|         data = null; | ||||
|         processing = null; | ||||
|         storage = null; | ||||
|         workflow = null; | ||||
|       }  | ||||
|   } | ||||
|  | ||||
|   Map<String, dynamic> toDashboard() { | ||||
| @@ -595,7 +621,7 @@ class Position extends SerializerDeserializer<Position> { | ||||
|   } | ||||
|   @override Map<String, dynamic> serialize() => { | ||||
|     "id": id, | ||||
|     "x": x, | ||||
|     "x": x , | ||||
|     "y": y, | ||||
|   }; | ||||
| } | ||||
| @@ -1,7 +1,9 @@ | ||||
| import 'package:flutter_flow_chart/flutter_flow_chart.dart'; | ||||
| import 'package:oc_front/models/abstract.dart'; | ||||
| import 'package:oc_front/models/response.dart'; | ||||
| import 'package:oc_front/models/search.dart'; | ||||
|  | ||||
| class Workspace extends SerializerDeserializer<Workspace> { | ||||
| class Workspace extends SerializerDeserializer<Workspace> implements ShallowData { | ||||
|   String? id; | ||||
|   String? name; | ||||
|   bool? active; | ||||
| @@ -24,10 +26,12 @@ class Workspace extends SerializerDeserializer<Workspace> { | ||||
|     this.shared, | ||||
|   }); | ||||
|  | ||||
|   @override String getID() => id ?? ""; | ||||
|   @override String getName() => name ?? ""; | ||||
|  | ||||
|   @override deserialize(dynamic json) { | ||||
|     try { json = json as Map<String, dynamic>; | ||||
|     } catch (e) { return Workspace(); }    | ||||
|     print(json); | ||||
|     return Workspace( | ||||
|       id: json.containsKey("id") ? json["id"] : null, | ||||
|       shared: json["shared"], | ||||
|   | ||||
| @@ -1,5 +1,6 @@ | ||||
| import 'package:flutter/material.dart'; | ||||
| import 'package:go_router/go_router.dart'; | ||||
|  | ||||
| abstract class AbstractFactory { | ||||
|   Widget factory(GoRouterState state, List<String> args); | ||||
|   bool searchFill(); | ||||
|   | ||||
| @@ -1,12 +1,19 @@ | ||||
| import 'package:flutter/material.dart'; | ||||
| import 'package:go_router/go_router.dart'; | ||||
| import 'package:oc_front/core/models/shared_workspace_local.dart'; | ||||
| import 'package:oc_front/core/models/workspace_local.dart'; | ||||
| import 'package:oc_front/core/sections/header/header.dart'; | ||||
| import 'package:oc_front/core/services/specialized_services/resource_service.dart'; | ||||
| import 'package:oc_front/core/services/specialized_services/shared_service.dart'; | ||||
| import 'package:oc_front/core/services/specialized_services/workspace_service.dart'; | ||||
| import 'package:oc_front/models/response.dart'; | ||||
| import 'package:oc_front/models/search.dart'; | ||||
| import 'package:oc_front/pages/shared.dart'; | ||||
| import 'package:oc_front/widgets/catalog.dart'; | ||||
| import 'package:oc_front/pages/abstract_page.dart'; | ||||
| import 'package:oc_front/core/sections/header/search.dart'; | ||||
| import 'package:oc_front/widgets/menu_clipper/workspace_menu.dart'; | ||||
| import 'package:oc_front/widgets/inputs/shallow_dropdown_input.dart'; | ||||
| import 'package:oc_front/widgets/inputs/shallow_text_input.dart'; | ||||
|  | ||||
| class CatalogFactory implements AbstractFactory { | ||||
|   static List<AbstractItem> items = []; | ||||
| @@ -25,18 +32,84 @@ class CatalogFactory implements AbstractFactory { | ||||
| } | ||||
|  | ||||
| class CatalogPageWidget extends StatefulWidget { | ||||
|   double? itemWidth; | ||||
|   final ResourceService search = ResourceService(); | ||||
|   CatalogPageWidget (): super(key: CatalogFactory.key); | ||||
|   CatalogPageWidget ({ | ||||
|     this.itemWidth, | ||||
|   }): super(key: CatalogFactory.key); | ||||
|   @override CatalogPageWidgetState createState() => CatalogPageWidgetState(); | ||||
| } | ||||
| class CatalogPageWidgetState extends State<CatalogPageWidget> {   | ||||
|   @override Widget build(BuildContext context) { | ||||
|     return Column( children : [ | ||||
|         CatalogFactory.items.isEmpty ? Container() : MenuWorkspaceWidget(), | ||||
|         CatalogFactory.items.isEmpty ? Container() :  | ||||
|         Row( children: [  | ||||
|           ShallowDropdownInputWidget( | ||||
|                 current: WorkspaceLocal.current, | ||||
|                 width: MediaQuery.of(context).size.width / 3, | ||||
|                 all: () async => WorkspaceLocal.getWorkspacesShallow(), | ||||
|                 type: SharedWorkspaceType.workspace, | ||||
|                 change: (String? change) { | ||||
|                   WorkspaceLocal.changeWorkspace(change.toString()); | ||||
|                 }, | ||||
|                 color: Colors.white, | ||||
|                 filled: const Color.fromRGBO(38, 166, 154, 1), | ||||
|                 hintColor: Colors.grey.shade300, | ||||
|                 canRemove: (String? remove) => remove != null, | ||||
|                 remove: (String? remove) async { | ||||
|                   if (remove == null) { return; } | ||||
|                   WorkspaceLocal.deleteWorkspace(remove); | ||||
|                 }, | ||||
|             ), | ||||
|           ShallowTextInputWidget( | ||||
|                 width: MediaQuery.of(context).size.width / 3, | ||||
|                 type: SharedWorkspaceType.workspace, | ||||
|                 color: Colors.white, | ||||
|                 filled: const Color.fromRGBO(38, 166, 154, 1), | ||||
|                 hintColor: Colors.grey.shade300, | ||||
|                 canRemove: (p0) => p0 != null, | ||||
|                 remove: (p0) async { | ||||
|                   await WorkspaceService().delete(context, p0, {}).then( (e) => WorkspaceLocal.deleteWorkspace(p0)); | ||||
|                 }, | ||||
|                 canLoad: (String? remove) => remove != null, | ||||
|                 load: (Map<String?, dynamic> add) async { | ||||
|                   if (add["name"] == null) { return; } | ||||
|                   WorkspaceLocal.createWorkspace(add["name"], context); | ||||
|                 }, | ||||
|             ), | ||||
|             ShallowDropdownInputWidget( | ||||
|             iconLoad: Icons.share_rounded, | ||||
|             tooltipLoad: 'share', | ||||
|             tooltipRemove: 'unshare', | ||||
|             color: Colors.white, | ||||
|             filled: const Color.fromRGBO(38, 166, 154, 1), | ||||
|             hintColor: Colors.grey.shade300, | ||||
|             type: SharedWorkspaceType.workspace, | ||||
|             all: () async => SharedWorkspaceLocal.workspaces.values.map(  | ||||
|               (e) => Shallow(id: e.id ?? "", name: e.name ?? "") ).toList(), | ||||
|             current: WorkspaceLocal.workspaces[WorkspaceLocal.current]?.shared, | ||||
|             width: (MediaQuery.of(context).size.width / 3), | ||||
|             canLoad: (String? change) => SharedWorkspaceLocal.workspaces[change] == null  | ||||
|               || !SharedWorkspaceLocal.workspaces[change]!.workspaces.map(  | ||||
|                 (e) => e.id ).contains(WorkspaceLocal.current), | ||||
|             canRemove: (String? change) => SharedWorkspaceLocal.workspaces[change] == null  | ||||
|               || SharedWorkspaceLocal.workspaces[change]!.workspaces.map(  | ||||
|                 (e) => e.id ).contains(WorkspaceLocal.current),  | ||||
|             load: (String val) async { | ||||
|               await SharedService().addWorkspace(context, val, WorkspaceLocal.current ?? ""); | ||||
|               // ignore: use_build_context_synchronously | ||||
|               SharedWorkspaceLocal.init(context, false); | ||||
|             }, | ||||
|             remove: (String val) async { | ||||
|               await SharedService().removeWorkspace(context, val, WorkspaceLocal.current ?? ""); | ||||
|                // ignore: use_build_context_synchronously | ||||
|               SharedWorkspaceLocal.init(context, false); | ||||
|             }) | ||||
|         ]), | ||||
|         SizedBox(  | ||||
|         width: MediaQuery.of(context).size.width, | ||||
|           height: CatalogFactory.items.isEmpty ? 0 :  MediaQuery.of(context).size.height - HeaderConstants.height - 50, | ||||
|         child: CatalogWidget(items: CatalogFactory.items) ) | ||||
|         child: SingleChildScrollView( child: CatalogWidget(items: CatalogFactory.items, itemWidth: widget.itemWidth) )), | ||||
|       ] | ||||
|     ); | ||||
|   } | ||||
|   | ||||
| @@ -36,7 +36,6 @@ class SchedulerPageWidgetState extends State<SchedulerPageWidget> { | ||||
|         "${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) {  | ||||
|         Map<String, List<WorkflowExecution>> data = {}; | ||||
|          | ||||
|         if (as.hasData && as.data!.data != null) { | ||||
|           for (var element in as.data!.data!.executions) { | ||||
|             if (element.executionData == null) { continue; } | ||||
| @@ -165,7 +164,7 @@ class SchedulerPageWidgetState extends State<SchedulerPageWidget> { | ||||
|                 ), | ||||
|                 Container(padding: const EdgeInsets.only(left: 20),  | ||||
|                   child: const Text("TO", style: TextStyle(color: Colors.white, fontSize: 15, fontWeight: FontWeight.w500))), | ||||
|                 Container( padding: const EdgeInsets.only(left: 20), | ||||
|                 Container( padding: const EdgeInsets.only(left: 20, right: 20), | ||||
|                   width: MediaQuery.of(context).size.width / 5, | ||||
|                   height: 30, | ||||
|                   child: DateTimeField(  | ||||
| @@ -219,6 +218,12 @@ class SchedulerPageWidgetState extends State<SchedulerPageWidget> { | ||||
|                                   contentPadding: EdgeInsets.symmetric(horizontal: 10, vertical: 5), | ||||
|                                 ), | ||||
|                           ) | ||||
|                 ), | ||||
|                 Tooltip( message: "refresh scheduler", | ||||
|                   child: InkWell( | ||||
|                     onTap: () => setState(() {}), | ||||
|                     child: const Icon(Icons.refresh, color: Colors.white,), | ||||
|                   ), | ||||
|                 ) | ||||
|               ])) | ||||
|           ), | ||||
|   | ||||
| @@ -1,9 +1,24 @@ | ||||
| import 'package:alert_banner/exports.dart'; | ||||
| import 'dart:async'; | ||||
|  | ||||
| import 'package:flutter/material.dart'; | ||||
| import 'package:go_router/go_router.dart'; | ||||
| import 'package:oc_front/core/models/shared_workspace_local.dart'; | ||||
| import 'package:oc_front/core/models/workspace_local.dart'; | ||||
| import 'package:oc_front/core/sections/header/header.dart'; | ||||
| import 'package:oc_front/core/services/router.dart'; | ||||
| import 'package:oc_front/core/services/specialized_services/peer_service.dart'; | ||||
| import 'package:oc_front/core/services/specialized_services/shared_service.dart'; | ||||
| import 'package:oc_front/core/services/specialized_services/workflow_service.dart'; | ||||
| import 'package:oc_front/models/response.dart'; | ||||
| import 'package:oc_front/models/shared.dart'; | ||||
| import 'package:oc_front/pages/abstract_page.dart'; | ||||
| import 'package:oc_front/widgets/dialog/new_shared_workspace.dart'; | ||||
| import 'package:oc_front/widgets/catalog.dart'; | ||||
| import 'package:oc_front/widgets/dialog/shallow_creation.dart'; | ||||
| import 'package:oc_front/widgets/inputs/shallow_text_input.dart'; | ||||
| import 'package:oc_front/widgets/items/shallow_item_row.dart'; | ||||
| import 'package:oc_front/widgets/inputs/shallow_dropdown_input.dart'; | ||||
|  | ||||
| enum SharedWorkspaceType { global, shared_workspace, workspace, workflow, peer, resource } | ||||
|  | ||||
| class  SharedFactory implements AbstractFactory { | ||||
|   static GlobalKey<SharedPageWidgetState> key = GlobalKey<SharedPageWidgetState>(); | ||||
| @@ -13,51 +28,349 @@ class  SharedFactory implements AbstractFactory { | ||||
| } | ||||
|  | ||||
| class SharedPageWidget extends StatefulWidget { | ||||
|   SharedWorkspaceType type = SharedWorkspaceType.global; | ||||
|   SharedPageWidget(): super(key: SharedFactory.key); | ||||
|   @override SharedPageWidgetState createState() => SharedPageWidgetState(); | ||||
|   static void search(BuildContext context) { } | ||||
|   static Widget factory() { return SharedPageWidget(); } | ||||
| } | ||||
| class SharedPageWidgetState extends State<SharedPageWidget> { | ||||
|   SharedService service = SharedService(); | ||||
|   Widget getMenuItem(SharedWorkspaceType workspaceType, IconData icon) { | ||||
|     var s = workspaceType == SharedWorkspaceType.global ? "dashboard" : workspaceType == SharedWorkspaceType.workspace ? "shared workspaces" : workspaceType == SharedWorkspaceType.workflow ? "shared workflows" : "peers engaged"; | ||||
|     return Tooltip( message: s, | ||||
|       child: InkWell( mouseCursor: SystemMouseCursors.click, | ||||
|         onTap: () => setState(() { | ||||
|           widget.type = workspaceType; | ||||
|         }), | ||||
|         child: Container( width: 50, height: 50, | ||||
|         color: widget.type == workspaceType ? Color.fromRGBO(38, 166, 154, 1) : Colors.transparent, | ||||
|         padding: const EdgeInsets.symmetric(vertical: 10),  | ||||
|         child : Icon(icon,  | ||||
|           color: widget.type == workspaceType ? Colors.white : Colors.white, size: 20)))); | ||||
|   } | ||||
|  | ||||
|   @override Widget build(BuildContext context) { | ||||
|     Future.delayed( const Duration(milliseconds: 100), () { | ||||
|       showDialog(context: context, builder: (BuildContext ctx) => AlertDialog( | ||||
|                                         titlePadding: EdgeInsets.zero, | ||||
|                                         insetPadding: EdgeInsets.zero, | ||||
|                                         backgroundColor: Colors.white, | ||||
|                                         shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(0)), | ||||
|                                         title:NewBoxSharedWidget())); | ||||
|     }); | ||||
|     return Expanded(  | ||||
|       child : Column( children: [  | ||||
|     GlobalKey<ShallowTextInputWidgetState> key = GlobalKey<ShallowTextInputWidgetState>(); | ||||
|     if (SharedWorkspaceLocal.current == null) {  | ||||
|       Future.delayed( const Duration(microseconds: 100), () { | ||||
|         HeaderConstants.setTitle("Choose a Shared Workspace"); | ||||
|         HeaderConstants.setDescription("select a shared workspace to continue"); | ||||
|       }); | ||||
|       Future.delayed( const Duration(milliseconds: 100), () { | ||||
|         showDialog( | ||||
|           barrierDismissible: false, | ||||
|           context: context, builder: (BuildContext ctx) => AlertDialog( | ||||
|             titlePadding: EdgeInsets.zero, | ||||
|             insetPadding: EdgeInsets.zero, | ||||
|             backgroundColor: Colors.white, | ||||
|             shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(0)), | ||||
|             title: ShallowCreationDialogWidget( | ||||
|               formKey: key, | ||||
|               canClose: () => SharedWorkspaceLocal.current != null, | ||||
|               context: context, | ||||
|               load: (p0) async { | ||||
|                 SharedWorkspaceLocal.current = p0; | ||||
|                 HeaderConstants.setTitle("Shared Workspace <${SharedWorkspaceLocal.workspaces[SharedWorkspaceLocal.current]?.name ?? ""}>"); | ||||
|                 HeaderConstants.setDescription(SharedWorkspaceLocal.workspaces[SharedWorkspaceLocal.current]?.description ?? ""); | ||||
|                 Future.delayed(const Duration(seconds: 1), () => SharedFactory.key.currentState?.setState(() {})); | ||||
|               }, | ||||
|               form: [ | ||||
|                 ShallowTextInputWidget( | ||||
|                   change :(p0) => key.currentState?.setState(() {}), | ||||
|                   canLoad: (po) => po != null && po.isNotEmpty, | ||||
|                   type: SharedWorkspaceType.shared_workspace, | ||||
|                   width: MediaQuery.of(context).size.width <= 540 ? MediaQuery.of(context).size.width - 140 : 400, | ||||
|                   attr: "description", | ||||
|                   color: Colors.black, | ||||
|                   hintColor: Colors.grey, | ||||
|                   filled: Colors.grey.shade300, | ||||
|                 ) | ||||
|               ], | ||||
|               create: (p0) async => await SharedService().post(context, p0, {}).then((value) { | ||||
|                 if (value.data != null) { | ||||
|                     SharedWorkspaceLocal.current = value.data!.id; | ||||
|                 } | ||||
|                 SharedWorkspaceLocal.init(context, true); | ||||
|  | ||||
|                 HeaderConstants.setTitle("Shared Workspace <${SharedWorkspaceLocal.workspaces[SharedWorkspaceLocal.current]?.name ?? ""}>"); | ||||
|                 HeaderConstants.setDescription(SharedWorkspaceLocal.workspaces[SharedWorkspaceLocal.current]?.description ?? ""); | ||||
|                 Future.delayed(const Duration(seconds: 1), () => SharedFactory.key.currentState?.setState(() {})); | ||||
|               }), | ||||
|               type: SharedWorkspaceType.shared_workspace, | ||||
|               all: () async => SharedWorkspaceLocal.workspaces.values.map(  | ||||
|                 (e) => Shallow(id: e.id ?? "", name: e.name ?? "") ).toList(), | ||||
|             ))); | ||||
|       }); | ||||
|     } else { | ||||
|       Future.delayed( const Duration(milliseconds: 100), () { | ||||
|         HeaderConstants.setTitle("Shared Workspace <${SharedWorkspaceLocal.workspaces[SharedWorkspaceLocal.current]?.name ?? ""}>"); | ||||
|         HeaderConstants.setDescription(SharedWorkspaceLocal.workspaces[SharedWorkspaceLocal.current]?.description ?? ""); | ||||
|       }); | ||||
|     } | ||||
|     Widget w = WorkspaceSharedPageWidget(type: widget.type); | ||||
|     List<Widget> addMenu = []; | ||||
|     SharedWorkspace? current = SharedWorkspaceLocal.workspaces[SharedWorkspaceLocal.current ?? ""]; | ||||
|     if (widget.type == SharedWorkspaceType.workspace) { | ||||
|       addMenu.add( Row( mainAxisAlignment: MainAxisAlignment.end, | ||||
|         children : [ ShallowDropdownInputWidget(  | ||||
|           tooltipLoad: "share", | ||||
|           tooltipRemove: "unshare", | ||||
|           iconLoad: Icons.share, | ||||
|           type: widget.type,  | ||||
|           current: WorkspaceLocal.current, | ||||
|           all: () async => WorkspaceLocal.getWorkspacesShallow(), | ||||
|           width: MediaQuery.of(context).size.width / 3, | ||||
|           canLoad: (String? change) => current == null || !current.workspaces.map( (e) => e.id ).contains(change), | ||||
|           canRemove: (String? change) => current == null || current.workspaces.map( (e) => e.id ).contains(change),  | ||||
|           load: (String val) async { | ||||
|             await service.addWorkspace(context, SharedWorkspaceLocal.current ?? "", val); | ||||
|             SharedWorkspaceLocal.init(context, false); | ||||
|           }, | ||||
|           remove: (String val) async { | ||||
|             await service.removeWorkspace(context, SharedWorkspaceLocal.current ?? "", val); | ||||
|             SharedWorkspaceLocal.init(context, false); | ||||
|           }) | ||||
|       ])); | ||||
|     } | ||||
|     if (widget.type == SharedWorkspaceType.workflow) { | ||||
|       addMenu.add( Row( mainAxisAlignment: MainAxisAlignment.end, | ||||
|         children : [ ShallowDropdownInputWidget(  | ||||
|           tooltipLoad: "share", | ||||
|           tooltipRemove: "unshare", | ||||
|           iconLoad: Icons.share, | ||||
|           type: widget.type, all: () async { | ||||
|             List<Shallow> shals = []; | ||||
|             await WorflowService().all(context).then((value) { | ||||
|                 if (value.data != null) { | ||||
|                   shals = value.data!.values.map((e) => Shallow(id: e["id"], name: e["name"])).toList(); | ||||
|                 } | ||||
|               }); | ||||
|             return shals; | ||||
|           }, | ||||
|           width: MediaQuery.of(context).size.width / 3, | ||||
|           canLoad: (String? change) => current == null || !current.workflows.map( (e) => e.id ).contains(change), | ||||
|           canRemove: (String? change) => current == null || current.workflows.map( (e) => e.id ).contains(change),  | ||||
|           load: (String change) async { | ||||
|             await service.addWorkflow(context, SharedWorkspaceLocal.current ?? "", change); | ||||
|           }, | ||||
|           remove: (String change) async { | ||||
|             await service.removeWorkflow(context, SharedWorkspaceLocal.current ?? "", change); | ||||
|           }) | ||||
|       ])); | ||||
|     } | ||||
|     if (widget.type == SharedWorkspaceType.peer) { | ||||
|       addMenu.add( Row( mainAxisAlignment: MainAxisAlignment.end, | ||||
|         children : [ ShallowDropdownInputWidget(  | ||||
|           tooltipLoad: "add", | ||||
|           iconLoad: Icons.add, | ||||
|           type: widget.type, all: () async { | ||||
|             List<Shallow> shals = []; | ||||
|             await PeerService().all(context).then((value) { | ||||
|                 if (value.data != null) { | ||||
|                   shals = value.data!.values.map((e) => Shallow(id: e["id"], name: e["name"])).toList(); | ||||
|                 } | ||||
|               }); | ||||
|             return shals; | ||||
|           }, | ||||
|           width: MediaQuery.of(context).size.width / 3, | ||||
|           canLoad: (String? change) => current == null || !current.peers.map( (e) => e.id ).contains(change), | ||||
|           canRemove: (String? change) => current == null || current.peers.map( (e) => e.id ).contains(change),  | ||||
|           load: (String change) async { | ||||
|             await service.addPeer(context, SharedWorkspaceLocal.current ?? "", change); | ||||
|           }, | ||||
|           remove: (String change) async { | ||||
|             await service.removePeer(context, SharedWorkspaceLocal.current ?? "", change); | ||||
|           }) | ||||
|       ])); | ||||
|     } | ||||
|     return Column( children: [  | ||||
|         Container( | ||||
|           height: 50, | ||||
|           color: const Color.fromRGBO(38, 166, 154, 1), | ||||
|           width: MediaQuery.of(context).size.width, | ||||
|         ), | ||||
|           padding: const EdgeInsets.only(left: 50), | ||||
|           child: Stack( alignment: Alignment.centerLeft, children: [ | ||||
|                           Tooltip( message: "open file", child: Padding( padding: const EdgeInsets.only(right: 15),  | ||||
|                             child: InkWell( mouseCursor: SystemMouseCursors.click, | ||||
|                               onTap: () { | ||||
|                                 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: ShallowCreationDialogWidget( | ||||
|                                         formKey: key, | ||||
|                                         canClose: () => SharedWorkspaceLocal.current != null, | ||||
|                                         context: context, | ||||
|                                         load: (p0) async { | ||||
|                                           SharedWorkspaceLocal.current = p0; | ||||
|                                           HeaderConstants.setTitle("Shared Workspace <${SharedWorkspaceLocal.workspaces[SharedWorkspaceLocal.current]?.name ?? ""}>"); | ||||
|                                           HeaderConstants.setDescription(SharedWorkspaceLocal.workspaces[SharedWorkspaceLocal.current]?.description ?? ""); | ||||
|                                           Future.delayed(const Duration(seconds: 1), () => SharedFactory.key.currentState?.setState(() {})); | ||||
|                                         }, | ||||
|                                         form: [ | ||||
|                                           ShallowTextInputWidget( | ||||
|                                             change :(p0) => key.currentState?.setState(() {}), | ||||
|                                             type: SharedWorkspaceType.shared_workspace, | ||||
|                                             width: MediaQuery.of(context).size.width <= 540 ? MediaQuery.of(context).size.width - 140 : 400, | ||||
|                                             attr: "description", | ||||
|                                             color: Colors.black, | ||||
|                                             hintColor: Colors.grey, | ||||
|                                             filled: Colors.grey.shade300, | ||||
|                                           ) | ||||
|                                         ], | ||||
|                                         create: (p0) async => await SharedService().post(context, p0, {}).then( (e) { | ||||
|                                           if (e.data != null) { | ||||
|                                             SharedWorkspaceLocal.current = e.data!.id; | ||||
|                                           } | ||||
|                                           SharedWorkspaceLocal.init(context, true); | ||||
|  | ||||
|                                           HeaderConstants.setTitle("Shared Workspace <${SharedWorkspaceLocal.workspaces[SharedWorkspaceLocal.current]?.name ?? ""}>"); | ||||
|                                           HeaderConstants.setDescription(SharedWorkspaceLocal.workspaces[SharedWorkspaceLocal.current]?.description ?? ""); | ||||
|                                           Future.delayed(const Duration(seconds: 1), () => SharedFactory.key.currentState?.setState(() {})); | ||||
|                                         }), | ||||
|                                         type: SharedWorkspaceType.shared_workspace, | ||||
|                                         all: () async => SharedWorkspaceLocal.workspaces.values.map(  | ||||
|                                           (e) => Shallow(id: e.id ?? "", name: e.name ?? "") ).toList(), | ||||
|                                       )); | ||||
|                                   }); | ||||
|                               },  | ||||
|                               child: const Icon(Icons.folder_open, color: Colors.white)))), | ||||
|                               Positioned( right: 0, child: Row( children: addMenu)) | ||||
|                         ])), | ||||
|         Row(  | ||||
|         children: [ | ||||
|           Container( | ||||
|             color: Colors.grey, | ||||
|             color: Colors.black, | ||||
|             height: MediaQuery.of(context).size.height - HeaderConstants.height - 50, | ||||
|             width: 50, | ||||
|             padding: const EdgeInsets.symmetric(vertical: 20, horizontal: 10), | ||||
|             child: const Column( | ||||
|             child: Column( | ||||
|               children: [ | ||||
|                 Tooltip( message: "dashboard", | ||||
|                   child: InkWell( mouseCursor: SystemMouseCursors.click, | ||||
|                     child: Padding( padding: EdgeInsets.symmetric(vertical: 10), child : Icon(Icons.dashboard, color: Colors.white, size: 20)))), | ||||
|                 Tooltip( message: "shared workspaces", | ||||
|                   child: InkWell( mouseCursor: SystemMouseCursors.click, | ||||
|                     child: Padding( padding: EdgeInsets.symmetric(vertical: 10), child : Icon(Icons.workspaces, color: Colors.white, size: 20)))), | ||||
|                 Tooltip( message: "shared workflows", | ||||
|                   child: InkWell( mouseCursor: SystemMouseCursors.click, | ||||
|                     child: Padding( padding: EdgeInsets.symmetric(vertical: 10), child : Icon(Icons.rebase_edit, color: Colors.white, size: 20)))), | ||||
|                 getMenuItem(SharedWorkspaceType.global, Icons.dashboard), | ||||
|                 getMenuItem(SharedWorkspaceType.workspace, Icons.workspaces), | ||||
|                 getMenuItem(SharedWorkspaceType.workflow, Icons.rebase_edit), | ||||
|                 getMenuItem(SharedWorkspaceType.peer, Icons.group), | ||||
|               ]) | ||||
|           ), | ||||
|           Container(  | ||||
|             height: MediaQuery.of(context).size.height - HeaderConstants.height - 50, | ||||
|             width:  MediaQuery.of(context).size.width -50, | ||||
|             color: widget.type == SharedWorkspaceType.workflow || widget.type == SharedWorkspaceType.peer ? Colors.grey.shade300 : Colors.white, | ||||
|             child: SingleChildScrollView( child: w )) | ||||
|         ] | ||||
|       ) ]) | ||||
|       ) ] | ||||
|     ); | ||||
|   } | ||||
| } | ||||
|  | ||||
| class WorkspaceSharedPageWidget extends StatefulWidget { | ||||
|   SharedWorkspaceType type = SharedWorkspaceType.global; | ||||
|   WorkspaceSharedPageWidget({ required this.type }): super(key: null); | ||||
|   @override WorkspaceSharedPageWidgetState createState() => WorkspaceSharedPageWidgetState(); | ||||
| } | ||||
| class WorkspaceSharedPageWidgetState extends State<WorkspaceSharedPageWidget> { | ||||
|  | ||||
|   @override Widget build(BuildContext context) { | ||||
|     if (SharedWorkspaceLocal.current == null) {  | ||||
|       return Container(); | ||||
|     } | ||||
|     var space = SharedWorkspaceLocal.workspaces[SharedWorkspaceLocal.current ?? ""]!; | ||||
|     List<Widget> items = []; | ||||
|     List<ShallowData> data = []; | ||||
|     if (widget.type == SharedWorkspaceType.global) { | ||||
|     } else if (widget.type == SharedWorkspaceType.workspace) { | ||||
|       data = space.workspaces; | ||||
|     } else if (widget.type == SharedWorkspaceType.workflow) { | ||||
|       data = space.workflows; | ||||
|     } else if (widget.type == SharedWorkspaceType.peer) { | ||||
|       data = space.peers; | ||||
|     } | ||||
|     var current = SharedWorkspaceLocal.workspaces[SharedWorkspaceLocal.current]; | ||||
|     for (var w in data) { | ||||
|       if (widget.type == SharedWorkspaceType.workspace) { | ||||
|         if (WorkspaceLocal.workspaces[w.getID()] == null) { continue; } | ||||
|         items.add(WorkspaceSharedItemPageWidget(name: "Workspace <${WorkspaceLocal.workspaces[w.getID()]!.name}>", id: w.getID())); | ||||
|       } else if (widget.type == SharedWorkspaceType.workflow || widget.type == SharedWorkspaceType.peer) { | ||||
|         List<IconData> badges = []; | ||||
|         if (widget.type == SharedWorkspaceType.peer && w.getID() == current?.creatorID) { | ||||
|           badges.add(Icons.star); | ||||
|         } | ||||
|         items.add(ShallowItemRowWidget( | ||||
|           item: w, badges: badges, | ||||
|           edit: widget.type == SharedWorkspaceType.workflow ? (String? change) { | ||||
|               if (change != null) { | ||||
|                 WorkspaceLocal.changeWorkspaceByName(change.split("~")[1]);   | ||||
|               } | ||||
|               Future.delayed(const Duration(seconds: 1), () => AppRouter.workflowIDItem.go(context, { "id": change ?? "" })); | ||||
|             } : null, | ||||
|           delete: (String? change) async { | ||||
|             if (change == null) { return; } | ||||
|             if (widget.type == SharedWorkspaceType.peer) { | ||||
|               await SharedService().removePeer(context, SharedWorkspaceLocal.current ?? "", change); | ||||
|             } else { | ||||
|               await SharedService().removePeer(context, SharedWorkspaceLocal.current ?? "", change); | ||||
|             } | ||||
|           }, | ||||
|           icon: widget.type == SharedWorkspaceType.workflow ? Icons.work_history_rounded : Icons.person, | ||||
|           contextWidth: 200) | ||||
|         ); | ||||
|       } | ||||
|      } | ||||
|      if (items.isEmpty) { | ||||
|         return Container(  | ||||
|           color: Colors.grey.shade300, | ||||
|           height: MediaQuery.of(context).size.height - HeaderConstants.height - 50, | ||||
|           width: MediaQuery.of(context).size.width - 50, | ||||
|           alignment: Alignment.center, | ||||
|           padding: const EdgeInsets.all(50), | ||||
|           child: Text("NO ITEMS SHARED", style: const TextStyle(fontSize: 25, fontWeight: FontWeight.w600, color: Colors.white))); | ||||
|      } | ||||
|      if (widget.type == SharedWorkspaceType.workflow || widget.type == SharedWorkspaceType.peer) { | ||||
|       return Padding(  | ||||
|         padding: const EdgeInsets.all(50), | ||||
|         child: Stack( alignment: Alignment.topLeft, children : items)); | ||||
|      } | ||||
|     return Column( mainAxisAlignment: MainAxisAlignment.start, children : items); | ||||
|   } | ||||
| } | ||||
|  | ||||
| class WorkspaceSharedItemPageWidget extends StatefulWidget { | ||||
|   bool open = true; | ||||
|   String id = ""; | ||||
|   String name = ""; | ||||
|   WorkspaceSharedItemPageWidget({ this.name = "", this.id = "" }): super(key: null); | ||||
|   @override WorkspaceSharedItemPageWidgetState createState() => WorkspaceSharedItemPageWidgetState(); | ||||
| } | ||||
| class WorkspaceSharedItemPageWidgetState extends State<WorkspaceSharedItemPageWidget> { | ||||
|     @override Widget build(BuildContext context) { | ||||
|       return Column( children: [ | ||||
|         Container(  | ||||
|           width: MediaQuery.of(context).size.width - 50, | ||||
|             height: 50, | ||||
|             padding: const EdgeInsets.symmetric(horizontal: 20), | ||||
|             decoration: BoxDecoration(color: Colors.grey.shade300), | ||||
|             child: Stack(  | ||||
|                 alignment: Alignment.centerLeft, | ||||
|                 children: [ | ||||
|                   Row(  | ||||
|                     children: [ | ||||
|                       const Padding(padding: EdgeInsets.only(right: 20), child: Icon(Icons.shopping_cart_outlined, size: 18, color: Colors.white)), | ||||
|                     Text(widget.name,  | ||||
|                       style: const TextStyle(fontSize: 15, color: Colors.white, fontWeight: FontWeight.w600)), | ||||
|                     ] | ||||
|                   ), | ||||
|                   Positioned( right: 0, top: 5, child: IconButton( icon: Icon(widget.open ? Icons.arrow_drop_up : Icons.arrow_drop_down, color: Colors.white), | ||||
|                     onPressed: () => setState(() { | ||||
|                       widget.open = !widget.open; | ||||
|                   }))) | ||||
|               ]) | ||||
|             ), | ||||
|           widget.open ? CatalogWidget(itemWidth: MediaQuery.of(context).size.width - 50,  | ||||
|           items: WorkspaceLocal.byWorkspace(widget.id)) : Container() | ||||
|         ]); | ||||
|     } | ||||
| } | ||||
| @@ -1,32 +1,40 @@ | ||||
| import 'package:flutter/material.dart'; | ||||
| import 'package:flutter_flow_chart/flutter_flow_chart.dart'; | ||||
| import 'package:go_router/go_router.dart'; | ||||
| import 'package:oc_front/core/models/shared_workspace_local.dart'; | ||||
| import 'package:oc_front/core/models/workspace_local.dart'; | ||||
| import 'package:oc_front/core/sections/header/header.dart'; | ||||
| import 'package:oc_front/core/services/specialized_services/shared_service.dart'; | ||||
| import 'package:oc_front/core/services/specialized_services/workflow_service.dart'; | ||||
| import 'package:oc_front/models/response.dart'; | ||||
| import 'package:oc_front/models/search.dart'; | ||||
| import 'package:oc_front/models/workflow.dart'; | ||||
| import 'package:oc_front/pages/abstract_page.dart'; | ||||
| import 'package:oc_front/widgets/dialog/new_workflow.dart'; | ||||
| import 'package:oc_front/widgets/forms/proxy_forms.dart'; | ||||
| import 'package:oc_front/pages/shared.dart'; | ||||
| import 'package:oc_front/widgets/dialog/shallow_creation.dart'; | ||||
| import 'package:oc_front/widgets/forms/processing_forms.dart'; | ||||
| import 'package:oc_front/widgets/forms/scheduler_forms.dart'; | ||||
| import 'package:oc_front/widgets/items/item_row.dart'; | ||||
| import 'package:oc_front/widgets/menu_clipper/shared_workspace_menu.dart'; | ||||
| import 'package:oc_front/widgets/menu_clipper/workspace_menu.dart'; | ||||
| import 'package:oc_front/widgets/inputs/shallow_dropdown_input.dart'; | ||||
|  | ||||
| Dashboard dash = Dashboard( | ||||
|   name: "workflow_${DateTime.now().toString().replaceAll(" ", "_").substring(0, DateTime.now().toString().length - 7)}"); | ||||
| class WorkflowFactory implements AbstractFactory { | ||||
|   static GlobalKey<WorkflowPageWidgetState> key = GlobalKey<WorkflowPageWidgetState>(); | ||||
|   @override bool searchFill() { return false; } | ||||
|   @override Widget factory(GoRouterState state, List<String> args) { return WorkflowPageWidget(); } | ||||
|   @override Widget factory(GoRouterState state, List<String> args) {  | ||||
|     String? id; | ||||
|     try { id = state.pathParameters[args.first]; | ||||
|     } catch (e) { } | ||||
|     return WorkflowPageWidget(id: id);  | ||||
|   } | ||||
|   @override void search(BuildContext context) { } | ||||
| } | ||||
| bool getAll = true; | ||||
|  | ||||
| class WorkflowPageWidget extends StatefulWidget { | ||||
|   WorkflowPageWidget () : super(key: WorkflowFactory.key); | ||||
|   String? id; | ||||
|   WorkflowPageWidget ({ this.id }) : super(key: WorkflowFactory.key); | ||||
|   @override WorkflowPageWidgetState createState() => WorkflowPageWidgetState(); | ||||
|   static void search(BuildContext context) { } | ||||
|   static Widget factory() { return WorkflowPageWidget(); } | ||||
| @@ -42,23 +50,11 @@ final WorflowService _service = WorflowService(); | ||||
|   } | ||||
|   Widget itemTooltipBuild(Object item) { | ||||
|     var e = item as AbstractItem; | ||||
|     return Container(color: Colors.white, child: ItemRowWidget(low: true, contextWidth: 300, item: e)); | ||||
|   } | ||||
|   List<DropdownMenuItem> getItems(Object? data) { | ||||
|     data = data as APIResponse<RawData>?; | ||||
|     if (data != null && data.data != null && data.data!.values.isNotEmpty) { | ||||
|       return data.data!.values.map((dynamic value) { | ||||
|                             return DropdownMenuItem<String>( | ||||
|                               value: "${value["id"] ?? ""}~${value["name"] ?? ""}", | ||||
|                               child: Text(value["name"]?.toString() ?? ""), | ||||
|                             ); | ||||
|                           }).toList(); | ||||
|     } | ||||
|     return []; | ||||
|     return Container(color: Colors.white, child: ItemRowWidget(low: true, contextWidth: 290, item: e)); | ||||
|   } | ||||
|   List<Widget> getForms(FlowData? obj) { | ||||
|     return obj == null ? [] : [ | ||||
|       ProxyFormsWidget(item: obj as AbstractItem, dash: dash), | ||||
|       ProcessingFormsWidget(item: obj as AbstractItem, dash: dash), | ||||
|     ]; | ||||
|   } | ||||
|  | ||||
| @@ -69,6 +65,7 @@ final WorflowService _service = WorflowService(); | ||||
|   } | ||||
|  | ||||
|   Future<void> loadDash(String selected) async { | ||||
|     dash.shouldSave = false; | ||||
|     if (selected.split("~").length > 1) { | ||||
|       dash.name = selected.split("~")[1]; | ||||
|       dash.id = selected.split("~")[0]; | ||||
| @@ -77,13 +74,15 @@ final WorflowService _service = WorflowService(); | ||||
|     } | ||||
|     await _service.get(context, dash.id ?? "").then((value) { | ||||
|       if (value.data != null) { | ||||
|         dash.clear(); | ||||
|         dash.deserialize(value.data!.toDashboard()); | ||||
|         Future.delayed(const Duration(seconds: 1), () => dash.shouldSave = true); | ||||
|       } | ||||
|     }); | ||||
|   } | ||||
|  | ||||
|   Future<void> saveDash(String? id) async { | ||||
|     if (id == null || !dash.isOpened) { return; } | ||||
|     if (id == null || !dash.isOpened || !dash.shouldSave) { return; } | ||||
|     var datas = WorkspaceLocal.byTopic("data", true).where( | ||||
|         (element) => dash.elements.map( (e) => e.element?.getID()).contains(element.id) ); | ||||
|     var dataCenter = WorkspaceLocal.byTopic("datacenter", true).where( | ||||
| @@ -106,11 +105,27 @@ final WorflowService _service = WorflowService(); | ||||
|     updateW.fromDashboard(dash.serialize()); | ||||
|     for (var item in (updateW.graph?.items.values ?? [] as List<GraphItem>)) { | ||||
|       if (item.position == null) { continue; } | ||||
|       item.position?.x = (item.position?.x ?? 0) + 52.5; | ||||
|       item.position?.y = (item.position?.y ?? 0) + 52.5; | ||||
|       item.position?.x = (item.position?.x ?? 0) + (item.width! / 2) + 7.5; | ||||
|       item.position?.y = (item.position?.y ?? 0) + (item.height! / 2) + 7.5; | ||||
|       for (var i in (updateW.graph?.links ?? [] as List<GraphLink>).where((element) => id == element.source?.id)) { | ||||
|         i.source?.x = (i.source?.x ?? 0) + (item.width! / 2) + 7; | ||||
|         i.source?.y = (i.source?.y ?? 0) + (item.width! / 2) + 7; | ||||
|       } | ||||
|       for (var i in (updateW.graph?.links ?? [] as List<GraphLink>).where((element) => id == element.destination?.id)) { | ||||
|         i.destination?.x = (i.destination?.x ?? 0) + (item.width! / 2) + 7.5; | ||||
|         i.destination?.y = (i.destination?.y ?? 0) + (item.width! / 2) + 7.5; | ||||
|       } | ||||
|     } | ||||
|     updateW.graph?.zoom = dash.getZoomFactor(); | ||||
|     await _service.put(context, id, updateW.serialize(), {});   | ||||
|     print("SAVE DASH"); | ||||
|     dash.addToHistory(); | ||||
|     await _service.put(context, id, updateW.serialize(), {}).then( (e) { | ||||
|       if (dash.addChange) { | ||||
|         dash.addChange = false; | ||||
|         WorkspaceLocal.init(context, false); | ||||
|         dash.selectedLeftMenuKey.currentState?.setState(() { }); | ||||
|       } | ||||
|     });   | ||||
|   } | ||||
|  | ||||
|   FlowData? transformToData(Map<String, dynamic> data) { | ||||
| @@ -125,24 +140,88 @@ final WorflowService _service = WorflowService(); | ||||
|     return null; | ||||
|   } | ||||
|  | ||||
|  | ||||
|   Widget onDashboardMenu(Dashboard dash) { | ||||
|     return ShallowDropdownInputWidget( | ||||
|             iconLoad: Icons.share, | ||||
|             tooltipLoad: 'share', | ||||
|             tooltipRemove: 'unshare', | ||||
|             filled: const Color.fromRGBO(38,166, 154, 1), | ||||
|             color: Colors.white, | ||||
|             hintColor: Colors.grey.shade300, | ||||
|             type: SharedWorkspaceType.workflow, | ||||
|             all: () async => SharedWorkspaceLocal.workspaces.values.map(  | ||||
|               (e) => Shallow(id: e.id ?? "", name: e.name ?? "") ).toList(), | ||||
|             current: WorkspaceLocal.workspaces[WorkspaceLocal.current]?.shared, | ||||
|             width: (MediaQuery.of(context).size.width / 3), | ||||
|             canLoad: (String? change) { | ||||
|               return SharedWorkspaceLocal.workspaces[change] == null  | ||||
|               || !SharedWorkspaceLocal.workspaces[change]!.workflows.map( (e) => e.id  | ||||
|                 ).contains(dash.id); | ||||
|             }, | ||||
|             canRemove: (String? change) => SharedWorkspaceLocal.workspaces[change] == null  | ||||
|               || SharedWorkspaceLocal.workspaces[change]!.workflows.map( (e) => e.id  | ||||
|                 ).contains(dash.id),  | ||||
|             load: (String val) async { | ||||
|               await SharedService().addWorkflow(context, val, dash.id ?? ""); | ||||
|               SharedWorkspaceLocal.init(context, false); | ||||
|               dash.selectedMenuKey.currentState?.setState(() { }); | ||||
|             }, | ||||
|             remove: (String val) async { | ||||
|               await SharedService().removeWorkflow(context, val, dash.id ?? ""); | ||||
|               SharedWorkspaceLocal.init(context, false); | ||||
|               dash.selectedMenuKey.currentState?.setState(() { }); | ||||
|             }); | ||||
|   } | ||||
|   Widget menuExtension() { | ||||
|     var quart = MediaQuery.of(context).size.width / 6; | ||||
|     return MenuWorkspaceWidget(simpliest: true, width: quart > 80 ? quart : 80, | ||||
|         onWorkspaceChange: () {  | ||||
|           dash.selectedLeftMenuKey.currentState?.setState(() { });  | ||||
|         }); | ||||
|     return ShallowDropdownInputWidget( | ||||
|                 current: WorkspaceLocal.current, | ||||
|                 width: quart > 80 ? quart : 80, | ||||
|                 all: () async => WorkspaceLocal.getWorkspacesShallow(), | ||||
|                 type: SharedWorkspaceType.workspace, | ||||
|                 change: (String? change) { | ||||
|                   WorkspaceLocal.changeWorkspace(change.toString()); | ||||
|                 } | ||||
|             ); | ||||
|   } | ||||
|  | ||||
|   Widget onDashboardMenu(Dashboard dash) { | ||||
|     return SharedMenuWorkspaceWidget(width: MediaQuery.of(context).size.width / 2.5, contextID: dash.id ?? "",  | ||||
|       excluded: dash.info["shared"] ?? [], | ||||
|       topMargin: 0, inner: true, type: SharedMenuWorkspaceType.workflow); | ||||
|   } | ||||
|  | ||||
|   Widget onDashboardAlertOpened(BuildContext context, Dashboard dash) { | ||||
|     return NewBoxWidget<Workflow>(service: _service, dash: dash,  | ||||
|         getItems: getItems); | ||||
|     return ShallowCreationDialogWidget( | ||||
|       canClose: () => dash.isOpened, | ||||
|       context: context, | ||||
|       load: (p0) async { | ||||
|         dash.isOpened = true; | ||||
|         if (dash.load != null) { | ||||
|           WorkspaceLocal.changeWorkspaceByName(p0.split("~")[1]);   | ||||
|             await dash.load!(p0);          | ||||
|           }  | ||||
|           dash.notifyListeners(); | ||||
|       }, | ||||
|       create: (p0) async => await _service.post(context, p0, {}).then( (value) { | ||||
|           dash.clear(); | ||||
|           dash.id = value.data?.getID() ?? ""; | ||||
|           dash.name = value.data?.getName() ?? ""; | ||||
|           dash.notifyListeners(); | ||||
|           WorkspaceLocal.init(context, true); | ||||
|           dash.isOpened = true; | ||||
|         } | ||||
|       ), | ||||
|       maptoDropdown: (e) => DropdownMenuItem<String>( | ||||
|                               value: "${e.id}~${e.name}", | ||||
|                               child: Text(e.name), | ||||
|                             ), | ||||
|       type: SharedWorkspaceType.workflow, | ||||
|       all: () async { | ||||
|         List<Shallow> res = []; | ||||
|         await _service.all(context).then( | ||||
|           (e) { | ||||
|             if (e.data != null) { | ||||
|               res = e.data!.values.map((e) => Shallow(id: e["id"] ?? "", name: e["name"] ?? "")).toList(); | ||||
|             } | ||||
|           } | ||||
|         ); | ||||
|         return res; | ||||
|       } | ||||
|     ); | ||||
|   } | ||||
|   @override Widget build(BuildContext context) { | ||||
|     dash.load = loadDash; | ||||
| @@ -151,20 +230,22 @@ final WorflowService _service = WorflowService(); | ||||
|     dash.infoItemWidget = getForms; | ||||
|     dash.infoWidget = getDashInfoForms; | ||||
|     var quart = MediaQuery.of(context).size.width / 6; | ||||
|     dash.defaultName = "workflow_${DateTime.now().toString().replaceAll(" ", "_").substring(0, DateTime.now().toString().length - 7)}"; | ||||
|     dash.defaultName = "workflow_${DateTime.now().toString().replaceAll(" ", "_" | ||||
|       ).substring(0, DateTime.now().toString().length - 7)}"; | ||||
|     return FlowChart<AbstractItem>( | ||||
|                 onDashboardAlertOpened: onDashboardAlertOpened, | ||||
|                 dashboard: dash, | ||||
|                 current: widget.id, | ||||
|                 itemWidget: itemBuild, | ||||
|                 menuWidget: onDashboardMenu, | ||||
|                 categories: const ["processing", "data", "datacenter", "storage", "workflows"], | ||||
|                 draggableItemBuilder: (cat) => WorkspaceLocal.byTopic(cat, false), | ||||
|                 itemWidgetTooltip: itemTooltipBuild, | ||||
|                 innerMenuWidth: quart > 80 ? quart : 80, | ||||
|                 menuExtension: MediaQuery.of(context).size.width > 600 ? menuExtension : null, | ||||
|                 width: MediaQuery.of(context).size.width, | ||||
|                 height: MediaQuery.of(context).size.height - HeaderConstants.height, | ||||
|                 onNewConnection: (p1, p2) { }, | ||||
|                 menuExtension: menuExtension, | ||||
|                 onDashboardTapped: (context, position) { }, | ||||
|                 onScaleUpdate: (newScale) { }, | ||||
|                 onDashboardSecondaryTapped: (context, position) { }, | ||||
|   | ||||
| @@ -4,14 +4,18 @@ import 'package:oc_front/models/search.dart'; | ||||
| import 'package:oc_front/widgets/items/item_row.dart'; | ||||
|  | ||||
| class CatalogWidget extends StatefulWidget { | ||||
|   double? itemWidth; | ||||
|   bool readOnly = false; | ||||
|   final List<AbstractItem>? items; | ||||
|   CatalogWidget ({ Key? key, this.items }): super(key: key); | ||||
|   CatalogWidget ({ Key? key, this.items, this.itemWidth, this.readOnly = false }): super(key: key); | ||||
|   @override CatalogWidgetState createState() => CatalogWidgetState(); | ||||
| } | ||||
| class CatalogWidgetState extends State<CatalogWidget> { | ||||
|   @override Widget build(BuildContext context) { | ||||
|     var items = widget.items ?? WorkspaceLocal.items; | ||||
|     List<ItemRowWidget> itemRows = items.map((e) => ItemRowWidget(contextWidth: MediaQuery.of(context).size.width, item: e)).toList(); | ||||
|     return SingleChildScrollView( child: Column( children: itemRows) ); | ||||
|     List<ItemRowWidget> itemRows = items.map((e) => ItemRowWidget( | ||||
|       readOnly: widget.readOnly, | ||||
|       contextWidth: widget.itemWidth ?? MediaQuery.of(context).size.width, item: e)).toList(); | ||||
|     return Column( children: itemRows); | ||||
|   } | ||||
| } | ||||
| @@ -17,7 +17,10 @@ class LoginWidgetState extends State<LoginWidget> { | ||||
|         child: Icon(Icons.person_search, size: 80, color: Colors.grey,))), | ||||
|       const Center(child: Text("WELCOME ON OPENCLOUD", style: TextStyle(fontSize: 25, fontWeight: FontWeight.w600, | ||||
|         color: Color.fromRGBO(38, 166, 154, 1)),)), | ||||
|       Padding(padding: const EdgeInsets.symmetric(vertical: 20), child: Divider(color: Colors.grey.shade300,),), | ||||
|       Container( | ||||
|         padding: const EdgeInsets.symmetric(vertical: 20), | ||||
|         decoration: BoxDecoration(border: Border(bottom: BorderSide(color: Colors.black))), | ||||
|       ), | ||||
|       Container( margin: const EdgeInsets.only(bottom: 10), child: Center(child: Row( mainAxisAlignment: MainAxisAlignment.center, | ||||
|         children: [  | ||||
|         Container(  | ||||
|   | ||||
| @@ -1,207 +0,0 @@ | ||||
| import 'package:flutter/material.dart'; | ||||
| import 'package:oc_front/models/response.dart'; | ||||
| import 'package:oc_front/core/services/router.dart'; | ||||
| import 'package:oc_front/core/services/specialized_services/shared_service.dart'; | ||||
|  | ||||
| class NewBoxSharedWidget extends StatefulWidget { | ||||
|   String? _selected; | ||||
|   SharedService service = SharedService(); | ||||
|   final TextEditingController _ctrl = TextEditingController(); | ||||
|   final TextEditingController _ctrlDescr = TextEditingController(); | ||||
|   NewBoxSharedWidget ({ super.key, }); | ||||
|   @override NewBoxSharedWidgetState createState() => NewBoxSharedWidgetState(); | ||||
| } | ||||
| class NewBoxSharedWidgetState extends State<NewBoxSharedWidget> { | ||||
|   GlobalKey<FormFieldState> key = GlobalKey<FormFieldState>(); | ||||
|   GlobalKey<FormFieldState> key2 = GlobalKey<FormFieldState>(); | ||||
|   @override Widget build(BuildContext context) { | ||||
|     return Container( | ||||
|       color: Colors.white, | ||||
|       padding: const EdgeInsets.only( top: 0, bottom: 20, left: 20, right: 20), | ||||
|       child: Column( | ||||
|           children: [ | ||||
|             Container(  | ||||
|               alignment: Alignment.centerRight, | ||||
|               height: 50, | ||||
|               child: Row( mainAxisAlignment: MainAxisAlignment.end, children: [ | ||||
|                 const Padding(padding: EdgeInsets.symmetric(horizontal: 10), child:  | ||||
|                   Text("load or create a new shared workspace", style: TextStyle(color: Colors.grey, fontSize: 15) | ||||
|                 )), | ||||
|                 Padding ( padding: const EdgeInsets.symmetric(horizontal: 10), child:  | ||||
|                   Tooltip( message: "back", child: InkWell(  | ||||
|                   mouseCursor: SystemMouseCursors.click, | ||||
|                   onTap: () {  | ||||
|                     AppRouter.catalog.go(context, {});  | ||||
|                   }, | ||||
|                   child: const Icon(Icons.arrow_back, color: Colors.black))), | ||||
|                 ), | ||||
|                 Row ( mainAxisAlignment: MainAxisAlignment.end, children: [ | ||||
|                   Tooltip( message: "close", child: InkWell(  | ||||
|                   mouseCursor: SystemMouseCursors.click, | ||||
|                   onTap: () { Navigator.pop(context); }, | ||||
|                   child: const Icon(Icons.close, color: Colors.black))), | ||||
|                 ]),  | ||||
|               ],), | ||||
|             ), | ||||
|             FutureBuilder<APIResponse<RawData>>( | ||||
|               future: widget.service.all(context), | ||||
|                 builder: (context, snapshot) { | ||||
|                 List<DropdownMenuItem> items = []; | ||||
|                 if (snapshot.data != null && snapshot.data!.data != null) { | ||||
|                   for (var item in snapshot.data!.data!.values) { | ||||
|                     items.add(DropdownMenuItem<String>( | ||||
|                       value: item["id"].toString(), | ||||
|                       child: Text(item["name"].toString()), | ||||
|                     )); | ||||
|                   } | ||||
|                 } | ||||
|                 if (widget._selected != null  | ||||
|                     && !items.where((element) => element.value == widget._selected).isNotEmpty) {  | ||||
|                   items.add(DropdownMenuItem<String>( | ||||
|                             value: widget._selected.toString(), | ||||
|                             child: Text(widget._selected.toString()), | ||||
|                   )); | ||||
|                 } | ||||
|               return  Row(  | ||||
|                 mainAxisAlignment: MainAxisAlignment.center, | ||||
|                 children : [  | ||||
|                   SizedBox( width: MediaQuery.of(context).size.width <= 540 ? MediaQuery.of(context).size.width - 140 : 400, height: 50,  | ||||
|                     child: DropdownButtonFormField( | ||||
|                       value: widget._selected, | ||||
|                       isExpanded: true, | ||||
|                       hint: const Text("load shared workspace...", style: TextStyle(color: Colors.grey, fontSize: 15)), | ||||
|                       decoration: InputDecoration(  | ||||
|                         filled: true, | ||||
|                         focusedBorder: const OutlineInputBorder( borderRadius: BorderRadius.zero, | ||||
|                             borderSide: BorderSide(color: Color.fromARGB(38, 166, 154, 1), width: 0), | ||||
|                         ), | ||||
|                         fillColor: Colors.grey.shade300, | ||||
|                         contentPadding: const EdgeInsets.only(left: 30, right: 30, top: 10, bottom: 30), | ||||
|                         enabledBorder: OutlineInputBorder( borderRadius: BorderRadius.zero, | ||||
|                             borderSide: BorderSide(color: Colors.grey.shade300, width: 0), | ||||
|                         ), | ||||
|                         border: OutlineInputBorder( borderRadius: BorderRadius.zero, | ||||
|                           borderSide: BorderSide(color: Colors.grey.shade300, width: 0)), | ||||
|                       ), | ||||
|                       items: items,  | ||||
|                       onChanged: (value) { | ||||
|                         setState(() { | ||||
|                           widget._selected = value.toString(); | ||||
|                         }); | ||||
|                       })), | ||||
|                   Tooltip( | ||||
|                     message: 'empty selection', | ||||
|                     child: InkWell(  | ||||
|                       mouseCursor: widget._selected == null || widget._selected!.isEmpty ? MouseCursor.defer : SystemMouseCursors.click, | ||||
|                       onTap: () {  | ||||
|                         if (widget._selected == null || widget._selected!.isEmpty) { return; } | ||||
|                         setState(() {  widget._selected = null; });  | ||||
|                       }, | ||||
|                       child: Container(  | ||||
|                         width: 50, height: 50, | ||||
|                         decoration: const BoxDecoration( color: Colors.black, | ||||
|                           border: Border(right: BorderSide(color: Colors.white))), | ||||
|                             child: Icon(Icons.refresh, color: widget._selected == null || widget._selected!.isEmpty  ? Colors.grey : Colors.white), | ||||
|                         ) | ||||
|                    ) | ||||
|                   ), | ||||
|                   Tooltip( | ||||
|                     message: 'load shared workspace selected', | ||||
|                     child: InkWell(  | ||||
|                       mouseCursor: widget._selected == null || widget._selected!.isEmpty   | ||||
|                         ? MouseCursor.defer : SystemMouseCursors.click, | ||||
|                       onTap: () async {  | ||||
|                       }, | ||||
|                       child: Container( | ||||
|                         width: 50, height: 50, | ||||
|                         color: Colors.black, | ||||
|                         child: Icon(Icons.open_in_browser_outlined,  | ||||
|                         color: widget._selected == null || widget._selected!.isEmpty ? Colors.grey : Colors.white), | ||||
|                       ) | ||||
|                     ) | ||||
|                   ) | ||||
|                  ]);}), | ||||
|               Row( | ||||
|                 mainAxisAlignment: MainAxisAlignment.center, | ||||
|                 crossAxisAlignment: CrossAxisAlignment.center, | ||||
|                 children: [ | ||||
|                   Container( | ||||
|                           margin: const EdgeInsets.only(top: 10), | ||||
|                           width: MediaQuery.of(context).size.width <= 540 ? MediaQuery.of(context).size.width - 90 : 450, | ||||
|                           height: 50, | ||||
|                           child: TextFormField( key: key, | ||||
|                             expands: true, | ||||
|                             maxLines: null, | ||||
|                             minLines: null, | ||||
|                             cursorColor: const Color.fromARGB(38, 166, 154, 1), | ||||
|                             controller: widget._ctrl, | ||||
|                             onChanged: (value) { widget._ctrl.text = value; },  | ||||
|                             validator: (value) => value == null || value.isEmpty ? "name is required" : null, | ||||
|                             decoration: InputDecoration( | ||||
|                               hintText: "name a new shared workspace...", | ||||
|                               fillColor: Colors.grey.shade300, | ||||
|                               filled: true, | ||||
|                               errorStyle: const TextStyle(fontSize: 0), | ||||
|                               contentPadding: const EdgeInsets.only(left: 30, right: 30, top: 15, bottom: 5), | ||||
|                               hintStyle: const TextStyle( | ||||
|                                 color: Colors.black, | ||||
|                                 fontSize: 14, | ||||
|                                 fontWeight: FontWeight.w300 | ||||
|                               ), | ||||
|                               border: InputBorder.none | ||||
|                             ) | ||||
|                           ) | ||||
|                         ), | ||||
|                         Tooltip( | ||||
|                           message: 'add', | ||||
|                           child:InkWell(  | ||||
|                             mouseCursor: widget._ctrl.value.text.isEmpty ? MouseCursor.defer : SystemMouseCursors.click, | ||||
|                             onTap: () async { | ||||
|                               if (key.currentState!.validate() && key2.currentState!.validate()) { | ||||
|                                 await widget.service.post(context, { | ||||
|                                   "name" :widget._ctrl.value.text,  | ||||
|                                   "description" : widget._ctrlDescr.value.text }, {}); | ||||
|                               } | ||||
|                             }, | ||||
|                             child: Container( | ||||
|                               margin: const EdgeInsets.only(top: 10), | ||||
|                               width: 50, | ||||
|                               height: 50, | ||||
|                               color: Colors.black, | ||||
|                               child: Icon(Icons.add, color: widget._ctrl.value.text.isEmpty ? Colors.grey : Colors.white) | ||||
|                             ) | ||||
|                           ) | ||||
|                         ) | ||||
|                 ]), | ||||
|             Container( | ||||
|                           margin: const EdgeInsets.only(top: 10), | ||||
|                           width: MediaQuery.of(context).size.width <= 540 ? MediaQuery.of(context).size.width - 40 : 500, | ||||
|                           height: 50, | ||||
|                           child: TextFormField( key: key2, | ||||
|                             expands: true, | ||||
|                             maxLines: null, | ||||
|                             minLines: null, | ||||
|                             cursorColor: const Color.fromARGB(38, 166, 154, 1), | ||||
|                             controller: widget._ctrlDescr, | ||||
|                             onChanged: (value) { widget._ctrlDescr.text = value; },  | ||||
|                             validator: (value) => value == null || value.isEmpty ? "name is required" : null, | ||||
|                             decoration: InputDecoration( | ||||
|                               hintText: "description of a new shared workspace...", | ||||
|                               fillColor: Colors.grey.shade300, | ||||
|                               filled: true, | ||||
|                               errorStyle: const TextStyle(fontSize: 0), | ||||
|                               contentPadding: const EdgeInsets.only(left: 30, right: 30, top: 15, bottom: 5), | ||||
|                               hintStyle: const TextStyle( | ||||
|                                 color: Colors.black, | ||||
|                                 fontSize: 14, | ||||
|                                 fontWeight: FontWeight.w300 | ||||
|                               ), | ||||
|                               border: InputBorder.none | ||||
|                             ) | ||||
|                           ) | ||||
|                         ), | ||||
|           ] | ||||
|         ) | ||||
|     ); | ||||
|   } | ||||
| } | ||||
| @@ -1,199 +0,0 @@ | ||||
| import 'package:flutter/material.dart'; | ||||
| import 'package:flutter_flow_chart/flutter_flow_chart.dart'; | ||||
| import 'package:oc_front/core/models/workspace_local.dart'; | ||||
| import 'package:oc_front/core/services/router.dart'; | ||||
| import 'package:oc_front/core/services/specialized_services/abstract_service.dart'; | ||||
| import 'package:oc_front/models/abstract.dart'; | ||||
| import 'package:oc_front/models/response.dart'; | ||||
|  | ||||
| abstract class New { | ||||
|   String name = ""; | ||||
| } | ||||
|  | ||||
| class NewBoxWidget<T extends SerializerDeserializer<dynamic>> extends StatefulWidget { | ||||
|   String? _selected; | ||||
|   Dashboard dash; | ||||
|   final TextEditingController _ctrl = TextEditingController(); | ||||
|   AbstractService<T> service;  | ||||
|   Function validate = () {}; | ||||
|   NewBoxWidget ({ super.key, required this.service, required this.dash, this.getItems }); | ||||
|   @override NewBoxWidgetState<T> createState() => NewBoxWidgetState<T>(); | ||||
|  | ||||
|   List<DropdownMenuItem> Function(APIResponse<T>? data)? getItems; | ||||
| } | ||||
| class NewBoxWidgetState<T extends SerializerDeserializer<dynamic>> extends State<NewBoxWidget> { | ||||
|   @override Widget build(BuildContext context) { | ||||
|     widget._ctrl.value = TextEditingValue(text: widget.dash.defaultName); | ||||
|     return Container( | ||||
|       color: Colors.white, | ||||
|       padding: const EdgeInsets.only( top: 0, bottom: 20, left: 20, right: 20), | ||||
|       child: Column( | ||||
|           children: [ | ||||
|             Container(  | ||||
|               alignment: Alignment.centerRight, | ||||
|               height: 50, | ||||
|               child: Row( mainAxisAlignment: MainAxisAlignment.end, children: [ | ||||
|                 Padding(padding: const EdgeInsets.symmetric(horizontal: 10), child:  | ||||
|                   Text("load or create a new workflow", style: const TextStyle(color: Colors.grey, fontSize: 15) | ||||
|                 )), | ||||
|                 Padding ( padding: const EdgeInsets.symmetric(horizontal: 10), child:  | ||||
|                   Tooltip( message: "back", child: InkWell(  | ||||
|                   mouseCursor: SystemMouseCursors.click, | ||||
|                   onTap: () {  | ||||
|                     AppRouter.catalog.go(context, {});  | ||||
|                   }, | ||||
|                   child: const Icon(Icons.arrow_back, color: Colors.black))), | ||||
|                 ), | ||||
|                 widget.dash.isOpened ? Row ( mainAxisAlignment: MainAxisAlignment.end, children: [ | ||||
|                   Tooltip( message: "close", child: InkWell(  | ||||
|                   mouseCursor: SystemMouseCursors.click, | ||||
|                   onTap: () { Navigator.pop(context); }, | ||||
|                   child: const Icon(Icons.close, color: Colors.black))), | ||||
|                 ]) : Container(),  | ||||
|               ],), | ||||
|             ), | ||||
|             FutureBuilder<APIResponse<RawData>>( | ||||
|               future: (widget.service as AbstractService<T>).all(context), | ||||
|                 builder: (context, snapshot) { | ||||
|                 List<DropdownMenuItem> items = widget.getItems != null ?  widget.getItems!(snapshot.data) : []; | ||||
|                 if (widget._selected != null  | ||||
|                     && !items.where((element) => element.value == widget._selected).isNotEmpty) {  | ||||
|                   items.add(DropdownMenuItem<String>( | ||||
|                             value: widget._selected.toString(), | ||||
|                             child: Text(widget._selected.toString()), | ||||
|                   )); | ||||
|                 } | ||||
|               return  Row(  | ||||
|                 mainAxisAlignment: MainAxisAlignment.center, | ||||
|                 children : [  | ||||
|                   SizedBox( width: MediaQuery.of(context).size.width <= 540 ? MediaQuery.of(context).size.width - 140 : 400, height: 50,  | ||||
|                     child: DropdownButtonFormField( | ||||
|                       value: widget._selected, | ||||
|                       isExpanded: true, | ||||
|                       hint: const Text("load workflow...", style: TextStyle(color: Colors.grey, fontSize: 15)), | ||||
|                       decoration: InputDecoration(  | ||||
|                         filled: true, | ||||
|                         focusedBorder: const OutlineInputBorder( borderRadius: BorderRadius.zero, | ||||
|                             borderSide: BorderSide(color: Color.fromARGB(38, 166, 154, 1), width: 0), | ||||
|                         ), | ||||
|                         fillColor: Colors.grey.shade300, | ||||
|                         contentPadding: const EdgeInsets.only(left: 30, right: 30, top: 10, bottom: 30), | ||||
|                         enabledBorder: OutlineInputBorder( borderRadius: BorderRadius.zero, | ||||
|                             borderSide: BorderSide(color: Colors.grey.shade300, width: 0), | ||||
|                         ), | ||||
|                         border: OutlineInputBorder( borderRadius: BorderRadius.zero, | ||||
|                           borderSide: BorderSide(color: Colors.grey.shade300, width: 0)), | ||||
|                       ), | ||||
|                       items: items,  | ||||
|                       onChanged: (value) { | ||||
|                         setState(() { | ||||
|                           widget._selected = value.toString(); | ||||
|                         }); | ||||
|                       })), | ||||
|                   Tooltip( | ||||
|                     message: 'empty selection', | ||||
|                     child: InkWell(  | ||||
|                       mouseCursor: widget._selected == null || widget._selected!.isEmpty ? MouseCursor.defer : SystemMouseCursors.click, | ||||
|                       onTap: () {  | ||||
|                         if (widget._selected == null || widget._selected!.isEmpty) { return; } | ||||
|                         setState(() {  widget._selected = null; });  | ||||
|                       }, | ||||
|                       child: Container(  | ||||
|                         width: 50, height: 50, | ||||
|                         decoration: const BoxDecoration( color: Colors.black, | ||||
|                           border: Border(right: BorderSide(color: Colors.white))), | ||||
|                             child: Icon(Icons.refresh, color: widget._selected == null || widget._selected!.isEmpty  ? Colors.grey : Colors.white), | ||||
|                         ) | ||||
|                    ) | ||||
|                   ), | ||||
|                   Tooltip( | ||||
|                     message: 'load workflow selected', | ||||
|                     child: InkWell(  | ||||
|                       mouseCursor: widget._selected == null || widget._selected!.isEmpty   | ||||
|                         ? MouseCursor.defer : SystemMouseCursors.click, | ||||
|                       onTap: () async {  | ||||
|                         if (widget._selected == null || widget._selected!.isEmpty) { return; } | ||||
|                         widget.dash.isOpened = true; | ||||
|                         if (widget._selected != null && widget.dash.load != null) { | ||||
|                           WorkspaceLocal.changeWorkspaceByName(widget._selected!.split("~")[1]);   | ||||
|                           await widget.dash.load!(widget._selected ?? "");          | ||||
|                         }  | ||||
|                         widget.dash.notifyListeners(); | ||||
|                         Navigator.pop(context); | ||||
|                       }, | ||||
|                       child: Container( | ||||
|                         width: 50, height: 50, | ||||
|                         color: Colors.black, | ||||
|                         child: Icon(Icons.open_in_browser_outlined,  | ||||
|                         color: widget._selected == null || widget._selected!.isEmpty ? Colors.grey : Colors.white), | ||||
|                       ) | ||||
|                     ) | ||||
|                   ) | ||||
|                  ]);}), | ||||
|                | ||||
|               Row( | ||||
|                 mainAxisAlignment: MainAxisAlignment.center, | ||||
|                 crossAxisAlignment: CrossAxisAlignment.center, | ||||
|                 children: [ | ||||
|                   Container( | ||||
|                           margin: const EdgeInsets.only(top: 10), | ||||
|                           width: MediaQuery.of(context).size.width <= 540 ? MediaQuery.of(context).size.width - 90 : 450, | ||||
|                           height: 50, | ||||
|                           child: TextFormField( | ||||
|                             expands: true, | ||||
|                             maxLines: null, | ||||
|                             minLines: null, | ||||
|                             cursorColor: const Color.fromARGB(38, 166, 154, 1), | ||||
|                             controller: widget._ctrl, | ||||
|                             onChanged: (value) {},  | ||||
|                             validator: (value) => value == null || value.isEmpty ? "name is required" : null, | ||||
|                             decoration: InputDecoration( | ||||
|                               hintText: "name a new workflow...", | ||||
|                               fillColor: Colors.grey.shade300, | ||||
|                               filled: true, | ||||
|                               contentPadding: const EdgeInsets.only(left: 30, right: 30, top: 15, bottom: 5), | ||||
|                               hintStyle: const TextStyle( | ||||
|                                 color: Colors.black, | ||||
|                                 fontSize: 14, | ||||
|                                 fontWeight: FontWeight.w300 | ||||
|                               ), | ||||
|                               border: InputBorder.none | ||||
|                             ) | ||||
|                           ) | ||||
|                         ), | ||||
|                         Tooltip( | ||||
|                           message: 'add', | ||||
|                           child:InkWell(  | ||||
|                             mouseCursor: widget._ctrl.value.text.isEmpty ? MouseCursor.defer : SystemMouseCursors.click, | ||||
|                             onTap: () async { | ||||
|                               if (widget._ctrl.value.text.isNotEmpty) { | ||||
|                                 await widget.service.post(context, { "name" : widget._ctrl.value.text }, {}).then( | ||||
|                                   (value) { | ||||
|                                     widget._selected = widget._ctrl.value.text; | ||||
|                                     widget._ctrl.value = const TextEditingValue(text: ""); | ||||
|                                     widget.dash.id = value.data?.serialize()["id"]; | ||||
|                                     widget.dash.name = widget._selected ?? ""; | ||||
|                                     widget.dash.notifyListeners(); | ||||
|                                     WorkspaceLocal.init(context, true); | ||||
|                                     widget.dash.isOpened = true; | ||||
|                                     // ignore: use_build_context_synchronously | ||||
|                                     Navigator.pop(context); | ||||
|                                   } | ||||
|                                 ); | ||||
|                               } | ||||
|                             }, | ||||
|                             child: Container( | ||||
|                               margin: const EdgeInsets.only(top: 10), | ||||
|                               width: 50, | ||||
|                               height: 50, | ||||
|                               color: Colors.black, | ||||
|                               child: Icon(Icons.add, color: widget._ctrl.value.text.isEmpty ? Colors.grey : Colors.white) | ||||
|                             ) | ||||
|                           ) | ||||
|                         ) | ||||
|                 ]) | ||||
|           ] | ||||
|         ) | ||||
|     ); | ||||
|   } | ||||
| } | ||||
							
								
								
									
										96
									
								
								lib/widgets/dialog/shallow_creation.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										96
									
								
								lib/widgets/dialog/shallow_creation.dart
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,96 @@ | ||||
| import 'package:flutter/material.dart'; | ||||
| import 'package:oc_front/models/response.dart'; | ||||
| import 'package:oc_front/core/services/router.dart'; | ||||
| import 'package:oc_front/pages/shared.dart'; | ||||
| import 'package:oc_front/widgets/inputs/shallow_dropdown_input.dart'; | ||||
| import 'package:oc_front/widgets/inputs/shallow_text_input.dart'; | ||||
|  | ||||
| class ShallowCreationDialogWidget extends StatefulWidget { | ||||
|   GlobalKey<ShallowTextInputWidgetState>? formKey; | ||||
|   BuildContext context; | ||||
|   bool Function()? canClose; | ||||
|   SharedWorkspaceType type = SharedWorkspaceType.workspace; | ||||
|   Future<List<Shallow>> Function()? all; | ||||
|   Future<void> Function(String)? load; | ||||
|   Future<void> Function(Map<String,dynamic>)? create; | ||||
|   bool Function(String?)? canLoad; | ||||
|   DropdownMenuItem Function(Shallow)? maptoDropdown; | ||||
|   List<ShallowTextInputWidget> form = []; | ||||
|  | ||||
|   ShallowCreationDialogWidget ({ super.key, required this.type, required this.all, this.load, this.formKey, | ||||
|     required this.create, this.form = const [], this.maptoDropdown, required this.context, this.canClose }) ; | ||||
|   @override ShallowCreationDialogState createState() => ShallowCreationDialogState(); | ||||
| } | ||||
| class ShallowCreationDialogState extends State<ShallowCreationDialogWidget> { | ||||
|   GlobalKey<FormFieldState> key = GlobalKey<FormFieldState>(); | ||||
|   GlobalKey<FormFieldState> key2 = GlobalKey<FormFieldState>(); | ||||
|   @override Widget build(BuildContext context) { | ||||
|     var t = widget.type == SharedWorkspaceType.workspace ? "workspace" : (widget.type == SharedWorkspaceType.workflow ? "workflow" : (widget.type == SharedWorkspaceType.shared_workspace ? "shared workspace" :"peer")); | ||||
|     return Container( | ||||
|       color: Colors.white, | ||||
|       padding: const EdgeInsets.only( top: 0, bottom: 20, left: 20, right: 20), | ||||
|       child: Column( | ||||
|           children: [ | ||||
|             Container(  | ||||
|               alignment: Alignment.centerRight, | ||||
|               height: 50, | ||||
|               child: Row( mainAxisAlignment: MainAxisAlignment.end, children: [ | ||||
|                 Padding(padding: const EdgeInsets.symmetric(horizontal: 10), child:  | ||||
|                   Text("load or create a new $t", style: const TextStyle(color: Colors.grey, fontSize: 15) | ||||
|                 )), | ||||
|                 Padding ( padding: const EdgeInsets.symmetric(horizontal: 10), child:  | ||||
|                   Tooltip( message: "back", child: InkWell(  | ||||
|                   mouseCursor: SystemMouseCursors.click, | ||||
|                   onTap: () {  | ||||
|                     AppRouter.catalog.go(context, {});  | ||||
|                   }, | ||||
|                   child: const Icon(Icons.arrow_back, color: Colors.black))), | ||||
|                 ), | ||||
|                 widget.canClose != null && !widget.canClose!() ? Container() :  Row ( mainAxisAlignment: MainAxisAlignment.end, children: [ | ||||
|                   Tooltip( message: "close", child: InkWell(  | ||||
|                   mouseCursor: SystemMouseCursors.click, | ||||
|                   onTap: () { Navigator.pop(context); }, | ||||
|                   child: const Icon(Icons.close, color: Colors.black))), | ||||
|                 ]),  | ||||
|               ],), | ||||
|             ), | ||||
|             ShallowDropdownInputWidget( | ||||
|               all: widget.all,  | ||||
|               type: widget.type, | ||||
|               width: MediaQuery.of(context).size.width <= 540 ? MediaQuery.of(context).size.width - 140 : 400, | ||||
|               load: (e) async { | ||||
|                 await widget.load!(e); | ||||
|                 Navigator.pop(widget.context); | ||||
|               }, | ||||
|               iconLoad: Icons.open_in_browser_outlined, | ||||
|               iconRemove: Icons.refresh, | ||||
|               maptoDropdown: widget.maptoDropdown, | ||||
|               canLoad: (p0) => p0 != null  && p0.isNotEmpty, | ||||
|               canRemove: (p0) => p0 != null  && p0.isNotEmpty, | ||||
|               tooltipRemove: "refresh selection", | ||||
|               deletion: true, | ||||
|               color: Colors.black, | ||||
|               hintColor: Colors.grey, | ||||
|               filled: Colors.grey.shade300, | ||||
|             ), | ||||
|             Container( height: 10), | ||||
|             ShallowTextInputWidget( | ||||
|               key: widget.formKey, | ||||
|               type: widget.type, | ||||
|               width: MediaQuery.of(context).size.width <= 540 ? MediaQuery.of(context).size.width - 140 : 400, | ||||
|               load: (e) async { | ||||
|                 await widget.create!(e); | ||||
|                 Navigator.pop(widget.context); | ||||
|               }, | ||||
|               forms: widget.form, | ||||
|               canLoad: (p0) => p0 != null && p0.isNotEmpty, | ||||
|               color: Colors.black, | ||||
|               hintColor: Colors.grey, | ||||
|               filled: Colors.grey.shade300, | ||||
|             ), | ||||
|             ...widget.form.map( (e) => Container( margin: const EdgeInsets.only(top: 10), child: e)), | ||||
|           ] | ||||
|         ) | ||||
|     ); | ||||
|   } | ||||
| } | ||||
| @@ -6,13 +6,13 @@ import 'package:oc_front/pages/workflow.dart'; | ||||
| 
 | ||||
| Map<String, Map<String, AbstractItem>> proxyWfItem = {}; | ||||
| 
 | ||||
| class ProxyFormsWidget extends StatefulWidget { | ||||
| class ProcessingFormsWidget extends StatefulWidget { | ||||
|   AbstractItem item; | ||||
|   Dashboard dash; | ||||
|   ProxyFormsWidget ({ super.key, required this.item, required this.dash }); | ||||
|   @override ProxyFormsWidgetState createState() => ProxyFormsWidgetState(); | ||||
|   ProcessingFormsWidget ({ super.key, required this.item, required this.dash }); | ||||
|   @override ProcessingFormsWidgetState createState() => ProcessingFormsWidgetState(); | ||||
| } | ||||
| class ProxyFormsWidgetState extends State<ProxyFormsWidget> { | ||||
| class ProcessingFormsWidgetState extends State<ProcessingFormsWidget> { | ||||
|   @override Widget build(BuildContext context) { | ||||
|     List<Widget> children = []; | ||||
|     var l = widget.item.model?.model?.keys ?? []; | ||||
| @@ -1,15 +1,18 @@ | ||||
| import 'package:alert_banner/exports.dart'; | ||||
| import 'package:cron/cron.dart'; | ||||
| import 'package:flutter/widgets.dart'; | ||||
| import 'package:intl/intl.dart' as intl; | ||||
| import 'package:flutter/material.dart'; | ||||
| import 'package:flutter_flow_chart/flutter_flow_chart.dart'; | ||||
| import 'package:flutter_advanced_switch/flutter_advanced_switch.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/specialized_services/workflow_service.dart'; | ||||
|  | ||||
| import 'package:oc_front/core/services/specialized_services/check_service.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/inputs/shallow_text_input.dart'; | ||||
|  | ||||
| class SchedulerFormsWidget extends StatefulWidget { | ||||
|   Dashboard item; | ||||
| @@ -45,6 +48,26 @@ class SchedulerFormsWidgetState extends State<SchedulerFormsWidget> { | ||||
|     } | ||||
|     List<GlobalKey<FormFieldState>> formKeys = [GlobalKey<FormFieldState>(), GlobalKey<FormFieldState>(),  | ||||
|       GlobalKey<FormFieldState>(), GlobalKey<FormFieldState>()]; | ||||
|     var shallow = ShallowTextInputWidget( | ||||
|         width: 250 - 1, | ||||
|         current: dash.name, | ||||
|         type: SharedWorkspaceType.workflow, | ||||
|         canRemove: (p0) => p0 != null && p0.isEmpty, | ||||
|         remove: (p0) async { | ||||
|           await WorflowService().delete(context, widget.item.id ?? "", {}).then((value) { | ||||
|             dash.clear(); | ||||
|             dash.isOpened = false; | ||||
|             dash.chartKey.currentState?.widget.flowChart.setState(() { }); | ||||
|           }); | ||||
|         }, | ||||
|       ); | ||||
|     shallow.change =(p0) => Future.delayed( const Duration(seconds: 2), () async { | ||||
|       if (shallow.compare == p0) { | ||||
|         await WorflowService().put(context, widget.item.id ?? "", { "name" : p0 }, {}); | ||||
|       } else { | ||||
|         shallow.compare = p0; | ||||
|       } | ||||
|     }); | ||||
|     return Column( children: [ | ||||
|       Container( padding: const EdgeInsets.all(10), width: 250, height: 60, | ||||
|         decoration: const BoxDecoration(border: Border(bottom: BorderSide(color: Colors.grey, width: 1))), | ||||
| @@ -52,9 +75,12 @@ class SchedulerFormsWidgetState extends State<SchedulerFormsWidget> { | ||||
|           Text("WORKFLOW INFO", style: TextStyle(fontSize: 15, fontWeight: FontWeight.bold), textAlign: TextAlign.center), | ||||
|           Text("<general>", style: TextStyle(fontSize: 12), textAlign: TextAlign.center), | ||||
|       ])), | ||||
|       Container(height: 20, | ||||
|         width: 250, | ||||
|       ), | ||||
|       Container(  | ||||
|         decoration: BoxDecoration( border: Border( | ||||
|           left: BorderSide(color: Colors.grey.shade300, width: 1), | ||||
|           bottom: const BorderSide(color: Colors.grey))), | ||||
|         child: shallow ), | ||||
|       const SizedBox(height: 20, width: 250 ), | ||||
|       AdvancedSwitch( | ||||
|           width: 140,  | ||||
|           initialValue: widget.item.scheduler["mode"] == 1,  | ||||
| @@ -67,6 +93,7 @@ class SchedulerFormsWidgetState extends State<SchedulerFormsWidget> { | ||||
|             setState(() { | ||||
|               widget.item.scheduler["mode"] = value == true ? 1 : 0; | ||||
|               if ((widget.item.scheduler["mode"] == 1 )) { widget.item.scheduler.remove("cron"); } | ||||
|               widget.item.save!(widget.item.id); | ||||
|             })); | ||||
|           },), | ||||
|       Container(height: 5), | ||||
| @@ -334,7 +361,11 @@ class SchedulerFormsWidgetState extends State<SchedulerFormsWidget> { | ||||
|       Container( | ||||
|         width: 250, | ||||
|         height: 20, | ||||
|         decoration: const BoxDecoration(border: Border(bottom: BorderSide(color: Colors.black, width: 1))), | ||||
|         decoration: const BoxDecoration(border: Border(bottom: BorderSide(color: Colors.grey, width: 1))), | ||||
|       ), | ||||
|       const SizedBox( | ||||
|         width: 250, | ||||
|         height: 10, | ||||
|       ), | ||||
|       Tooltip( message: "check booking", | ||||
|                               child: InkWell( mouseCursor: SystemMouseCursors.click,  | ||||
| @@ -367,13 +398,13 @@ class SchedulerFormsWidgetState extends State<SchedulerFormsWidget> { | ||||
|                                     setState(() {}); | ||||
|                                   } | ||||
|                                 ); | ||||
|                               }, child: Container( margin: const EdgeInsets.all(10), | ||||
|                               }, child: Container( margin: const EdgeInsets.only(bottom: 5), | ||||
|                                 decoration: BoxDecoration(borderRadius: BorderRadius.circular(5),  | ||||
|                                   border: Border.all(color: widget.booking == null && !dash.scheduleActive ? Colors.grey :  (widget.booking == true || dash.scheduleActive  ? Colors.green : Colors.red), width: 1)), | ||||
|                                   border: Border.all(color: widget.booking == null && !dash.scheduleActive ? Colors.black :  (widget.booking == true || dash.scheduleActive  ? Colors.green : Colors.red), width: 1)), | ||||
|                                 width: 200, height: 30, | ||||
|                                 child: Icon( | ||||
|                                   Icons.verified_outlined,  | ||||
|                                   color: widget.booking == null && !dash.scheduleActive ? Colors.grey :  (widget.booking == true || dash.scheduleActive ? Colors.green : Colors.red)), | ||||
|                                   color: widget.booking == null && !dash.scheduleActive ? Colors.black :  (widget.booking == true || dash.scheduleActive ? Colors.green : Colors.red)), | ||||
|                               )) | ||||
|                             ), | ||||
|       Tooltip( message: dash.scheduleActive ? "unbook" : "book", | ||||
| @@ -387,7 +418,7 @@ class SchedulerFormsWidgetState extends State<SchedulerFormsWidget> { | ||||
|                                     } else { k.currentState!.save();} | ||||
|                                   } | ||||
|                                 } | ||||
|                                 DateTime now = DateTime.now().add(const Duration(minutes: 5)); | ||||
|                                 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) { | ||||
| @@ -396,7 +427,7 @@ class SchedulerFormsWidgetState extends State<SchedulerFormsWidget> { | ||||
|                                 } | ||||
|                                 widget.item.save!(widget.item.id); | ||||
|                                 setState(() {   }); | ||||
|                               }, child: Container( margin: const EdgeInsets.all(10), | ||||
|                               }, 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)), | ||||
|                                 width: 200, height: 30, | ||||
| @@ -411,16 +442,18 @@ class SchedulerFormsWidgetState extends State<SchedulerFormsWidget> { | ||||
|           decoration: const BoxDecoration(border: Border(top: BorderSide(color: Colors.black))), | ||||
|         ), | ||||
|         Container( alignment: Alignment.center, padding: const EdgeInsets.symmetric(horizontal: 20), | ||||
|           child: Text( textAlign: TextAlign.center, | ||||
|           child:Text( textAlign: TextAlign.center, overflow: TextOverflow.ellipsis, | ||||
|             style: const TextStyle(fontSize: 14, color: Colors.black, fontWeight: FontWeight.bold), | ||||
|             "Workflow is shared in ${(widget.item.info["shared"] as List<dynamic>).length} workspace(s)")), | ||||
|         ...(widget.item.info["shared"] as List<dynamic>).where( (e) => SharedWorkspaceLocal.getSharedWorkspace(e) != null  | ||||
|         ).map((e) { | ||||
|           var sw = SharedWorkspaceLocal.getSharedWorkspace(e); | ||||
|           return Container( alignment: Alignment.center, padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 5), | ||||
|             child: Row(  children: [  | ||||
|               const Padding(padding: EdgeInsets.only(right: 10), child: Icon(Icons.work, color: Colors.grey, size: 15)), | ||||
|               Text(style: const TextStyle(fontSize: 12, color: Colors.grey), | ||||
|               "Workspace: ${SharedWorkspaceLocal.getSharedWorkspace(e)!.name}") ])); | ||||
|               "Workspace: ${sw != null && sw.name != null ?  | ||||
|               "${sw.name!.substring(0, sw.name!.length > 15 ? 12 : sw.name!.length)}${sw.name!.length > 15 ? "..." : ""}" : ""}") ])); | ||||
|         },) | ||||
|       ]) : Container() | ||||
|     ]); | ||||
|   | ||||
							
								
								
									
										121
									
								
								lib/widgets/inputs/shallow_dropdown_input.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										121
									
								
								lib/widgets/inputs/shallow_dropdown_input.dart
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,121 @@ | ||||
| import 'package:flutter/material.dart'; | ||||
| import 'package:oc_front/models/response.dart'; | ||||
| import 'package:oc_front/pages/shared.dart'; | ||||
| class ShallowDropdownInputWidget extends StatefulWidget { | ||||
|   double? width; | ||||
|   SharedWorkspaceType type = SharedWorkspaceType.workspace; | ||||
|   Future<List<Shallow>> Function()? all; | ||||
|   Future<void> Function(String)? load; | ||||
|   Future<void>  Function(String)? remove; | ||||
|   bool Function(String?)? canLoad; | ||||
|   bool Function(String?)? canRemove; | ||||
|   void Function(String?)? change; | ||||
|   DropdownMenuItem Function(Shallow)? maptoDropdown; | ||||
|   String? current; | ||||
|  | ||||
|   IconData? iconLoad; | ||||
|   IconData? iconRemove; | ||||
|  | ||||
|   String? hint; | ||||
|  | ||||
|   String? tooltipLoad; | ||||
|   String? tooltipRemove; | ||||
|  | ||||
|   Color? filled; | ||||
|   Color? hintColor; | ||||
|   Color? color; | ||||
|  | ||||
|   bool deletion = false; | ||||
|  | ||||
|   ShallowDropdownInputWidget ({ Key? key, this.width, this.current, required this.all, | ||||
|   this.iconLoad, this.iconRemove, this.hint, this.filled, this.hintColor, this.color, | ||||
|   this.tooltipLoad, this.tooltipRemove, this.deletion = false, this.maptoDropdown, | ||||
|   required this.type, this.canLoad, this.canRemove, this.load, this.remove, this.change }): super(key: key); | ||||
|   @override ShallowDropdownInputWidgetState createState() => ShallowDropdownInputWidgetState(); | ||||
| } | ||||
| class ShallowDropdownInputWidgetState extends State<ShallowDropdownInputWidget> { | ||||
|   @override Widget build(BuildContext context) { | ||||
|     if (widget.deletion && widget.remove == null) { | ||||
|       widget.remove =(p0) async => widget.current = null; | ||||
|     } | ||||
|     var t = widget.type == SharedWorkspaceType.workspace ? "workspace" : (widget.type == SharedWorkspaceType.workflow ? "workflow" : "peer"); | ||||
|     return FutureBuilder(future: widget.all!(), builder: (b, s) { | ||||
|       List<DropdownMenuItem> items = []; | ||||
|       if (widget.maptoDropdown != null) { | ||||
|         items = s.data?.map((e) => widget.maptoDropdown!(e)).toList() ?? <DropdownMenuItem>[]; | ||||
|       } else { | ||||
|         items = s.data?.map((e) => DropdownMenuItem(value: e.id,child: Text(e.name),)).toList() ?? <DropdownMenuItem>[]; | ||||
|       }  | ||||
|       return Row( children: [ | ||||
|           Tooltip( message: widget.hint ?? "current $t", child: | ||||
|           Theme( | ||||
|             data: Theme.of(context).copyWith( | ||||
|               canvasColor: Colors.grey.shade300, | ||||
|             ), | ||||
|             child: Container( height: 50, width: (widget.width ?? MediaQuery.of(context).size.width) - (widget.load == null ? 0 : 50) - (widget.remove == null ? 0 : 50),  | ||||
|             decoration: const BoxDecoration( | ||||
|               color: Colors.white, | ||||
|             ),   | ||||
|             child:  DropdownButtonFormField( | ||||
|                       onChanged: (value) { | ||||
|                         setState(() { | ||||
|                           widget.current = value; | ||||
|                           if (widget.change != null) { | ||||
|                             widget.change!(value); | ||||
|                           } | ||||
|                         }); | ||||
|                       }, | ||||
|                       value: widget.current != null && !items.map( ((e) => e.value)).contains(widget.current) ? null : widget.current, | ||||
|                       isExpanded: true, | ||||
|                       style: TextStyle(color: widget.color ?? Colors.black, fontSize: 15), | ||||
|                       hint: Text(widget.hint ?? "load $t...",  | ||||
|                         style: TextStyle(color: widget.hintColor ??Colors.grey.shade300, fontSize: 14)), | ||||
|                       icon:  Icon(                // Add this | ||||
|                         Icons.arrow_drop_down,  // Add this | ||||
|                         color: widget.hintColor ?? Colors.grey ,   // Add this | ||||
|                        ), | ||||
|                       decoration: InputDecoration(  | ||||
|                         filled: true, | ||||
|                         suffixIconColor: widget.hintColor ?? Colors.grey , | ||||
|                         focusedBorder: InputBorder.none, | ||||
|                         fillColor: widget.filled ??Colors.white, | ||||
|                         enabledBorder: InputBorder.none, | ||||
|                         border: InputBorder.none, | ||||
|                         contentPadding: EdgeInsets.only(left: (widget.width ?? 400) < 200 ? 0 : 30, right: (widget.width ?? 400) < 200 ? 0 : 30, top: 18, bottom: 18), | ||||
|                       ), | ||||
|                       items: items,  | ||||
|                       )))), | ||||
|           widget.load == null ? Container() : Tooltip( | ||||
|             message: widget.tooltipLoad ?? "load $t", | ||||
|             child:InkWell(  | ||||
|             mouseCursor: SystemMouseCursors.click, | ||||
|             onTap: () async { | ||||
|               if (widget.canLoad == null || !widget.canLoad!(widget.current) || widget.load == null || widget.current == null) { | ||||
|                 return; | ||||
|               } | ||||
|               await widget.load!(widget.current!); | ||||
|               setState(() {  }); | ||||
|             }, | ||||
|             child: Container( width: 50,height: 50, | ||||
|               color: Colors.black, | ||||
|               child: Icon( widget.iconLoad ?? Icons.add, color: widget.current == null || widget.canLoad == null || !widget.canLoad!(widget.current) ? Colors.grey : Colors.white) | ||||
|             ) | ||||
|           ) | ||||
|         ), | ||||
|         widget.remove == null ? Container() : Tooltip( | ||||
|             message: widget.tooltipRemove ?? "remove $t", | ||||
|             child: InkWell( mouseCursor: SystemMouseCursors.click, | ||||
|               onTap: () async { | ||||
|                 if (widget.canRemove == null || !widget.canRemove!(widget.current) || widget.remove == null || widget.current == null) { | ||||
|                   return; | ||||
|                 } | ||||
|                 await widget.remove!(widget.current!); | ||||
|                 setState(() {  }); | ||||
|             }, | ||||
|             child: Container( width: 50,height: 50, | ||||
|               decoration: BoxDecoration(color: Colors.black, border: Border(left: BorderSide(color: Colors.grey.shade300))), | ||||
|               child: Icon(widget.iconRemove ?? Icons.delete, color: widget.current == null || widget.canRemove == null || !widget.canRemove!(widget.current) ? Colors.grey : Colors.white)) ) | ||||
|           ), | ||||
|         ]); }); | ||||
|   } | ||||
| } | ||||
							
								
								
									
										137
									
								
								lib/widgets/inputs/shallow_text_input.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										137
									
								
								lib/widgets/inputs/shallow_text_input.dart
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,137 @@ | ||||
| import 'package:flutter/material.dart'; | ||||
| import 'package:oc_front/models/response.dart'; | ||||
| import 'package:oc_front/pages/shared.dart'; | ||||
| class ShallowTextInputWidget extends StatefulWidget { | ||||
|   double? width; | ||||
|   SharedWorkspaceType type = SharedWorkspaceType.workspace; | ||||
|   Future<void> Function(Map<String,dynamic>)? load; | ||||
|   Future<void> Function(String)? loadStr; | ||||
|   Future<void>  Function(String)? remove; | ||||
|   bool Function(String?)? canLoad; | ||||
|   bool Function(String?)? canRemove; | ||||
|   void Function(String?)? change; | ||||
|   String? current; | ||||
|   String? compare; | ||||
|  | ||||
|   IconData? iconLoad; | ||||
|   IconData? iconRemove; | ||||
|  | ||||
|   String? hint; | ||||
|  | ||||
|   String? tooltipLoad; | ||||
|   String? tooltipRemove; | ||||
|  | ||||
|   Color? filled; | ||||
|   Color? hintColor; | ||||
|   Color? color; | ||||
|   List<ShallowTextInputWidget> forms = []; | ||||
|  | ||||
|   String? attr; | ||||
|  | ||||
|   ShallowTextInputWidget ({ Key? key, this.width, this.current, this.attr, | ||||
|   this.iconLoad, this.iconRemove, this.hint, this.forms = const [], this.loadStr, | ||||
|   this.tooltipLoad = "", this.tooltipRemove = "", | ||||
|   this.filled, this.hintColor, this.color, | ||||
|   required this.type, this.canLoad, this.canRemove, this.load, this.remove, this.change }): super(key: key); | ||||
|   @override ShallowTextInputWidgetState createState() => ShallowTextInputWidgetState(); | ||||
|  | ||||
|   Map<String, dynamic> serialize() { | ||||
|     Map<String, dynamic> map = { "name" : current }; | ||||
|     for (var form in forms) { | ||||
|       if (form.attr == null) { | ||||
|         continue; | ||||
|       } | ||||
|       map[form.attr!] = form.current; | ||||
|     } | ||||
|     return map; | ||||
|   } | ||||
|  | ||||
|   bool validate() { | ||||
|     return canLoad == null ? true : canLoad!(current); | ||||
|   } | ||||
| } | ||||
| class ShallowTextInputWidgetState extends State<ShallowTextInputWidget> { | ||||
|   bool validForms() { | ||||
|     for (var form in widget.forms) { | ||||
|       if (!form.validate()) { | ||||
|         return false; | ||||
|       } | ||||
|     } | ||||
|     return true; | ||||
|   } | ||||
|  | ||||
|   @override Widget build(BuildContext context) { | ||||
|     var t = widget.type == SharedWorkspaceType.workspace ? "workspace" : (widget.type == SharedWorkspaceType.workflow ? "workflow" : "peer"); | ||||
|     return Row( children: [ | ||||
|           Tooltip( message: widget.hint ?? "current $t", child: | ||||
|           Theme( | ||||
|             data: Theme.of(context).copyWith( | ||||
|               canvasColor: Colors.grey.shade300, | ||||
|             ), | ||||
|             child: Container( height: 50, width: (widget.width ?? MediaQuery.of(context).size.width) - (widget.load == null ? 0 : 50) - (widget.remove == null ? 0 : 50),  | ||||
|             decoration: BoxDecoration( | ||||
|               color: Colors.white, | ||||
|             ),        | ||||
|             child:  TextFormField( | ||||
|                       onChanged: (value) { | ||||
|                         setState(() { | ||||
|                           widget.current = value; | ||||
|                           if (widget.change != null) { | ||||
|                             widget.change!(value); | ||||
|                           } | ||||
|                         }); | ||||
|                       }, | ||||
|                       initialValue: widget.current, | ||||
|                       style: TextStyle(color: widget.color ?? Colors.black, fontSize: 15), | ||||
|                       decoration: InputDecoration(  | ||||
|                         filled: true, | ||||
|                         border: InputBorder.none, | ||||
|                         focusedBorder: InputBorder.none, | ||||
|                         disabledBorder: InputBorder.none, | ||||
|                         enabledBorder: InputBorder.none, | ||||
|                         fillColor: widget.filled ?? Colors.white, | ||||
|                         hintText: widget.hint ?? "enter $t ${widget.attr ?? "name"}...",  | ||||
|                         contentPadding: const EdgeInsets.only(left: 30, right: 30, top: 18, bottom: 18), | ||||
|                         hintStyle: TextStyle(color: widget.hintColor ??const Color.fromARGB(255, 85, 44, 44), fontSize: 14)), | ||||
|                       ), | ||||
|                       ))), | ||||
|           widget.load == null && widget.loadStr == null ? Container() : Tooltip( | ||||
|             message: widget.tooltipLoad ?? "add $t", | ||||
|             child:InkWell(  | ||||
|             mouseCursor: SystemMouseCursors.click, | ||||
|             onTap: () async { | ||||
|               if (widget.canLoad == null || !widget.canLoad!(widget.current) || !validForms() | ||||
|               || (widget.load == null && widget.loadStr == null)  || widget.current == null) { | ||||
|                 return; | ||||
|               } | ||||
|               if (widget.loadStr != null) { | ||||
|                 await widget.loadStr!(widget.current!); | ||||
|               } else { | ||||
|                 await widget.load!(widget.serialize()); | ||||
|               } | ||||
|               setState(() {  }); | ||||
|             }, | ||||
|             child: Container( width: 50,height: 50, | ||||
|               color: Colors.black, | ||||
|               child: Icon( widget.iconLoad ?? Icons.add, color: widget.current == null || !validForms() | ||||
|               || widget.canLoad == null || !widget.canLoad!(widget.current) ? Colors.grey : Colors.white) | ||||
|             ) | ||||
|           ) | ||||
|         ), | ||||
|         widget.remove == null ? Container() : Tooltip( | ||||
|             message: widget.tooltipRemove ?? "refresh entry", | ||||
|             child: InkWell( mouseCursor: SystemMouseCursors.click, | ||||
|               onTap: () async { | ||||
|                 if (widget.canRemove == null || !widget.canRemove!(widget.current) || widget.remove == null || widget.current == null) { | ||||
|                   return; | ||||
|                 } | ||||
|                 await widget.remove!(widget.current!); | ||||
|                 setState(() {  }); | ||||
|             }, | ||||
|             child: Container( width: 50,height: 50, | ||||
|               decoration: BoxDecoration(color: Colors.black, border: Border(left: BorderSide(color: Colors.grey.shade300))), | ||||
|               child: Icon(widget.iconRemove ?? Icons.delete, color: widget.current == null || widget.canRemove == null || !widget.canRemove!(widget.current) ? Colors.grey : Colors.white)) ) | ||||
|           ), | ||||
|         ]); | ||||
|   } | ||||
| } | ||||
| @@ -18,7 +18,7 @@ class ItemRowWidget extends StatefulWidget { | ||||
| } | ||||
| class ItemRowWidgetState extends State<ItemRowWidget> { | ||||
|   @override Widget build(BuildContext context) { | ||||
|     double imageSize = MediaQuery.of(context).size.width != widget.contextWidth ? 0 : 80; | ||||
|     double imageSize = widget.contextWidth <= 400 ? 0 : 80; | ||||
|     var ratio = MediaQuery.of(context).size.width != widget.contextWidth ? 0.5 : 1; // 2; | ||||
|     var itemWidth = (((widget.contextWidth - imageSize) / 3) - 80) / ratio; | ||||
|     itemWidth = itemWidth > 100 ? 100 : ( itemWidth < 40 ? 40 : itemWidth ); | ||||
| @@ -30,6 +30,7 @@ class ItemRowWidgetState extends State<ItemRowWidget> { | ||||
|     Widget w = Container( | ||||
|       width: widget.contextWidth, | ||||
|       height: 100, | ||||
|       padding: EdgeInsets.only(left: imageSize == 0 ? 20 : 0), | ||||
|       decoration: BoxDecoration( border: Border(bottom: BorderSide(color: Colors.grey.shade300)) ), | ||||
|       child: Row( children: [ | ||||
|           widget.low ? Container( padding: const EdgeInsets.only(left: 10),) : Container( padding: const EdgeInsets.all(10),  | ||||
|   | ||||
							
								
								
									
										74
									
								
								lib/widgets/items/shallow_item_row.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										74
									
								
								lib/widgets/items/shallow_item_row.dart
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,74 @@ | ||||
| import 'dart:math'; | ||||
|  | ||||
| import 'package:flutter/material.dart'; | ||||
| import 'package:oc_front/models/response.dart'; | ||||
|  | ||||
| const List<GlobalKey<State>> _empty = []; | ||||
| // ignore: must_be_immutable | ||||
| class ShallowItemRowWidget extends StatefulWidget { | ||||
|   bool readOnly = false; | ||||
|   double contextWidth = 0; | ||||
|   ShallowData item; | ||||
|   IconData? icon; | ||||
|   bool low = false; | ||||
|   bool show = false; | ||||
|   List<IconData> badges = []; | ||||
|   void Function(String?)? delete; | ||||
|   void Function(String?)? edit; | ||||
|   List<GlobalKey<State>> keys = []; | ||||
|   ShallowItemRowWidget ({ super.key, this.low = false, this.icon, this.delete, this.edit, this.badges = const [], | ||||
|     required this.contextWidth, this.readOnly = false, required this.item, this.keys = _empty }); | ||||
|   @override ShallowItemRowWidgetState createState() => ShallowItemRowWidgetState(); | ||||
| } | ||||
| class ShallowItemRowWidgetState extends State<ShallowItemRowWidget> { | ||||
|   @override Widget build(BuildContext context) { | ||||
|     Widget w = Tooltip( message: widget.item.getName(), child: MouseRegion(  | ||||
|       onHover: (e) => setState(() { | ||||
|         widget.show = true; | ||||
|       }), | ||||
|       onExit: (e) => setState(() { | ||||
|         widget.show = false; | ||||
|       }), | ||||
|       child: Container( | ||||
|       height: widget.contextWidth, width: widget.contextWidth, | ||||
|       padding: const EdgeInsets.all(20), | ||||
|       decoration: BoxDecoration( borderRadius: BorderRadius.circular(4), color: Colors.white, | ||||
|         boxShadow: const [BoxShadow(color: Colors.grey, spreadRadius: 1, blurRadius: 1, offset: Offset(0, 1))]), | ||||
|       child: Stack( children: [  | ||||
|         widget.show ? Positioned( left: 0, top: 0, | ||||
|           child: Row( children: [ | ||||
|             Padding( padding: const EdgeInsets.only(right: 5), | ||||
|               child: widget.edit == null ? Container() : InkWell( mouseCursor:  SystemMouseCursors.click, | ||||
|               onTap: () =>  widget.edit!(widget.item.getID() + "~" + widget.item.getName()), child: const Icon(Icons.edit, color: Colors.grey,))), | ||||
|             Padding( padding: const EdgeInsets.only(right: 5), | ||||
|               child: widget.delete == null ? Container() : InkWell( mouseCursor:  SystemMouseCursors.click, | ||||
|               onTap: () => widget.delete!(widget.item.getID()), child: const Icon(Icons.delete, color: Colors.grey,))), | ||||
|           ] )) : Container(), | ||||
|         Positioned( right: 0, top: 0, | ||||
|           child: Row( children: widget.badges.map( (e) => Padding( padding: const EdgeInsets.only(left: 5), child: Icon(e, color: Colors.orange.shade300,))).toList() )), | ||||
|         Column( children: [ | ||||
|           widget.low || widget.icon == null ? Container( padding: const EdgeInsets.only(left: 10),) : Container( padding: const EdgeInsets.all(10),  | ||||
|             constraints: BoxConstraints(maxWidth: widget.contextWidth, minWidth: widget.contextWidth), | ||||
|             child: Icon( widget.icon!, size: widget.contextWidth / 1.9, color: const Color(0xFFF67C0B9),)), | ||||
|             Container( | ||||
|               child: Padding(padding: widget.contextWidth != MediaQuery.of(context).size.width ?  | ||||
|               const EdgeInsets.symmetric(horizontal: 10) : const EdgeInsets.symmetric(horizontal: 20), | ||||
|                 child: Column(crossAxisAlignment: CrossAxisAlignment.start,  | ||||
|                   mainAxisAlignment: MainAxisAlignment.center, children: [ | ||||
|                   Row( children: [  | ||||
|                     Expanded( child: Center( child: Text(widget.item.getName().toUpperCase(),  | ||||
|                       style: const TextStyle(fontSize: 15,  | ||||
|                       overflow: TextOverflow.ellipsis,  | ||||
|                       fontWeight: FontWeight.w600, color: Colors.grey)), | ||||
|                     )) | ||||
|                   ]), | ||||
|                 ],) | ||||
|               ) | ||||
|             ), | ||||
|           ]) | ||||
|         ])))); | ||||
|     return widget.readOnly || widget.low ? w : InkWell( mouseCursor:  SystemMouseCursors.click, | ||||
|       onTap: () { }, | ||||
|       child: w ); | ||||
|   }  | ||||
| } | ||||
| @@ -60,7 +60,7 @@ class LogWidgetState extends State<LogWidget> { | ||||
|             child: Icon( widget.expanded ? Icons.keyboard_arrow_down_outlined : Icons.arrow_forward_ios, size: widget.expanded ? 25 : 15,  | ||||
|             color: map.isEmpty ? Colors.grey : Colors.black, weight: widget.expanded ? 100 : 1000,)))), | ||||
|         Padding( padding: const EdgeInsets.only(right: 10), | ||||
|           child: Text("${widget.item.timestamp?.toString()}",  | ||||
|           child: Text("${widget.item.timestamp?.toLocal().toString().substring(3)}",  | ||||
|             style: const TextStyle(fontSize: 13, color: Colors.black, fontWeight: FontWeight.w500))), | ||||
|         Tooltip( message : "copy to clipboard", child: InkWell( child: const Icon(Icons.copy, size: 15, color: Colors.grey), onTap: () { | ||||
|           if (widget.item.message != null) { | ||||
|   | ||||
| @@ -1,142 +0,0 @@ | ||||
| import 'package:flutter/material.dart'; | ||||
| import 'package:oc_front/core/models/shared_workspace_local.dart'; | ||||
| import 'package:oc_front/core/services/specialized_services/shared_service.dart'; | ||||
| import 'package:oc_front/models/shared.dart'; | ||||
| import 'package:oc_front/pages/catalog.dart'; | ||||
| import 'package:oc_front/pages/catalog_item.dart'; | ||||
| import 'package:oc_front/pages/workflow.dart'; | ||||
|  | ||||
| enum SharedMenuWorkspaceType { workspace, workflow, peer } | ||||
|  | ||||
| class SharedMenuWorkspaceWidget extends StatefulWidget { | ||||
|   List<dynamic> excluded = []; | ||||
|   SharedMenuWorkspaceType type = SharedMenuWorkspaceType.workspace; | ||||
|   double? width; | ||||
|   String contextID; | ||||
|   SharedService service = SharedService(); | ||||
|   String? selected; | ||||
|   bool inner = false; | ||||
|   bool reverse = false; | ||||
|   double? topMargin; | ||||
|   String? before; | ||||
|   TextEditingController ctrl = TextEditingController(); | ||||
|   SharedMenuWorkspaceWidget ({ Key? key, this.width, required this.contextID, this.selected, | ||||
|     this.type = SharedMenuWorkspaceType.workspace, this.topMargin, this.excluded = const [], | ||||
|     this.inner = false, this.reverse = false, this.before}): super(key: key);  | ||||
|   @override SharedMenuWorkspaceWidgetState createState() => SharedMenuWorkspaceWidgetState(); | ||||
| } | ||||
| class SharedMenuWorkspaceWidgetState extends State<SharedMenuWorkspaceWidget> { | ||||
|   @override Widget build(BuildContext context) { | ||||
|     return Row( children: [ | ||||
|           Tooltip( message: "current workspace", child: | ||||
|           Theme( | ||||
|             data: Theme.of(context).copyWith( | ||||
|               canvasColor: Colors.grey, | ||||
|             ), | ||||
|             child: Container(  | ||||
|             margin: EdgeInsets.only(top: widget.topMargin ?? (widget.inner ? 0 : 10)),   | ||||
|             height: 50, width: (widget.width ?? MediaQuery.of(context).size.width) - 100,  | ||||
|             decoration: BoxDecoration( | ||||
|               color: widget.reverse ? Colors.white :  ( widget.inner ? Color.fromRGBO(38, 166, 154, 1) : Colors.grey.shade300 ), | ||||
|               border: const Border(bottom: BorderSide(color: Colors.transparent, width: 1)) | ||||
|             ), | ||||
|             padding: EdgeInsets.only(left: (widget.width ?? 400) < 400 ? 20 : 50, right: (widget.width ?? 400) < 400 ? 20 : 0), | ||||
|             child:  DropdownButtonFormField( | ||||
|                       value: widget.selected, | ||||
|                       isExpanded: true, | ||||
|                       style: const TextStyle(color:Colors.black, fontSize: 15), | ||||
|                       hint: Text("choose shared workspace...", style: TextStyle(color: widget.inner ? Colors.grey.shade300 : Colors.grey, fontSize: 15)), | ||||
|                       icon: Icon(                // Add this | ||||
|                         Icons.arrow_drop_down,  // Add this | ||||
|                         color: widget.inner ? Colors.white : Colors.grey,   // Add this | ||||
|                        ), | ||||
|                       decoration: InputDecoration(  | ||||
|                         filled: true, | ||||
|                         suffixIconColor: widget.inner ? Colors.grey.shade300 : Colors.grey, | ||||
|                         focusedBorder: const OutlineInputBorder( borderRadius: BorderRadius.zero, | ||||
|                             borderSide: BorderSide(color: Colors.transparent, width: 0), | ||||
|                         ), | ||||
|                         fillColor: widget.reverse ? Colors.white :  (widget.inner ? const Color.fromRGBO(38, 166, 154, 1) : Colors.grey.shade300), | ||||
|                         contentPadding: EdgeInsets.only(left: 0 , right: (widget.width ?? 400) < 400 ? 0 : 30, top: 10, bottom: 30), | ||||
|                         enabledBorder: const OutlineInputBorder( borderRadius: BorderRadius.zero, | ||||
|                             borderSide: BorderSide(color: Colors.transparent, width: 0), | ||||
|                         ), | ||||
|                         border: const OutlineInputBorder( borderRadius: BorderRadius.zero, | ||||
|                           borderSide: BorderSide(color: Colors.transparent, width: 0)), | ||||
|                       ), | ||||
|                       items: SharedWorkspaceLocal.workspaces.values.where((element) => !widget.excluded.contains(element.id) | ||||
|                         ).map((e) => DropdownMenuItem( | ||||
|                         value: e.id ,child: Text(e.name ?? ""),)).toList(), | ||||
|                       onChanged: (value) { | ||||
|                         setState(() { | ||||
|                           widget.before = widget.selected; | ||||
|                           widget.selected = value.toString(); | ||||
|                         }); | ||||
|                       })))), | ||||
|           Tooltip( | ||||
|                           message: 'share', | ||||
|                           child:InkWell(  | ||||
|                             mouseCursor: widget.selected == null || widget.selected == widget.before ? MouseCursor.defer : SystemMouseCursors.click, | ||||
|                             onTap: () async { | ||||
|                               if (widget.selected != null && widget.contextID != "" && widget.selected != widget.before) { | ||||
|                                 if (widget.type == SharedMenuWorkspaceType.peer) { | ||||
|                                   await widget.service.addPeer(context, widget.selected!, widget.contextID); | ||||
|                                 } else if (widget.type == SharedMenuWorkspaceType.workflow) { | ||||
|                                   await widget.service.addWorkflow(context, widget.selected!, widget.contextID); | ||||
|                                 } else { | ||||
|                                   await widget.service.addWorkspace(context, widget.selected!, widget.contextID); | ||||
|                                 } | ||||
|                                 SharedWorkspaceLocal.init(context, false); | ||||
|                                 setState(() {}); | ||||
|                                 dash.selectedLeftMenuKey.currentState?.setState(() { }); | ||||
|                                 CatalogFactory.key.currentState?.setState(() {}); | ||||
|                                 CatalogItemFactory.key.currentState?.setState(() {}); | ||||
|                                 WorkflowFactory.key.currentState?.setState(() {}); | ||||
|                               }  | ||||
|                             }, | ||||
|                             child: Container( | ||||
|                               margin: EdgeInsets.only(top: widget.topMargin ?? (widget.inner ? 0 : 10)), | ||||
|                               width: 50, | ||||
|                               height: 50, | ||||
|                               color: Colors.black, | ||||
|                               child: Icon(Icons.share_rounded,  | ||||
|                                 color: widget.selected == null || widget.selected == widget.before ? Colors.grey : Colors.white) | ||||
|                             ) | ||||
|                           ) | ||||
|           ), | ||||
|           Tooltip( | ||||
|                           message: 'unshare', | ||||
|                           child:InkWell(  | ||||
|                             mouseCursor: widget.selected == null || widget.selected == widget.before ? MouseCursor.defer : SystemMouseCursors.click, | ||||
|                             onTap: () async { | ||||
|                               if (widget.selected != null && widget.contextID != "" && widget.selected != widget.before) { | ||||
|                                 if (widget.type == SharedMenuWorkspaceType.peer) { | ||||
|                                   await widget.service.removePeer(context, widget.selected!, widget.contextID); | ||||
|                                 } else if (widget.type == SharedMenuWorkspaceType.workflow) { | ||||
|                                   await widget.service.removeWorkflow(context, widget.selected!, widget.contextID); | ||||
|                                 } else { | ||||
|                                   await widget.service.removeWorkspace(context, widget.selected!, widget.contextID); | ||||
|                                 } | ||||
|                                 SharedWorkspaceLocal.init(context, false); | ||||
|                                 setState(() {}); | ||||
|                                 dash.selectedLeftMenuKey.currentState?.setState(() { }); | ||||
|                                 CatalogFactory.key.currentState?.setState(() {}); | ||||
|                                 CatalogItemFactory.key.currentState?.setState(() {}); | ||||
|                                 WorkflowFactory.key.currentState?.setState(() {}); | ||||
|                               }  | ||||
|                             }, | ||||
|                             child: Container( | ||||
|                               decoration: const BoxDecoration( | ||||
|                                  color: Colors.black, | ||||
|                                 border: Border(left: BorderSide(color: Colors.white, width: 1)) | ||||
|                               ), | ||||
|                               margin: EdgeInsets.only( top: widget.topMargin ?? (widget.inner ? 0 : 10 )), | ||||
|                               width: 50, | ||||
|                               height: 50, | ||||
|                               child: Icon(Icons.delete, color: widget.selected == null || widget.selected == widget.before ? Colors.grey : Colors.white) | ||||
|                             ) | ||||
|                           ) | ||||
|           ) | ||||
|         ]); | ||||
|   } | ||||
| } | ||||
| @@ -1,119 +0,0 @@ | ||||
| import 'package:flutter/material.dart'; | ||||
| import 'package:oc_front/core/models/workspace_local.dart'; | ||||
| import 'package:oc_front/widgets/menu_clipper/shared_workspace_menu.dart'; | ||||
| class MenuWorkspaceWidget extends StatefulWidget { | ||||
|   bool simpliest = false; | ||||
|   double? width; | ||||
|   void Function()? onWorkspaceChange; | ||||
|   TextEditingController ctrl = TextEditingController(); | ||||
|   MenuWorkspaceWidget ({ Key? key, this.simpliest = false, this.width, this.onWorkspaceChange }): super(key: key); | ||||
|   @override MenuWorkspaceWidgetState createState() => MenuWorkspaceWidgetState(); | ||||
| } | ||||
| class MenuWorkspaceWidgetState extends State<MenuWorkspaceWidget> { | ||||
|   @override Widget build(BuildContext context) { | ||||
|      | ||||
|     return Row( children: [ | ||||
|           Tooltip( message: "current workspace", child: | ||||
|           Theme( | ||||
|             data: Theme.of(context).copyWith( | ||||
|               canvasColor: widget.simpliest ? Colors.grey.shade300 : Colors.grey, | ||||
|             ), | ||||
|             child: Container( height: 50, width: widget.width ?? MediaQuery.of(context).size.width / ( widget.simpliest ? 1 : 3),  | ||||
|             decoration: BoxDecoration( | ||||
|               color: widget.simpliest ? Colors.white : const Color.fromRGBO(38, 166, 154, 1), | ||||
|               border: Border(bottom: BorderSide(color: widget.simpliest ? Colors.grey.shade300 : Colors.transparent, width: 1)) | ||||
|             ), | ||||
|             padding: EdgeInsets.only(left: (widget.width ?? 400) < 400 ? 20 : 50, right: (widget.width ?? 400) < 400 ? 20 : 0), | ||||
|             child:  DropdownButtonFormField( | ||||
|                       value: WorkspaceLocal.getCurrentWorkspace()?.id, | ||||
|                       isExpanded: true, | ||||
|                       style: TextStyle(color: widget.simpliest ? Colors.black : Colors.white, fontSize: 15), | ||||
|                       hint: Text("load workspace...", style: TextStyle(color: Colors.grey.shade300, fontSize: 15)), | ||||
|                       icon: Icon(                // Add this | ||||
|                         Icons.arrow_drop_down,  // Add this | ||||
|                         color: widget.simpliest ? Colors.grey : Colors.white,   // Add this | ||||
|                        ), | ||||
|                       decoration: InputDecoration(  | ||||
|                         filled: true, | ||||
|                         prefixIconColor: widget.simpliest ? Colors.grey : Colors.white, | ||||
|                         icon: Icon(Icons.shopping_cart, color: Colors.grey.shade300), | ||||
|                         suffixIconColor: widget.simpliest ? Colors.grey : Colors.white, | ||||
|                         focusedBorder: const OutlineInputBorder( borderRadius: BorderRadius.zero, | ||||
|                             borderSide: BorderSide(color: Colors.transparent, width: 0), | ||||
|                         ), | ||||
|                         fillColor: widget.simpliest ? Colors.white : const Color.fromRGBO(38, 166, 154, 1), | ||||
|                         contentPadding: EdgeInsets.only(left: (widget.width ?? 400) < 400 ? 0 : 30, right: (widget.width ?? 400) < 400 ? 0 : 30, top: 10, bottom: 30), | ||||
|                         enabledBorder: const OutlineInputBorder( borderRadius: BorderRadius.zero, | ||||
|                             borderSide: BorderSide(color: Colors.transparent, width: 0), | ||||
|                         ), | ||||
|                         border: const OutlineInputBorder( borderRadius: BorderRadius.zero, | ||||
|                           borderSide: BorderSide(color: Colors.transparent, width: 0)), | ||||
|                       ), | ||||
|                       items: WorkspaceLocal.getWorkspacesIDS().map((e) => DropdownMenuItem( | ||||
|                         value: e.id,child: Text(e.name ?? ""),)).toList(),  | ||||
|                       onChanged: (value) { | ||||
|                         setState(() { | ||||
|                           WorkspaceLocal.changeWorkspace(value.toString()); | ||||
|                           if (widget.onWorkspaceChange != null) { | ||||
|                             widget.onWorkspaceChange!(); | ||||
|                           } | ||||
|                         }); | ||||
|                       })))), | ||||
|  | ||||
|           widget.simpliest ? Container() : Row( | ||||
|                 mainAxisAlignment: MainAxisAlignment.center, | ||||
|                 crossAxisAlignment: CrossAxisAlignment.center, | ||||
|                 children: [ | ||||
|                   Container( | ||||
|                           width: (MediaQuery.of(context).size.width / 3) - 50, | ||||
|                           height: 50, | ||||
|                           decoration: const BoxDecoration(border: Border(left: BorderSide(color: Colors.white))), | ||||
|                           child: TextFormField( | ||||
|                             expands: true, | ||||
|                             maxLines: null, | ||||
|                             minLines: null, | ||||
|                             style: const TextStyle(color: Colors.white, fontSize: 15), | ||||
|                             cursorColor: const Color.fromARGB(38, 166, 154, 1), | ||||
|                             controller: widget.ctrl, | ||||
|                             onChanged: (value) { setState(() { }); },  | ||||
|                             validator: (value) => value == null || value.isEmpty ? "name is required" : null, | ||||
|                             decoration: InputDecoration( | ||||
|                               hintText: "name a new workspace...", | ||||
|                               fillColor: const Color.fromRGBO(38, 166, 154, 1), | ||||
|                               filled: true, | ||||
|                               contentPadding: const EdgeInsets.only(left: 30, right: 30, top: 15, bottom: 5), | ||||
|                               hintStyle: TextStyle( | ||||
|                                 color: Colors.grey.shade300, | ||||
|                                 fontSize: 15, | ||||
|                                 fontWeight: FontWeight.w400 | ||||
|                               ), | ||||
|                               border: InputBorder.none | ||||
|                             ) | ||||
|                           ) | ||||
|                         ), | ||||
|                         Tooltip( | ||||
|                           message: 'add', | ||||
|                           child:InkWell(  | ||||
|                             mouseCursor: widget.ctrl.value.text.isEmpty ? MouseCursor.defer : SystemMouseCursors.click, | ||||
|                             onTap: () async { | ||||
|                               if (widget.ctrl.value.text.isNotEmpty) { | ||||
|                                 WorkspaceLocal.createWorkspace(widget.ctrl.value.text, context); | ||||
|                               } | ||||
|                             }, | ||||
|                             child: Container( | ||||
|                               width: 50, | ||||
|                               height: 50, | ||||
|                               color: Colors.black, | ||||
|                               child: Icon(Icons.add, color: widget.ctrl.value.text.isEmpty ? Colors.grey : Colors.white) | ||||
|                             ) | ||||
|                           ) | ||||
|                         ) | ||||
|                 ]), | ||||
|           widget.simpliest ? Container() : SharedMenuWorkspaceWidget( inner: true, | ||||
|             excluded: const[], | ||||
|             before: WorkspaceLocal.workspaces[WorkspaceLocal.current]!.shared, | ||||
|             selected: WorkspaceLocal.workspaces[WorkspaceLocal.current]!.shared, | ||||
|             contextID: WorkspaceLocal.current ?? "", width: (MediaQuery.of(context).size.width / 3)) | ||||
|         ]); | ||||
|   } | ||||
| } | ||||
| @@ -1,6 +1,6 @@ | ||||
| import 'package:flutter/material.dart'; | ||||
| import 'package:oc_front/core/services/router.dart'; | ||||
| import 'package:oc_front/widgets/menu_clipper/arrow_clipper.dart'; | ||||
| import 'package:oc_front/widgets/menus/arrow_clipper.dart'; | ||||
| 
 | ||||
| class TooltipWidget extends StatefulWidget { | ||||
|   int index = -1; | ||||
| @@ -43,7 +43,7 @@ class ScheduleWidgetState extends State<ScheduleWidget> { | ||||
|     List<Widget> children = []; | ||||
|     if (selected != null) { | ||||
|       for (var wf in widget.data[selected!] ?? (<WorkflowExecution>[])) { | ||||
|         DateTime d2 = DateTime.parse(wf.executionData!); | ||||
|         DateTime d2 = DateTime.parse(wf.executionData!).toLocal(); | ||||
|         children.add( InkWell( | ||||
|           onTap: () => setState(() { selectedReal = wf.executionData; }), | ||||
|           child: Container( margin: const EdgeInsets.all(10), | ||||
|   | ||||
| @@ -1,4 +1,5 @@ | ||||
| import 'package:flutter/material.dart'; | ||||
| import 'package:flutter_box_transform/flutter_box_transform.dart'; | ||||
| import 'package:oc_front/core/sections/header/header.dart'; | ||||
| import 'package:oc_front/models/workflow.dart'; | ||||
| import 'package:oc_front/widgets/sheduler_items/schedule.dart'; | ||||
| @@ -25,9 +26,9 @@ class SchedulerItemWidgetState extends State<SchedulerItemWidget> { | ||||
|             List<Widget> widgets = []; | ||||
|             for (var ev in widget.data[element] ?? ([] as List<WorkflowExecution>)) { | ||||
|               widget.keys[ev.executionData!] = GlobalKey(); | ||||
|               var d2 = DateTime.parse(ev.executionData!); | ||||
|               var d2 = DateTime.parse(ev.executionData!).toLocal(); | ||||
|               DateTime? d3; | ||||
|               try { d3 = DateTime.parse(ev.endDate!); | ||||
|               try { d3 = DateTime.parse(ev.endDate!).toLocal(); | ||||
|               } catch (e) { /* */ } | ||||
|               widgets.add(InkWell( | ||||
|                 onTap: () => widget.parent?.setState(() {  | ||||
| @@ -79,7 +80,11 @@ class SchedulerItemWidgetState extends State<SchedulerItemWidget> { | ||||
|               ))); | ||||
|             } | ||||
|             var date = DateTime.parse(element); | ||||
|             children.add(Column( children: [ExpansionTile( | ||||
|             children.add(Container(  | ||||
|               decoration: const BoxDecoration(  | ||||
|                 border: Border(bottom: BorderSide(color: Colors.black)), | ||||
|               ), | ||||
|               child: Column( children: [ExpansionTile( | ||||
|               enabled: widget.enabled, | ||||
|               shape: const ContinuousRectangleBorder(), | ||||
|               iconColor: Colors.grey, | ||||
| @@ -97,9 +102,7 @@ class SchedulerItemWidgetState extends State<SchedulerItemWidget> { | ||||
|               ),  | ||||
|               collapsedIconColor: Colors.grey, | ||||
|               children: widgets, | ||||
|             ),  | ||||
|               Divider(color: Colors.grey.shade300, height: 1) | ||||
|             ])); | ||||
|             )]))); | ||||
|           } | ||||
|           Future.delayed( const Duration(milliseconds: 100), () { | ||||
|             if (selectedReal != null) { | ||||
|   | ||||
| @@ -23,6 +23,7 @@ typedef ConnectionListener = void Function( | ||||
| /// It notifies changes to [FlowChart] | ||||
| // | ||||
| class Dashboard extends ChangeNotifier { | ||||
|   bool shouldSave = true; | ||||
|   GlobalKey<FlowChartSelectedMenuState> selectedMenuKey = GlobalKey<FlowChartSelectedMenuState>(); | ||||
|   GlobalKey<FlowChartLeftMenuState> selectedLeftMenuKey = GlobalKey<FlowChartLeftMenuState>(); | ||||
|   GlobalKey<FlowChartMenuState> chartMenuKey = GlobalKey<FlowChartMenuState>(); | ||||
| @@ -49,6 +50,7 @@ class Dashboard extends ChangeNotifier { | ||||
|   List<Widget> Function(FlowData? obj)? infoItemWidget; | ||||
|   List<Widget> Function()? infoWidget; | ||||
|   FlowData? Function(Map<String, dynamic> json)? transformToData; | ||||
|   bool addChange = false; | ||||
|   /// | ||||
|   Dashboard({ | ||||
|     this.id, | ||||
| @@ -91,7 +93,6 @@ class Dashboard extends ChangeNotifier { | ||||
|     } | ||||
|     tempHistory = []; | ||||
|     history = []; | ||||
|     addToHistory(); | ||||
|   } | ||||
|  | ||||
|   Future<void> Function(String cat)? load; | ||||
| @@ -267,6 +268,7 @@ class Dashboard extends ChangeNotifier { | ||||
|     } | ||||
|     selectedMenuKey.currentState?.setState(() { }); | ||||
|     chartMenuKey.currentState?.setState(() { }); | ||||
|     addToHistory(); | ||||
|   } | ||||
|  | ||||
|   /// add listener called when a new connection is created | ||||
| @@ -291,21 +293,62 @@ class Dashboard extends ChangeNotifier { | ||||
|     handlerFeedbackOffset = offset; | ||||
|   } | ||||
|  | ||||
|   void addArrows(ArrowPainter f) { | ||||
|     arrows.add(f); | ||||
|     addChange = true; | ||||
|     if (save != null) { | ||||
|       save!(id); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   void removeArrows(bool Function(ArrowPainter) f) { | ||||
|     arrows.removeWhere((element) => f(element)); | ||||
|     if (save != null) { | ||||
|       save!(id); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   void removeElements(bool Function(FlowElement<FlowData>) f) { | ||||
|     elements.removeWhere((element) => f(element)); | ||||
|     if (save != null) { | ||||
|       save!(id); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   void clear() { | ||||
|     elements.clear(); | ||||
|     arrows.clear(); | ||||
|     tempHistory = []; | ||||
|     history = []; | ||||
|     scheduler = {}; | ||||
|     info = {}; | ||||
|     scheduleActive = false; | ||||
|     notifyListeners(); | ||||
|   } | ||||
|   bool noHistory = false; | ||||
|   void addToHistory() { | ||||
|     if (noHistory) { | ||||
|       Future.delayed(Duration(seconds: 2), () { | ||||
|         noHistory = false; | ||||
|       }); | ||||
|       return; | ||||
|     } | ||||
|     if (tempHistory.length >= 50) { tempHistory.removeAt(0); } | ||||
|     tempHistory.add(toMap()); | ||||
|     if (save != null) { save!(id); } | ||||
|     history = tempHistory.map((e) => e).toList(); | ||||
|     chartKey.currentState?.setState(() { }); | ||||
|     chartMenuKey.currentState?.setState(() { }); | ||||
|   } | ||||
|   bool isBack = false; | ||||
|   void back() {  | ||||
|     tempHistory.removeLast();  | ||||
|     if (tempHistory.length == 0) return; | ||||
|     copyFromMap(tempHistory.last); | ||||
|     chartKey.currentState?.setState(() { }); | ||||
|     chartMenuKey.currentState?.setState(() { }); | ||||
|     if (canBack()) { | ||||
|       noHistory = true; | ||||
|       tempHistory.removeLast();  | ||||
|       if (tempHistory.length > 0) { | ||||
|         copyFromMap(tempHistory.last); | ||||
|       } | ||||
|       chartKey.currentState?.setState(() { }); | ||||
|       chartMenuKey.currentState?.setState(() { }); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   bool canBack() { | ||||
| @@ -318,6 +361,7 @@ class Dashboard extends ChangeNotifier { | ||||
|  | ||||
|   void forward() { | ||||
|     if (canForward()) { | ||||
|       noHistory = true; | ||||
|       tempHistory.add(history[tempHistory.length]);  | ||||
|       copyFromMap(tempHistory.last); | ||||
|       chartKey.currentState?.setState(() { }); | ||||
| @@ -332,6 +376,9 @@ class Dashboard extends ChangeNotifier { | ||||
|     bool notify = true, | ||||
|   }) { | ||||
|     element.isResizing = resizable; | ||||
|     if (save != null) { | ||||
|       save!(id); | ||||
|     } | ||||
|     if (notify) notifyListeners(); | ||||
|   } | ||||
|  | ||||
| @@ -347,6 +394,10 @@ class Dashboard extends ChangeNotifier { | ||||
|     } | ||||
|     element.setScale(1, gridBackgroundParams.scale); | ||||
|     elements.add(element); | ||||
|     addChange = true; | ||||
|     if (save != null) { | ||||
|       save!(id); | ||||
|     } | ||||
|     if (notify) { | ||||
|       notifyListeners(); | ||||
|     } | ||||
| @@ -361,7 +412,6 @@ class Dashboard extends ChangeNotifier { | ||||
|  | ||||
|   @override | ||||
|   void notifyListeners() { | ||||
|     addToHistory(); | ||||
|     super.notifyListeners(); | ||||
|   } | ||||
|  | ||||
|   | ||||
| @@ -107,6 +107,7 @@ class FlowElement<T extends FlowData> extends ChangeNotifier { | ||||
|     return false; | ||||
|   } | ||||
|   factory FlowElement.fromMap(Dashboard dashboard, Map<String, dynamic> map) { | ||||
|     print("FlowElement.fromMap ${map}"); | ||||
|     final e = FlowElement<T>( | ||||
|       element: (dashboard.transformToData != null | ||||
|           ? dashboard.transformToData!(map['element'] ?? {}) | ||||
| @@ -341,6 +342,7 @@ class FlowElement<T extends FlowData> extends ChangeNotifier { | ||||
|   Map<String, dynamic> toMap() { | ||||
|     return <String, dynamic>{ | ||||
|       'widget': widget, | ||||
|       'element': element?.serialize(), | ||||
|       'positionDx': position.dx, | ||||
|       'positionDy': position.dy, | ||||
|       'size.width': size.width, | ||||
|   | ||||
| @@ -56,8 +56,10 @@ class FlowChart<T extends FlowData> extends StatefulWidget { | ||||
|     required this.draggableItemBuilder, | ||||
|     this.onDashboardAlertOpened, | ||||
|     this.menuWidget, | ||||
|     this.current, | ||||
|     this.menuExtension, | ||||
|   }) {} | ||||
|   final String? current; | ||||
|   final List<String> categories; | ||||
|   final double width; | ||||
|   final double height; | ||||
| @@ -303,18 +305,25 @@ class FlowChartState<T extends FlowData> extends State<FlowChart> { | ||||
|   @override | ||||
|   Widget build(BuildContext context) { | ||||
|     if (!widget.dashboard.isOpened && widget.onDashboardAlertOpened != null ) { | ||||
|       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.id != null) { | ||||
|         widget.dashboard.isOpened  = true; | ||||
|         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)); | ||||
|            | ||||
|         }); }); | ||||
|       } | ||||
|     } else { | ||||
|       widget.dashboard.isOpened  = true; | ||||
|     } | ||||
|     /// get dashboard position after first frame is drawn | ||||
|     WidgetsBinding.instance.addPostFrameCallback((timeStamp) { | ||||
| @@ -371,7 +380,7 @@ class FlowChartState<T extends FlowData> extends State<FlowChart> { | ||||
|         if (event is KeyDownEvent && event.logicalKey == LogicalKeyboardKey.add) { | ||||
|           change = true; | ||||
|           for (var el in widget.dashboard.elementSelected) { | ||||
|               widget.dashboard.elements.add(FlowElement<T>( | ||||
|               widget.dashboard.addElement(FlowElement<T>( | ||||
|                 element: el.element as T, | ||||
|                 dashboard: widget.dashboard, | ||||
|                 id: const Uuid().v4(), | ||||
| @@ -387,13 +396,13 @@ class FlowChartState<T extends FlowData> extends State<FlowChart> { | ||||
|         } | ||||
|         if (event is KeyDownEvent && event.logicalKey == LogicalKeyboardKey.delete) { | ||||
|           change = true; | ||||
|           widget.dashboard.elements.removeWhere( (el) => el.isSelected ); | ||||
|           widget.dashboard.removeElements( (el) => el.isSelected ); | ||||
|           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.arrows.removeWhere( (el) => el.isSelected ); | ||||
|           widget.dashboard.removeArrows( (el) => el.isSelected ); | ||||
|         } | ||||
|         if (change) { | ||||
|           DrawingArrow.instance.notifyListeners(); | ||||
| @@ -466,11 +475,11 @@ class FlowChartState<T extends FlowData> extends State<FlowChart> { | ||||
|         widget.dashboard.isMenu ? Positioned(top: 50, child: FlowChartLeftMenu<T>( | ||||
|           key: widget.dashboard.selectedLeftMenuKey, | ||||
|           dashboard: widget.dashboard,  | ||||
|           menuExtension: widget.menuExtension, | ||||
|           categories: widget.categories, | ||||
|           height: widget.height, | ||||
|           innerMenuWidth: widget.innerMenuWidth, | ||||
|           itemWidth: widget.itemWidth, | ||||
|           menuExtension: widget.menuExtension, | ||||
|           draggableItemBuilder: widget.draggableItemBuilder as List<T> Function(String cat), | ||||
|           getDraggable: getDraggable, | ||||
|         ) ) | ||||
| @@ -745,7 +754,7 @@ class ChartWidgetState<T extends FlowData> extends State<ChartWidget> { | ||||
|                         if (!hoverImportant) { | ||||
|                           for (var sel in widget.dashboard.elements) { sel.isSelected = false; } | ||||
|                           for (var sel in widget.dashboard.arrows) { sel.isSelected = false; } | ||||
|                           Future.delayed(Duration(seconds: 1), () { | ||||
|                           Future.delayed(Duration(milliseconds: 100), () { | ||||
|                             widget.dashboard.selectedMenuKey.currentState?.setState(() {}); | ||||
|                             DrawingArrow.instance.notifyListeners(); | ||||
|                           }); | ||||
|   | ||||
| @@ -69,7 +69,9 @@ class FlowChartLeftMenuState<T extends FlowData> extends State<FlowChartLeftMenu | ||||
|             Container( | ||||
|                           width: widget.innerMenuWidth, | ||||
|                           height: 50, | ||||
|                           decoration: const BoxDecoration(border: Border(left: BorderSide(color: Colors.white))), | ||||
|                           decoration: BoxDecoration(border: Border( | ||||
|                             right: BorderSide(color: Colors.grey.shade300), | ||||
|                             left: BorderSide(color: Colors.white))), | ||||
|                           child: TextFormField( | ||||
|                             style: const TextStyle(color: Colors.black, fontSize: 15), | ||||
|                             cursorColor: const Color.fromARGB(38, 166, 154, 1), | ||||
|   | ||||
| @@ -20,7 +20,7 @@ class FlowChartSelectedMenuState extends State<FlowChartSelectedMenu> { | ||||
|         width: 250, | ||||
|         height: widget.height, | ||||
|         color: Colors.grey.shade300, | ||||
|         child: Column( children: [ ...widget.dashboard.infoItemWidget != null ? | ||||
|         child: SingleChildScrollView( child:  Column( children: [ ...widget.dashboard.infoItemWidget != null ? | ||||
|           widget.dashboard.infoItemWidget!(widget.dashboard.elementSelected.first.element)  | ||||
|           : [], | ||||
|           widget.dashboard.arrowsSelected.isNotEmpty || widget.dashboard.elementSelected.isNotEmpty ? Container(  | ||||
| @@ -33,13 +33,13 @@ class FlowChartSelectedMenuState extends State<FlowChartSelectedMenu> { | ||||
|                             Tooltip( message: "remove", | ||||
|                               child: InkWell( mouseCursor: SystemMouseCursors.click,  | ||||
|                               onTap: () { | ||||
|                                 widget.dashboard.arrows.removeWhere((element) {  | ||||
|                                 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; | ||||
|                                 });  | ||||
|                                 widget.dashboard.elements.removeWhere((element) => element.isSelected);  | ||||
|                                 widget.dashboard.removeElements((element) => element.isSelected);  | ||||
|                                 Future.delayed(Duration(milliseconds: 100), () { | ||||
|                                   widget.dashboard.chartKey.currentState?.setState(() { }); | ||||
|                                 }); | ||||
| @@ -53,13 +53,13 @@ class FlowChartSelectedMenuState extends State<FlowChartSelectedMenu> { | ||||
|                               child: InkWell( mouseCursor: SystemMouseCursors.click,  | ||||
|                               onTap: () { | ||||
|                                 for (var sel in widget.dashboard.elementSelected) { | ||||
|                                   widget.dashboard.elements.add(FlowElement.fromMap(widget.dashboard, sel.toMap())); | ||||
|                                   widget.dashboard.addElement(FlowElement.fromMap(widget.dashboard, sel.toMap())); | ||||
|                                   widget.dashboard.elements.last.position += Offset(50, 50); | ||||
|                                 } | ||||
|                                 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), | ||||
|                                 decoration: BoxDecoration(borderRadius: BorderRadius.circular(5), border: Border.all(color: Colors.black, width: 1)), | ||||
|                                 width: 200, height: 30, | ||||
|                                 child: Icon(Icons.copy, color: Colors.black), | ||||
| @@ -68,7 +68,7 @@ class FlowChartSelectedMenuState extends State<FlowChartSelectedMenu> { | ||||
|                           ]) | ||||
|                         ) : Container() | ||||
|         ]) | ||||
|        ); | ||||
|        )); | ||||
|     } else if (widget.isDashboardInfo && widget.dashboard.infoWidget != null) { | ||||
|        w = Container( | ||||
|         width: 250, | ||||
| @@ -100,7 +100,7 @@ class FlowChartSelectedMenuState extends State<FlowChartSelectedMenu> { | ||||
|                                 constraints: BoxConstraints(maxWidth: 100), | ||||
|                                 child: Row( children: [  | ||||
|                                   MySeparator( | ||||
|                                     width: 45,  | ||||
|                                     width: 65,  | ||||
|                                     dashWidth: widget.dashboard.defaultDashWidth,  | ||||
|                                     dashSpace: widget.dashboard.defaultDashSpace,  | ||||
|                                     color: Colors.black  | ||||
| @@ -193,7 +193,7 @@ class FlowChartSelectedMenuState extends State<FlowChartSelectedMenu> { | ||||
|                           Tooltip( message: "stroke width", | ||||
|                             child: Container( | ||||
|                               margin: EdgeInsets.only(left: 10), | ||||
|                               width: 45, height: 25, | ||||
|                               width: 75, height: 25, | ||||
|                               child: TextFormField( textAlign: TextAlign.center, | ||||
|                               readOnly: widget.dashboard.defaultDashWidth <= 0, | ||||
|                               initialValue: "${widget.dashboard.defaultStroke}", | ||||
| @@ -280,7 +280,7 @@ class FlowChartSelectedMenuState extends State<FlowChartSelectedMenu> { | ||||
|                           Tooltip( message: "space dash", | ||||
|                             child: Container( | ||||
|                               margin: EdgeInsets.only(top: 10), | ||||
|                               width: 105 / 2, height: 25, | ||||
|                               width: 155 / 2, height: 25, | ||||
|                               child: TextFormField( textAlign: TextAlign.center, | ||||
|                               readOnly: widget.dashboard.defaultDashWidth <= 0, | ||||
|                               initialValue: "${widget.dashboard.defaultDashWidth}", | ||||
| @@ -318,7 +318,7 @@ class FlowChartSelectedMenuState extends State<FlowChartSelectedMenu> { | ||||
|                           Tooltip( message: "space width", | ||||
|                             child: Container( | ||||
|                               margin: EdgeInsets.only(left: 10, top: 10), | ||||
|                               width: 105 / 2, height: 25, | ||||
|                               width: 155 / 2, height: 25, | ||||
|                               child: TextFormField( textAlign: TextAlign.center, | ||||
|                               initialValue: "${widget.dashboard.defaultDashSpace}", | ||||
|                               onChanged: (value) {  | ||||
| @@ -414,7 +414,7 @@ class FlowChartSelectedMenuState extends State<FlowChartSelectedMenu> { | ||||
|                             Tooltip( message: "forward size", | ||||
|                               child: Container( | ||||
|                                 margin: EdgeInsets.only(left: 10, top: 10), | ||||
|                                 width: 135, height: 25, | ||||
|                                 width: 185, height: 25, | ||||
|                                 child: TextFormField( textAlign: TextAlign.center, | ||||
|                                 initialValue: "${widget.dashboard.defaultForwardWidth}", | ||||
|                                 onChanged: (value) {  | ||||
| @@ -466,7 +466,7 @@ class FlowChartSelectedMenuState extends State<FlowChartSelectedMenu> { | ||||
|                             Tooltip( message: "back size", | ||||
|                               child: Container( | ||||
|                                 margin: EdgeInsets.only(left: 10, top: 10), | ||||
|                                 width: 135, height: 25, | ||||
|                                 width: 185, height: 25, | ||||
|                                 child: TextFormField( textAlign: TextAlign.center, | ||||
|                                 initialValue: "${widget.dashboard.defaultBackWidth}", | ||||
|                                 onChanged: (value) {  | ||||
| @@ -522,13 +522,13 @@ class FlowChartSelectedMenuState extends State<FlowChartSelectedMenu> { | ||||
|                             Tooltip( message: "remove", | ||||
|                               child: InkWell( mouseCursor: SystemMouseCursors.click,  | ||||
|                               onTap: () { | ||||
|                                 widget.dashboard.arrows.removeWhere((element) {  | ||||
|                                 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; | ||||
|                                 });  | ||||
|                                 widget.dashboard.elements.removeWhere((element) => element.isSelected);  | ||||
|                                 widget.dashboard.removeElements((element) => element.isSelected);  | ||||
|                                 Future.delayed(Duration(milliseconds: 100), () { | ||||
|                                   widget.dashboard.chartKey.currentState?.setState(() { }); | ||||
|                                 }); | ||||
| @@ -542,7 +542,7 @@ class FlowChartSelectedMenuState extends State<FlowChartSelectedMenu> { | ||||
|                               child: InkWell( mouseCursor: SystemMouseCursors.click,  | ||||
|                               onTap: () { | ||||
|                                 for (var sel in widget.dashboard.elementSelected) { | ||||
|                                   widget.dashboard.elements.add(FlowElement.fromMap(widget.dashboard, sel.toMap())); | ||||
|                                   widget.dashboard.addElement(FlowElement.fromMap(widget.dashboard, sel.toMap())); | ||||
|                                   widget.dashboard.elements.last.position += Offset(50, 50); | ||||
|                                 } | ||||
|                                 Future.delayed(Duration(milliseconds: 100), () { | ||||
|   | ||||
| @@ -226,6 +226,7 @@ class DrawingArrow extends ChangeNotifier { | ||||
|   /// | ||||
|   void setFrom(Offset from) { | ||||
|     this.from = from; | ||||
|      | ||||
|     notifyListeners(); | ||||
|   } | ||||
|  | ||||
| @@ -350,7 +351,7 @@ class DrawArrowState extends State<DrawArrow> { | ||||
|               ); | ||||
|             if ( widget.flow.widget.dashboard.arrows.where( | ||||
|                   (element) => element.fromID == "${widget.srcElement.id}_${widget.index}").isEmpty) { | ||||
|                 widget.flow.widget.dashboard.arrows.add(painter);  | ||||
|                 widget.flow.widget.dashboard.addArrows(painter);  | ||||
|                 widget.flow.widget.dashboard.save!(widget.flow.widget.dashboard.id); | ||||
|             } else { | ||||
|               var i = widget.flow.widget.dashboard.arrows.indexWhere( | ||||
| @@ -481,9 +482,9 @@ class ArrowPainter extends CustomPainter { | ||||
|     final e = ArrowPainter( | ||||
|       connIndex: map['connIndex'] as int, | ||||
|       elementIndex: map['elementIndex'] as int, | ||||
|       toID: map['toID'] as String, | ||||
|       toID: map['toID'] != null ? map['toID'] as String : "", | ||||
|       fromID: map['fromID'] as String, | ||||
|       isSelected: map['isSelected'] as bool, | ||||
|       isSelected: map['isSelected'] != null ? map['isSelected'] as bool : false, | ||||
|       params: ArrowParams.fromMap(map['params']), | ||||
|       from: Offset( | ||||
|         map['fromDx'] as double, | ||||
| @@ -500,14 +501,17 @@ class ArrowPainter extends CustomPainter { | ||||
|  | ||||
|   Map<String, dynamic> toMap() { | ||||
|     return { | ||||
|         'toID': toID, | ||||
|         'fromID': fromID, | ||||
|         'elementIndex': elementIndex, | ||||
|         'connIndex': connIndex, | ||||
|         'isSelected': isSelected.toString(), | ||||
|         'params': params.toJson(), | ||||
|         'from': from.toString(), | ||||
|         'to': to.toString(), | ||||
|         'pivots': json.encode(pivots.map((e) => e.toMap()).toList()), | ||||
|         'isSelected': isSelected, | ||||
|         'params': params.toMap(), | ||||
|         "fromDx" : from.dx, | ||||
|         "fromDy" : from.dy, | ||||
|         "toDx" : to.dx, | ||||
|         "toDy" : to.dy, | ||||
|         'pivots': pivots.map((e) => e.toMap()).toList(), | ||||
|       }; | ||||
|   } | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user