intermediate

This commit is contained in:
mr
2024-08-08 08:42:32 +02:00
parent 593f03648b
commit ceeebfc964
74 changed files with 3784 additions and 634 deletions

View File

@@ -1,5 +1,7 @@
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';
@@ -24,24 +26,47 @@ class NewBoxWidgetState<T extends SerializerDeserializer<dynamic>> extends State
widget._ctrl.value = TextEditingValue(text: widget.dash.defaultName);
return Container(
color: Colors.white,
padding: const EdgeInsets.all(20),
padding: const EdgeInsets.only( top: 0, bottom: 20, left: 20, right: 20),
child: Column(
children: [
Row(
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 : [
FutureBuilder<APIResponse<T>>(
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 SizedBox( width: MediaQuery.of(context).size.width <= 540 ? MediaQuery.of(context).size.width - 140 : 400, height: 50,
SizedBox( width: MediaQuery.of(context).size.width <= 540 ? MediaQuery.of(context).size.width - 140 : 400, height: 50,
child: DropdownButtonFormField(
value: widget._selected,
isExpanded: true,
@@ -59,12 +84,12 @@ class NewBoxWidgetState<T extends SerializerDeserializer<dynamic>> extends State
border: OutlineInputBorder( borderRadius: BorderRadius.zero,
borderSide: BorderSide(color: Colors.grey.shade300, width: 0)),
),
items: items, onChanged: (value) {
items: items,
onChanged: (value) {
setState(() {
widget._selected = value.toString();
});
}));
}),
})),
Tooltip(
message: 'empty selection',
child: InkWell(
@@ -86,9 +111,13 @@ class NewBoxWidgetState<T extends SerializerDeserializer<dynamic>> extends State
child: InkWell(
mouseCursor: widget._selected == null || widget._selected!.isEmpty
? MouseCursor.defer : SystemMouseCursors.click,
onTap: () {
onTap: () async {
if (widget._selected == null || widget._selected!.isEmpty) { return; }
widget.dash.name = widget._selected ?? widget.dash.name;
if (widget._selected != null && widget.dash.load != null) {
await widget.dash.load!(widget._selected ?? "");
WorkspaceLocal.init(context, true);
}
widget.dash.isOpened = true;
widget.dash.notifyListeners();
Navigator.pop(context);
},
@@ -100,7 +129,8 @@ class NewBoxWidgetState<T extends SerializerDeserializer<dynamic>> extends State
)
)
)
]),
]);}),
Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
@@ -115,7 +145,7 @@ class NewBoxWidgetState<T extends SerializerDeserializer<dynamic>> extends State
minLines: null,
cursorColor: const Color.fromARGB(38, 166, 154, 1),
controller: widget._ctrl,
onChanged: (value) => setState(() { widget._ctrl.value = TextEditingValue(text: value); }),
onChanged: (value) {},
validator: (value) => value == null || value.isEmpty ? "name is required" : null,
decoration: InputDecoration(
hintText: "name a new workflow...",
@@ -137,13 +167,19 @@ class NewBoxWidgetState<T extends SerializerDeserializer<dynamic>> extends State
mouseCursor: widget._ctrl.value.text.isEmpty ? MouseCursor.defer : SystemMouseCursors.click,
onTap: () async {
if (widget._ctrl.value.text.isNotEmpty) {
await widget.service.post(context, {}, { "workflowName" : widget._ctrl.value.text });
widget._selected = widget._ctrl.value.text;
widget._ctrl.value = const TextEditingValue(text: "");
widget.dash.name = widget._selected ?? widget.dash.name;
widget.dash.notifyListeners();
// ignore: use_build_context_synchronously
Navigator.pop(context);
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(

View File

@@ -0,0 +1,73 @@
import 'package:flutter/material.dart';
import 'package:oc_front/models/search.dart';
class DataFormsWidget extends StatefulWidget {
DataItem item;
String purpose = "";
Function validate = () {};
DataFormsWidget ({ super.key, required this.item });
@override DataFormsWidgetState createState() => DataFormsWidgetState();
}
class DataFormsWidgetState extends State<DataFormsWidget> {
@override Widget build(BuildContext context) {
return Column( children: [
Tooltip( message: "protocols",
child: Container(
margin: const EdgeInsets.only(left: 10),
width: 45, height: 25,
child: TextFormField( textAlign: TextAlign.center,
initialValue: widget.item.protocols.join(","),
onChanged: (value) {
widget.item.protocols = value.split(",");
},
style: const TextStyle(fontSize: 12),
decoration: const InputDecoration(
fillColor: Colors.white,
filled: true,
labelText: "protocols",
labelStyle: TextStyle(fontSize: 10),
border: OutlineInputBorder(),
contentPadding: EdgeInsets.symmetric(horizontal: 10, vertical: 5),
),
))),
Tooltip( message: "datatype",
child: Container(
margin: const EdgeInsets.only(left: 10),
width: 45, height: 25,
child: TextFormField( textAlign: TextAlign.center,
initialValue: widget.item.dataType,
onChanged: (value) {
widget.item.dataType = value;
},
style: const TextStyle(fontSize: 12),
decoration: const InputDecoration(
fillColor: Colors.white,
filled: true,
labelText: "datatype",
labelStyle: TextStyle(fontSize: 10),
border: OutlineInputBorder(),
contentPadding: EdgeInsets.symmetric(horizontal: 10, vertical: 5),
),
))),
Tooltip( message: "example",
child: Container(
margin: const EdgeInsets.only(left: 10),
width: 45, height: 25,
child: TextFormField( textAlign: TextAlign.center,
initialValue: widget.item.exemple,
onChanged: (value) {
widget.item.exemple = value;
},
style: const TextStyle(fontSize: 12),
decoration: const InputDecoration(
fillColor: Colors.white,
filled: true,
labelText: "example",
labelStyle: TextStyle(fontSize: 10),
border: OutlineInputBorder(),
contentPadding: EdgeInsets.symmetric(horizontal: 10, vertical: 5),
),
)))
]);
}
}

View File

@@ -0,0 +1,61 @@
import 'package:flutter/material.dart';
import 'package:oc_front/models/search.dart';
import 'package:oc_front/pages/workflow.dart';
Map<String, Map<String, AbstractItem>> proxyWfItem = {};
class ProxyFormsWidget extends StatefulWidget {
AbstractItem item;
ProxyFormsWidget ({ super.key, required this.item });
@override ProxyFormsWidgetState createState() => ProxyFormsWidgetState();
}
class ProxyFormsWidgetState extends State<ProxyFormsWidget> {
@override Widget build(BuildContext context) {
List<Widget> children = [];
var l = widget.item.model?.model?.keys ?? [];
for (var child in l) {
if (widget.item.model!.model![child]!.type != "string") { continue; }
children.add(
Tooltip( message: child,
child: Container( margin: EdgeInsets.only(top: children.isEmpty ? 0 : 15),
width: 160, height: 30,
child: TextFormField( textAlign: TextAlign.start,
initialValue: widget.item.model?.model?[child]?.value,
onChanged: (value) {
widget.item.model ?? Model();
Future.delayed(const Duration(seconds: 2), () {
if (widget.item.model!.model?[child]?.value == value) {
dash.save!(dash.id);
}
});
widget.item.model?.model?[child]?.value = value;
},
style: const TextStyle(fontSize: 12),
decoration: InputDecoration(
hintText: "enter $child...",
fillColor: Colors.white,
filled: true,
labelText: child,
alignLabelWithHint: false,
errorStyle: const TextStyle(fontSize: 0),
hintStyle: const TextStyle(fontSize: 10),
labelStyle: const TextStyle(fontSize: 10),
floatingLabelBehavior: FloatingLabelBehavior.always,
enabledBorder: const OutlineInputBorder(borderSide: BorderSide(color: Colors.grey)),
border: const OutlineInputBorder(borderSide: BorderSide(color: Colors.grey)),
contentPadding: const EdgeInsets.symmetric(horizontal: 10, vertical: 5),
),
)))
);
}
return Column( children: [
Container( padding: const EdgeInsets.all(10), width: 200, height: 60, margin: const EdgeInsets.only(bottom: 15),
decoration: const BoxDecoration(border: Border(bottom: BorderSide(color: Colors.grey, width: 1))),
child: const Column( mainAxisAlignment: MainAxisAlignment.center, children: [
Text("ELEMENT INFO", style: TextStyle(fontSize: 15, fontWeight: FontWeight.bold), textAlign: TextAlign.center),
Text("<general>", style: TextStyle(fontSize: 12), textAlign: TextAlign.center),
])),
...children
]);
}
}

View File

@@ -0,0 +1,288 @@
import 'package:cron/cron.dart';
import 'package:intl/intl.dart' as intl;
import 'package:flutter/material.dart';
import 'package:flutter_flow_chart/flutter_flow_chart.dart';
import 'package:flutter_advanced_switch/flutter_advanced_switch.dart';
import 'package:datetime_picker_formfield/datetime_picker_formfield.dart';
class SchedulerFormsWidget extends StatefulWidget {
Dashboard item;
String purpose = "";
Function validate = () {};
SchedulerFormsWidget ({ super.key, required this.item });
@override SchedulerFormsWidgetState createState() => SchedulerFormsWidgetState();
}
class SchedulerFormsWidgetState extends State<SchedulerFormsWidget> {
@override Widget build(BuildContext context) {
if (widget.item.schedulerState["service"] == null) { widget.item.schedulerState["service"] = true; }
List<GlobalKey<FormFieldState>> formKeys = [GlobalKey<FormFieldState>(), GlobalKey<FormFieldState>(),
GlobalKey<FormFieldState>(), GlobalKey<FormFieldState>()];
return Column( children: [
Container( padding: const EdgeInsets.all(10), width: 200, height: 60,
decoration: const BoxDecoration(border: Border(bottom: BorderSide(color: Colors.grey, width: 1))),
child: const Column( mainAxisAlignment: MainAxisAlignment.center, children: [
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),
AdvancedSwitch(
width: 140,
initialValue: widget.item.schedulerState["service"] == true,
activeColor: Colors.green, inactiveColor: Colors.green,
activeChild: const Text("service", style: TextStyle(color: Colors.white)),
inactiveChild: const Text("cron task", style: TextStyle(color: Colors.white)),
borderRadius: const BorderRadius.all(Radius.circular(15)), height: 30.0, disabledOpacity: 0.5,
onChanged: (value) {
Future.delayed(const Duration(milliseconds: 100), () =>
setState(() {
widget.item.schedulerState["service"] = value;
if ((widget.item.schedulerState["service"] == true )) { widget.item.scheduler.remove("cron"); }
}));
},),
Container(height: 5),
Tooltip( message: "event name",
child: Container( height: 40, margin: const EdgeInsets.only(top: 5),
padding: const EdgeInsets.symmetric(vertical: 5, horizontal: 20),
child: TextFormField( key: formKeys[0],
initialValue: "${widget.item.schedulerState["service"] == true ? "" : "cron_"}${widget.item.scheduler["name"] ?? "${widget.item.name}_event"}",
onChanged: (value) {
widget.item.scheduler["name"] = value;
},
onSaved: (value) {
widget.item.scheduler["name"] = value ?? "${widget.item.schedulerState["service"] == true ? "" : "cron_"}${widget.item.scheduler["name"] ?? "${widget.item.name}_event"}";
},
validator: (value) => value == null || value.isEmpty ? "not empty" : null,
style: const TextStyle(fontSize: 12),
decoration: const InputDecoration(
floatingLabelBehavior: FloatingLabelBehavior.always,
fillColor: Colors.white,
filled: true,
hintText: "enter event name...",
labelText: "event name*",
errorStyle: TextStyle(fontSize: 0),
hintStyle: TextStyle(fontSize: 10),
labelStyle: TextStyle(fontSize: 10),
error: null,
enabledBorder: OutlineInputBorder(borderSide: BorderSide(color: Colors.grey)),
border: OutlineInputBorder(borderSide: BorderSide(color: Colors.grey)),
contentPadding: EdgeInsets.symmetric(horizontal: 10, vertical: 5),
),
))),
Tooltip( message: "start event",
child: Container( height: 40, margin: const EdgeInsets.only(top: 5),
padding: const EdgeInsets.symmetric(vertical: 5, horizontal: 20),
child: DateTimeField( key: formKeys[1],
resetIcon: const Icon(Icons.close, size: 15),
onSaved: (value) {
widget.item.scheduler["start"] = "${(value ?? DateTime.now()).toIso8601String()}Z";
},
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: Colors.grey.shade300,
tertiary: Colors.grey,
secondary: Colors.grey,
primary: Colors.black),
),
child: child ?? Container(),
);
return w;
},
context: context,
firstDate: DateTime(1900),
initialDate: DateTime.parse(widget.item.scheduler["start"] ?? currentValue?.toIso8601String() ?? ""),
lastDate: DateTime(2100)
);
if (date != null) {
var time = await showTimePicker(context: context,
initialTime: TimeOfDay(hour: date.hour, minute: date.minute),
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: Colors.grey.shade300,
tertiary: Colors.grey,
secondary: Colors.grey,
primary: Colors.black),
),
child: child ?? Container(),
);
return w;
},
);
date = date.add(Duration(hours: time?.hour ?? 0, minutes: time?.minute ?? 0));
}
return date;
},
format: intl.DateFormat('y-M-dd hh:mm:ss'),
initialValue: DateTime.parse(widget.item.scheduler["start"] ?? DateTime.now().toIso8601String()),
onChanged: (value) {
widget.item.scheduler["start"] = "${(value ?? DateTime.now()).toIso8601String()}Z";
},
validator: (value) => value == null ? "not empty" : null,
style: const TextStyle(fontSize: 12),
decoration: const InputDecoration(
floatingLabelBehavior: FloatingLabelBehavior.always,
fillColor: Colors.white,
filled: true,
alignLabelWithHint: false,
hintText: "enter start event...",
labelText: "start event*",
errorStyle: TextStyle(fontSize: 0),
hintStyle: TextStyle(fontSize: 10),
labelStyle: TextStyle(fontSize: 10),
enabledBorder: OutlineInputBorder(borderSide: BorderSide(color: Colors.grey)),
border: OutlineInputBorder(borderSide: BorderSide(color: Colors.grey)),
contentPadding: EdgeInsets.symmetric(horizontal: 10, vertical: 5),
),
))),
Tooltip( message: "end event",
child: Container( height: 40, margin: const EdgeInsets.only(top: 5),
padding: const EdgeInsets.symmetric(vertical: 5, horizontal: 20),
child: DateTimeField( key: formKeys[2],
validator: (value) {
return value == null && !(widget.item.schedulerState["service"] == true ) ? "not empty" : null;
},
resetIcon: const Icon(Icons.close, size: 15),
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: Colors.grey.shade300,
tertiary: Colors.grey,
secondary: Colors.grey,
primary: Colors.black),
),
child: child ?? Container(),
);
return w;
},
context: context,
firstDate: DateTime(1900),
initialDate: DateTime.parse(widget.item.scheduler["start"] ?? currentValue?.toIso8601String() ?? ""),
lastDate: DateTime(2100)
);
if (date != null) {
var time = await showTimePicker(context: context,
initialTime: TimeOfDay(hour: date.hour, minute: date.minute),
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: Colors.grey.shade300,
tertiary: Colors.grey,
secondary: Colors.grey,
primary: Colors.black),
),
child: child ?? Container(),
);
return w;
},
);
date = date.add(Duration(hours: time?.hour ?? 0, minutes: time?.minute ?? 0));
}
return date;
},
format: intl.DateFormat('y-M-dd hh:mm:ss'),
initialValue: widget.item.scheduler["end"] != null ? DateTime.parse(widget.item.scheduler["end"]!) : null,
onSaved: (value) {
if (value != null) {
widget.item.scheduler["end"] = "${(value).toIso8601String()}Z";
}
},
onChanged: (value) {
if (value == null) { return; }
widget.item.scheduler["end"] = "${value.toIso8601String()}Z";
},
style: const TextStyle(fontSize: 12),
decoration: InputDecoration(
fillColor: Colors.white,
floatingLabelBehavior: FloatingLabelBehavior.always,
filled: true,
alignLabelWithHint: false,
hintText: "enter end event...",
labelText: "end event${!(widget.item.schedulerState["service"] == true) ? "*" : ""}",
errorStyle: const TextStyle(fontSize: 0),
hintStyle: const TextStyle(fontSize: 10),
labelStyle: const TextStyle(fontSize: 10),
enabledBorder: const OutlineInputBorder(borderSide: BorderSide(color: Colors.grey)),
border: const OutlineInputBorder(borderSide: BorderSide(color: Colors.grey)),
contentPadding: const EdgeInsets.symmetric(horizontal: 10, vertical: 5),
),
))),
widget.item.schedulerState["service"] == true ? Container() : Tooltip( message: "schedule",
child: Container( height: 40, margin: const EdgeInsets.only(top: 5),
padding: const EdgeInsets.symmetric(vertical: 5, horizontal: 20),
child: TextFormField( key: formKeys[3],
initialValue: widget.item.scheduler["cron"],
onChanged: (value) {
widget.item.scheduler["cron"] = value;
},
onSaved: (value) {
if (value != null) {
widget.item.scheduler["cron"] = value;
}
},
validator: (value) {
var cron = Cron();
try {
cron.schedule(Schedule.parse(value ?? ""), () {});
} catch (e) {
return "invalid cron";
}
return value == null || value.isEmpty ? "not empty" : null;
},
style: const TextStyle(fontSize: 12),
decoration: const InputDecoration(
floatingLabelBehavior: FloatingLabelBehavior.always,
fillColor: Colors.white,
filled: true,
hintText: "enter schedule...",
labelText: "schedule*",
errorStyle: TextStyle(fontSize: 0),
hintStyle: TextStyle(fontSize: 10),
labelStyle: TextStyle(fontSize: 10),
error: null,
enabledBorder: OutlineInputBorder(borderSide: BorderSide(color: Colors.grey)),
border: OutlineInputBorder(borderSide: BorderSide(color: Colors.grey)),
contentPadding: EdgeInsets.symmetric(horizontal: 10, vertical: 5),
),
))),
const Divider(color: Colors.grey),
Tooltip( message: "save",
child: InkWell( mouseCursor: SystemMouseCursors.click,
onTap: () {
for (var k in formKeys) {
if (k.currentState != null) {
if (!k.currentState!.validate()) {
return;
} else { k.currentState!.save();}
}
}
widget.item.schedulerSave = true;
widget.item.save!(widget.item.id);
}, child: Container( margin: const EdgeInsets.all(10),
decoration: BoxDecoration(borderRadius: BorderRadius.circular(5), border: Border.all(color: Colors.black, width: 1)),
width: 140, height: 30,
child: const Icon(Icons.save_outlined, color: Colors.black),
))
),
]);
}
}

