diff --git a/Dockerfile b/Dockerfile index 2573f7e..28d8f9b 100644 --- a/Dockerfile +++ b/Dockerfile @@ -11,6 +11,7 @@ ARG ITEM_HOST="http://localhost:8087/oc" ARG SCHEDULER_HOST="http://localhost:8090/oc" ARG LOGS_HOST="http://localhost:3100" ARG PEER_HOST="http://localhost:8093/oc" +ARG DATACENTER_HOST="http://localhost:8092/oc" ARG COLLABORATIVE_AREA_HOST="http://localhost:8091/oc" # define variables ARG FLUTTER_SDK=/usr/local/flutter @@ -47,6 +48,7 @@ RUN flutter build web \ --dart-define=SCHEDULER_HOST=$SCHEDULER_HOST \ --dart-define=LOGS_HOST=$LOGS_HOST \ --dart-define=ITEM_HOST=$ITEM_HOST \ + --dart-define=DATACENTER_HOST=$DATACENTER_HOST # once heare the app will be compiled and ready to deploy # use nginx to deploy diff --git a/lib/core/sections/header/header.dart b/lib/core/sections/header/header.dart index d389c14..68c3028 100644 --- a/lib/core/sections/header/header.dart +++ b/lib/core/sections/header/header.dart @@ -21,6 +21,7 @@ class HeaderConstants { static GlobalKey headerKey = GlobalKey(); static final List noHeader = [ AppRouter.scheduler, + AppRouter.compute, AppRouter.shared, AppRouter.workflowItem, AppRouter.workflowIDItem, @@ -37,12 +38,16 @@ class HeaderConstants { static setTitle(String? v) { title = v; - HeaderConstants.headerWidget?.setState(() {}); + Future.delayed(Duration(milliseconds: 100), () { + HeaderConstants.headerWidget?.setState(() {}); + }); } static setDescription(String? v) { description = v; - HeaderConstants.headerWidget?.setState(() {}); + Future.delayed(Duration(milliseconds: 100), () { + HeaderConstants.headerWidget?.setState(() {}); + }); } static bool isNoHeader(String route) { diff --git a/lib/core/services/auth.service.dart b/lib/core/services/auth.service.dart index c05cd09..8c3b308 100644 --- a/lib/core/services/auth.service.dart +++ b/lib/core/services/auth.service.dart @@ -63,13 +63,11 @@ class AuthService { } static Future refresh(String accessToken, String username, Duration duration) async { - print("REFRESH ${duration}"); Future.delayed(duration, () { service.post("/refresh", { "access_token": accessToken, "username": username }, null).then((token) { - print("REFRESH ${token.data}"); if (token.code == 200 && token.data != null) { localStorage.setItem('accessToken', token.data?.value['access_token']); localStorage.setItem('username', username); diff --git a/lib/core/services/router.dart b/lib/core/services/router.dart index 99f7a64..fd6aff5 100644 --- a/lib/core/services/router.dart +++ b/lib/core/services/router.dart @@ -60,16 +60,14 @@ class AppRouter { 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: "catalog", factory: CatalogFactory()); static final RouterItem scheduler = RouterItem(icon: Icons.schedule, label: "scheduled tasks", route: "scheduler", factory: SchedulerFactory()); + static final RouterItem compute = RouterItem(icon: Icons.dns_outlined, label: "my compute", route: "compute", factory: DatacenterFactory()); static final RouterItem shared = RouterItem(icon: Icons.share_rounded, label: "collaborative area", route: "shared", factory: SharedFactory()); - static List zones = [ catalog, workflowItem, scheduler, - RouterItem(icon: Icons.dns_outlined, label: "my compute", route: "compute", - description: "Manage & monitor your compute.", help: "not implemented for now", - factory: DatacenterFactory()), + compute, RouterItem(icon: Icons.public_outlined, label: "localisations", route: "map", factory: MapFactory()), shared, workflowIDItem, diff --git a/lib/core/services/specialized_services/booking_service.dart b/lib/core/services/specialized_services/booking_service.dart new file mode 100644 index 0000000..05988e6 --- /dev/null +++ b/lib/core/services/specialized_services/booking_service.dart @@ -0,0 +1,24 @@ +import 'package:flutter/material.dart'; +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/response.dart'; +import 'package:oc_front/models/workflow.dart'; + +class BookingExecutionService extends AbstractService { + @override APIService service = APIService( + baseURL: const String.fromEnvironment('DATACENTER_HOST', defaultValue: 'http://localhost:8080/datacenter') + ); + @override String subPath = "/booking/"; + + @override Future> search(BuildContext? context, List words, Map params) { + print("${subPath}search/${words.join("/")}"); + return service.get("${subPath}search/${words.join("/")}", false, context); + } + + @override Future> post(BuildContext? context, Map body, Map params) { + return throw UnimplementedError(); + } + @override Future> put(BuildContext? context, String id, Map body, Map params) { + return throw UnimplementedError(); + } +} \ No newline at end of file diff --git a/lib/models/response.dart b/lib/models/response.dart index 6b09a0d..afb7a37 100644 --- a/lib/models/response.dart +++ b/lib/models/response.dart @@ -69,7 +69,8 @@ class SimpleData extends SerializerDeserializer { class RawData extends SerializerDeserializer { RawData({ this.values = const []}); List values = []; - @override deserialize(dynamic json) { return RawData(values: json ?? []); } + @override deserialize(dynamic json) { + return RawData(values: json ?? []); } @override Map serialize() => { }; } diff --git a/lib/models/search.dart b/lib/models/search.dart index 04eca43..55fff55 100644 --- a/lib/models/search.dart +++ b/lib/models/search.dart @@ -817,7 +817,6 @@ class ComputeItem extends SerializerDeserializer implements Abstrac gpus: json.containsKey("gpus") ? fromListJson(json["gpus"], GPU()) : [], ram: json.containsKey("ram") ? RAM().deserialize(json["ram"]) : null, ); - print(w.technology); if (w.logo != null) { // var image = Image.network(w.logo!); diff --git a/lib/pages/datacenter.dart b/lib/pages/datacenter.dart index ce567fd..266a357 100644 --- a/lib/pages/datacenter.dart +++ b/lib/pages/datacenter.dart @@ -1,6 +1,12 @@ +import 'package:datetime_picker_formfield/datetime_picker_formfield.dart'; import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; +import 'package:oc_front/core/services/specialized_services/booking_service.dart'; +import 'package:oc_front/main.dart'; +import 'package:intl/intl.dart' as intl; +import 'package:oc_front/models/workflow.dart'; import 'package:oc_front/pages/abstract_page.dart'; +import 'package:oc_front/widgets/sheduler_items/schedule.dart'; class DatacenterFactory implements AbstractFactory { @override GlobalKey getKey() { return key; } @@ -12,13 +18,202 @@ class DatacenterFactory implements AbstractFactory { } class ComputePageWidget extends StatefulWidget { + bool isList = true; + DateTime start = DateTime.now(); + DateTime end = DateTime.now().add(const Duration(days: 180)); + final BookingExecutionService _service = BookingExecutionService(); + ComputePageWidget () : super(key: DatacenterFactory.key); @override ComputePageWidgetState createState() => ComputePageWidgetState(); static Widget factory() { return ComputePageWidget(); } } class ComputePageWidgetState extends State { + List colors = [Colors.blue, Colors.orange, redColor, Colors.green, redColor]; + List titles = ["SCHEDULED", "RUNNING", "FAILURE", "SUCCESS", "FORGOTTEN"]; + @override Widget build(BuildContext context) { - return Column( children: []); + return FutureBuilder( + future: widget._service.search(context, [ + "${widget.start.year}-${widget.start.month > 9 ? widget.start.month : "0${widget.start.month}"}-${widget.start.day > 9 ? widget.start.day : "0${widget.start.day}"}", + "${widget.end.year}-${widget.end.month > 9 ? widget.end.month : "0${widget.end.month}"}-${widget.end.day > 9 ? widget.end.day : "0${widget.end.day}"}"], {}), + builder: (ctx, as) { + Map> data = {}; + if (as.hasData && as.data!.data != null) { + for (var element in as.data!.data!.executions) { + if (element.executionData == null) { continue; } + DateTime dateTime = DateTime.parse(element.executionData!); + DateTime date = DateTime(dateTime.year, dateTime.month, dateTime.day); + var str = "${date.toIso8601String()}Z"; + if (data[str] == null) { data[str] = []; } + data[str]!.add(element); + data[str]!.sort((a, b) => DateTime.parse(a.executionData!).compareTo(DateTime.parse(b.executionData!))); + } + } + GlobalKey k = GlobalKey(); + for (var da in data.keys) { + for (var exec in data[da]!) { + String start = ""; + String end = ""; + try { + if (exec.endDate != null && exec.endDate != "") { + var startD = DateTime.parse(exec.executionData!); + var endD = DateTime.parse(exec.endDate!); + var diff = endD.difference(startD); + if (diff.inDays < 30) { + var rest = ((30 - diff.inDays) ~/ 2) - 1; + start = (startD.subtract(Duration(days: rest)).microsecondsSinceEpoch).toString(); + end = (endD.add(Duration(days: rest)).microsecondsSinceEpoch).toString(); + } else { + start = (startD.microsecondsSinceEpoch).toString(); + end = (startD.add( const Duration(days: 29)).microsecondsSinceEpoch).toString(); + } + } else { + start = (DateTime.parse(exec.executionData!).subtract( const Duration(days: 14)).microsecondsSinceEpoch).toString(); + end = (DateTime.parse(exec.executionData!).add( const Duration(days: 14)).microsecondsSinceEpoch).toString(); + } + } catch(e) { /* */ } + k.currentState?.setState(() { k.currentState?.widget.loading = true; }); + } + } + return Column( children: [ + Container( color: lightColor, + height: 50, width: getMainWidth(context), + child: Padding(padding: const EdgeInsets.symmetric(horizontal: 50), + child: Row( children: [ + Padding(padding: const EdgeInsets.only(right: 30), + child: Tooltip( message: widget.isList ? "calendar view" : "list view", + child: InkWell( child: Icon( widget.isList ? Icons.calendar_month : Icons.list, color: Colors.white + , size: 25 ), + onTap: () { + widget.isList = !widget.isList; + k.currentState?.setState(() { k.currentState?.widget.isList = widget.isList; }); + }) + ), + ), + Container(padding: const EdgeInsets.only(left: 20), + width: getMainWidth(context) / 5, + height: 30, + child: DateTimeField( + validator: (value) { + return null; + }, + resetIcon: null, + onShowPicker: (context, currentValue) async { + var date = await showDatePicker( + builder: (BuildContext context, Widget? child) { + Widget w = Theme( + data: ThemeData( + cardTheme: CardTheme(elevation: 0, shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(0))), + dialogTheme: DialogTheme(elevation: 0, shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(0))), + colorScheme: ColorScheme.light( + background: midColor, + tertiary: Colors.grey, + secondary: Colors.grey, + primary: Colors.black), + ), + child: child ?? Container(), + ); + return w; + }, + context: context, + firstDate: DateTime(1900), + initialDate: widget.start, + lastDate: DateTime(2100) + ); + return date; + }, + + format: intl.DateFormat('y-M-dd hh:mm:ss'), + initialValue: widget.start, + onChanged: (value) { + if (value == null) { return; } + setState(() { widget.start = value; }); + }, + style: const TextStyle(fontSize: 12), + decoration: const InputDecoration( + fillColor: Colors.white, + floatingLabelBehavior: FloatingLabelBehavior.always, + filled: true, + alignLabelWithHint: false, + hintText: "enter start date...", + labelText: "", + errorStyle: TextStyle(fontSize: 0), + hintStyle: TextStyle(fontSize: 10), + labelStyle: TextStyle(fontSize: 15, color: Colors.black, fontWeight: FontWeight.w500), + enabledBorder: OutlineInputBorder(borderSide: BorderSide(color: Colors.transparent)), + border: OutlineInputBorder(borderSide: BorderSide(color: Colors.transparent)), + contentPadding: EdgeInsets.symmetric(horizontal: 10, vertical: 5), + ), + ) + ), + 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, right: 20), + width: getMainWidth(context) / 5, + height: 30, + child: DateTimeField( + validator: (value) { + return null; + }, + resetIcon: null, + onShowPicker: (context, currentValue) async { + var date = await showDatePicker( + builder: (BuildContext context, Widget? child) { + Widget w = Theme( + data: ThemeData( + cardTheme: CardTheme(elevation: 0, shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(0))), + dialogTheme: DialogTheme(elevation: 0, shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(0))), + colorScheme: ColorScheme.light( + background: midColor, + tertiary: Colors.grey, + secondary: Colors.grey, + primary: Colors.black), + ), + child: child ?? Container(), + ); + return w; + }, + context: context, + firstDate: DateTime(1900), + initialDate: widget.end, + lastDate: DateTime(2100) + ); + return date; + }, + format: intl.DateFormat('y-M-dd hh:mm:ss'), + initialValue: widget.end, + onChanged: (value) { + if (value == null) { return; } + setState(() { widget.start = value; }); + }, + style: const TextStyle(fontSize: 12), + decoration: const InputDecoration( + fillColor: Colors.white, + floatingLabelBehavior: FloatingLabelBehavior.always, + filled: true, + alignLabelWithHint: false, + hintText: "enter end date...", + labelText: "", + errorStyle: TextStyle(fontSize: 0), + hintStyle: TextStyle(fontSize: 10), + labelStyle: TextStyle(fontSize: 15, color: Colors.black, fontWeight: FontWeight.w500), + enabledBorder: OutlineInputBorder(borderSide: BorderSide(color: Colors.transparent)), + border: OutlineInputBorder(borderSide: BorderSide(color: Colors.transparent)), + contentPadding: EdgeInsets.symmetric(horizontal: 10, vertical: 5), + ), + ) + ), + Tooltip( message: "refresh scheduler", + child: InkWell( + onTap: () => setState(() {}), + child: const Icon(Icons.refresh, color: Colors.white,), + ), + ) + ])) + ), + ScheduleWidget( key: k, data: data, start: widget.start, end : widget.end, isList: widget.isList, isBox: false) + ]); + }); } } \ No newline at end of file diff --git a/lib/pages/scheduler.dart b/lib/pages/scheduler.dart index be57664..2712fa2 100644 --- a/lib/pages/scheduler.dart +++ b/lib/pages/scheduler.dart @@ -29,8 +29,8 @@ class SchedulerPageWidget extends StatefulWidget { static Widget factory() { return SchedulerPageWidget(); } } class SchedulerPageWidgetState extends State { - List colors = [Colors.blue, Colors.orange, redColor, Colors.green]; - List titles = ["SCHEDULED", "RUNNING", "FAILURE", "SUCCESS"]; + List colors = [Colors.blue, Colors.orange, redColor, Colors.green, redColor]; + List titles = ["SCHEDULED", "RUNNING", "FAILURE", "SUCCESS", "FORGOTTEN"]; @override Widget build(BuildContext context) { return FutureBuilder( diff --git a/lib/widgets/sheduler_items/schedule.dart b/lib/widgets/sheduler_items/schedule.dart index 09fe5e1..d55cb1a 100644 --- a/lib/widgets/sheduler_items/schedule.dart +++ b/lib/widgets/sheduler_items/schedule.dart @@ -1,6 +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/main.dart'; import 'package:oc_front/models/logs.dart'; import 'package:oc_front/models/workflow.dart'; @@ -19,7 +18,9 @@ class ScheduleWidget extends StatefulWidget { bool loading = true; Map> data; bool isList = true; - ScheduleWidget ({ super.key, required this.data, required this.start, required this.end, this.isList = true, this.loading = false}); + bool isBox = true; + ScheduleWidget ({ super.key, required this.data, required this.start, required this.end, + this.isBox =true, this.isList = true, this.loading = false}); @override ScheduleWidgetState createState() => ScheduleWidgetState(); } String? selected; @@ -27,8 +28,8 @@ String? selectedReal; class ScheduleWidgetState extends State { String search = ""; String? level; - List colors = [Colors.blue, Colors.orange, redColor, Colors.green]; - List titles = ["SCHEDULED", "RUNNING", "FAILURE", "SUCCESS"]; + List colors = [Colors.blue, Colors.orange, redColor, Colors.green, redColor]; + List titles = ["SCHEDULED", "RUNNING", "FAILURE", "SUCCESS", "FORGOTTEN"]; DateTime getFocusedDay() { if (selected != null) { return DateTime.parse(selected!); } @@ -36,8 +37,8 @@ class ScheduleWidgetState extends State { } @override Widget build(BuildContext context) { - bool isInfo = getMainWidth(context) <= 600 && selected != null; - double w = selected != null ? getMainWidth(context) - menuSize : getMainWidth(context); + bool isInfo = getMainWidth(context) <= 600 && selected != null && widget.isBox; + double w = selected != null && widget.isBox ? getMainWidth(context) - menuSize : getMainWidth(context); List children = []; if (selected != null) { for (var wf in widget.data[selected!] ?? ([])) { @@ -94,7 +95,7 @@ class ScheduleWidgetState extends State { : SchedulerCalendarWidget(data: widget.data, start: widget.start, end: widget.end, parent: this, focusedDay: getFocusedDay(),) ), - fork.TransformableBox( + !widget.isBox ? Container() : fork.TransformableBox( rect: rect, constraints: BoxConstraints( maxWidth: isInfo ? getMainWidth(context) : (selected != null ? getMainWidth(context) / 2 : 0), minWidth: selected != null ? 300 : 0), diff --git a/lib/widgets/sheduler_items/scheduler_calendar.dart b/lib/widgets/sheduler_items/scheduler_calendar.dart index a0dc983..17e75f0 100644 --- a/lib/widgets/sheduler_items/scheduler_calendar.dart +++ b/lib/widgets/sheduler_items/scheduler_calendar.dart @@ -24,8 +24,8 @@ class SchedulerCalendarWidget extends StatefulWidget { @override SchedulerCalendarWidgetState createState() => SchedulerCalendarWidgetState(); } class SchedulerCalendarWidgetState extends State { - List colors = [Colors.blue, Colors.orange, redColor, Colors.green]; - List titles = ["SCHEDULED", "RUNNING", "FAILURE", "SUCCESS"]; + List colors = [Colors.blue, Colors.orange, redColor, Colors.green, redColor]; + List titles = ["SCHEDULED", "RUNNING", "FAILURE", "SUCCESS", "FORGOTTEN"]; bool isEvent(Map> data, DateTime day) { if (data[day.toIso8601String()] == null || data[day.toIso8601String()]!.isEmpty) { return false; } return true; diff --git a/lib/widgets/sheduler_items/scheduler_item.dart b/lib/widgets/sheduler_items/scheduler_item.dart index dd9884d..4d32780 100644 --- a/lib/widgets/sheduler_items/scheduler_item.dart +++ b/lib/widgets/sheduler_items/scheduler_item.dart @@ -1,6 +1,7 @@ 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/main.dart'; import 'package:oc_front/models/workflow.dart'; import 'package:oc_front/widgets/sheduler_items/schedule.dart'; @@ -17,8 +18,8 @@ class SchedulerItemWidget extends StatefulWidget { @override SchedulerItemWidgetState createState() => SchedulerItemWidgetState(); } class SchedulerItemWidgetState extends State { - List colors = [Colors.blue, Colors.orange, Colors.red, Colors.green]; - List titles = ["SCHEDULED", "RUNNING", "FAILURE", "SUCCESS"]; + List colors = [Colors.blue, Colors.orange, redColor, Colors.green, redColor]; + List titles = ["SCHEDULED", "RUNNING", "FAILURE", "SUCCESS", "FORGOTTEN"]; @override Widget build(BuildContext context) { List children = []; @@ -42,8 +43,7 @@ class SchedulerItemWidgetState extends State { padding: const EdgeInsets.symmetric(vertical: 20, horizontal: 50), decoration: BoxDecoration( border: selectedReal == ev.executionData ? - Border.all(color: const Color.fromRGBO(38, 166, 154, 1), width: 2) - : Border(top: BorderSide(color: Colors.grey.shade300)), + Border.all(color: lightColor, width: 2) : Border(top: BorderSide(color: midColor)), ), child: Row(children: [ Container( width: 110, @@ -64,7 +64,7 @@ class SchedulerItemWidgetState extends State { )), SizedBox( width: (widget.width - 340) / 2, child: Padding( - padding: const EdgeInsets.only(left: 20), + padding: const EdgeInsets.only(left: 17), child: Container( padding: const EdgeInsets.symmetric(horizontal: 20), child: Text(d3 != null ? "killed at ${d3.day}/${d3.month}/${d3.year} ${d3.hour}:${d3.minute}:${d3.second}" : "infinite run till process end", overflow: TextOverflow.ellipsis, @@ -72,7 +72,7 @@ class SchedulerItemWidgetState extends State { )), SizedBox( child: Padding( - padding: const EdgeInsets.only(left: 20), + padding: const EdgeInsets.only(left: 17), child: Text("${d2.hour > 9 ? d2.hour : "0${d2.hour}"}:${d2.minute > 9 ? d2.minute : "0${d2.minute}"}:${d2.second > 9 ? d2.second : "0${d2.second}"}", overflow: TextOverflow.ellipsis, style: const TextStyle(fontSize: 25, color: Colors.grey, fontWeight: FontWeight.w500)))) @@ -81,12 +81,12 @@ class SchedulerItemWidgetState extends State { } var date = DateTime.parse(element); children.add(Container( - decoration: const BoxDecoration( - border: Border(bottom: BorderSide(color: Colors.black)), + decoration: BoxDecoration( + border: Border(bottom: BorderSide(color: Colors.grey.shade300)), ), - child: Column( children: [ExpansionTile( + child: Column( children: [ ExpansionTile( enabled: widget.enabled, - shape: const ContinuousRectangleBorder(), + shape: const ContinuousRectangleBorder(side : BorderSide(color: Colors.grey)), iconColor: Colors.grey, initiallyExpanded: true, title: SizedBox( @@ -110,11 +110,15 @@ class SchedulerItemWidgetState extends State { } }); return Container( + decoration: BoxDecoration( + color: children.isNotEmpty ? Colors.transparent : midColor, + border: Border( right: BorderSide( color: children.isNotEmpty ? Colors.transparent : Colors.white) ), + ), alignment: children.isNotEmpty ? Alignment.topLeft : Alignment.center, - color: children.isNotEmpty ? Colors.transparent : Colors.white, - width: children.isNotEmpty ? MediaQuery.of(context).size.width : null, - height: MediaQuery.of(context).size.height - HeaderConstants.height - 50, - child: children.isNotEmpty ? SingleChildScrollView( child: Column( children: children)) : const Text("NO DATA FOUND", style: TextStyle(color: Colors.grey, fontSize: 30)) + width: children.isNotEmpty ? getMainWidth(context) : null, + height: getMainHeight(context) - 50, + child: children.isNotEmpty ? SingleChildScrollView( child: Column( children: children)) : const Text( + "NO DATA FOUND", style: TextStyle(color: Colors.grey, fontSize: 30)) ); } } \ No newline at end of file diff --git a/library/flutter_flow_chart/lib/src/flow_chart.dart b/library/flutter_flow_chart/lib/src/flow_chart.dart index 0028e3c..6931776 100755 --- a/library/flutter_flow_chart/lib/src/flow_chart.dart +++ b/library/flutter_flow_chart/lib/src/flow_chart.dart @@ -298,16 +298,21 @@ class HoverMenuState extends State { } } -var node = FocusNode(); class FlowChartState extends State { - - + var node = FocusNode(); + bool isCtrl = false; @override void initState() { node.requestFocus(); super.initState(); } + @override + void dispose() { + node.requestFocus(); + super.dispose(); + } + @override Widget build(BuildContext context) { if (!widget.dashboard.isOpened && widget.onDashboardAlertOpened != null ) { @@ -331,7 +336,7 @@ class FlowChartState extends State { } else { widget.dashboard.isOpened = true; } - /// get dashboard position after first frame is drawn + /// get dashboard positi(event is KeyDownEvent || event is KeyRepeatEvent) &&on after first frame is drawn WidgetsBinding.instance.addPostFrameCallback((timeStamp) { if (mounted) { final object = context.findRenderObject() as RenderBox?; @@ -348,41 +353,18 @@ class FlowChartState extends State { if (kIsWeb) BrowserContextMenu.disableContextMenu(); return KeyboardListener( focusNode: node, + autofocus: true, onKeyEvent: (event) { bool change = false; - /*if ((event is KeyDownEvent || event is KeyRepeatEvent) && event.logicalKey == LogicalKeyboardKey.arrowUp) { - change = true; - for (var el in widget.dashboard.elements) { - if (el.isSelected) { - el.position = Offset(el.position.dx, el.position.dy - 10); - } - } + if (event.logicalKey == LogicalKeyboardKey.controlLeft) { + isCtrl = event is KeyDownEvent || event is KeyRepeatEvent; } - if ((event is KeyDownEvent || event is KeyRepeatEvent) && event.logicalKey == LogicalKeyboardKey.arrowDown) { - change = true; - for (var el in widget.dashboard.elements) { - if (el.isSelected) { - el.position = Offset(el.position.dx, el.position.dy + 10); - } - } + if (event is KeyDownEvent || event.logicalKey == LogicalKeyboardKey.keyZ && isCtrl) { + widget.dashboard.back(); } - if ((event is KeyDownEvent || event is KeyRepeatEvent) && event.logicalKey == LogicalKeyboardKey.arrowLeft) { - change = true; - for (var el in widget.dashboard.elements) { - if (el.isSelected) { - el.position = Offset(el.position.dx - 10, el.position.dy); - } - } + if (event is KeyDownEvent || event.logicalKey == LogicalKeyboardKey.keyY && isCtrl) { + widget.dashboard.forward(); } - if ((event is KeyDownEvent || event is KeyRepeatEvent) && event.logicalKey == LogicalKeyboardKey.arrowRight) { - change = true; - for (var el in widget.dashboard.elements) { - if (el.isSelected) { - el.position = Offset(el.position.dx + 10, el.position.dy); - } - } - }*/ - if (event is KeyDownEvent && event.logicalKey == LogicalKeyboardKey.add) { change = true; for (var el in widget.dashboard.elementSelected) { @@ -413,6 +395,7 @@ class FlowChartState extends State { if (change) { DrawingArrow.instance.notifyListeners(); widget.dashboard.chartKey.currentState?.setState(() { }); + node.requestFocus(); } }, child: ClipRect( @@ -455,7 +438,6 @@ class FlowChartState extends State { String newID = const Uuid().v4(); double ratio = 1; if (e.getWidth() != null && e.getHeight() != null) { - print("${e.getWidth()} ${e.getHeight()}"); var h = e.getHeight()! < e.getWidth()! ? e.getHeight()! + 20 : e.getHeight()!; var w = e.getWidth()! < e.getHeight()! ? e.getWidth()! + 20 : e.getWidth()!; ratio = (h / w); diff --git a/library/flutter_flow_chart/lib/src/ui/element_widget.dart b/library/flutter_flow_chart/lib/src/ui/element_widget.dart index 554533e..adc3d63 100755 --- a/library/flutter_flow_chart/lib/src/ui/element_widget.dart +++ b/library/flutter_flow_chart/lib/src/ui/element_widget.dart @@ -147,6 +147,12 @@ class ElementWidgetState extends State { secondaryTapDownPos = details.globalPosition, onTap: () { setState(() { + if (!(widget.dashboard.flutterChartKey.currentState?.isCtrl ?? true)) { + for (var element in widget.dashboard.elements) { + element.isSelected = false; + element.dashboard.chartKey.currentState?. setState(() { }); + } + } widget.element.isSelected = !widget.element.isSelected; for (var sel in widget.dashboard.arrows) { sel.isSelected = false; } widget.dashboard.selectedMenuKey.currentState?. setState(() { }); diff --git a/local_run.sh b/local_run.sh index ab102d2..2fb4d06 100755 --- a/local_run.sh +++ b/local_run.sh @@ -8,5 +8,6 @@ LOGS_HOST='http://localhost:3100' PEER_HOST='http://localhost:8093/oc' COLLABORATIVE_AREA_HOST='http://localhost:8091/oc' AUTH_HOST='http://localhost:8094/oc' +DATACENTER_HOST='http://localhost:8092/oc' -flutter run -d linux --dart-define=AUTH_HOST=$AUTH_HOST --dart-define=WORKSPACE_HOST=$WORKSPACE_HOST --dart-define=WORKFLOW_HOST=$WORKFLOW_HOST --dart-define=PEER_HOST=$PEER_HOST --dart-define=COLLABORATIVE_AREA_HOST=$COLLABORATIVE_AREA_HOST --dart-define=SCHEDULER_HOST=$SCHEDULER_HOST --dart-define=LOGS_HOST=$LOGS_HOST --dart-define=ITEM_HOST=$ITEM_HOST \ No newline at end of file +flutter run -d linux --dart-define=DATACENTER_HOST=$DATACENTER_HOST --dart-define=AUTH_HOST=$AUTH_HOST --dart-define=WORKSPACE_HOST=$WORKSPACE_HOST --dart-define=WORKFLOW_HOST=$WORKFLOW_HOST --dart-define=PEER_HOST=$PEER_HOST --dart-define=COLLABORATIVE_AREA_HOST=$COLLABORATIVE_AREA_HOST --dart-define=SCHEDULER_HOST=$SCHEDULER_HOST --dart-define=LOGS_HOST=$LOGS_HOST --dart-define=ITEM_HOST=$ITEM_HOST \ No newline at end of file