This commit is contained in:
mr 2025-02-17 09:35:56 +01:00
parent 313ef43e9c
commit 3d6b4bf3b3
7 changed files with 137 additions and 14 deletions

View File

@ -8,11 +8,7 @@ class WorkflowExecutionService extends AbstractService<WorkflowExecutions> {
@override APIService<WorkflowExecutions> service = APIService<WorkflowExecutions>( @override APIService<WorkflowExecutions> service = APIService<WorkflowExecutions>(
baseURL: const String.fromEnvironment('SCHEDULER_HOST', defaultValue: 'http://localhost:8080/scheduler') baseURL: const String.fromEnvironment('SCHEDULER_HOST', defaultValue: 'http://localhost:8080/scheduler')
); );
@override String subPath = "/"; @override String subPath = "/execution/";
Future<APIResponse<WorkflowExecutions>> schedule(BuildContext? context, String id, Map<String, dynamic> body, Map<String, dynamic> params) {
return service.post("${subPath}workflow/$id", body, context);
}
@override Future<APIResponse<WorkflowExecutions>> search(BuildContext? context, List<String> words, Map<String, dynamic> params) { @override Future<APIResponse<WorkflowExecutions>> search(BuildContext? context, List<String> words, Map<String, dynamic> params) {
return service.get("${subPath}search/${words.join("/")}", false, context); return service.get("${subPath}search/${words.join("/")}", false, context);

View File

@ -0,0 +1,28 @@
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 SchedulerService extends AbstractService<WorkflowExecution> {
@override APIService<WorkflowExecution> service = APIService<WorkflowExecution>(
baseURL: const String.fromEnvironment('SCHEDULER_HOST', defaultValue: 'http://localhost:8080/scheduler')
);
@override String subPath = "/";
Future<APIResponse<WorkflowExecution>> schedule(BuildContext? context, String id, Map<String, dynamic> body, Map<String, dynamic> params) {
print("$subPath$id");
return service.post("$subPath$id", body, context);
}
@override Future<APIResponse<WorkflowExecution>> search(BuildContext? context, List<String> words, Map<String, dynamic> params) {
return throw UnimplementedError();
}
@override Future<APIResponse<WorkflowExecution>> post(BuildContext? context, Map<String, dynamic> body, Map<String, String> params) {
return throw UnimplementedError();
}
@override Future<APIResponse<WorkflowExecution>> put(BuildContext? context, String id, Map<String, dynamic> body, Map<String, String> params) {
return throw UnimplementedError();
}
}

View File

@ -147,6 +147,34 @@ class Param extends SerializerDeserializer<Param> {
} }
} }
class Credential extends SerializerDeserializer<Credential> {
String? login;
String? password;
Credential({
this.login,
this.password,
});
@override
Credential deserialize(json) {
try { json = json as Map<String, dynamic>;
} catch (e) { return Credential(); }
return Credential(
login: json.containsKey("login") ? json["login"] : null,
password: json.containsKey("password") ? json["password"] : null,
);
}
@override
Map<String, dynamic> serialize() {
return {
"login": login,
"password": password,
};
}
}
abstract class AbstractItem<X extends AbstractPricing, Y extends AbstractPartnerShip<X>, S extends AbstractInstance<X,Y>, T extends FlowData> extends FlowData implements SerializerDeserializer<T>, Infos { abstract class AbstractItem<X extends AbstractPricing, Y extends AbstractPartnerShip<X>, S extends AbstractInstance<X,Y>, T extends FlowData> extends FlowData implements SerializerDeserializer<T>, Infos {
String? id; String? id;
String? name; String? name;
@ -303,6 +331,8 @@ abstract class AbstractInstance<X extends AbstractPricing, S extends AbstractPar
List<Param> env = []; List<Param> env = [];
List<Param> inputs = []; List<Param> inputs = [];
List<Param> outputs = []; List<Param> outputs = [];
Credential? credential;
bool isEnv(String key) { bool isEnv(String key) {
for (var e in env) { for (var e in env) {
@ -331,6 +361,7 @@ abstract class AbstractInstance<X extends AbstractPricing, S extends AbstractPar
this.inputs = json.containsKey("inputs") ? fromListJson(json["inputs"], Param()) : []; this.inputs = json.containsKey("inputs") ? fromListJson(json["inputs"], Param()) : [];
this.outputs = json.containsKey("outputs") ? fromListJson(json["outputs"], Param()) : []; this.outputs = json.containsKey("outputs") ? fromListJson(json["outputs"], Param()) : [];
this.location = json.containsKey("location") ? Location().deserialize(json["location"]) : null; this.location = json.containsKey("location") ? Location().deserialize(json["location"]) : null;
this.credential = json.containsKey("credential") ? Credential().deserialize(json["credential"]) : null;
this.partnerships = json.containsKey("partnerships") ? fromListJson(json["partnerships"], ex) : []; this.partnerships = json.containsKey("partnerships") ? fromListJson(json["partnerships"], ex) : [];
} }
@ -343,6 +374,7 @@ abstract class AbstractInstance<X extends AbstractPricing, S extends AbstractPar
"env": toListJson(env), "env": toListJson(env),
"inputs": toListJson(inputs), "inputs": toListJson(inputs),
"outputs": toListJson(outputs), "outputs": toListJson(outputs),
"credential": credential?.serialize(), // TODO CREDENTIAL FORM
"partnerships": partnerships.map((e) => e.serialize()).toList(), "partnerships": partnerships.map((e) => e.serialize()).toList(),
}; };
} }