View File

@@ -25,14 +25,14 @@ class ItemRowWidgetState extends State<ItemRowWidget> {
var endWidth = (itemWidth * ratio) + 80;
Image? image;
if (widget.item.logo != null) {
image = Image.memory(base64Decode(widget.item.logo ?? ""), width: imageSize, height: imageSize);
image = Image.network(widget.item.logo ?? "", width: imageSize, height: imageSize);
}
Widget w = Container(
width: widget.contextWidth,
height: 100,
decoration: BoxDecoration( border: Border(bottom: BorderSide(color: Colors.grey.shade300)) ),
child: Row( children: [
widget.low ? Container( padding: EdgeInsets.only(left: 10),) : Padding( padding: const EdgeInsets.all(10),
widget.low ? Container( padding: const EdgeInsets.only(left: 10),) : Padding( padding: const EdgeInsets.all(10),
child: image ?? Image.network('https://get-picto.com/wp-content/uploads/2024/01/logo-instagram-png.webp',
height: imageSize, width: imageSize)),
Container(
@@ -51,7 +51,7 @@ class ItemRowWidgetState extends State<ItemRowWidget> {
isStorage(widget.item.topic) ? Colors.red : Colors.grey,
borderRadius: BorderRadius.circular(4),
),
child: Text( MediaQuery.of(context).size.width < 600 ? "" : widget.item.type.toString(),
child: Text( MediaQuery.of(context).size.width < 600 ? "" : widget.item.topic.toString(),
style: const TextStyle(fontSize: 10, color: Colors.white, fontWeight: FontWeight.w600)),
),
Expanded( child: Text(widget.item.name?.toUpperCase() ?? "",
@@ -59,7 +59,7 @@ class ItemRowWidgetState extends State<ItemRowWidget> {
)
]),
Text( "From ${widget.item.owner ?? "unknown owner"}",
style: TextStyle(fontSize: 14, color: Colors.grey, overflow: TextOverflow.ellipsis)),
style: const TextStyle(fontSize: 14, color: Colors.grey, overflow: TextOverflow.ellipsis)),
Text(widget.item.shortDescription ?? "", style: const TextStyle(fontSize: 12, overflow: TextOverflow.ellipsis)),
],)
)

View File

@@ -11,16 +11,13 @@ class DataItemWidgetState extends State<DataItemWidget> {
@override Widget build(BuildContext context) {
return Wrap( children: [
Padding(padding: EdgeInsets.symmetric(vertical: 20, horizontal: 100),
child: Text("type : ${widget.item.dtype ?? "unknown type"}",
style: TextStyle(fontSize: 15, fontWeight: FontWeight.w600))),
Padding(padding: EdgeInsets.symmetric(horizontal: 100, vertical: 20),
child: Text("location : ${widget.item.location ?? "unknown location"}",
child: Text("type : ${widget.item.dataType ?? "unknown type"}",
style: TextStyle(fontSize: 15, fontWeight: FontWeight.w600))),
Padding(padding: EdgeInsets.symmetric(horizontal: 100, vertical: 20),
child: Text("protocol : ${widget.item.protocol.isEmpty ? "no protocol founded" : widget.item.protocol.join(",")}",
child: Text("protocol : ${widget.item.protocols.isEmpty ? "no protocol founded" : widget.item.protocols.join(",")}",
style: TextStyle(fontSize: 15, fontWeight: FontWeight.w600))),
Padding(padding: EdgeInsets.symmetric(horizontal: 100, vertical: 20),
child: Text("ex : ${widget.item.example ?? "no example"}",
child: Text("ex : ${widget.item.exemple ?? "no example"}",
style: TextStyle(fontSize: 15, fontWeight: FontWeight.w600))),
]);
}

73
lib/widgets/logs.dart Normal file
View File

@@ -0,0 +1,73 @@
import 'package:alert_banner/exports.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:oc_front/models/logs.dart';
import 'package:oc_front/widgets/dialog/alert.dart';
class LogsWidget extends StatefulWidget {
final List<Log> items;
LogsWidget ({ Key? key, required this.items }): super(key: key);
@override LogsWidgetState createState() => LogsWidgetState();
}
class LogsWidgetState extends State<LogsWidget> {
@override Widget build(BuildContext context) {
List<LogWidget> itemRows = widget.items.map((e) => LogWidget(item: e)).toList();
return SingleChildScrollView( child: Column( children: itemRows ) );
}
}
class LogWidget extends StatefulWidget {
final Log item;
bool expanded = false;
LogWidget ({ Key? key, required this.item }): super(key: key);
@override LogWidgetState createState() => LogWidgetState();
}
class LogWidgetState extends State<LogWidget> {
@override Widget build(BuildContext context) {
return Padding( padding: const EdgeInsets.only(top: 10, left: 30, right: 30), child: Wrap( children: [
Row( mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Container( width: 10, height: 15, color: widget.item.level?.toLowerCase() == "info" ? Colors.green :
( widget.item.level?.toLowerCase() == "error" ? Colors.red : (
widget.item.level?.toLowerCase() == "warning" ? Colors.orange : Colors.blue))),
InkWell( mouseCursor: widget.item.map.isEmpty ? MouseCursor.defer : SystemMouseCursors.click, onTap: () {
if (widget.item.map.isNotEmpty ) {
setState(() {
widget.expanded = !widget.expanded;
});
}
}, child: Container( height: 20,
child: Padding( padding: EdgeInsets.symmetric(horizontal: widget.expanded ? 0 : 5),
child: Icon( widget.expanded ? Icons.keyboard_arrow_down_outlined : Icons.arrow_forward_ios, size: widget.expanded ? 25 : 15,
color: widget.item.map.isEmpty ? Colors.grey : Colors.black, weight: widget.expanded ? 100 : 1000,)))),
Padding( padding: const EdgeInsets.only(right: 10),
child: Text("${widget.item.timestamp?.toString()}",
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) {
Clipboard.setData(ClipboardData(text: widget.item.message!));
showAlertBanner(context, () {}, const InfoAlertBannerChild(text: "Copy to clipboard"), // <-- Put any widget here you want!
alertBannerLocation: AlertBannerLocation.bottom,);
}
})),
]),
widget.expanded ? Container(
margin: const EdgeInsets.symmetric(vertical: 10),
decoration: BoxDecoration( color: Colors.grey,
borderRadius: BorderRadius.circular(4)),
padding: const EdgeInsets.all(10),
child: Column( children: widget.item.map.keys.map((e) =>
Padding( padding: const EdgeInsets.all(2), child: Row( mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [Flexible( child:Text("$e: \"${widget.item.map[e]}\"",
style: const TextStyle(fontSize: 11, color: Colors.white))), ])
)).toList()
)) : Container(),
Row( mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [Flexible( child:Text(widget.item.message ?? "unknown message",
style: const TextStyle(fontSize: 14, color: Colors.black))), ])
]));
}
}

View File

@@ -0,0 +1,116 @@
import 'dart:ffi';
import 'package:flutter/material.dart';
import 'package:oc_front/core/models/workspace_local.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 : 2),
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 / 2) - 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)
)
)
)
])
]);
}
}

