2024-08-08 08:42:32 +02:00
|
|
|
import 'package:alert_banner/exports.dart';
|
|
|
|
import 'package:flutter/material.dart';
|
|
|
|
import 'package:flutter/services.dart';
|
2024-08-22 15:46:16 +02:00
|
|
|
import 'package:json_string/json_string.dart';
|
2024-11-19 16:41:47 +01:00
|
|
|
import 'package:oc_front/core/services/specialized_services/logs_service.dart';
|
2024-11-08 13:59:22 +01:00
|
|
|
import 'package:oc_front/main.dart';
|
2024-08-08 08:42:32 +02:00
|
|
|
import 'package:oc_front/models/logs.dart';
|
2024-11-19 16:41:47 +01:00
|
|
|
import 'package:oc_front/models/workflow.dart';
|
2024-08-08 08:42:32 +02:00
|
|
|
import 'package:oc_front/widgets/dialog/alert.dart';
|
|
|
|
|
|
|
|
class LogsWidget extends StatefulWidget {
|
2024-08-22 15:46:16 +02:00
|
|
|
String? level;
|
|
|
|
String search = "";
|
2024-11-19 16:41:47 +01:00
|
|
|
|
|
|
|
WorkflowExecution? exec;
|
|
|
|
LogsWidget ({ Key? key, this.search = "", this.level, this.exec }): super(key: key);
|
2024-08-08 08:42:32 +02:00
|
|
|
@override LogsWidgetState createState() => LogsWidgetState();
|
|
|
|
}
|
2024-11-19 16:41:47 +01:00
|
|
|
|
2024-08-08 08:42:32 +02:00
|
|
|
class LogsWidgetState extends State<LogsWidget> {
|
|
|
|
@override Widget build(BuildContext context) {
|
2024-11-19 16:41:47 +01:00
|
|
|
if (widget.exec == null) {
|
|
|
|
return Container();
|
|
|
|
} else {
|
|
|
|
String start = "";
|
|
|
|
String end = "";
|
|
|
|
try {
|
|
|
|
if (widget.exec!.endDate != null && widget.exec!.endDate != "") {
|
|
|
|
var startD = DateTime.parse(widget.exec!.executionData!);
|
|
|
|
var endD = DateTime.parse(widget.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(widget.exec!.executionData!).subtract( const Duration(days: 14)).microsecondsSinceEpoch).toString();
|
|
|
|
end = (DateTime.parse(widget.exec!.executionData!).add( const Duration(days: 14)).microsecondsSinceEpoch).toString();
|
|
|
|
}
|
|
|
|
} catch(e) { /* */ }
|
|
|
|
return FutureBuilder(future: LogsService().search(context, [], {
|
|
|
|
"workflow_execution_id": widget.exec!.id,
|
|
|
|
"start": start,
|
|
|
|
"end": end
|
|
|
|
}), builder: (a, b) {
|
|
|
|
Future.delayed(const Duration(minutes: 1), () {
|
|
|
|
setState(() {});
|
|
|
|
});
|
|
|
|
List<Log> logs = [];
|
|
|
|
if (b.data != null && b.data!.data != null) {
|
|
|
|
var d = b.data!.data!;
|
|
|
|
for( var r in d.result) {
|
|
|
|
for (var element in r.logs) {
|
|
|
|
element.level = r.level;
|
|
|
|
logs.add(element);
|
|
|
|
}
|
|
|
|
logs.sort((a, b) => a.timestamp!.compareTo(b.timestamp!));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
List<LogWidget> itemRows = logs.where((element) => (element.message?.toLowerCase().contains(widget.search.toLowerCase()) ?? true)
|
|
|
|
&& (widget.level?.contains(element.level ?? "") ?? true) ).map((e) => LogWidget(item: e)).toList();
|
|
|
|
return Stack( children: [
|
|
|
|
SingleChildScrollView( child: itemRows.isEmpty ?
|
|
|
|
Container( height: getMainHeight(context) - 100,
|
|
|
|
child: const Center( child: Text("no log registered", style: TextStyle(color: Colors.grey, fontSize: 25 ),)))
|
|
|
|
: Column( children: [...itemRows, Container(height: 50,) ] ) ),
|
|
|
|
]);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2024-08-08 08:42:32 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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) {
|
2024-08-22 15:46:16 +02:00
|
|
|
Map<String, dynamic> map = {};
|
|
|
|
try { map = JsonString(widget.item.rawMessage?.replaceAll("\\", "") ?? "").decodedValue as Map<String, dynamic>;
|
|
|
|
} catch (e) { /* */}
|
|
|
|
return Container(
|
|
|
|
decoration: const BoxDecoration(
|
|
|
|
border: Border(bottom: BorderSide(color: Colors.white)),
|
|
|
|
),
|
|
|
|
padding: const EdgeInsets.only(top: 10, left: 30, right: 30, bottom: 10),
|
|
|
|
child: Wrap( children: [
|
2024-08-08 08:42:32 +02:00
|
|
|
Row( mainAxisAlignment: MainAxisAlignment.start,
|
|
|
|
crossAxisAlignment: CrossAxisAlignment.center,
|
|
|
|
children: [
|
|
|
|
Container( width: 10, height: 15, color: widget.item.level?.toLowerCase() == "info" ? Colors.green :
|
2024-11-08 13:59:22 +01:00
|
|
|
( widget.item.level?.toLowerCase() == "error" ? redColor : (
|
2024-08-08 08:42:32 +02:00
|
|
|
widget.item.level?.toLowerCase() == "warning" ? Colors.orange : Colors.blue))),
|
2024-08-22 15:46:16 +02:00
|
|
|
InkWell( mouseCursor: map.isEmpty ? MouseCursor.defer : SystemMouseCursors.click, onTap: () {
|
|
|
|
if (map.isNotEmpty ) {
|
2024-08-08 08:42:32 +02:00
|
|
|
setState(() {
|
|
|
|
widget.expanded = !widget.expanded;
|
|
|
|
});
|
|
|
|
}
|
2024-08-22 15:46:16 +02:00
|
|
|
}, child: SizedBox( height: 20,
|
2024-08-08 08:42:32 +02:00
|
|
|
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,
|
2024-08-22 15:46:16 +02:00
|
|
|
color: map.isEmpty ? Colors.grey : Colors.black, weight: widget.expanded ? 100 : 1000,)))),
|
2024-08-08 08:42:32 +02:00
|
|
|
Padding( padding: const EdgeInsets.only(right: 10),
|
2024-08-30 12:52:32 +02:00
|
|
|
child: Text("${widget.item.timestamp?.toLocal().toString().substring(3)}",
|
2024-08-08 08:42:32 +02:00
|
|
|
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),
|
2024-08-22 15:46:16 +02:00
|
|
|
child: Column( children: map.keys.map((e) =>
|
2024-08-08 08:42:32 +02:00
|
|
|
Padding( padding: const EdgeInsets.all(2), child: Row( mainAxisAlignment: MainAxisAlignment.start,
|
|
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
2024-08-22 15:46:16 +02:00
|
|
|
children: [Flexible( child:Text("$e: \"${map[e]}\"",
|
2024-08-08 08:42:32 +02:00
|
|
|
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))), ])
|
|
|
|
]));
|
|
|
|
}
|
|
|
|
}
|