View File

@ -0,0 +1,58 @@
import 'package:flutter/material.dart';
import 'package:flutter_flow_chart/flutter_flow_chart.dart';
import 'package:oc_front/models/resources/resources.dart';
import 'package:oc_front/widgets/inputs/sub_text_input.dart';
// ignore: must_be_immutable
class CredentialsFormsWidget extends StatefulWidget {
int instanceID = 0;
Dashboard dash;
AbstractItem item;
String elementID;
CredentialsFormsWidget({ super.key, required this.item, required this.dash, required this.elementID });
@override CredentialsFormsWidgetState createState() => CredentialsFormsWidgetState();
}
class CredentialsFormsWidgetState extends State<CredentialsFormsWidget> {
@override Widget build(BuildContext context) {
List<Widget> widgets = [];
var instance = widget.item.getSelectedInstance();
if (instance != null && instance.credential != null) {
var creds = instance.credential!;
widgets.add(Container( margin: EdgeInsets.only(bottom: 15),
width: 200, decoration: BoxDecoration( border: Border(bottom: BorderSide(color: Colors.grey))),
));
widgets.add(Container(
padding: const EdgeInsets.only(bottom: 10),
width: 180,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text("<CREDENTIALS>", style: const TextStyle(fontSize: 13, fontWeight: FontWeight.bold), textAlign: TextAlign.center),
SubTextInputWidget(subkey: "login", width: 180, empty: false, change: (value) {
creds.password = value;
for (var el in widget.dash.elements) {
if (el.id == widget.elementID) {
el.element = widget.item;
break;
}
}
widget.dash.saveDash(widget.dash.id, context);
}, initialValue: creds.login),
SubTextInputWidget(subkey: "password", width: 180, empty: false, change: (value) {
creds.password = value;
for (var el in widget.dash.elements) {
if (el.id == widget.elementID) {
el.element = widget.item;
break;
}
}
widget.dash.saveDash(widget.dash.id, context);
}, initialValue: creds.password, readOnly: false,),
],)
));
widgets.add(Container( padding: EdgeInsets.only(bottom: 15), width: 200 ));
}
return Column(children: widgets);
}
}

View File