View File

@@ -0,0 +1,179 @@
import 'package:flutter/material.dart';
import 'package:oc_front/core/sections/header/header.dart';
import 'package:oc_front/core/services/specialized_services/logs_service.dart';
import 'package:oc_front/models/logs.dart';
import 'package:oc_front/models/workflow.dart';
import 'package:oc_front/widgets/logs.dart';
import 'package:oc_front/widgets/sheduler_items/scheduler_calendar.dart';
import 'package:oc_front/widgets/sheduler_items/scheduler_item.dart';
// ignore: must_be_immutable
class ScheduleWidget extends StatefulWidget {
DateTime start;
DateTime end;
bool isDayPlanner = true;
Map<String, List<WorkflowExecution>> data;
bool isList = true;
ScheduleWidget ({ super.key, required this.data, required this.start, required this.end, this.isList = true });
@override ScheduleWidgetState createState() => ScheduleWidgetState();
}
class ScheduleWidgetState extends State<ScheduleWidget> {
LogsService _service = LogsService();
String? selected;
String? selectedReal;
List<Color> colors = [Colors.blue, Colors.orange, Colors.red, Colors.green];
List<String> titles = ["SCHEDULED", "RUNNING", "FAILURE", "SUCCESS"];
DateTime getFocusedDay() {
if (selected != null) { return DateTime.parse(selected!); }
return DateTime.now();
}
@override Widget build(BuildContext context) {
bool isInfo = MediaQuery.of(context).size.width <= 600 && selected != null;
double w = selected != null ? MediaQuery.of(context).size.width - 300 : MediaQuery.of(context).size.width;
List<Widget> children = [];
if (selected != null) {
for (var wf in widget.data[selected!] ?? (<WorkflowExecution>[])) {
DateTime d2 = DateTime.parse(wf.executionData!);
children.add( InkWell(
onTap: () => setState(() { selectedReal = wf.executionData; }),
child: Container( margin: const EdgeInsets.all(10),
decoration: BoxDecoration(
border: Border.all(color: selectedReal != null && selectedReal == wf.executionData ? const Color.fromRGBO(38, 166, 154, 1) : Colors.transparent, width: 2),
borderRadius: BorderRadius.circular(4), color: Colors.white
),
child: Container(
padding: const EdgeInsets.symmetric(vertical: 10, horizontal: 20),
child: Row(children: [
Container( width: 10, height: 10,
decoration: BoxDecoration(
color: colors[(wf.status ?? 1) - 1],
borderRadius: BorderRadius.circular(4),
),
),
Container( width: (400 - 250),
child: Padding(
padding: const EdgeInsets.only(left: 20),
child: Text(wf.name?.toUpperCase() ?? "", overflow: TextOverflow.ellipsis,
style: const TextStyle(color: Colors.black, fontSize: 12, fontWeight: FontWeight.w500)),
)),
Container(
child: Padding(
padding: const EdgeInsets.only(left: 20),
child: Text("${d2.hour > 9 ? d2.hour : "0${d2.hour}"}:${d2.minute > 9 ? d2.minute : "0${d2.minute}"}", overflow: TextOverflow.ellipsis,
style: const TextStyle(fontSize: 15,
color: Colors.grey, fontWeight: FontWeight.w500))))
])
))
));
}
}
String? selectedID;
String? start;
String? end;
if (selectedReal != null) {
try {
var sel = widget.data[selected!]!.firstWhere((element) => element.executionData == selectedReal);
selectedID = sel.id;
print(sel.endDate);
if (sel.endDate != null && sel.endDate != "") {
var startD = DateTime.parse(sel.executionData!);
var endD = DateTime.parse(sel.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(sel.executionData!).subtract( const Duration(days: 14)).microsecondsSinceEpoch).toString();
end = (DateTime.parse(sel.executionData!).add( const Duration(days: 14)).microsecondsSinceEpoch).toString();
}
} catch(e) { /* */ }
}
return Row( children: [
isInfo ? Container() : SizedBox( width: w,
child: widget.isList ? SchedulerItemWidget(data: widget.data, parent: this, focusedDay: getFocusedDay(), width: w)
: SchedulerCalendarWidget(data: widget.data, start: widget.start,
end: widget.end, parent: this, focusedDay: getFocusedDay(),)
),
Container(
height: MediaQuery.of(context).size.height - HeaderConstants.height - 50,
width: isInfo ? MediaQuery.of(context).size.width : (selected != null ? 300 : 0),
color: Colors.grey.shade300,
child: Column(
children: [
Row( children: [
InkWell( onTap: () => setState(() { widget.isDayPlanner = true; }),
child: Tooltip( message: "day planning", child:
Container( height: 50, width: (isInfo ? MediaQuery.of(context).size.width : (selected != null ? 300 : 0)) / (selectedReal != null ? 2 : 1 ),
alignment: Alignment.center,
decoration: BoxDecoration(
color: widget.isDayPlanner ? Colors.grey : Colors.transparent,
border: Border(bottom: BorderSide(color: Colors.grey.shade400), right: BorderSide(color: Colors.grey.shade400))),
child: Icon(Icons.calendar_today_outlined, color: widget.isDayPlanner ? Colors.white : Colors.grey),
)
)),
InkWell( onTap: () => setState(() { widget.isDayPlanner = false; }),
child: Tooltip( message: "monitor task", child:
Container( height: 50, width: selectedReal == null ? 0 : ((isInfo ? MediaQuery.of(context).size.width : (selected != null ? 300 : 0)) / 2),
alignment: Alignment.center,
decoration: BoxDecoration(
color: !widget.isDayPlanner ? Colors.grey : Colors.transparent,
border: Border(bottom: BorderSide(color: Colors.grey.shade400))
),
child: Icon(Icons.monitor_heart_outlined, size: 25,
color: !widget.isDayPlanner ? Colors.white : Colors.grey),
)
))
]),
Container( width: isInfo ? MediaQuery.of(context).size.width : (selected != null ? 300 : 0), height: MediaQuery.of(context).size.height - HeaderConstants.height - 100,
child: SingleChildScrollView( child: Column(
mainAxisAlignment: children.isEmpty ? MainAxisAlignment.center : MainAxisAlignment.start,
children: [
...( widget.isDayPlanner ? children : ( selectedID != null ? [
FutureBuilder(future: _service.search(context, [], {
"workflow_execution_id": selectedID,
"start": start,
"end": end
}), builder: (ctx, as) {
var speLog = Log(level: "error", timestamp: DateTime.now());
speLog.getMessage("{\"Name\":\"oc-monitor-unonip-fauta9hswg\",\"Namespace\":\"argo\",\"Status\":\"Pending\",\"PodRunning\":false,\"Completed\":false,\"Created\":\"Tue Aug 06 11:33:52 +0200 (now)\",\"Started\":\"\",\"Duration\":\"\",\"Progress\":\"\"}");
var speLog2 = Log(level: "warning", timestamp: DateTime.now());
speLog2.getMessage("{\"Name\":\"oc-monitor-unonip-fauta9hswg\",\"Namespace\":\"argo\",\"Status\":\"Running\",\"PodRunning\":false,\"Completed\":false,\"Created\":\"Tue Aug 06 11:33:52 +0200 (now)\",\"Started\":\"Tue Aug 06 11:33:52 +0200 (now)\",\"Duration\":\"0 seconds\",\"Progress\":\"0/1\"}");
List<Log> logs = [
Log(
level: "info",
message: "No logs found",
timestamp: DateTime.now()
),
speLog,
speLog2
];
if (as.hasData && as.data!.data != null) {
var d = as.data!.data!;
for( var r in d.data?.result ?? <Logs> []) {
for (var element in r.logs) {
element.level = r.level;
logs.add(element);
}
}
}
logs.sort((a, b) => a.timestamp!.compareTo(b.timestamp!));
return LogsWidget(items: logs);
})
] : [])),
children.isEmpty ? Container( height: 100, alignment: Alignment.center, child: const Text("No event found", style: const TextStyle(color: Colors.grey, fontSize: 20))) : Container()
]))
)
],
),
)
]);
}
}

View File

@@ -0,0 +1,175 @@
import 'package:flutter/material.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';
import 'package:table_calendar/table_calendar.dart';
// ignore: must_be_immutable
class SchedulerCalendarWidget extends StatefulWidget {
Map<String, List<WorkflowExecution>> data;
DateTime start;
DateTime end;
DateTime focusedDay;
CalendarFormat format = CalendarFormat.month;
bool enabled = true;
ScheduleWidgetState? parent;
SchedulerCalendarWidget ({ super.key,
required this.data,
required this.start,
required this.end,
required this.parent,
required this.focusedDay,
this.enabled = true});
@override SchedulerCalendarWidgetState createState() => SchedulerCalendarWidgetState();
}
class SchedulerCalendarWidgetState extends State<SchedulerCalendarWidget> {
List<Color> colors = [Colors.blue, Colors.orange, Colors.red, Colors.green];
List<String> titles = ["SCHEDULED", "RUNNING", "FAILURE", "SUCCESS"];
bool isEvent(Map<String, List<WorkflowExecution>> data, DateTime day) {
if (data[day.toIso8601String()] == null || data[day.toIso8601String()]!.isEmpty) { return false; }
return true;
}
@override Widget build(BuildContext context) {
widget.focusedDay = widget.focusedDay.isBefore(widget.start) ? widget.start : (
widget.focusedDay.isAfter(widget.end) ? widget.end : widget.focusedDay );
return Container(
padding: const EdgeInsets.only(left: 20, right: 20, bottom: 20),
height: MediaQuery.of(context).size.height - HeaderConstants.height - 50,
child: TableCalendar<Event>(
firstDay: widget.start,
lastDay: widget.end,
focusedDay: widget.focusedDay,
calendarStyle: const CalendarStyle(
markersMaxCount: 3,
markersAnchor: 0,
markersAlignment: Alignment.topCenter
),
selectedDayPredicate: (day) => day == widget.focusedDay,
calendarFormat: widget.format,
calendarBuilders: CalendarBuilders(
markerBuilder: (context, day, events) {
List<Widget> children = [];
for (var ev in events) {
if (children.length == 2 && events.length > 3) {
children.add( InkWell( onTap: () => widget.parent!.setState(() {
widget.parent!.selected = day.toIso8601String();
widget.parent!.selectedReal = null;
widget.parent!.widget.isDayPlanner = true;
}),
child: Container(
padding: const EdgeInsets.symmetric(horizontal: 10.0, vertical: 2),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(4),
color: Colors.grey.shade300,
),
child: const Text("...", style: TextStyle(color: Colors.white, fontSize: 10)),
)));
break;
}
children.add(InkWell( onTap: () => widget.parent!.setState(() {
widget.parent!.selected = day.toIso8601String();
widget.parent!.selectedReal = ev.executionData;
if (widget.parent!.selectedReal == null) {
widget.parent!.widget.isDayPlanner = true;
}
}),
child: Container(
padding: const EdgeInsets.symmetric(horizontal: 10.0, vertical: 2),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(4),
color: ev.color,
),
child: Text(ev.title.length < 30 ? ev.title : "${ev.title.substring(0, 28)}...", style: const TextStyle(color: Colors.white, fontSize: 10)),
)));
}
return Column(mainAxisAlignment: MainAxisAlignment.center, children: children);
},
defaultBuilder: (context, date, events) => Container(
alignment: Alignment.center,
margin:const EdgeInsets.all(2.0),
decoration: BoxDecoration(
border: Border.all(color: Colors.grey.shade300),
shape: BoxShape.rectangle,
),
child: !isEvent(widget.data, date) ? Text(
date.day.toString(),
style: const TextStyle(color: Colors.grey),
) : Column( children: [ Container( padding: const EdgeInsets.symmetric(vertical: 5), child: Text(
date.day.toString(),
style: const TextStyle(color: Colors.grey),
)) ])
),
outsideBuilder: (context, day, focusedDay) => Container(
alignment: Alignment.center,
margin: const EdgeInsets.all(2.0),
decoration: BoxDecoration(
border: Border.all(color: Colors.grey.shade300),
color: Colors.grey.shade300,
shape: BoxShape.rectangle,
),
child: Text(
day.day.toString(),
style: const TextStyle(color: Colors.black),
),
),
selectedBuilder: (context, date, events) => Container(
alignment: Alignment.center,
margin: const EdgeInsets.all(2.0),
decoration: BoxDecoration(
border: Border.all(color: const Color.fromRGBO(38, 166, 154, 1), width: 2),
shape: BoxShape.rectangle,
),
child: !isEvent(widget.data, date) ? Text(
date.day.toString(),
style: const TextStyle(color: Colors.grey),
) : Column( children: [ Container( padding: const EdgeInsets.symmetric(vertical: 5), child: Text(
date.day.toString(),
style: const TextStyle(color: Colors.grey),
)) ]),
),
todayBuilder: (context, date, events) => Container(
margin: const EdgeInsets.all(2.0),
alignment: Alignment.center,
decoration: BoxDecoration(
color: const Color.fromRGBO(38, 166, 154, .5),
shape: BoxShape.rectangle,
border: Border.all(color: Colors.grey),
),
child: Text(
date.day.toString(),
style: const TextStyle(color: Colors.white),
),
),
),
onFormatChanged: (format) => setState(() {
widget.format = format;
}),
onDaySelected: (selectedDay, focusedDay) {
widget.parent!.setState(() {
widget.parent!.selected = selectedDay.toIso8601String();
widget.parent!.selectedReal = null;
widget.parent!.widget.isDayPlanner = true;
});
},
shouldFillViewport: true,
eventLoader: (day) {
return widget.data[day.toIso8601String()] != null ? widget.data[day.toIso8601String()]!.map((e) {
DateTime dateTime = DateTime.parse(e.executionData!);
return Event("[${dateTime.hour > 9 ? dateTime.hour : "0${dateTime.hour}"}:${dateTime.minute > 9 ? dateTime.minute : "0${dateTime.minute}"}] ${e.name}",
colors[(e.status ?? 1) - 1], e.executionData );
}).toList() : [];
},
));
}
}
class Event {
final String title;
String? executionData;
Color color;
Event(this.title, this.color, this.executionData);
@override
String toString() => title;
}