@ -3,6 +3,7 @@ import 'package:flutter/material.dart';
import 'package:oc_front/models/workflow.dart'; import 'package:oc_front/models/workflow.dart';
import 'package:oc_front/models/resources/resources.dart'; import 'package:oc_front/models/resources/resources.dart';
import 'package:oc_front/core/services/perms_service.dart'; import 'package:oc_front/core/services/perms_service.dart';
import 'package:oc_front/widgets/forms/credentials_forms.dart';
import 'package:oc_front/widgets/forms/sub_keys_forms.dart'; import 'package:oc_front/widgets/forms/sub_keys_forms.dart';
import 'package:flutter_flow_chart/flutter_flow_chart.dart'; import 'package:flutter_flow_chart/flutter_flow_chart.dart';
import 'package:oc_front/widgets/inputs/sub_text_input.dart'; import 'package:oc_front/widgets/inputs/sub_text_input.dart';
@ -77,6 +78,7 @@ class ResourceFormsWidgetState extends State<ResourceFormsWidget> {
} }
} }
instancesCat.add(ContainerFormsWidget(dash: widget.dash, item: widget.item, elementID: widget.elementID)); instancesCat.add(ContainerFormsWidget(dash: widget.dash, item: widget.item, elementID: widget.elementID));
instancesCat.add(CredentialsFormsWidget(dash: widget.dash, item: widget.item, elementID: widget.elementID));
if (instancesCat.isNotEmpty) { if (instancesCat.isNotEmpty) {
instancesCat.add(Container( instancesCat.add(Container(
width: 200, decoration: BoxDecoration( border: Border(bottom: BorderSide(color: Colors.grey))), width: 200, decoration: BoxDecoration( border: Border(bottom: BorderSide(color: Colors.grey))),

View File

@ -1,6 +1,7 @@
import 'package:cron/cron.dart'; import 'package:cron/cron.dart';
import 'package:oc_front/core/services/specialized_services/workflow_execution_service.dart'; import 'package:oc_front/core/services/specialized_services/workflow_execution_service.dart';
import 'package:oc_front/core/services/specialized_services/workflow_scheduler_service.dart';
import 'package:oc_front/main.dart'; import 'package:oc_front/main.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:intl/intl.dart' as intl; import 'package:intl/intl.dart' as intl;
@ -33,13 +34,15 @@ class SchedulerFormsWidget extends StatefulWidget {
String? errorEndDate; String? errorEndDate;
String? errorCron; String? errorCron;
Function validate = () {}; Function validate = () {};
final WorkflowExecutionService _service = WorkflowExecutionService(); final SchedulerService _schedulerService = SchedulerService();
final WorkflowExecutionService _executionService = WorkflowExecutionService();
SchedulerFormsWidget ({ super.key, required this.item, }); SchedulerFormsWidget ({ super.key, required this.item, });
@override SchedulerFormsWidgetState createState() => SchedulerFormsWidgetState(); @override SchedulerFormsWidgetState createState() => SchedulerFormsWidgetState();
} }
class SchedulerFormsWidgetState extends State<SchedulerFormsWidget> { class SchedulerFormsWidgetState extends State<SchedulerFormsWidget> {
CheckService check = CheckService(); CheckService check = CheckService();
void save(List<GlobalKey<FormFieldState>> formKeys) { void save(List<GlobalKey<FormFieldState>> formKeys) {
print("save");
widget.error = null; widget.error = null;
widget.errorEndDate = null; widget.errorEndDate = null;
widget.errorCron = null; widget.errorCron = null;
@ -81,7 +84,7 @@ class SchedulerFormsWidgetState extends State<SchedulerFormsWidget> {
} }
} }
Duration durationBefore = widget.schedule.start!.difference(DateTime.now().toUtc()) + Duration(seconds: 5); Duration durationBefore = widget.schedule.start!.difference(DateTime.now().toUtc()) + Duration(seconds: 5);
widget._service.schedule(context, widget.item.id ?? "", widget.schedule.serialize(), {}).then((value) { widget._schedulerService.schedule(context, widget.item.id ?? "", widget.schedule.serialize(), {}).then((value) {
setState(() { widget.valid = true; }); setState(() { widget.valid = true; });
Future.delayed(durationBefore, () { Future.delayed(durationBefore, () {
try { try {
@ -131,7 +134,7 @@ class SchedulerFormsWidgetState extends State<SchedulerFormsWidget> {
@override Widget build(BuildContext context) { @override Widget build(BuildContext context) {
if (widget.shouldSearch && widget.item.name != "") { if (widget.shouldSearch && widget.item.name != "") {
widget.shouldSearch = false; widget.shouldSearch = false;
widget._service.search(null, [widget.item.name], {}).then((value) { widget._executionService.search(null, [widget.item.name], {}).then((value) {
if (value.data != null) { if (value.data != null) {
try { try {
setState(() { setState(() {
@ -480,13 +483,14 @@ class SchedulerFormsWidgetState extends State<SchedulerFormsWidget> {
Container( Container(
width: 200, width: 200,
height: 20, height: 20,
decoration: const BoxDecoration(border: Border(bottom: BorderSide(color: Colors.grey, width: 1))), decoration: BoxDecoration(border: Border(bottom: BorderSide(color:
PermsService.getPerm(Perms.WORKFLOW_BOOKING)? Colors.grey : Colors.transparent, width: 1))),
), ),
const SizedBox( const SizedBox(
width: 200, width: 200,
height: 10, height: 10,
), ),
Tooltip( message: "check booking", child: InkWell( mouseCursor: SystemMouseCursors.click, PermsService.getPerm(Perms.WORKFLOW_BOOKING)? Tooltip( message: "check booking", child: InkWell( mouseCursor: SystemMouseCursors.click,
onTap: () { PermsService.getPerm(Perms.WORKFLOW_BOOKING) ? checkBooking(formKeys, null) : null; onTap: () { PermsService.getPerm(Perms.WORKFLOW_BOOKING) ? checkBooking(formKeys, null) : null;
}, child: Container( margin: const EdgeInsets.only(bottom: 5, left: 10, right: 10), }, child: Container( margin: const EdgeInsets.only(bottom: 5, left: 10, right: 10),
decoration: BoxDecoration(borderRadius: BorderRadius.circular(5), decoration: BoxDecoration(borderRadius: BorderRadius.circular(5),
@ -497,17 +501,17 @@ class SchedulerFormsWidgetState extends State<SchedulerFormsWidget> {
child: Icon( Icons.verified_outlined, child: Icon( Icons.verified_outlined,
color: widget.booking == null ? Colors.black : (widget.booking == true ? Colors.green : redColor)), color: widget.booking == null ? Colors.black : (widget.booking == true ? Colors.green : redColor)),
)) ))
), ): Container(),
Tooltip( message: "book", child: InkWell( mouseCursor: SystemMouseCursors.click, PermsService.getPerm(Perms.WORKFLOW_BOOKING) ? Tooltip( message: "book", child: InkWell( mouseCursor: SystemMouseCursors.click,
onTap: () { onTap: () {
PermsService.getPerm(Perms.WORKFLOW_BOOKING) && PermsService.getPerm(Perms.WORKFLOW_EDIT) ? setState(() { save(formKeys); }) : null; setState(() { save(formKeys); });
}, child: Container( margin: const EdgeInsets.only(top: 5, bottom: 10, left: 10, right: 10), }, child: Container( margin: const EdgeInsets.only(top: 5, bottom: 10, left: 10, right: 10),
decoration: BoxDecoration(borderRadius: BorderRadius.circular(5), decoration: BoxDecoration(borderRadius: BorderRadius.circular(5),
border: Border.all(color: dash.error != null ? Colors.red : ( PermsService.getPerm(Perms.WORKFLOW_BOOKING) ?(widget.valid ? Colors.green : Colors.black) : Colors.grey ))), border: Border.all(color: dash.error != null ? Colors.red : ( PermsService.getPerm(Perms.WORKFLOW_BOOKING) ?(widget.valid ? Colors.green : Colors.black) : Colors.grey ))),
width: 200, height: 30, width: 200, height: 30,
child: Icon(Icons.schedule_send, color: dash.error != null ? Colors.red : (widget.valid ? Colors.green : Colors.black)), child: Icon(Icons.schedule_send, color: dash.error != null ? Colors.red : (widget.valid ? Colors.green : Colors.black)),
)) ))
), ) : Container(),
Column( children: [ Column( children: [
Container( Container(
height: 15, width: 200, height: 15, width: 200,

View File

@ -4,6 +4,7 @@ import 'package:flutter_flow_chart/src/ui/draw_arrow.dart';
import 'package:flutter_flow_chart/flutter_flow_chart.dart'; import 'package:flutter_flow_chart/flutter_flow_chart.dart';
import 'package:flutter_colorpicker/flutter_colorpicker.dart'; import 'package:flutter_colorpicker/flutter_colorpicker.dart';
import 'package:number_text_input_formatter/number_text_input_formatter.dart'; import 'package:number_text_input_formatter/number_text_input_formatter.dart';
import 'package:uuid/uuid.dart';
class FlowChartSelectedMenu extends StatefulWidget { class FlowChartSelectedMenu extends StatefulWidget {
Dashboard dashboard; Dashboard dashboard;
@ -50,6 +51,8 @@ class FlowChartSelectedMenuState extends State<FlowChartSelectedMenu> {
child: InkWell( mouseCursor: SystemMouseCursors.click, child: InkWell( mouseCursor: SystemMouseCursors.click,
onTap: () { onTap: () {
for (var sel in widget.dashboard.elementSelected) { for (var sel in widget.dashboard.elementSelected) {
var el =FlowElement.fromMap(widget.dashboard, sel.toMap());
el.id = Uuid().v8();
widget.dashboard.addElement(FlowElement.fromMap(widget.dashboard, sel.toMap()), context); widget.dashboard.addElement(FlowElement.fromMap(widget.dashboard, sel.toMap()), context);
widget.dashboard.elements.last.position += Offset(50, 50); widget.dashboard.elements.last.position += Offset(50, 50);
} }