View File

@@ -0,0 +1,115 @@
import 'package:flutter/material.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';
// ignore: must_be_immutable
class SchedulerItemWidget extends StatefulWidget {
Map<String, List<WorkflowExecution>> data;
bool enabled = true;
DateTime focusedDay;
double width = 0;
ScheduleWidgetState? parent;
Map<String, GlobalKey> keys = {};
SchedulerItemWidget ({ super.key, required this.data, required this.focusedDay,
this.enabled = true, required this.parent, this.width = 0});
@override SchedulerItemWidgetState createState() => SchedulerItemWidgetState();
}
class SchedulerItemWidgetState extends State<SchedulerItemWidget> {
List<Color> colors = [Colors.blue, Colors.orange, Colors.red, Colors.green];
List<String> titles = ["SCHEDULED", "RUNNING", "FAILURE", "SUCCESS"];
@override Widget build(BuildContext context) {
List<Widget> children = [];
for (var element in widget.data.keys.toList()..sort((a, b) => DateTime.parse(a).compareTo(DateTime.parse(b)))) {
List<Widget> widgets = [];
for (var ev in widget.data[element] ?? ([] as List<WorkflowExecution>)) {
widget.keys[ev.executionData!] = GlobalKey();
var d2 = DateTime.parse(ev.executionData!);
DateTime? d3;
try {
d3 = DateTime.parse(ev.endDate!);
} catch (e) { /* */ }
widgets.add(InkWell(
onTap: () => widget.parent?.setState(() {
widget.parent?.selected = widget.parent?.selected != element ? element : null;
widget.parent?.selectedReal = widget.parent?.selected == null ? null : ev.executionData;
if (widget.parent!.selectedReal == null) {
widget.parent!.widget.isDayPlanner = true;
}
}),
child: Container( key: widget.keys[ev.executionData!],
padding: const EdgeInsets.symmetric(vertical: 20, horizontal: 50),
decoration: BoxDecoration(
border: widget.parent?.selected == element ? Border.all(color: const Color.fromRGBO(38, 166, 154, 1), width: 2)
: Border(top: BorderSide(color: Colors.grey.shade300)),
),
child: Row(children: [
Container( width: 110,
decoration: BoxDecoration(
color: colors[(ev.status ?? 1) - 1],
borderRadius: BorderRadius.circular(4),
),
padding: const EdgeInsets.symmetric(horizontal: 10.0, vertical: 5),
child: Text(titles[(ev.status ?? 1) - 1],
overflow: TextOverflow.ellipsis, textAlign: TextAlign.center,
style: const TextStyle( color: Colors.white))
),
SizedBox( width: (widget.width - 312) / 2,
child: Padding(
padding: const EdgeInsets.only(left: 20),
child: Text(ev.name?.toUpperCase() ?? "", overflow: TextOverflow.ellipsis,
style: const TextStyle(color: Colors.black, fontWeight: FontWeight.w500)),
)),
SizedBox( width: (widget.width - 312) / 2,
child: Padding(
padding: const EdgeInsets.only(left: 20),
child: Container( padding: const EdgeInsets.symmetric(horizontal: 20),
child: Text(d3 != null ? "killed at ${d3.day}/${d3.month}/${d3.year} ${d3.hour}:${d3.minute}"
: "infinite run till process end", overflow: TextOverflow.ellipsis,
style: const TextStyle( fontSize: 12, color: Colors.grey, fontWeight: FontWeight.w500))),
)),
SizedBox(
child: Padding(
padding: const EdgeInsets.only(left: 20),
child: Text("${d2.hour > 9 ? d2.hour : "0${d2.hour}"}:${d2.minute > 9 ? d2.minute : "0${d2.minute}"}", overflow: TextOverflow.ellipsis,
style: const TextStyle(fontSize: 25,
color: Colors.grey, fontWeight: FontWeight.w500))))
])
)));
}
var date = DateTime.parse(element);
children.add(Column( children: [Container(
child: ExpansionTile(
enabled: widget.enabled,
shape: ContinuousRectangleBorder(),
iconColor: Colors.grey,
initiallyExpanded: true,
title: SizedBox(
child : Row( children: [
const Padding(padding: EdgeInsets.only(right: 10),
child: Icon(Icons.view_day, color: Colors.grey)),
Flexible(
child: Padding(
padding: const EdgeInsets.only(right: 5),
child: Text("${date.day > 9 ? date.day : "0${date.day}"}-${date.hour > 9 ? date.hour : "0${date.hour}"}-${date.year}".toUpperCase(), overflow: TextOverflow.ellipsis,
style: const TextStyle(color: Colors.black, fontWeight: FontWeight.w500))))
])
),
collapsedIconColor: Colors.grey,
children: widgets,
)),
Divider(color: Colors.grey.shade300, height: 1)
]));
}
Future.delayed( const Duration(milliseconds: 100), () {
if (widget.parent?.selectedReal != null) {
widget.keys[widget.parent!.selectedReal!]?.currentContext?.findRenderObject()?.showOnScreen();
}
});
return SingleChildScrollView( child: Container(
height: MediaQuery.of(context).size.height - HeaderConstants.height - 50,
child: Column( children: children))
);
}
}