intermediate
This commit is contained in:
@@ -1,29 +0,0 @@
|
||||
import 'package:oc_front/models/search.dart';
|
||||
|
||||
class Graphs {
|
||||
static const Map<String, Graph> graphs = {};
|
||||
|
||||
static Graph getGraph(String id) {
|
||||
return graphs[id]!;
|
||||
}
|
||||
|
||||
static void addGraph(String id, Graph graph) {
|
||||
graphs[id] = graph;
|
||||
}
|
||||
|
||||
static void removeGraph(String id) {
|
||||
graphs.remove(id);
|
||||
}
|
||||
|
||||
static void clear() {
|
||||
graphs.clear();
|
||||
}
|
||||
}
|
||||
|
||||
class Graph {
|
||||
String id;
|
||||
List<AbstractItem> items = [];
|
||||
|
||||
Graph({ required this.id, required this.items }) {
|
||||
}
|
||||
}
|
||||
@@ -1,84 +1,177 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_flow_chart/flutter_flow_chart.dart';
|
||||
import 'package:oc_front/core/sections/end_drawer.dart';
|
||||
import 'package:oc_front/models/search.dart';
|
||||
import 'package:oc_front/models/workspace.dart';
|
||||
import 'package:oc_front/core/services/specialized_services/item_service.dart';
|
||||
import 'package:oc_front/core/services/specialized_services/workspace_service.dart';
|
||||
import 'package:oc_front/pages/catalog.dart';
|
||||
import 'package:oc_front/pages/catalog_item.dart';
|
||||
import 'package:oc_front/pages/workflow.dart';
|
||||
|
||||
class WorkSpaceItem {
|
||||
String? id;
|
||||
String? name;
|
||||
WorkSpaceItem({this.id, this.name});
|
||||
}
|
||||
|
||||
class WorkspaceLocal {
|
||||
static Workspace? workspace;
|
||||
static String? current;
|
||||
static Map<String, Workspace> workspaces = {};
|
||||
static final WorkspaceService _service = WorkspaceService();
|
||||
static List<AbstractItem> items = [];
|
||||
static void init(BuildContext context) {
|
||||
_service.all(context).then((value) {
|
||||
workspace = value.data;
|
||||
if (workspace != null) {
|
||||
if (workspace!.data.isNotEmpty) {
|
||||
ItemService<DataItem, DataItem> dataService = ItemService<DataItem, DataItem>();
|
||||
for (var element in workspace!.data) {
|
||||
if (WorkspaceLocal.hasItemByID(element)) { continue; }
|
||||
dataService.get(context, element).then(
|
||||
(value) { if (value.data != null) { items.add(value.data!); } }
|
||||
);
|
||||
|
||||
static void init(BuildContext context, bool changeCurrent) {
|
||||
_service.all(context).then((value) {
|
||||
if (value.data != null && value.data!.values.isNotEmpty ) {
|
||||
var vals = value.data!.values;
|
||||
for (var element in vals) {
|
||||
var ws = Workspace().deserialize(element);
|
||||
if (ws.id == null) { continue; }
|
||||
workspaces[ws.id!] = ws;
|
||||
if (current == null) {
|
||||
current ??= ws.id;
|
||||
workspaces[current!] = ws;
|
||||
_service.put(context, ws.id!, { "active" : true }, {});
|
||||
}
|
||||
}
|
||||
if (workspace!.computing.isNotEmpty) {
|
||||
ItemService<ComputingItem, ComputingItem> computingService = ItemService<ComputingItem, ComputingItem>();
|
||||
for (var element in workspace!.computing) {
|
||||
if (WorkspaceLocal.hasItemByID(element)) { continue; }
|
||||
computingService.get(context, element).then(
|
||||
(value) { if (value.data != null) { items.add(value.data!); } }
|
||||
);
|
||||
}
|
||||
}
|
||||
if (workspace!.datacenter.isNotEmpty) {
|
||||
ItemService<DataCenterItem, DataCenterItem> dataCenterService = ItemService<DataCenterItem, DataCenterItem>();
|
||||
for (var element in workspace!.datacenter) {
|
||||
if (WorkspaceLocal.hasItemByID(element)) { continue; }
|
||||
dataCenterService.get(context, element).then(
|
||||
(value) { if (value.data != null) { items.add(value.data!); } }
|
||||
);
|
||||
}
|
||||
}
|
||||
if (workspace!.storage.isNotEmpty) {
|
||||
ItemService<StorageItem, StorageItem> storageService = ItemService<StorageItem, StorageItem>();
|
||||
for (var element in workspace!.storage) {
|
||||
if (WorkspaceLocal.hasItemByID(element)) { continue; }
|
||||
storageService.get(context, element).then(
|
||||
(value) { if (value.data != null) { items.add(value.data!); } }
|
||||
);
|
||||
if (ws.active == true && changeCurrent) {
|
||||
current = ws.id;
|
||||
}
|
||||
fill();
|
||||
}
|
||||
} else {
|
||||
WorkspaceLocal.createWorkspace("main", context);
|
||||
}
|
||||
});
|
||||
}
|
||||
static List<AbstractItem> byTopic(String topic) {
|
||||
|
||||
static void fill() {
|
||||
items = [];
|
||||
if (workspaces[current] != null) {
|
||||
for (var element in workspaces[current]!.datas) {
|
||||
if (WorkspaceLocal.hasItemByID(element.getID())) { continue; }
|
||||
items.add(element);
|
||||
}
|
||||
for (var element in workspaces[current]!.processings) {
|
||||
if (WorkspaceLocal.hasItemByID(element.getID())) { continue; }
|
||||
items.add(element); }
|
||||
for (var element in workspaces[current]!.datacenters) {
|
||||
if (WorkspaceLocal.hasItemByID(element.getID())) { continue; }
|
||||
items.add(element);
|
||||
}
|
||||
for (var element in workspaces[current]!.storages) {
|
||||
if (WorkspaceLocal.hasItemByID(element.getID())) { continue; }
|
||||
items.add(element);
|
||||
}
|
||||
for (var element in workspaces[current]!.workflows) {
|
||||
if (WorkspaceLocal.hasItemByID(element.getID())) { continue; }
|
||||
items.add(element);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static Workspace? getCurrentWorkspace() {
|
||||
return workspaces[current];
|
||||
}
|
||||
|
||||
static Future<void> deleteWorkspace(String id) async {
|
||||
if (workspaces.containsKey(id) && workspaces.length == 1) { return; }
|
||||
workspaces.remove(id);
|
||||
await _service.delete(null, id, {});
|
||||
current = workspaces.keys.first;
|
||||
}
|
||||
|
||||
static Future<void> createWorkspace(String name, BuildContext? context) async {
|
||||
Workspace n = Workspace(name: name);
|
||||
await _service.post(context, n.serialize(), {}).then((value) {
|
||||
if (value.data != null) {
|
||||
workspaces[value.data!.id!] = value.data!;
|
||||
current = value.data!.id;
|
||||
fill();
|
||||
endDrawerKey.currentState?.setState(() {});
|
||||
CatalogFactory.key.currentState?.setState(() {});
|
||||
CatalogItemFactory.key.currentState?.setState(() {});
|
||||
WorkflowFactory.key.currentState?.setState(() {});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
static void changeWorkspace(String id) {
|
||||
current = id;
|
||||
fill();
|
||||
endDrawerKey.currentState?.setState(() {});
|
||||
CatalogFactory.key.currentState?.setState(() {});
|
||||
CatalogItemFactory.key.currentState?.setState(() {});
|
||||
WorkflowFactory.key.currentState?.setState(() {});
|
||||
}
|
||||
|
||||
static List<WorkSpaceItem> getWorkspacesIDS() {
|
||||
List<WorkSpaceItem> res = [];
|
||||
for (var element in workspaces.entries) {
|
||||
res.add(WorkSpaceItem(id: element.key, name: element.value.name));
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
static List<AbstractItem> byTopic(String topic, bool all) {
|
||||
if (all) {
|
||||
List<AbstractItem<FlowData>> d = [];
|
||||
for (var w in workspaces.values) {
|
||||
d = [ ...d, ...w.datas.where((element) => !d.map( (d2) => d2.id).contains(element.id)) ];
|
||||
d = [ ...d, ...w.datacenters.where((element) => !d.map( (d2) => d2.id).contains(element.id)) ];
|
||||
d = [ ...d, ...w.processings.where((element) => !d.map( (d2) => d2.id).contains(element.id)) ];
|
||||
d = [ ...d, ...w.storages.where((element) => !d.map( (d2) => d2.id).contains(element.id)) ];
|
||||
d = [ ...d, ...w.workflows.where((element) => !d.map( (d2) => d2.id).contains(element.id)) ];
|
||||
}
|
||||
return d.where((element) => element.topic.toString() == topic).toList();
|
||||
}
|
||||
return WorkspaceLocal.items.where((element) => element.topic.toString() == topic).toList();
|
||||
}
|
||||
|
||||
static AbstractItem? getItem(String id) {
|
||||
static AbstractItem? getItem(String id, bool all) {
|
||||
if (all) {
|
||||
List<AbstractItem<FlowData>> d = [];
|
||||
for (var w in workspaces.values) {
|
||||
d = [ ...d, ...w.datas.where((element) => element.id.toString() == id).where((element) => !d.map( (d2) => d2.id).contains(element.id)) ];
|
||||
d = [ ...d, ...w.datacenters.where((element) => element.id.toString() == id).where((element) => !d.map( (d2) => d2.id).contains(element.id)) ];
|
||||
d = [ ...d, ...w.processings.where((element) => element.id.toString() == id).where((element) => !d.map( (d2) => d2.id).contains(element.id)) ];
|
||||
d = [ ...d, ...w.storages.where((element) => element.id.toString() == id).where((element) => !d.map( (d2) => d2.id).contains(element.id)) ];
|
||||
d = [ ...d, ...w.workflows.where((element) => element.id.toString() == id).where((element) => !d.map( (d2) => d2.id).contains(element.id)) ];
|
||||
}
|
||||
return d.isEmpty ? null : d.first;
|
||||
}
|
||||
var found = WorkspaceLocal.items.where((element) => element.id.toString() == id);
|
||||
return found.isEmpty ? null : found.first;
|
||||
}
|
||||
|
||||
static void addItem(AbstractItem item) {
|
||||
if (!WorkspaceLocal.hasItem(item)) {
|
||||
if (!WorkspaceLocal.hasItem(item) && workspaces[current] != null && workspaces[current]!.id != null) {
|
||||
items.add(item);
|
||||
try {
|
||||
_service.post(null, {}, { "id" : item.id.toString(), "rtype" : item.type.toString() });
|
||||
if (item.topic == "data") { workspaces[current]!.datas.add(item as DataItem); }
|
||||
if (item.topic == "processing") { workspaces[current]!.processings.add(item as ProcessingItem); }
|
||||
if (item.topic == "datacenter") { workspaces[current]!.datacenters.add(item as DataCenterItem); }
|
||||
if (item.topic == "storage") { workspaces[current]!.storages.add(item as StorageItem); }
|
||||
if (item.topic == "workflow") { workspaces[current]!.workflows.add(item as WorkflowItem); }
|
||||
try { _service.put(null, workspaces[current]!.id!, workspaces[current]!.serialize(), {});
|
||||
} catch (e) { /* */ }
|
||||
_service.put(null, item.id ?? "", workspaces[current]!.serialize(), {});
|
||||
}
|
||||
}
|
||||
static void removeItem(AbstractItem item) {
|
||||
items = items.where((element) => element.name != item.name).toList();
|
||||
try { _service.delete(null, { "id" : item.id.toString(), "rtype" : item.type.toString() });
|
||||
if (item.topic == "data") { workspaces[current]!.datas.removeWhere( (e) => e.id == item.id); }
|
||||
if (item.topic == "processing") { workspaces[current]!.processings.removeWhere( (e) => e.id == item.id); }
|
||||
if (item.topic == "datacenter") { workspaces[current]!.datacenters.removeWhere( (e) => e.id == item.id); }
|
||||
if (item.topic == "storage") { workspaces[current]!.storages.removeWhere( (e) => e.id == item.id); }
|
||||
if (item.topic == "workflow") { workspaces[current]!.workflows.removeWhere( (e) => e.id == item.id); }
|
||||
try { _service.put(null, workspaces[current]!.id!, workspaces[current]!.serialize(), {});
|
||||
} catch (e) { /* */ }
|
||||
_service.put(null, item.id ?? "", workspaces[current]!.serialize(), {});
|
||||
}
|
||||
static bool hasItemByID(String id) {
|
||||
return items.where((element) => element.id == id).isNotEmpty;
|
||||
}
|
||||
static bool hasItem(AbstractItem item) {
|
||||
return items.where((element) => element.name == item.name).isNotEmpty;
|
||||
return items.where((element) => element.id == item.id).isNotEmpty;
|
||||
}
|
||||
static void clear() => items.clear();
|
||||
}
|
||||
@@ -3,6 +3,7 @@ import 'package:oc_front/models/search.dart';
|
||||
import 'package:oc_front/pages/catalog.dart';
|
||||
import 'package:oc_front/core/models/workspace_local.dart';
|
||||
import 'package:oc_front/widgets/items/item_row.dart';
|
||||
import 'package:oc_front/widgets/menu_clipper/workspace_menu.dart';
|
||||
|
||||
GlobalKey<EndDrawerWidgetState> endDrawerKey = GlobalKey<EndDrawerWidgetState>();
|
||||
class EndDrawerWidget extends StatefulWidget {
|
||||
@@ -33,7 +34,8 @@ class EndDrawerWidgetState extends State<EndDrawerWidget> {
|
||||
|
||||
),
|
||||
),
|
||||
itemRows.isEmpty ? Container( height: MediaQuery.of(context).size.height - 50,
|
||||
MenuWorkspaceWidget(simpliest: true, width: 400),
|
||||
itemRows.isEmpty ? Container( height: MediaQuery.of(context).size.height - 100,
|
||||
color: Colors.grey.shade300,
|
||||
child: const Center(child: Text("WORKSPACE IS EMPTY",
|
||||
style: TextStyle(fontSize: 25, fontWeight: FontWeight.w600, color: Colors.white))))
|
||||
|
||||
@@ -61,7 +61,7 @@ class SearchWidgetState extends State<SearchWidget> {
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Container(
|
||||
width: MediaQuery.of(context).size.width - 300 - 100,
|
||||
width: MediaQuery.of(context).size.width - 400 > 0 ? MediaQuery.of(context).size.width - 300 - 100 : MediaQuery.of(context).size.width,
|
||||
height: 50,
|
||||
color: Colors.white,
|
||||
child: TextField(
|
||||
|
||||
@@ -82,18 +82,17 @@ class APIService<T extends SerializerDeserializer> {
|
||||
_dio.options.headers["authorization"] = auth;
|
||||
_dio.interceptors.clear();
|
||||
var response = await _request(url, method, body, options);
|
||||
print(response);
|
||||
if (response.statusCode != null && response.statusCode! < 400) {
|
||||
if (method == "delete") { cache.remove(url); return APIResponse<T>(); }
|
||||
APIResponse<T> resp = APIResponse<T>().deserialize(response.data);
|
||||
if (resp.error == "") {
|
||||
if (method == "get") { cache[url]=resp; }
|
||||
if (context != null && succeed != "") {
|
||||
// ignore: use_build_context_synchronously
|
||||
showAlertBanner(context, () {}, InfoAlertBannerChild(text: succeed), // <-- Put any widget here you want!
|
||||
alertBannerLocation: AlertBannerLocation.bottom,);
|
||||
}
|
||||
try { return cache[url] as APIResponse<T>;
|
||||
} catch (e) { return APIResponse(); }
|
||||
return resp;
|
||||
}
|
||||
err = resp.error ?? "internal error";
|
||||
}
|
||||
|
||||
@@ -52,9 +52,10 @@ class AppRouter {
|
||||
description: "View to select & create new workflow.", help: "Workflow only access to your workspace datas. If a an element of your flow is missing, perhaps means it's missing in workspace.",
|
||||
factory: WorkflowFactory());
|
||||
static final RouterItem catalogItem = RouterItem(description: "", help: "", route: "catalog/:id", factory: CatalogItemFactory(), args: ["id"]);
|
||||
static final RouterItem catalog= RouterItem(icon: Icons.book_outlined, label: "catalog searcher", route: home, factory: CatalogFactory());
|
||||
|
||||
static List<RouterItem> zones = [
|
||||
RouterItem(icon: Icons.book_outlined, label: "catalog searcher", route: home, factory: CatalogFactory()),
|
||||
catalog,
|
||||
workflowItem,
|
||||
RouterItem(icon: Icons.schedule, label: "scheduled tasks", route: "scheduler", factory: SchedulerFactory()),
|
||||
RouterItem(icon: Icons.dns_outlined, label: "my datacenter", route: "datacenter",
|
||||
|
||||
@@ -6,10 +6,22 @@ import 'package:oc_front/core/services/api_service.dart';
|
||||
abstract class AbstractService<T extends SerializerDeserializer> {
|
||||
abstract APIService<T> service;
|
||||
abstract String subPath;
|
||||
|
||||
Future<APIResponse<T>> search(BuildContext? context, List<String> words, Map<String, dynamic> params) { throw UnimplementedError(); }
|
||||
Future<APIResponse<RawData>> all(BuildContext? context) {
|
||||
return service.raw(subPath, null, "get");
|
||||
}
|
||||
Future<APIResponse<T>> get(BuildContext? context, String id) {
|
||||
return service.get("$subPath$id", true, context);
|
||||
}
|
||||
Future<APIResponse<T>> post(BuildContext? context, Map<String, dynamic> body, Map<String, String> params) {
|
||||
return service.post(subPath, body, context);
|
||||
}
|
||||
Future<APIResponse<T>> put(BuildContext? context, String id, Map<String, dynamic> body, Map<String, String> params) {
|
||||
return service.put("$subPath$id", body, context);
|
||||
}
|
||||
Future<APIResponse<T>> delete(BuildContext? context, String id, Map<String, String> params) {
|
||||
return service.delete("$subPath$id", context);
|
||||
}
|
||||
}
|
||||
|
||||
Future<APIResponse<T>> all(BuildContext? context) { throw UnimplementedError(); }
|
||||
Future<APIResponse<T>> get(BuildContext? context, String id);
|
||||
Future<APIResponse<T>> post(BuildContext? context, Map<String, dynamic> body, Map<String, String> params);
|
||||
Future<APIResponse<T>> put(BuildContext? context, String id, Map<String, dynamic> body, Map<String, String> params) { throw UnimplementedError(); }
|
||||
Future<APIResponse<T>> delete(BuildContext? context, Map<String, String> params) { throw UnimplementedError(); }
|
||||
}
|
||||
@@ -1,24 +1,11 @@
|
||||
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/abstract.dart';
|
||||
import 'package:oc_front/models/response.dart';
|
||||
import 'package:oc_front/models/search.dart';
|
||||
|
||||
class ItemService<S extends AbstractItem, T extends SerializerDeserializer<S>> extends AbstractService<T> {
|
||||
@override APIService<T> service = APIService<T>(
|
||||
baseURL: const String.fromEnvironment('ITEM_HOST', defaultValue: 'http://localhost:49618')
|
||||
baseURL: const String.fromEnvironment('ITEM_HOST', defaultValue: 'http://localhost:8087')
|
||||
);
|
||||
@override String subPath = "/v1/${getTopic(S)}";
|
||||
|
||||
@override Future<APIResponse<T>> all(BuildContext? context) { throw UnimplementedError(); }
|
||||
@override Future<APIResponse<T>> get(BuildContext? context, String id) {
|
||||
if (id.contains(",")) { return service.get("$subPath/multi/$id", true, context); }
|
||||
return service.get("$subPath/$id", true, context);
|
||||
}
|
||||
@override Future<APIResponse<T>> post(BuildContext? context, Map<String, dynamic> body, Map<String, String> params) {
|
||||
return service.post("$subPath/", body, context);
|
||||
}
|
||||
@override Future<APIResponse<T>> put(BuildContext? context, String id, Map<String, dynamic> body, Map<String, String> params) { throw UnimplementedError(); }
|
||||
@override Future<APIResponse<T>> delete(BuildContext? context, Map<String, String> params) { throw UnimplementedError(); }
|
||||
@override String subPath = "/oc/${getTopic(S)}/";
|
||||
}
|
||||
34
lib/core/services/specialized_services/logs_service.dart
Normal file
34
lib/core/services/specialized_services/logs_service.dart
Normal file
@@ -0,0 +1,34 @@
|
||||
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/logs.dart';
|
||||
import 'package:oc_front/models/response.dart';
|
||||
|
||||
class LogsService extends AbstractService<LogResults> {
|
||||
@override APIService<LogResults> service = APIService<LogResults>(
|
||||
baseURL: const String.fromEnvironment('SCHEDULER_HOST', defaultValue: 'http://localhost:3100')
|
||||
);
|
||||
@override String subPath = "/loki/api/v1/";
|
||||
|
||||
@override Future<APIResponse<LogResults>> search(BuildContext? context, List<String> words, Map<String, dynamic> params) {
|
||||
List<String> v = [];
|
||||
for (var p in params.keys) {
|
||||
if (p == "start" || p == "end") { continue; }
|
||||
v.add("$p=\"${params[p]}\"");
|
||||
}
|
||||
return service.get("${subPath}query_range?query={${v.join(", ")}}&start=${params["start"]}&end=${params["end"]}", false, context);
|
||||
}
|
||||
|
||||
@override Future<APIResponse<LogResults>> get(BuildContext? context, String id) {
|
||||
throw UnimplementedError();
|
||||
}
|
||||
@override Future<APIResponse<LogResults>> post(BuildContext? context, Map<String, dynamic> body, Map<String, String> params) {
|
||||
throw UnimplementedError();
|
||||
}
|
||||
@override Future<APIResponse<LogResults>> put(BuildContext? context, String id, Map<String, dynamic> body, Map<String, String> params) {
|
||||
throw UnimplementedError();
|
||||
}
|
||||
@override Future<APIResponse<LogResults>> delete(BuildContext? context, String id, Map<String, String> params) {
|
||||
throw UnimplementedError();
|
||||
}
|
||||
}
|
||||
23
lib/core/services/specialized_services/resource_service.dart
Normal file
23
lib/core/services/specialized_services/resource_service.dart
Normal file
@@ -0,0 +1,23 @@
|
||||
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/search.dart';
|
||||
|
||||
class ResourceService extends AbstractService<Resource> {
|
||||
@override APIService<Resource> service = APIService<Resource>(
|
||||
baseURL: const String.fromEnvironment('ITEM_HOST', defaultValue: 'http://localhost:8087')
|
||||
);
|
||||
@override String subPath = "/oc/resource/";
|
||||
|
||||
@override Future<APIResponse<Resource>> search(BuildContext? context, List<String> words, Map<String, dynamic> params) {
|
||||
return service.get("${subPath}search/${words.join("/")}", false, context);
|
||||
}
|
||||
|
||||
@override Future<APIResponse<Resource>> post(BuildContext? context, Map<String, dynamic> body, Map<String, String> params) {
|
||||
return throw UnimplementedError();
|
||||
}
|
||||
@override Future<APIResponse<Resource>> put(BuildContext? context, String id, Map<String, dynamic> body, Map<String, String> params) {
|
||||
return throw UnimplementedError();
|
||||
}
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
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/search.dart';
|
||||
|
||||
class SearchService extends AbstractService<Search> {
|
||||
@override APIService<Search> service = APIService<Search>(
|
||||
baseURL: const String.fromEnvironment('SEARCH_HOST', defaultValue: 'http://localhost:49618')
|
||||
);
|
||||
@override String subPath = "/v1/search";
|
||||
@override Future<APIResponse<Search>> all(BuildContext? context) { throw UnimplementedError(); }
|
||||
@override Future<APIResponse<Search>> get(BuildContext? context, String id) {
|
||||
return service.get("$subPath/byWord?word=$id", true, context);
|
||||
}
|
||||
@override Future<APIResponse<Search>> post(BuildContext? context, Map<String, dynamic> body, Map<String, String> params) { throw UnimplementedError(); }
|
||||
@override Future<APIResponse<Search>> put(BuildContext? context, String id, Map<String, dynamic> body, Map<String, String> params) { throw UnimplementedError(); }
|
||||
@override Future<APIResponse<Search>> delete(BuildContext? context, Map<String, String> params) { throw UnimplementedError(); }
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
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 WorkflowExecutionService extends AbstractService<WorkflowExecutions> {
|
||||
@override APIService<WorkflowExecutions> service = APIService<WorkflowExecutions>(
|
||||
baseURL: const String.fromEnvironment('SCHEDULER_HOST', defaultValue: 'http://localhost:8090')
|
||||
);
|
||||
@override String subPath = "/oc/workflow_execution/";
|
||||
|
||||
@override Future<APIResponse<WorkflowExecutions>> search(BuildContext? context, List<String> words, Map<String, dynamic> params) {
|
||||
return service.get("${subPath}search/${words.join("/")}", false, context);
|
||||
}
|
||||
|
||||
@override Future<APIResponse<WorkflowExecutions>> post(BuildContext? context, Map<String, dynamic> body, Map<String, String> params) {
|
||||
return throw UnimplementedError();
|
||||
}
|
||||
@override Future<APIResponse<WorkflowExecutions>> put(BuildContext? context, String id, Map<String, dynamic> body, Map<String, String> params) {
|
||||
return throw UnimplementedError();
|
||||
}
|
||||
}
|
||||
@@ -1,26 +1,10 @@
|
||||
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 WorflowService extends AbstractService<RawData> {
|
||||
@override APIService<RawData> service = APIService<RawData>(
|
||||
baseURL: const String.fromEnvironment('WORKFLOW_HOST', defaultValue: 'http://localhost:49618')
|
||||
class WorflowService extends AbstractService<Workflow> {
|
||||
@override APIService<Workflow> service = APIService<Workflow>(
|
||||
baseURL: const String.fromEnvironment('WORKFLOW_HOST', defaultValue: 'http://localhost:8088')
|
||||
);
|
||||
@override String subPath = "/v1/workflow/";
|
||||
@override Future<APIResponse<RawData>> all(BuildContext? context) {
|
||||
return service.get(subPath, true, context);
|
||||
}
|
||||
@override Future<APIResponse<RawData>> get(BuildContext? context, String id) { throw UnimplementedError(); }
|
||||
@override Future<APIResponse<RawData>> post(BuildContext? context, Map<String, dynamic> body, Map<String, String> params) {
|
||||
String path = "?";
|
||||
for (var key in params.keys) { path += "$key=${params[key]}&"; }
|
||||
return service.post("$subPath$path", body, context);
|
||||
}
|
||||
@override Future<APIResponse<RawData>> put(BuildContext? context, String id, Map<String, dynamic> body, Map<String, String> params) {
|
||||
throw UnimplementedError();
|
||||
}
|
||||
@override Future<APIResponse<RawData>> delete(BuildContext? context, Map<String, String> params) {
|
||||
throw UnimplementedError();
|
||||
}
|
||||
@override String subPath = "/oc/workflow/";
|
||||
}
|
||||
@@ -1,30 +1,10 @@
|
||||
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/workspace.dart';
|
||||
|
||||
class WorkspaceService extends AbstractService<Workspace> {
|
||||
@override APIService<Workspace> service = APIService<Workspace>(
|
||||
baseURL: const String.fromEnvironment('WORKSPACE_HOST', defaultValue: 'http://localhost:49618')
|
||||
baseURL: const String.fromEnvironment('WORKSPACE_HOST', defaultValue: 'http://localhost:8089')
|
||||
);
|
||||
@override String subPath = "/v1/workspace/";
|
||||
|
||||
@override Future<APIResponse<Workspace>> all(BuildContext? context) {
|
||||
return service.get("$subPath/list", true, context);
|
||||
}
|
||||
@override Future<APIResponse<Workspace>> get(BuildContext? context, String id) { throw UnimplementedError(); }
|
||||
@override Future<APIResponse<Workspace>> post(BuildContext? context, Map<String, dynamic> body, Map<String, String> params) {
|
||||
String path = "?";
|
||||
for (var key in params.keys) { path += "$key=${params[key]}&"; }
|
||||
return service.post("$subPath$path", body, context);
|
||||
}
|
||||
@override Future<APIResponse<Workspace>> put(BuildContext? context, String id, Map<String, dynamic> body, Map<String, String> params) {
|
||||
throw UnimplementedError();
|
||||
}
|
||||
@override Future<APIResponse<Workspace>> delete(BuildContext? context, Map<String, String> params) {
|
||||
String path = "?";
|
||||
for (var key in params.keys) { path += "$key=${params[key]}&"; }
|
||||
return service.delete("$subPath$path", context);
|
||||
}
|
||||
@override String subPath = "/oc/workspace/";
|
||||
}
|
||||
@@ -50,7 +50,7 @@ class _MainPageState extends State<MainPage> {
|
||||
// The Flutter framework has been optimized to make rerunning build methods
|
||||
// fast, so that you can just rebuild anything that needs updating rather
|
||||
// than having to individually change instances of widgets.
|
||||
WorkspaceLocal.init(context);
|
||||
WorkspaceLocal.init(context, false);
|
||||
scaffoldKey = GlobalKey<ScaffoldState>();
|
||||
return Scaffold(
|
||||
key: scaffoldKey,
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import 'dart:convert';
|
||||
import 'dart:developer' as developer;
|
||||
|
||||
abstract class SerializerDeserializer<T> {
|
||||
T deserialize(dynamic json);
|
||||
|
||||
116
lib/models/logs.dart
Normal file
116
lib/models/logs.dart
Normal file
@@ -0,0 +1,116 @@
|
||||
import 'package:oc_front/models/abstract.dart';
|
||||
import 'package:json_string/json_string.dart';
|
||||
|
||||
class LogResults extends SerializerDeserializer<LogResults> {
|
||||
String? status;
|
||||
LogsResult? data;
|
||||
|
||||
LogResults({
|
||||
this.status,
|
||||
this.data,
|
||||
});
|
||||
|
||||
String getID() {
|
||||
return "";
|
||||
}
|
||||
|
||||
@override deserialize(dynamic json) {
|
||||
try { json = json as Map<String, dynamic>;
|
||||
} catch (e) { return LogResults(); }
|
||||
return LogResults(
|
||||
status: json.containsKey("status") ? json["status"] : "",
|
||||
data: json.containsKey("data") ? LogsResult().deserialize(json["data"]) : null,
|
||||
);
|
||||
}
|
||||
@override Map<String, dynamic> serialize() {
|
||||
return { };
|
||||
}
|
||||
}
|
||||
|
||||
class LogsResult extends SerializerDeserializer<LogsResult> {
|
||||
List<Logs> result;
|
||||
LogsResult({
|
||||
this.result = const [],
|
||||
});
|
||||
|
||||
String getID() {
|
||||
return "";
|
||||
}
|
||||
|
||||
@override deserialize(dynamic json) {
|
||||
try { json = json as Map<String, dynamic>;
|
||||
} catch (e) { return LogsResult(); }
|
||||
return LogsResult(
|
||||
result: json.containsKey("result") ? fromListJson(json["result"], Logs()) : [],
|
||||
);
|
||||
}
|
||||
@override Map<String, dynamic> serialize() {
|
||||
return { };
|
||||
}
|
||||
}
|
||||
|
||||
class Logs extends SerializerDeserializer<Logs> {
|
||||
String? level;
|
||||
List<Log> logs = [];
|
||||
Logs({
|
||||
this.level,
|
||||
});
|
||||
|
||||
String getID() {
|
||||
return "";
|
||||
}
|
||||
|
||||
@override deserialize(dynamic json) {
|
||||
try { json = json as Map<String, dynamic>;
|
||||
} catch (e) { return Logs(); }
|
||||
return Logs(
|
||||
level: json.containsKey("stream") && (json["stream"] as Map<String, dynamic>).containsKey("level") ? json["stream"]["level"] : "",
|
||||
|
||||
);
|
||||
}
|
||||
@override Map<String, dynamic> serialize() {
|
||||
return { };
|
||||
}
|
||||
}
|
||||
|
||||
class Log extends SerializerDeserializer<Log> {
|
||||
DateTime? timestamp;
|
||||
String? message;
|
||||
|
||||
String? level;
|
||||
Map<String, dynamic> map = {};
|
||||
Log({
|
||||
this.timestamp,
|
||||
this.message,
|
||||
this.level
|
||||
});
|
||||
|
||||
String getID() {
|
||||
return "";
|
||||
}
|
||||
|
||||
String getMessage(String mess) {
|
||||
var jsonString = mess;
|
||||
try {
|
||||
var j = JsonString(mess.replaceAll("\\", "")).decodedValue as Map<String, dynamic>;
|
||||
map = j;
|
||||
if (j["Status"] == "Pending") {
|
||||
jsonString = "${j["Name"]} : [${j["Namespace"]}] Status: ${j["Status"]}... \nCreated at ${j["Created"].toString().replaceAllMapped(RegExp(r'\(\w+\)'), (match) { return ''; }).replaceAllMapped(RegExp(r'\+\w+'), (match) { return ''; })}";
|
||||
} else {
|
||||
jsonString = "${j["Name"]} : [${j["Namespace"]}] ${j["Status"]} ${j["Progress"]} (${j["Duration"].toString().replaceAll("seconds", "s")})\nStarted at ${j["Created"].toString().replaceAllMapped(RegExp(r'\(\w+\)'), (match) { return ''; }).replaceAllMapped(RegExp(r'\+\w+'), (match) { return ''; })}";
|
||||
}
|
||||
} on JsonFormatException catch (e) { /* */ }
|
||||
message = jsonString;
|
||||
return jsonString;
|
||||
}
|
||||
|
||||
@override deserialize(dynamic json) {
|
||||
try { json = json as List<dynamic>;
|
||||
} catch (e) { return Log(); }
|
||||
return Log(
|
||||
timestamp: json.isNotEmpty ? DateTime.parse(json[0]) : null,
|
||||
message: json.length > 1 ? getMessage(json[1].toString()) : null,
|
||||
);
|
||||
}
|
||||
@override Map<String, dynamic> serialize() { return { }; }
|
||||
}
|
||||
@@ -1,5 +1,7 @@
|
||||
import 'package:oc_front/models/abstract.dart';
|
||||
import 'package:oc_front/models/logs.dart';
|
||||
import 'package:oc_front/models/search.dart';
|
||||
import 'package:oc_front/models/workflow.dart';
|
||||
import 'package:oc_front/models/workspace.dart';
|
||||
|
||||
Map<Type, SerializerDeserializer> refs = <Type, SerializerDeserializer> {
|
||||
@@ -9,15 +11,21 @@ Map<Type, SerializerDeserializer> refs = <Type, SerializerDeserializer> {
|
||||
DataItem: DataItem(),
|
||||
DataCenterItem: DataCenterItem(),
|
||||
StorageItem: StorageItem(),
|
||||
ComputingItem: ComputingItem(),
|
||||
ProcessingItem: ProcessingItem(),
|
||||
Workflow: Workflow(),
|
||||
Resource: Resource(),
|
||||
WorkflowExecutions: WorkflowExecutions(),
|
||||
LogResults: LogResults(),
|
||||
};
|
||||
|
||||
class APIResponse<T extends SerializerDeserializer> {
|
||||
APIResponse({
|
||||
this.data,
|
||||
this.code = 200,
|
||||
this.error = "",
|
||||
this.offset = 0,
|
||||
});
|
||||
int code = 200;
|
||||
int offset = 0;
|
||||
T? data ;
|
||||
String? error = "";
|
||||
@@ -28,18 +36,22 @@ class APIResponse<T extends SerializerDeserializer> {
|
||||
}
|
||||
|
||||
APIResponse<T> deserialize(dynamic j) {
|
||||
dynamic data;
|
||||
try { data = j["data"];
|
||||
} catch (e) { data = j; }
|
||||
try {
|
||||
return APIResponse<T>(
|
||||
data: refs[T]!.deserialize(j),
|
||||
data: refs[T]!.deserialize(data),
|
||||
code: j.containsKey("code") && j["code"] != null ? j["code"] : 200,
|
||||
error: j.containsKey("error") && j["error"] != null ? j["error"] : "",
|
||||
);
|
||||
} catch (e) { return APIResponse<T>( data: refs[T]!.deserialize(j), ); }
|
||||
|
||||
} catch (e) { return APIResponse<T>( data: refs[T]!.deserialize(data), ); }
|
||||
}
|
||||
}
|
||||
|
||||
class RawData extends SerializerDeserializer<RawData> {
|
||||
RawData({ this.values = const []});
|
||||
dynamic values;
|
||||
@override deserialize(dynamic json) { return RawData(values: json); }
|
||||
List<dynamic> values = [];
|
||||
@override deserialize(dynamic json) { return RawData(values: json ?? []); }
|
||||
@override Map<String, dynamic> serialize() => { };
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import 'package:flutter_flow_chart/flutter_flow_chart.dart';
|
||||
import 'package:oc_front/models/abstract.dart';
|
||||
|
||||
const List<ComputingItem> _emptyComputing = [];
|
||||
const List<ProcessingItem> _emptyComputing = [];
|
||||
const List<DataItem> _emptyData = [];
|
||||
const List<DataCenterItem> _emptyDataCenter = [];
|
||||
const List<StorageItem> _emptyStorage = [];
|
||||
@@ -11,248 +12,539 @@ class Search extends SerializerDeserializer<Search> {
|
||||
this.data = _emptyData,
|
||||
this.storage = _emptyStorage,
|
||||
});
|
||||
List<ComputingItem> computing;
|
||||
List<ProcessingItem> computing;
|
||||
List<DataCenterItem> datacenter;
|
||||
List<DataItem> data;
|
||||
List<StorageItem> storage;
|
||||
@override deserialize(dynamic json) {
|
||||
json = json as Map<String, dynamic>;
|
||||
return Search(
|
||||
computing: json.containsKey("computing") ? fromListJson(json["computing"], ComputingItem()) : [],
|
||||
computing: json.containsKey("processing") ? fromListJson(json["processing"], ProcessingItem()) : [],
|
||||
datacenter: json.containsKey("datacenter") ? fromListJson(json["datacenter"], DataCenterItem()) : [],
|
||||
data: json.containsKey("data") ? fromListJson(json["data"], DataItem()) : [],
|
||||
storage: json.containsKey("storage") ? fromListJson(json["storage"], StorageItem()) : [],
|
||||
);
|
||||
}
|
||||
@override Map<String, dynamic> serialize() => {};
|
||||
@override Map<String, dynamic> serialize() => {
|
||||
"processing": toListJson<ProcessingItem>(computing),
|
||||
"datacenter": toListJson<DataCenterItem>(datacenter),
|
||||
"data": toListJson<DataItem>(data),
|
||||
"storage": toListJson<StorageItem>(storage),
|
||||
};
|
||||
}
|
||||
const List<String> _empty = [];
|
||||
abstract class AbstractItem {
|
||||
|
||||
class Resource implements SerializerDeserializer<Resource> {
|
||||
List<DataItem> datas = [];
|
||||
List<ProcessingItem> processings = [];
|
||||
List<StorageItem> storages = [];
|
||||
List<DataCenterItem> datacenters = [];
|
||||
List<WorkflowItem> workflows = [];
|
||||
|
||||
Resource({
|
||||
this.datas = const [],
|
||||
this.processings = const [],
|
||||
this.storages = const [],
|
||||
this.datacenters = const [],
|
||||
this.workflows = const [],
|
||||
});
|
||||
|
||||
@override Resource deserialize(json) {
|
||||
try { json = json as Map<String, dynamic>;
|
||||
} catch (e) { return Resource(); }
|
||||
return Resource(
|
||||
datacenters: json.containsKey("datacenter_resource") ? fromListJson(json["datacenter_resource"], DataCenterItem()) : [],
|
||||
datas: json.containsKey("data_resource") ? fromListJson(json["data_resource"], DataItem()) : [],
|
||||
processings: json.containsKey("processing_resource") ? fromListJson(json["processing_resource"], ProcessingItem()) : [],
|
||||
storages: json.containsKey("storage_resource") ? fromListJson(json["storage_resource"], StorageItem()) : [],
|
||||
workflows: json.containsKey("workflow_resource") ? fromListJson(json["workflow_resource"], WorkflowItem()) : [],
|
||||
);
|
||||
}
|
||||
|
||||
@override Map<String, dynamic> serialize() {
|
||||
return {
|
||||
"datacenter_resource": toListJson<DataCenterItem>(datacenters),
|
||||
"data_resource": toListJson<DataItem>(datas),
|
||||
"processing_resource": toListJson<ProcessingItem>(processings),
|
||||
"storage_resource": toListJson<StorageItem>(storages),
|
||||
"workflow_resource": toListJson<WorkflowItem>(workflows),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
abstract class AbstractItem<T extends FlowData> extends FlowData implements SerializerDeserializer<T> {
|
||||
String? id;
|
||||
String? name;
|
||||
String? logo;
|
||||
String? type;
|
||||
String? owner;
|
||||
String? ownerLogo;
|
||||
String? source;
|
||||
String? description;
|
||||
String? shortDescription;
|
||||
double? price;
|
||||
String? licence;
|
||||
List<dynamic> inputs = [];
|
||||
List<dynamic> outputs = [];
|
||||
ResourceModel? model;
|
||||
String topic = "";
|
||||
|
||||
AbstractItem({
|
||||
this.id,
|
||||
this.name,
|
||||
this.logo,
|
||||
this.owner,
|
||||
this.ownerLogo,
|
||||
this.price,
|
||||
this.source,
|
||||
this.licence,
|
||||
this.description,
|
||||
this.model,
|
||||
this.shortDescription,
|
||||
this.inputs = const [],
|
||||
this.outputs = const [],
|
||||
});
|
||||
|
||||
@override String getID() {
|
||||
return id ?? "";
|
||||
}
|
||||
|
||||
@override String getName() {
|
||||
return name ?? "";
|
||||
}
|
||||
}
|
||||
|
||||
class Model extends SerializerDeserializer<Model> {
|
||||
dynamic value;
|
||||
String? type;
|
||||
bool readonly = false;
|
||||
|
||||
Model({
|
||||
this.value,
|
||||
this.type,
|
||||
this.readonly = false,
|
||||
});
|
||||
|
||||
@override deserialize(dynamic json) {
|
||||
try { json = json as Map<String, dynamic>;
|
||||
} catch (e) { return Model(); }
|
||||
return Model(
|
||||
value: json.containsKey("value") ? json["value"] : null,
|
||||
type: json.containsKey("type") ? json["type"] : null,
|
||||
readonly: json.containsKey("readonly") ? json["readonly"] : false,
|
||||
);
|
||||
}
|
||||
@override Map<String, dynamic> serialize() => {
|
||||
"value": value,
|
||||
"type": type,
|
||||
"readonly": readonly,
|
||||
};
|
||||
}
|
||||
|
||||
class ResourceModel extends SerializerDeserializer<ResourceModel> {
|
||||
String? id;
|
||||
String? type;
|
||||
Map<String, Model>? model;
|
||||
|
||||
ResourceModel({
|
||||
this.id,
|
||||
this.type,
|
||||
this.model,
|
||||
});
|
||||
|
||||
@override deserialize(dynamic json) {
|
||||
try { json = json as Map<String, dynamic>;
|
||||
} catch (e) { return ResourceModel(); }
|
||||
return ResourceModel(
|
||||
id: json.containsKey("id") ? json["id"] : null,
|
||||
type: json.containsKey("type") ? json["type"] : null,
|
||||
model: json.containsKey("model") ? fromMapJson(json["model"], Model()) : {},
|
||||
);
|
||||
}
|
||||
@override Map<String, dynamic> serialize() => {
|
||||
"id": id,
|
||||
"type": type,
|
||||
"model": toMapJson<Model>(model ?? {}),
|
||||
};
|
||||
}
|
||||
|
||||
Type? getTopicType(String topic) {
|
||||
if (topic == "computing") { return ComputingItem; }
|
||||
if (topic == "processing") { return ProcessingItem; }
|
||||
else if (topic == "data") { return DataItem; }
|
||||
else if (topic == "datacenter") { return DataCenterItem; }
|
||||
else if (topic == "storage") { return StorageItem; }
|
||||
else if (topic == "workflow") { return WorkflowItem; }
|
||||
else { return null; }
|
||||
}
|
||||
|
||||
String getTopic(Type type) {
|
||||
if (type == ComputingItem) { return "computing"; }
|
||||
if (type == AbstractItem) { return "resource"; }
|
||||
if (type == ProcessingItem) { return "processing"; }
|
||||
if (type == DataItem) { return "data"; }
|
||||
if (type == DataCenterItem) { return "datacenter"; }
|
||||
if (type == StorageItem) { return "storage"; }
|
||||
if (type == WorkflowItem) { return "workflow"; }
|
||||
return "";
|
||||
}
|
||||
|
||||
bool isComputing(String topic) => topic == "computing";
|
||||
bool isComputing(String topic) => topic == "processing";
|
||||
bool isData(String topic) => topic == "data";
|
||||
bool isDataCenter(String topic) => topic == "datacenter";
|
||||
bool isStorage(String topic) => topic == "storage";
|
||||
bool isWorkflow(String topic) => topic == "workflow";
|
||||
|
||||
class ComputingItem extends SerializerDeserializer<ComputingItem> implements AbstractItem {
|
||||
ComputingItem({
|
||||
class ProcessingItem extends SerializerDeserializer<ProcessingItem> implements AbstractItem<ProcessingItem> {
|
||||
ProcessingItem({
|
||||
this.id,
|
||||
this.name,
|
||||
this.logo,
|
||||
this.type,
|
||||
this.owner,
|
||||
this.ownerLogo,
|
||||
this.price,
|
||||
this.image,
|
||||
this.command,
|
||||
this.source,
|
||||
this.licence,
|
||||
this.description,
|
||||
this.requirements,
|
||||
this.ports = _empty,
|
||||
this.shortDescription,
|
||||
this.dinputs = _empty,
|
||||
this.doutputs = _empty,
|
||||
this.arguments = _empty,
|
||||
this.environment = _empty,
|
||||
this.inputs = _empty,
|
||||
this.outputs = _empty,
|
||||
|
||||
this.cpus = const [],
|
||||
this.gpus = const [],
|
||||
this.ram,
|
||||
this.storage,
|
||||
this.parrallel = false,
|
||||
this.scallingModel,
|
||||
this.diskIO,
|
||||
|
||||
this.model,
|
||||
});
|
||||
@override ResourceModel? model;
|
||||
@override String? id;
|
||||
@override String? name;
|
||||
@override String? logo;
|
||||
@override String? type;
|
||||
@override String? source;
|
||||
@override String? ownerLogo;
|
||||
@override String? owner;
|
||||
@override String topic = "computing";
|
||||
double? price;
|
||||
String? image;
|
||||
String? command;
|
||||
String? licence;
|
||||
List<dynamic> ports;
|
||||
List<dynamic> dinputs;
|
||||
List<dynamic> doutputs;
|
||||
List<dynamic> arguments;
|
||||
@override String topic = "processing";
|
||||
@override double? price;
|
||||
@override String? licence;
|
||||
@override List<dynamic> inputs;
|
||||
@override List<dynamic> outputs;
|
||||
@override String? description;
|
||||
@override String? shortDescription;
|
||||
List<dynamic> environment;
|
||||
ExecRequirements? requirements;
|
||||
|
||||
// Special Attributes
|
||||
List<CPU> cpus = [];
|
||||
List<GPU> gpus = [];
|
||||
RAM? ram;
|
||||
int? storage;
|
||||
bool parrallel = false;
|
||||
int? scallingModel;
|
||||
String? diskIO;
|
||||
|
||||
@override String getID() {
|
||||
return id ?? "";
|
||||
}
|
||||
|
||||
@override String getName() {
|
||||
return name ?? "";
|
||||
}
|
||||
@override deserialize(dynamic json) {
|
||||
try { json = json as Map<String, dynamic>;
|
||||
} catch (e) { return ComputingItem(); }
|
||||
return ComputingItem(
|
||||
id: json.containsKey("ID") ? json["ID"] : null,
|
||||
} catch (e) { return ProcessingItem(); }
|
||||
return ProcessingItem(
|
||||
id: json.containsKey("id") ? json["id"] : null,
|
||||
name: json.containsKey("name") ? json["name"] : null,
|
||||
logo: json.containsKey("logo") ? json["logo"] : null,
|
||||
type: json.containsKey("type") ? json["type"] : null,
|
||||
owner: json.containsKey("owner") ? json["owner"] : null,
|
||||
ownerLogo: json.containsKey("owner_logo") ? json["owner_logo"] : null,
|
||||
price: json.containsKey("price") ? json["price"]?.toDouble() : null,
|
||||
image: json.containsKey("image") ? json["image"] : null,
|
||||
command: json.containsKey("command") ? json["command"] : null,
|
||||
licence: json.containsKey("licence") ? json["licence"] : null,
|
||||
description: json.containsKey("description") ? json["description"] : null,
|
||||
ports: json["ports"] ?? [],
|
||||
shortDescription: json.containsKey("short_description") ? json["short_description"] : null,
|
||||
dinputs: json["dinputs"] ?? [],
|
||||
doutputs: json["doutputs"] ?? [],
|
||||
arguments: json["arguments"] ?? [],
|
||||
environment: json["environment"] ?? [],
|
||||
requirements: json.containsKey("requirements") ? ExecRequirements().deserialize(json["execution_requirements"]) : null,
|
||||
inputs: json["inputs"] ?? [],
|
||||
outputs: json["outputs"] ?? [],
|
||||
source: json.containsKey("source") ? json["source"] : null,
|
||||
|
||||
model: json.containsKey("resource_model") ? ResourceModel().deserialize(json["resource_model"]) : null,
|
||||
cpus: json.containsKey("cpus") ? fromListJson(json["cpus"], CPU()) : [],
|
||||
gpus: json.containsKey("gpus") ? fromListJson(json["gpus"], GPU()) : [],
|
||||
ram: json.containsKey("ram") ? RAM().deserialize(json["ram"]) : null,
|
||||
storage: json.containsKey("storage") ? json["storage"] : null,
|
||||
parrallel: json.containsKey("parrallel") ? json["parrallel"] : false,
|
||||
scallingModel: json.containsKey("scalling_model") ? json["scalling_model"] : null,
|
||||
diskIO: json.containsKey("disk_io") ? json["disk_io"] : null,
|
||||
);
|
||||
}
|
||||
@override Map<String, dynamic> serialize() => {};
|
||||
@override Map<String, dynamic> serialize() => {
|
||||
"id": id,
|
||||
"name": name,
|
||||
"logo": logo,
|
||||
"owner": owner,
|
||||
"owner_logo": ownerLogo,
|
||||
"price": price,
|
||||
"licence": licence,
|
||||
"description": description,
|
||||
"short_description": shortDescription,
|
||||
"inputs": inputs,
|
||||
"outputs": outputs,
|
||||
"source": source,
|
||||
"resource_model": model?.serialize(),
|
||||
"cpus": toListJson<CPU>(cpus),
|
||||
"gpus": toListJson<GPU>(gpus),
|
||||
"ram": ram?.serialize(),
|
||||
"storage": storage,
|
||||
"parrallel": parrallel,
|
||||
"scalling_model": scallingModel,
|
||||
"disk_io": diskIO,
|
||||
};
|
||||
}
|
||||
|
||||
class ExecRequirements extends SerializerDeserializer<ExecRequirements> {
|
||||
ExecRequirements({
|
||||
this.ram,
|
||||
this.cpus,
|
||||
this.gpus,
|
||||
this.diskIO,
|
||||
this.scallingModel,
|
||||
this.parallel = false,
|
||||
class WorkflowItem extends SerializerDeserializer<WorkflowItem> implements AbstractItem<WorkflowItem> {
|
||||
WorkflowItem({
|
||||
this.id,
|
||||
this.name,
|
||||
this.logo,
|
||||
this.owner,
|
||||
this.ownerLogo,
|
||||
this.price,
|
||||
this.source,
|
||||
this.licence,
|
||||
this.description,
|
||||
this.shortDescription,
|
||||
this.inputs = _empty,
|
||||
this.outputs = _empty,
|
||||
this.model,
|
||||
this.workflowID,
|
||||
});
|
||||
double? ram;
|
||||
double? cpus;
|
||||
double? gpus;
|
||||
String? diskIO;
|
||||
bool parallel = false;
|
||||
double? scallingModel;
|
||||
@override ResourceModel? model;
|
||||
@override String? id;
|
||||
@override String? name;
|
||||
@override String? logo;
|
||||
@override String? source;
|
||||
@override String? ownerLogo;
|
||||
@override String? owner;
|
||||
@override String topic = "workflow";
|
||||
@override double? price;
|
||||
@override String? licence;
|
||||
@override List<dynamic> inputs;
|
||||
@override List<dynamic> outputs;
|
||||
@override String? description;
|
||||
@override String? shortDescription;
|
||||
|
||||
String? workflowID;
|
||||
@override String getID() {
|
||||
return id ?? "";
|
||||
}
|
||||
|
||||
@override String getName() {
|
||||
return name ?? "";
|
||||
}
|
||||
@override deserialize(dynamic json) {
|
||||
try { json = json as Map<String, dynamic>;
|
||||
} catch (e) { return ExecRequirements(); }
|
||||
return ExecRequirements(
|
||||
ram: json.containsKey("ram") ? json["ram"]?.toDouble() : null,
|
||||
cpus: json.containsKey("cpus") ? json["cpus"]?.toDouble() : null,
|
||||
gpus: json.containsKey("gpus") ? json["gpus"]?.toDouble() : null,
|
||||
diskIO: json.containsKey("disk_io") ? json["disk_io"] : null,
|
||||
scallingModel: json.containsKey("scaling_model") ? json["scaling_model"]?.toDouble() : null,
|
||||
parallel: json.containsKey("parallel") ? json["parallel"] : false,
|
||||
} catch (e) { return WorkflowItem(); }
|
||||
return WorkflowItem(
|
||||
id: json.containsKey("id") ? json["id"] : null,
|
||||
name: json.containsKey("name") ? json["name"] : null,
|
||||
logo: json.containsKey("logo") ? json["logo"] : null,
|
||||
owner: json.containsKey("owner") ? json["owner"] : null,
|
||||
ownerLogo: json.containsKey("owner_logo") ? json["owner_logo"] : null,
|
||||
price: json.containsKey("price") ? json["price"]?.toDouble() : null,
|
||||
licence: json.containsKey("licence") ? json["licence"] : null,
|
||||
description: json.containsKey("description") ? json["description"] : null,
|
||||
shortDescription: json.containsKey("short_description") ? json["short_description"] : null,
|
||||
inputs: json["inputs"] ?? [],
|
||||
outputs: json["outputs"] ?? [],
|
||||
source: json.containsKey("source") ? json["source"] : null,
|
||||
model: json.containsKey("resource_model") ? ResourceModel().deserialize(json["resource_model"]) : null,
|
||||
workflowID: json.containsKey("workflow_id") ? json["workflow_id"] : null,
|
||||
);
|
||||
}
|
||||
@override Map<String, dynamic> serialize() => {};
|
||||
@override Map<String, dynamic> serialize() => {
|
||||
"id": id,
|
||||
"name": name,
|
||||
"logo": logo,
|
||||
"owner": owner,
|
||||
"owner_logo": ownerLogo,
|
||||
"price": price,
|
||||
"licence": licence,
|
||||
"description": description,
|
||||
"short_description": shortDescription,
|
||||
"inputs": inputs,
|
||||
"outputs": outputs,
|
||||
"source": source,
|
||||
"resource_model": model?.serialize(),
|
||||
"workflow_id": workflowID,
|
||||
};
|
||||
}
|
||||
|
||||
class DataItem extends SerializerDeserializer<DataItem> implements AbstractItem {
|
||||
class DataItem extends SerializerDeserializer<DataItem> implements AbstractItem<DataItem> {
|
||||
DataItem({
|
||||
this.id,
|
||||
this.name,
|
||||
this.logo,
|
||||
this.type,
|
||||
this.dtype,
|
||||
this.owner,
|
||||
this.example,
|
||||
this.location,
|
||||
this.ownerLogo,
|
||||
this.price,
|
||||
this.source,
|
||||
this.licence,
|
||||
this.description,
|
||||
this.protocol = _empty,
|
||||
this.shortDescription,
|
||||
this.inputs = _empty,
|
||||
this.outputs = _empty,
|
||||
this.model,
|
||||
this.protocols = const [],
|
||||
this.dataType,
|
||||
this.exemple,
|
||||
});
|
||||
@override String? id;
|
||||
@override String? name;
|
||||
@override String? logo;
|
||||
@override String? type;
|
||||
@override String topic = "data";
|
||||
String? dtype;
|
||||
String? example;
|
||||
String? location;
|
||||
@override String? description;
|
||||
List<dynamic> protocol;
|
||||
@override String? shortDescription;
|
||||
@override String? source;
|
||||
@override String? ownerLogo;
|
||||
@override String? owner;
|
||||
|
||||
@override String topic = "data";
|
||||
@override double? price;
|
||||
@override String? licence;
|
||||
@override List<dynamic> inputs;
|
||||
@override List<dynamic> outputs;
|
||||
@override String? description;
|
||||
@override String? shortDescription;
|
||||
@override ResourceModel? model;
|
||||
// Special Attributes
|
||||
List<String> protocols = [];
|
||||
String? dataType;
|
||||
String? exemple;
|
||||
@override String getName() {
|
||||
return name ?? "";
|
||||
}
|
||||
@override String getID() {
|
||||
return id ?? "";
|
||||
}
|
||||
@override deserialize(dynamic json) {
|
||||
try { json = json as Map<String, dynamic>;
|
||||
} catch (e) { return DataItem(); }
|
||||
return DataItem(
|
||||
id: json.containsKey("ID") ? json["ID"] : null,
|
||||
id: json.containsKey("id") ? json["id"] : null,
|
||||
name: json.containsKey("name") ? json["name"] : null,
|
||||
logo: json.containsKey("logo") ? json["logo"] : null,
|
||||
type: json.containsKey("type") ? json["type"] : null,
|
||||
owner: json.containsKey("owner") ? json["owner"] : null,
|
||||
dtype: json.containsKey("dtype") ? json["dtype"] : null,
|
||||
example: json.containsKey("example") ? json["example"] : null,
|
||||
location: json.containsKey("location") ? json["location"] : null,
|
||||
ownerLogo: json.containsKey("owner_logo") ? json["owner_logo"] : null,
|
||||
price: json.containsKey("price") ? json["price"]?.toDouble() : null,
|
||||
licence: json.containsKey("licence") ? json["licence"] : null,
|
||||
description: json.containsKey("description") ? json["description"] : null,
|
||||
protocol: json["protocol"] ?? [],
|
||||
shortDescription: json.containsKey("short_description") ? json["short_description"] : null
|
||||
shortDescription: json.containsKey("short_description") ? json["short_description"] : null,
|
||||
inputs: json["inputs"] ?? [],
|
||||
outputs: json["outputs"] ?? [],
|
||||
source: json.containsKey("source") ? json["source"] : null,
|
||||
model: json.containsKey("resource_model") ? ResourceModel().deserialize(json["resource_model"]) : null,
|
||||
protocols: json.containsKey("protocols") ? json["protocols"] : [],
|
||||
dataType: json.containsKey("data_type") ? json["data_type"] : null,
|
||||
exemple: json.containsKey("exemple") ? json["exemple"] : null,
|
||||
);
|
||||
}
|
||||
@override Map<String, dynamic> serialize() => {};
|
||||
@override Map<String, dynamic> serialize() => {
|
||||
"id": id,
|
||||
"name": name,
|
||||
"logo": logo,
|
||||
"owner": owner,
|
||||
"owner_logo": ownerLogo,
|
||||
"price": price,
|
||||
"licence": licence,
|
||||
"description": description,
|
||||
"short_description": shortDescription,
|
||||
"inputs": inputs,
|
||||
"outputs": outputs,
|
||||
"source": source,
|
||||
"resource_model": model?.serialize(),
|
||||
"protocols": protocols,
|
||||
"data_type": dataType,
|
||||
"exemple": exemple,
|
||||
};
|
||||
}
|
||||
const List<GPU> _emptyGPU = [];
|
||||
class DataCenterItem extends SerializerDeserializer<DataCenterItem> implements AbstractItem {
|
||||
|
||||
class DataCenterItem extends SerializerDeserializer<DataCenterItem> implements AbstractItem<DataCenterItem> {
|
||||
DataCenterItem({
|
||||
this.id,
|
||||
this.cpu,
|
||||
this.ram,
|
||||
this.name,
|
||||
this.logo,
|
||||
this.type,
|
||||
this.owner,
|
||||
this.acronym,
|
||||
this.bookingPrice,
|
||||
this.ownerLogo,
|
||||
this.price,
|
||||
this.source,
|
||||
this.licence,
|
||||
this.description,
|
||||
this.hosts = _empty,
|
||||
this.gpus = _emptyGPU,
|
||||
this.shortDescription,
|
||||
this.inputs = _empty,
|
||||
this.outputs = _empty,
|
||||
this.model,
|
||||
this.cpus = const [],
|
||||
this.gpus = const [],
|
||||
this.ram,
|
||||
});
|
||||
CPU? cpu;
|
||||
RAM? ram;
|
||||
@override String? id;
|
||||
@override String? name;
|
||||
@override String? logo;
|
||||
@override String? type;
|
||||
@override String? source;
|
||||
@override String? ownerLogo;
|
||||
@override String? owner;
|
||||
@override String topic = "datacenter";
|
||||
String? acronym;
|
||||
List<GPU> gpus = [];
|
||||
@override double? price;
|
||||
@override String? licence;
|
||||
@override List<dynamic> inputs;
|
||||
@override List<dynamic> outputs;
|
||||
@override String? description;
|
||||
List<dynamic> hosts;
|
||||
double? bookingPrice;
|
||||
@override String? shortDescription;
|
||||
|
||||
@override ResourceModel? model;
|
||||
// Special Attributes
|
||||
List<CPU> cpus = [];
|
||||
List<GPU> gpus = [];
|
||||
RAM? ram;
|
||||
@override String getID() {
|
||||
return id ?? "";
|
||||
}
|
||||
@override String getName() {
|
||||
return name ?? "";
|
||||
}
|
||||
@override deserialize(dynamic json) {
|
||||
try { json = json as Map<String, dynamic>;
|
||||
} catch (e) { return DataCenterItem(); }
|
||||
return DataCenterItem(
|
||||
id: json.containsKey("ID") ? json["ID"] : null,
|
||||
ram: json.containsKey("ram") ? RAM().deserialize(json["ram"]) : null,
|
||||
cpu: json.containsKey("cpu") ? CPU().deserialize(json["cpu"]) : null,
|
||||
acronym: json.containsKey("acronym") ? json["acronym"] : null,
|
||||
id: json.containsKey("id") ? json["id"] : null,
|
||||
name: json.containsKey("name") ? json["name"] : null,
|
||||
logo: json.containsKey("logo") ? json["logo"] : null,
|
||||
type: json.containsKey("type") ? json["type"] : null,
|
||||
owner: json.containsKey("owner") ? json["owner"] : null,
|
||||
bookingPrice: json.containsKey("bookingPrice") ? json["bookingPrice"]?.toDouble() : null,
|
||||
ownerLogo: json.containsKey("owner_logo") ? json["owner_logo"] : null,
|
||||
price: json.containsKey("price") ? json["price"]?.toDouble() : null,
|
||||
licence: json.containsKey("licence") ? json["licence"] : null,
|
||||
description: json.containsKey("description") ? json["description"] : null,
|
||||
hosts: json["hosts"] ?? [],
|
||||
shortDescription: json.containsKey("short_description") ? json["short_description"] : null,
|
||||
gpus: json.containsKey("gpus") ? fromListJson(json["gpus"] ?? [], GPU()) : [],
|
||||
inputs: json["inputs"] ?? [],
|
||||
outputs: json["outputs"] ?? [],
|
||||
source: json.containsKey("source") ? json["source"] : null,
|
||||
model: json.containsKey("resource_model") ? ResourceModel().deserialize(json["resource_model"]) : null,
|
||||
cpus: json.containsKey("cpus") ? fromListJson(json["cpus"], CPU()) : [],
|
||||
gpus: json.containsKey("gpus") ? fromListJson(json["gpus"], GPU()) : [],
|
||||
ram: json.containsKey("ram") ? RAM().deserialize(json["ram"]) : null,
|
||||
);
|
||||
}
|
||||
@override Map<String, dynamic> serialize() => {};
|
||||
@override Map<String, dynamic> serialize() => {
|
||||
"id": id,
|
||||
"name": name,
|
||||
"logo": logo,
|
||||
"owner": owner,
|
||||
"owner_logo": ownerLogo,
|
||||
"price": price,
|
||||
"licence": licence,
|
||||
"description": description,
|
||||
"short_description": shortDescription,
|
||||
"inputs": inputs,
|
||||
"outputs": outputs,
|
||||
"source": source,
|
||||
"resource_model": model?.serialize(),
|
||||
"cpus": toListJson<CPU>(cpus),
|
||||
"gpus": toListJson<GPU>(gpus),
|
||||
"ram": ram?.serialize(),
|
||||
};
|
||||
}
|
||||
class CPU extends SerializerDeserializer<CPU> {
|
||||
CPU({
|
||||
@@ -279,7 +571,13 @@ class CPU extends SerializerDeserializer<CPU> {
|
||||
shared: json.containsKey("shared") ? json["shared"] : false,
|
||||
);
|
||||
}
|
||||
@override Map<String, dynamic> serialize() => {};
|
||||
@override Map<String, dynamic> serialize() => {
|
||||
"cores": cores,
|
||||
"platform": platform,
|
||||
"architecture": architecture,
|
||||
"minimumMemory": minimumMemory,
|
||||
"shared": shared,
|
||||
};
|
||||
}
|
||||
class GPU extends SerializerDeserializer<GPU> {
|
||||
GPU({
|
||||
@@ -303,7 +601,12 @@ class GPU extends SerializerDeserializer<GPU> {
|
||||
tensorCores: json.containsKey("tensor_cores") ? json["tensor_cores"]?.toDouble() : null,
|
||||
);
|
||||
}
|
||||
@override Map<String, dynamic> serialize() => {};
|
||||
@override Map<String, dynamic> serialize() => {
|
||||
"cuda_cores": cudaCores,
|
||||
"memory": memory,
|
||||
"model": model,
|
||||
"tensor_cores": tensorCores,
|
||||
};
|
||||
}
|
||||
class RAM extends SerializerDeserializer<RAM> {
|
||||
RAM({
|
||||
@@ -321,61 +624,108 @@ class RAM extends SerializerDeserializer<RAM> {
|
||||
size: json.containsKey("size") ? json["size"]?.toDouble() : null,
|
||||
);
|
||||
}
|
||||
@override Map<String, dynamic> serialize() => {};
|
||||
@override Map<String, dynamic> serialize() => {
|
||||
"ecc": ecc,
|
||||
"size": size,
|
||||
};
|
||||
}
|
||||
class StorageItem extends SerializerDeserializer<StorageItem> implements AbstractItem {
|
||||
class StorageItem extends SerializerDeserializer<StorageItem> implements AbstractItem<StorageItem> {
|
||||
StorageItem({
|
||||
this.id,
|
||||
this.url,
|
||||
this.size,
|
||||
this.name,
|
||||
this.logo,
|
||||
this.type,
|
||||
this.owner,
|
||||
this.acronym,
|
||||
this.throughput,
|
||||
this.redundancy,
|
||||
this.ownerLogo,
|
||||
this.price,
|
||||
this.source,
|
||||
this.licence,
|
||||
this.description,
|
||||
this.bookingPrice,
|
||||
this.shortDescription,
|
||||
this.inputs = _empty,
|
||||
this.outputs = _empty,
|
||||
this.acronym,
|
||||
this.type,
|
||||
this.size,
|
||||
this.url,
|
||||
this.encryption = false,
|
||||
this.redundancy,
|
||||
this.throughput,
|
||||
this.model,
|
||||
});
|
||||
@override String? id;
|
||||
String? url;
|
||||
@override String? name;
|
||||
@override String? logo;
|
||||
@override String? type;
|
||||
@override String? id;
|
||||
@override String? name;
|
||||
@override String? logo;
|
||||
@override String? source;
|
||||
@override String? ownerLogo;
|
||||
@override String? owner;
|
||||
@override String topic = "storage";
|
||||
double? size;
|
||||
@override String? owner;
|
||||
@override double? price;
|
||||
@override String? licence;
|
||||
@override List<dynamic> inputs;
|
||||
@override List<dynamic> outputs;
|
||||
@override String? description;
|
||||
@override String? shortDescription;
|
||||
@override ResourceModel? model;
|
||||
// special attributes
|
||||
String? acronym;
|
||||
String? type;
|
||||
int? size;
|
||||
String? url;
|
||||
bool encryption = false;
|
||||
String? redundancy;
|
||||
String? throughput;
|
||||
@override String? description;
|
||||
double? bookingPrice;
|
||||
bool encryption = false;
|
||||
@override String? shortDescription;
|
||||
|
||||
|
||||
@override String getName() {
|
||||
return name ?? "";
|
||||
}
|
||||
@override String getID() {
|
||||
return id ?? "";
|
||||
}
|
||||
@override deserialize(dynamic json) {
|
||||
try { json = json as Map<String, dynamic>;
|
||||
} catch (e) { return StorageItem(); }
|
||||
return StorageItem(
|
||||
id: json.containsKey("ID") ? json["ID"] : null,
|
||||
url: json.containsKey("URL") ? json["URL"] : null,
|
||||
size: json.containsKey("size") ? json["size"]?.toDouble() : null,
|
||||
id: json.containsKey("id") ? json["id"] : null,
|
||||
name: json.containsKey("name") ? json["name"] : null,
|
||||
logo: json.containsKey("logo") ? json["logo"] : null,
|
||||
type: json.containsKey("type") ? json["type"] : null,
|
||||
owner: json.containsKey("owner") ? json["owner"] : null,
|
||||
acronym: json.containsKey("DCacronym") ? json["DCacronym"] : null,
|
||||
bookingPrice: json.containsKey("bookingPrice") ? json["bookingPrice"]?.toDouble() : null,
|
||||
ownerLogo: json.containsKey("owner_logo") ? json["owner_logo"] : null,
|
||||
price: json.containsKey("price") ? json["price"]?.toDouble() : null,
|
||||
licence: json.containsKey("licence") ? json["licence"] : null,
|
||||
description: json.containsKey("description") ? json["description"] : null,
|
||||
throughput: json.containsKey("throughput") ? json["throughput"] : [],
|
||||
shortDescription: json.containsKey("short_description") ? json["short_description"] : null,
|
||||
redundancy: json.containsKey("redundancy") ? json["redundancy"] : [],
|
||||
inputs: json["inputs"] ?? [],
|
||||
outputs: json["outputs"] ?? [],
|
||||
source: json.containsKey("source") ? json["source"] : null,
|
||||
model: json.containsKey("resource_model") ? ResourceModel().deserialize(json["resource_model"]) : null,
|
||||
acronym: json.containsKey("acronym") ? json["acronym"] : null,
|
||||
type: json.containsKey("type") ? json["type"] : null,
|
||||
size: json.containsKey("size") ? json["size"] : null,
|
||||
url: json.containsKey("url") ? json["url"] : null,
|
||||
encryption: json.containsKey("encryption") ? json["encryption"] : false,
|
||||
redundancy: json.containsKey("redundancy") ? json["redundancy"] : null,
|
||||
throughput: json.containsKey("throughput") ? json["throughput"] : null,
|
||||
);
|
||||
}
|
||||
@override Map<String, dynamic> serialize() => {};
|
||||
@override Map<String, dynamic> serialize() => {
|
||||
"id": id,
|
||||
"name": name,
|
||||
"logo": logo,
|
||||
"owner": owner,
|
||||
"owner_logo": ownerLogo,
|
||||
"price": price,
|
||||
"licence": licence,
|
||||
"description": description,
|
||||
"short_description": shortDescription,
|
||||
"inputs": inputs,
|
||||
"outputs": outputs,
|
||||
"source": source,
|
||||
"resource_model": model?.serialize(),
|
||||
"acronym": acronym,
|
||||
"type": type,
|
||||
"size": size,
|
||||
"url": url,
|
||||
"encryption": encryption,
|
||||
"redundancy": redundancy,
|
||||
"throughput": throughput,
|
||||
};
|
||||
}
|
||||
559
lib/models/workflow.dart
Normal file
559
lib/models/workflow.dart
Normal file
@@ -0,0 +1,559 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_colorpicker/flutter_colorpicker.dart';
|
||||
import 'package:flutter_flow_chart/flutter_flow_chart.dart';
|
||||
import 'package:oc_front/core/models/workspace_local.dart';
|
||||
import 'package:oc_front/models/abstract.dart';
|
||||
import 'package:oc_front/models/search.dart';
|
||||
|
||||
class WorkflowExecutions extends SerializerDeserializer<WorkflowExecutions> {
|
||||
List<WorkflowExecution> executions = [];
|
||||
String? executionData;
|
||||
int? status;
|
||||
String? workflowId;
|
||||
|
||||
WorkflowExecutions({
|
||||
this.executions = const [],
|
||||
});
|
||||
|
||||
@override deserialize(dynamic json) {
|
||||
try { json = json as List<dynamic>;
|
||||
} catch (e) { return WorkflowExecutions(); }
|
||||
return WorkflowExecutions(
|
||||
executions: fromListJson(json, WorkflowExecution()),
|
||||
);
|
||||
}
|
||||
|
||||
@override Map<String, dynamic> serialize() {
|
||||
return {};
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class WorkflowExecution extends SerializerDeserializer<WorkflowExecution> {
|
||||
String? id;
|
||||
String? name;
|
||||
String? executionData;
|
||||
String? endDate;
|
||||
int? status;
|
||||
String? workflowId;
|
||||
|
||||
|
||||
WorkflowExecution({
|
||||
this.id,
|
||||
this.executionData,
|
||||
this.status,
|
||||
this.workflowId,
|
||||
this.name,
|
||||
this.endDate,
|
||||
});
|
||||
|
||||
@override deserialize(dynamic json) {
|
||||
try { json = json as Map<String, dynamic>;
|
||||
} catch (e) { return WorkflowExecution(); }
|
||||
return WorkflowExecution(
|
||||
id: json.containsKey("id") ? json["id"] : "",
|
||||
endDate: json.containsKey("end_date") ? json["end_date"] : "",
|
||||
executionData: json.containsKey("execution_date") ? json["execution_date"] : "",
|
||||
status: json.containsKey("status") ? json["status"] : 1,
|
||||
workflowId: json.containsKey("workflow_id") ? json["workflow_id"] : "",
|
||||
name: json.containsKey("name") ? json["name"] : "",
|
||||
);
|
||||
}
|
||||
|
||||
@override Map<String, dynamic> serialize() {
|
||||
return {
|
||||
"id": id,
|
||||
"name": name,
|
||||
"end_date": endDate,
|
||||
"execution_data": executionData,
|
||||
"status": status,
|
||||
"workflow_id": workflowId,
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class Workflow extends SerializerDeserializer<Workflow> {
|
||||
String? id;
|
||||
String? name;
|
||||
List<dynamic> data;
|
||||
List<dynamic> datacenter;
|
||||
List<dynamic> storage;
|
||||
List<dynamic> processing;
|
||||
List<dynamic> workflows;
|
||||
Graph? graph;
|
||||
Scheduler? schedule;
|
||||
|
||||
Workflow({
|
||||
this.id,
|
||||
this.name = "",
|
||||
this.data = const [],
|
||||
this.datacenter = const [],
|
||||
this.storage = const [],
|
||||
this.processing = const [],
|
||||
this.workflows = const [],
|
||||
this.graph,
|
||||
this.schedule,
|
||||
});
|
||||
|
||||
String getID() {
|
||||
return id ?? "";
|
||||
}
|
||||
|
||||
@override deserialize(dynamic json) {
|
||||
try { json = json as Map<String, dynamic>;
|
||||
} catch (e) { return Workflow(); }
|
||||
return Workflow(
|
||||
id: json.containsKey("id") ? json["id"] : "",
|
||||
name: json.containsKey("name") ? json["name"] : "",
|
||||
workflows: json.containsKey("workflows") ? json["workflows"] : [],
|
||||
processing: json.containsKey("processings") ? json["processings"] : [],
|
||||
datacenter: json.containsKey("datacenters") ? json["datacenters"] : [],
|
||||
data: json.containsKey("datas") ? json["datas"] : [],
|
||||
storage: json.containsKey("storages") ? json["storages"] : [],
|
||||
graph: json.containsKey("graph") ? Graph().deserialize(json["graph"]) : null,
|
||||
schedule: json.containsKey("schedule") ? Scheduler().deserialize(json["schedule"]) : null,
|
||||
);
|
||||
}
|
||||
@override Map<String, dynamic> serialize() {
|
||||
var obj = {
|
||||
"id": id,
|
||||
"name": name,
|
||||
"datas": data,
|
||||
"datacenters" : datacenter,
|
||||
"storages": storage,
|
||||
"processings": processing,
|
||||
"workflows": workflows,
|
||||
"schedule": schedule?.serialize(),
|
||||
};
|
||||
if (graph != null) {
|
||||
obj["graph"] = graph!.serialize();
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
||||
void fromDashboard(Map<String, dynamic> j) {
|
||||
id = j["id"];
|
||||
name = j["name"];
|
||||
if (j.containsKey("graph")) {
|
||||
graph = Graph();
|
||||
graph!.fromDashboard(j["graph"]);
|
||||
}
|
||||
if (j.containsKey("schedule")) {
|
||||
schedule = Scheduler();
|
||||
schedule!.fromDashboard(j["schedule"]);
|
||||
}
|
||||
}
|
||||
Map<String, dynamic> toDashboard() {
|
||||
return {
|
||||
"id": id,
|
||||
"name": name,
|
||||
"graph": graph?.toDashboard(),
|
||||
"schedule": schedule?.toDashboard(),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
class Scheduler extends SerializerDeserializer<Scheduler> {
|
||||
String? id;
|
||||
String? name;
|
||||
String? cron;
|
||||
DateTime? start;
|
||||
DateTime? end;
|
||||
|
||||
Scheduler({
|
||||
this.id,
|
||||
this.name,
|
||||
this.cron,
|
||||
this.start,
|
||||
this.end
|
||||
});
|
||||
|
||||
void fromDashboard(Map<String, dynamic> j) {
|
||||
id = j["id"];
|
||||
name = j["name"];
|
||||
cron = j["cron"];
|
||||
start = DateTime.parse(j["start"]);
|
||||
if (j.containsKey("end") && j["end"] != null) {
|
||||
end = DateTime.parse(j["end"]);
|
||||
}
|
||||
|
||||
}
|
||||
Map<String, dynamic> toDashboard() {
|
||||
return {
|
||||
"id": id,
|
||||
"name": name,
|
||||
"cron": cron,
|
||||
"start": start?.toIso8601String(),
|
||||
"end": end?.toIso8601String(),
|
||||
};
|
||||
}
|
||||
|
||||
@override deserialize(dynamic json) {
|
||||
try { json = json as Map<String, dynamic>;
|
||||
} catch (e) { return Scheduler(); }
|
||||
return Scheduler(
|
||||
id: json.containsKey("id") ? json["id"] : null,
|
||||
name: json.containsKey("name") ? json["name"] : "",
|
||||
cron: json.containsKey("cron") ? json["cron"] : "",
|
||||
start: json.containsKey("start") ? DateTime.parse(json["start"]) : null,
|
||||
end: json.containsKey("end") ? DateTime.parse(json["end"]) : null,
|
||||
);
|
||||
}
|
||||
@override Map<String, dynamic> serialize() => {
|
||||
"id": id,
|
||||
"name": name,
|
||||
"cron": cron ?? "",
|
||||
"start": start?.toIso8601String(),
|
||||
"end": end?.toIso8601String(),
|
||||
};
|
||||
}
|
||||
class Graph extends SerializerDeserializer<Graph> {
|
||||
double zoom;
|
||||
Map<String, GraphItem> items = {};
|
||||
List<GraphLink> links = [];
|
||||
|
||||
Graph({
|
||||
this.zoom = 1,
|
||||
this.items = const {},
|
||||
this.links = const [],
|
||||
});
|
||||
|
||||
void fromDashboard(Map<String, dynamic> j) {
|
||||
items = {};
|
||||
for (var el in (j["elements"] as Map<dynamic, dynamic>).values) {
|
||||
var d = GraphItem();
|
||||
d.fromDashboard(el as Map<String, dynamic>);
|
||||
items[d.id ?? ""] = d;
|
||||
}
|
||||
links = (j["arrows"] as List<dynamic>).map( (el) {
|
||||
var d = GraphLink();
|
||||
d.fromDashboard(el);
|
||||
return d;
|
||||
}).toList();
|
||||
j["zoom"] = zoom;
|
||||
}
|
||||
|
||||
Map<String, dynamic> toDashboard() {
|
||||
List<Map<String, dynamic>> elements = [];
|
||||
List<Map<String, dynamic>> arrows = [];
|
||||
for (var el in items.values) {
|
||||
elements.add(el.toDashboard());
|
||||
}
|
||||
for (var l in links) {
|
||||
arrows.add(l.toDashboard());
|
||||
}
|
||||
return {
|
||||
"zoom": zoom,
|
||||
"elements": elements,
|
||||
"arrows": arrows,
|
||||
};
|
||||
}
|
||||
|
||||
@override deserialize(dynamic json) {
|
||||
try { json = json as Map<String, dynamic>;
|
||||
} catch (e) { return Graph(); }
|
||||
return Graph(
|
||||
zoom: json.containsKey("zoom") ? double.parse(json["zoom"].toString()) : 0,
|
||||
links: json.containsKey("links") ? fromListJson(json["links"], GraphLink()) : [],
|
||||
items: json.containsKey("items") ? fromMapJson<GraphItem>(json["items"], GraphItem()) : {},
|
||||
);
|
||||
}
|
||||
@override Map<String, dynamic> serialize() => {
|
||||
"zoom": zoom,
|
||||
"items": toMapJson(items),
|
||||
"links": toListJson(links),
|
||||
};
|
||||
}
|
||||
|
||||
class GraphLink extends SerializerDeserializer<GraphLink> {
|
||||
Position? source;
|
||||
Position? destination;
|
||||
GraphLinkStyle? style;
|
||||
|
||||
GraphLink({
|
||||
this.source,
|
||||
this.destination,
|
||||
this.style,
|
||||
});
|
||||
|
||||
void fromDashboard(Map<String, dynamic> j) {
|
||||
source = Position(id: j["from"]["id"], x: j["from"]["x"], y: j["from"]["y"]);
|
||||
destination = Position(id: j["to"]["id"], x: j["to"]["x"], y: j["to"]["y"]);
|
||||
style = GraphLinkStyle();
|
||||
style!.fromDashboard(j["params"]);
|
||||
}
|
||||
|
||||
Map<String, dynamic> toDashboard() {
|
||||
return {
|
||||
"from": {
|
||||
"id": source?.id ?? "",
|
||||
"x" : source?.x ?? 0,
|
||||
"y": source?.y ?? 0,
|
||||
},
|
||||
"to": {
|
||||
"id": destination?.id ?? "",
|
||||
"x" : destination?.x ?? 0,
|
||||
"y": destination?.y ?? 0,
|
||||
},
|
||||
"params": style?.toDashboard(),
|
||||
};
|
||||
}
|
||||
|
||||
@override deserialize(dynamic json) {
|
||||
try { json = json as Map<String, dynamic>;
|
||||
} catch (e) { return GraphLink(); }
|
||||
return GraphLink(
|
||||
source: json.containsKey("source") ? Position().deserialize(json["source"]) : null,
|
||||
destination: json.containsKey("destination") ? Position().deserialize(json["destination"]) : null,
|
||||
style: json.containsKey("style") ? GraphLinkStyle().deserialize(json["style"]) : null,
|
||||
);
|
||||
}
|
||||
@override Map<String, dynamic> serialize() {
|
||||
var obj = <String, dynamic>{};
|
||||
if (source != null) {
|
||||
obj["source"] = source!.serialize();
|
||||
}
|
||||
if (destination != null) {
|
||||
obj["destination"] = destination!.serialize();
|
||||
}
|
||||
if (style != null) {
|
||||
obj["style"] = style!.serialize();
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
}
|
||||
|
||||
class GraphLinkStyle extends SerializerDeserializer<GraphLinkStyle> {
|
||||
Color color = Colors.black;
|
||||
double stroke = 1;
|
||||
double tension = 23;
|
||||
double headRadius = 10;
|
||||
double dashWidth = 0;
|
||||
double dashSpace = 0;
|
||||
double startArrowWidth = 1;
|
||||
double endArrowWidth = 10;
|
||||
Position? startArrow;
|
||||
Position? endArrow;
|
||||
ArrowStyle arrowStyle = ArrowStyle.curve;
|
||||
ArrowDirection arrowDirection = ArrowDirection.forward;
|
||||
|
||||
GraphLinkStyle({
|
||||
this.color = Colors.black,
|
||||
this.stroke = 1,
|
||||
this.tension = 23,
|
||||
this.headRadius = 10,
|
||||
this.dashWidth = 0,
|
||||
this.dashSpace = 0,
|
||||
this.startArrowWidth = 10,
|
||||
this.endArrowWidth = 10,
|
||||
this.startArrow,
|
||||
this.endArrow,
|
||||
this.arrowStyle = ArrowStyle.curve,
|
||||
this.arrowDirection = ArrowDirection.forward
|
||||
});
|
||||
|
||||
void fromDashboard(Map<String, dynamic> j) {
|
||||
dashSpace = j["dash_space"];
|
||||
dashWidth = j["dash_width"];
|
||||
endArrowWidth = j["backward_arrow_width"];
|
||||
startArrowWidth = j["forward_arrow_width"];
|
||||
stroke = j["thickness"];
|
||||
arrowDirection = ArrowDirection.values.firstWhere((element) => element.index == j["direction"]);
|
||||
headRadius = j["head_radius"];
|
||||
color = Color(j["color"]);
|
||||
arrowStyle = ArrowStyle.values.firstWhere((element) => element.index == j["arrow_style"]);
|
||||
tension = j["tension"];
|
||||
startArrow = Position(x: j["start_arrow_position_x"], y: j["start_arrow_position_y"]);
|
||||
endArrow = Position(x: j["end_arrow_position_x"], y: j["end_arrow_position_y"]);
|
||||
}
|
||||
|
||||
Map<String, dynamic> toDashboard() {
|
||||
return {
|
||||
"dash_space": dashSpace,
|
||||
"dash_width": dashWidth,
|
||||
"backward_arrow_width": endArrowWidth,
|
||||
"forward_arrow_width": startArrowWidth,
|
||||
"thickness": stroke,
|
||||
"direction": arrowDirection.index,
|
||||
"head_radius": headRadius,
|
||||
"tail_length": 25.0,
|
||||
"color": int.parse(color.toHexString(), radix: 16),
|
||||
"arrow_style" : arrowStyle.index,
|
||||
"tension" : tension,
|
||||
"start_arrow_position_x": startArrow?.x ?? 0,
|
||||
"start_arrow_position_y": startArrow?.y ?? 0,
|
||||
"end_arrow_position_x": endArrow?.x ?? 0,
|
||||
"end_arrow_position_y": endArrow?.y ?? 0,
|
||||
};
|
||||
}
|
||||
|
||||
@override deserialize(dynamic json) {
|
||||
try { json = json as Map<String, dynamic>;
|
||||
} catch (e) { return GraphLinkStyle(); }
|
||||
return GraphLinkStyle(
|
||||
color: json.containsKey("color") ? Color(json["color"] as int) : Colors.black,
|
||||
stroke: json.containsKey("stroke") ? double.parse(json["stroke"].toString()) : 0,
|
||||
tension: json.containsKey("tension") ? double.parse(json["tension"].toString()) : 0,
|
||||
headRadius: json.containsKey("head_radius") ? double.parse(json["head_radius"].toString()) : 0,
|
||||
dashWidth: json.containsKey("dash_width") ? double.parse(json["dash_width"].toString()) : 0,
|
||||
dashSpace: json.containsKey("dash_space") ? double.parse(json["dash_space"].toString()) : 0,
|
||||
startArrow: json.containsKey("start_arrow") ? Position().deserialize(json["start_arrow"]) : null,
|
||||
endArrow: json.containsKey("end_arrow") ? Position().deserialize(json["end_arrow"]) : null,
|
||||
arrowDirection: json.containsKey("arrow_direction") ? ArrowDirection.values.firstWhere((el) => el.index == json["arrow_direction"]) : ArrowDirection.forward,
|
||||
arrowStyle: json.containsKey("arrow_style") ? ArrowStyle.values.firstWhere((el) => el.index == json["arrow_style"]) : ArrowStyle.curve,
|
||||
startArrowWidth: json.containsKey("start_arrow_width") ? double.parse(json["start_arrow_width"].toString()) : 0,
|
||||
endArrowWidth: json.containsKey("end_arrow_width") ? double.parse(json["end_arrow_width"].toString()) : 0,
|
||||
);
|
||||
}
|
||||
@override Map<String, dynamic> serialize() {
|
||||
var obj = <String, dynamic> {
|
||||
"color" : int.parse(color.toHexString(), radix: 16),
|
||||
"stroke" : stroke,
|
||||
"tension" : tension,
|
||||
"head_radius" : headRadius,
|
||||
"dash_width" : dashWidth,
|
||||
"dash_space" : dashSpace,
|
||||
"arrow_direction" : arrowDirection.index,
|
||||
"arrow_style" : arrowStyle.index,
|
||||
"start_arrow_width" : startArrowWidth,
|
||||
"end_arrow_width" : endArrowWidth,
|
||||
};
|
||||
if (startArrow != null) {
|
||||
obj["start_arrow"] = startArrow!.serialize();
|
||||
}
|
||||
if (endArrow != null) {
|
||||
obj["end_arrow"] = endArrow!.serialize();
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
}
|
||||
|
||||
class GraphItem extends SerializerDeserializer<GraphItem> {
|
||||
String? id;
|
||||
double? width;
|
||||
double? height;
|
||||
Position? position;
|
||||
DataItem? data;
|
||||
ProcessingItem? processing;
|
||||
StorageItem? storage;
|
||||
DataCenterItem? datacenter;
|
||||
WorkflowItem? workflow;
|
||||
|
||||
GraphItem({
|
||||
this.id,
|
||||
this.width,
|
||||
this.height,
|
||||
this.position,
|
||||
this.data,
|
||||
this.processing,
|
||||
this.storage,
|
||||
this.datacenter,
|
||||
this.workflow,
|
||||
});
|
||||
|
||||
void fromDashboard(Map<String, dynamic> j) {
|
||||
id = j["id"];
|
||||
position = Position(x: j["x"], y: j["y"]);
|
||||
width = j["width"];
|
||||
height = j["height"];
|
||||
|
||||
var abs = WorkspaceLocal.getItem(j["element"]?["id"] ?? "", true) as AbstractItem<FlowData>?;
|
||||
if (abs != null) {
|
||||
if (abs.topic == "data") {
|
||||
data = DataItem().deserialize(abs.serialize());
|
||||
data!.model = ResourceModel().deserialize(j["element"]["resource_model"]);
|
||||
}
|
||||
if (abs.topic == "processing") {
|
||||
processing = ProcessingItem().deserialize(abs.serialize());
|
||||
processing!.model = ResourceModel().deserialize(j["element"]["resource_model"]);
|
||||
}
|
||||
if (abs.topic == "datacenter") {
|
||||
datacenter = DataCenterItem().deserialize(abs.serialize());
|
||||
datacenter!.model = ResourceModel().deserialize(j["element"]["resource_model"]);
|
||||
}
|
||||
if (abs.topic == "storage") {
|
||||
storage = StorageItem().deserialize(abs.serialize());
|
||||
storage!.model = ResourceModel().deserialize(j["element"]["resource_model"]);
|
||||
}
|
||||
if (abs.topic == "workflow") {
|
||||
workflow = WorkflowItem().deserialize(abs.serialize());
|
||||
workflow!.model = ResourceModel().deserialize(j["element"]["resource_model"]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Map<String, dynamic> toDashboard() {
|
||||
Map<String, dynamic> element = {};
|
||||
for(var el in [data, processing, storage, datacenter, workflow]) {
|
||||
if (el != null && el.getID() != "") {
|
||||
element = el.serialize();
|
||||
break;
|
||||
}
|
||||
}
|
||||
return {
|
||||
"id": id,
|
||||
"x": (position?.x ?? 0),
|
||||
"y": (position?.y ?? 0),
|
||||
"width": width ?? 0,
|
||||
"height": height ?? 0,
|
||||
"element": element,
|
||||
};
|
||||
}
|
||||
|
||||
@override deserialize(dynamic json) {
|
||||
try { json = json as Map<String, dynamic>;
|
||||
} catch (e) { return GraphItem(); }
|
||||
return GraphItem(
|
||||
id: json.containsKey("id") ? json["id"] : null,
|
||||
width: json.containsKey("width") ? double.parse(json["width"].toString()) : null,
|
||||
height: json.containsKey("height") ? double.parse(json["height"].toString()) : null,
|
||||
position: json.containsKey("position") ? Position().deserialize(json["position"]) : null,
|
||||
data: json.containsKey("data") ? DataItem().deserialize(json["data"]) : null,
|
||||
processing: json.containsKey("processing") ? ProcessingItem().deserialize(json["processing"]) : null,
|
||||
storage: json.containsKey("storage") ? StorageItem().deserialize(json["storage"]) : null,
|
||||
datacenter: json.containsKey("datacenter") ? DataCenterItem().deserialize(json["datacenter"]) : null,
|
||||
workflow: json.containsKey("workflow") ? WorkflowItem().deserialize(json["workflow"]) : null,
|
||||
);
|
||||
}
|
||||
@override Map<String, dynamic> serialize() {
|
||||
return {
|
||||
"id": id,
|
||||
"width": width,
|
||||
"height": height,
|
||||
"data": data?.serialize(),
|
||||
"processing": processing?.serialize(),
|
||||
"storage": storage?.serialize(),
|
||||
"datacenter": datacenter?.serialize(),
|
||||
"workflow": workflow?.serialize(),
|
||||
"position": position?.serialize(),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
class Position extends SerializerDeserializer<Position> {
|
||||
String? id;
|
||||
double? x;
|
||||
double? y;
|
||||
|
||||
Position({
|
||||
this.id,
|
||||
this.x,
|
||||
this.y,
|
||||
});
|
||||
|
||||
@override deserialize(dynamic json) {
|
||||
try { json = json as Map<String, dynamic>;
|
||||
} catch (e) { return Position(); }
|
||||
return Position(
|
||||
id: json.containsKey("id") ? json["id"] : null,
|
||||
x: json.containsKey("x") ? double.parse(json["x"].toString()) : null,
|
||||
y: json.containsKey("y") ? double.parse(json["y"].toString()) : null,
|
||||
);
|
||||
}
|
||||
@override Map<String, dynamic> serialize() => {
|
||||
"id": id,
|
||||
"x": x,
|
||||
"y": y,
|
||||
};
|
||||
}
|
||||
@@ -1,29 +1,48 @@
|
||||
import 'package:oc_front/models/abstract.dart';
|
||||
import 'package:oc_front/models/search.dart';
|
||||
|
||||
class Workspace extends SerializerDeserializer<Workspace> {
|
||||
String? id;
|
||||
List<dynamic> data;
|
||||
List<dynamic> datacenter;
|
||||
List<dynamic> storage;
|
||||
List<dynamic> computing;
|
||||
String? name;
|
||||
bool? active;
|
||||
List<DataItem> datas;
|
||||
List<DataCenterItem> datacenters;
|
||||
List<StorageItem> storages;
|
||||
List<ProcessingItem> processings;
|
||||
List<WorkflowItem> workflows;
|
||||
|
||||
Workspace({
|
||||
this.id,
|
||||
this.computing = const [],
|
||||
this.data = const [],
|
||||
this.datacenter = const [],
|
||||
this.storage = const [],
|
||||
this.name,
|
||||
this.active = false,
|
||||
this.workflows = const [],
|
||||
this.datas = const [],
|
||||
this.datacenters = const [],
|
||||
this.storages = const [],
|
||||
this.processings = const [],
|
||||
});
|
||||
|
||||
@override deserialize(dynamic json) {
|
||||
try { json = json as Map<String, dynamic>;
|
||||
} catch (e) { return Workspace(); }
|
||||
return Workspace(
|
||||
computing: json.containsKey("computing") ? json["computing"] : [],
|
||||
datacenter: json.containsKey("datacenter") ? json["datacenter"] : [],
|
||||
data: json.containsKey("data") ? json["data"] : [],
|
||||
storage: json.containsKey("storage") ? json["storage"] : [],
|
||||
id: json.containsKey("id") ? json["id"] : null,
|
||||
name: json.containsKey("name") ? json["name"] : null,
|
||||
active: json.containsKey("active") ? json["active"] : false,
|
||||
processings: json.containsKey("processing_resources") ? fromListJson(json["processing_resources"], ProcessingItem()) : [],
|
||||
storages: json.containsKey("storage_resources") ? fromListJson(json["storage_resources"], StorageItem()) : [],
|
||||
datacenters: json.containsKey("datacenter_resources") ? fromListJson(json["datacenter_resources"], DataCenterItem()) : [],
|
||||
datas: json.containsKey("data_resources") ? fromListJson(json["data_resources"], DataItem()) : [],
|
||||
workflows: json.containsKey("workflow_resources") ? fromListJson(json["workflow_resources"], WorkflowItem()) : []
|
||||
);
|
||||
}
|
||||
@override Map<String, dynamic> serialize() => {};
|
||||
@override Map<String, dynamic> serialize() => {
|
||||
"id": id,
|
||||
"name": name,
|
||||
"processings": processings.map((e) => e.id).toList(),
|
||||
"storages": storages.map((e) => e.id).toList(),
|
||||
"datacenters": datacenters.map((e) => e.id).toList(),
|
||||
"datas": datas.map((e) => e.id).toList(),
|
||||
"workflows": workflows.map((e) => e.id).toList(),
|
||||
};
|
||||
}
|
||||
@@ -1,11 +1,12 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:oc_front/core/sections/header/header.dart';
|
||||
import 'package:oc_front/core/services/specialized_services/resource_service.dart';
|
||||
import 'package:oc_front/models/search.dart';
|
||||
import 'package:oc_front/widgets/catalog.dart';
|
||||
import 'package:oc_front/pages/abstract_page.dart';
|
||||
import 'package:oc_front/core/sections/header/search.dart';
|
||||
import 'package:oc_front/core/services/specialized_services/search_service.dart';
|
||||
import 'package:oc_front/widgets/menu_clipper/workspace_menu.dart';
|
||||
|
||||
class CatalogFactory implements AbstractFactory {
|
||||
static List<AbstractItem> items = [];
|
||||
@@ -13,10 +14,10 @@ class CatalogFactory implements AbstractFactory {
|
||||
@override bool searchFill() { return CatalogFactory.items.isEmpty; }
|
||||
@override Widget factory(GoRouterState state, List<String> args) { return CatalogPageWidget(); }
|
||||
@override void search(BuildContext context) {
|
||||
CatalogFactory.key.currentState?.widget.search.get(context, SearchConstants.get()!).then((value) {
|
||||
CatalogFactory.key.currentState?.widget.search.search(context, [ SearchConstants.get()! ], {}).then((value) {
|
||||
if (value.data == null) { return; }
|
||||
CatalogFactory.items = [
|
||||
...value.data!.computing, ...value.data!.data, ...value.data!.storage, ...value.data!.datacenter,];
|
||||
CatalogFactory.items = [ ...value.data!.workflows,
|
||||
...value.data!.processings, ...value.data!.datas, ...value.data!.storages, ...value.data!.datacenters,];
|
||||
searchWidgetKey.currentState?.setState(() {});
|
||||
CatalogFactory.key.currentState?.setState(() {});
|
||||
});
|
||||
@@ -24,16 +25,17 @@ class CatalogFactory implements AbstractFactory {
|
||||
}
|
||||
|
||||
class CatalogPageWidget extends StatefulWidget {
|
||||
final SearchService search = SearchService();
|
||||
final ResourceService search = ResourceService();
|
||||
CatalogPageWidget (): super(key: CatalogFactory.key);
|
||||
@override CatalogPageWidgetState createState() => CatalogPageWidgetState();
|
||||
}
|
||||
class CatalogPageWidgetState extends State<CatalogPageWidget> {
|
||||
@override Widget build(BuildContext context) {
|
||||
return Column( children : [
|
||||
CatalogFactory.items.isEmpty ? Container() : MenuWorkspaceWidget(),
|
||||
SizedBox(
|
||||
width: MediaQuery.of(context).size.width,
|
||||
height: CatalogFactory.items.isEmpty ? 0 : MediaQuery.of(context).size.height - HeaderConstants.height,
|
||||
height: CatalogFactory.items.isEmpty ? 0 : MediaQuery.of(context).size.height - HeaderConstants.height - 50,
|
||||
child: CatalogWidget(items: CatalogFactory.items) )
|
||||
]
|
||||
);
|
||||
|
||||
@@ -16,8 +16,8 @@ class CatalogItemFactory implements AbstractFactory {
|
||||
var item = CatalogFactory.items.firstWhere( (element) => element.id == id );
|
||||
return CatalogItemPageWidget(item : item);
|
||||
} catch (e) {
|
||||
var item = WorkspaceLocal.getItem(id ?? "");
|
||||
if (item != null) { return CatalogItemPageWidget(item : item); }
|
||||
var item = WorkspaceLocal.getItem(id ?? "", false);
|
||||
if (item != null) { return CatalogItemPageWidget(item : item as AbstractItem); }
|
||||
return Container();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
import 'package:datetime_picker_formfield/datetime_picker_formfield.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:intl/intl.dart' as intl;
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:oc_front/core/services/specialized_services/workflow_execution_service.dart';
|
||||
import 'package:oc_front/models/workflow.dart';
|
||||
import 'package:oc_front/pages/abstract_page.dart';
|
||||
import 'package:table_calendar/table_calendar.dart';
|
||||
import 'package:oc_front/widgets/sheduler_items/schedule.dart';
|
||||
|
||||
class SchedulerFactory implements AbstractFactory {
|
||||
static GlobalKey<SchedulerPageWidgetState> key = GlobalKey<SchedulerPageWidgetState>();
|
||||
@@ -11,18 +15,169 @@ class SchedulerFactory implements AbstractFactory {
|
||||
}
|
||||
|
||||
class SchedulerPageWidget extends StatefulWidget {
|
||||
bool isList = true;
|
||||
DateTime start = DateTime.now();
|
||||
DateTime end = DateTime.now().add(const Duration(days: 180));
|
||||
final WorkflowExecutionService _service = WorkflowExecutionService();
|
||||
SchedulerPageWidget(): super(key: SchedulerFactory.key);
|
||||
@override SchedulerPageWidgetState createState() => SchedulerPageWidgetState();
|
||||
static void search(BuildContext context) { }
|
||||
static Widget factory() { return SchedulerPageWidget(); }
|
||||
}
|
||||
class SchedulerPageWidgetState extends State<SchedulerPageWidget> {
|
||||
|
||||
List<Color> colors = [Colors.blue, Colors.orange, Colors.red, Colors.green];
|
||||
List<String> titles = ["SCHEDULED", "RUNNING", "FAILURE", "SUCCESS"];
|
||||
|
||||
@override Widget build(BuildContext context) {
|
||||
return TableCalendar(
|
||||
firstDay: DateTime.utc(2010, 10, 16),
|
||||
lastDay: DateTime.utc(2030, 3, 14),
|
||||
focusedDay: DateTime.now(),
|
||||
);
|
||||
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<String, List<WorkflowExecution>> 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<ScheduleWidgetState> k = GlobalKey<ScheduleWidgetState>();
|
||||
return Column( children: [
|
||||
Container( color: const Color.fromRGBO(38, 166, 154, 1),
|
||||
height: 50, width: MediaQuery.of(context).size.width,
|
||||
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: MediaQuery.of(context).size.width / 5,
|
||||
height: 30,
|
||||
child: DateTimeField(
|
||||
validator: (value) {
|
||||
return 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: 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),
|
||||
width: MediaQuery.of(context).size.width / 5,
|
||||
height: 30,
|
||||
child: DateTimeField(
|
||||
validator: (value) {
|
||||
return 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: 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),
|
||||
),
|
||||
)
|
||||
)
|
||||
]))
|
||||
),
|
||||
ScheduleWidget( key: k, data: data, start: widget.start, end : widget.end, isList: widget.isList )
|
||||
]);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_flow_chart/flutter_flow_chart.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
@@ -8,10 +6,16 @@ import 'package:oc_front/core/sections/header/header.dart';
|
||||
import 'package:oc_front/core/services/specialized_services/workflow_service.dart';
|
||||
import 'package:oc_front/models/response.dart';
|
||||
import 'package:oc_front/models/search.dart';
|
||||
import 'package:oc_front/models/workflow.dart';
|
||||
import 'package:oc_front/pages/abstract_page.dart';
|
||||
import 'package:oc_front/widgets/dialog/new_box.dart';
|
||||
import 'package:oc_front/widgets/forms/proxy_forms.dart';
|
||||
import 'package:oc_front/widgets/forms/scheduler_forms.dart';
|
||||
import 'package:oc_front/widgets/items/item_row.dart';
|
||||
Dashboard dash = Dashboard(name: "workflow_${DateTime.now().toString().replaceAll(" ", "_").substring(0, DateTime.now().toString().length - 7)}");
|
||||
import 'package:oc_front/widgets/menu_clipper/workspace_menu.dart';
|
||||
|
||||
Dashboard dash = Dashboard(
|
||||
name: "workflow_${DateTime.now().toString().replaceAll(" ", "_").substring(0, DateTime.now().toString().length - 7)}");
|
||||
class WorkflowFactory implements AbstractFactory {
|
||||
static GlobalKey<WorkflowPageWidgetState> key = GlobalKey<WorkflowPageWidgetState>();
|
||||
@override bool searchFill() { return false; }
|
||||
@@ -29,8 +33,10 @@ class WorkflowPageWidgetState extends State<WorkflowPageWidget> {
|
||||
final WorflowService _service = WorflowService();
|
||||
Widget itemBuild(Object item) {
|
||||
var e = item as AbstractItem;
|
||||
return e.logo != null ? Image.memory(base64Decode(e.logo ?? ""), fit: BoxFit.fill)
|
||||
: Image.network('https://get-picto.com/wp-content/uploads/2024/01/logo-instagram-png.webp', fit: BoxFit.fill);
|
||||
return Tooltip( message: item.name ?? "",
|
||||
child: e.logo != null ? Image.network(e.logo ?? "", fit: BoxFit.fill)
|
||||
: Image.network('https://get-picto.com/wp-content/uploads/2024/01/logo-instagram-png.webp',
|
||||
fit: BoxFit.fill));
|
||||
}
|
||||
Widget itemTooltipBuild(Object item) {
|
||||
var e = item as AbstractItem;
|
||||
@@ -39,30 +45,113 @@ final WorflowService _service = WorflowService();
|
||||
List<DropdownMenuItem> getItems(Object? data) {
|
||||
data = data as APIResponse<RawData>?;
|
||||
if (data != null && data.data != null && data.data!.values.isNotEmpty) {
|
||||
return (data.data!.values as List<dynamic>).map((dynamic value) {
|
||||
return data.data!.values.map((dynamic value) {
|
||||
return DropdownMenuItem<String>(
|
||||
value: value.toString(),
|
||||
child: Text(value.toString()),
|
||||
value: "${value["id"] ?? ""}~${value["name"] ?? ""}",
|
||||
child: Text(value["name"]?.toString() ?? ""),
|
||||
);
|
||||
}).toList();
|
||||
}
|
||||
return [];
|
||||
}
|
||||
List<Widget> getForms(FlowData? obj) {
|
||||
return obj == null ? [] : [
|
||||
ProxyFormsWidget(item: obj as AbstractItem),
|
||||
];
|
||||
}
|
||||
|
||||
List<Widget> getDashInfoForms() {
|
||||
return [
|
||||
SchedulerFormsWidget(item: dash),
|
||||
];
|
||||
}
|
||||
|
||||
Future<void> loadDash(String selected) async {
|
||||
if (selected.split("~").length > 1) {
|
||||
dash.name = selected.split("~")[1];
|
||||
dash.id = selected.split("~")[0];
|
||||
} else {
|
||||
dash.name = selected;
|
||||
}
|
||||
await _service.get(context, dash.id ?? "").then((value) {
|
||||
if (value.data != null) {
|
||||
dash.deserialize(value.data!.toDashboard());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Future<void> saveDash(String? id) async {
|
||||
if (id == null || !dash.isOpened) { return; }
|
||||
var datas = WorkspaceLocal.byTopic("data", true).where(
|
||||
(element) => dash.elements.map( (e) => e.element?.getID()).contains(element.id) );
|
||||
var dataCenter = WorkspaceLocal.byTopic("datacenter", true).where(
|
||||
(element) => dash.elements.map( (e) => e.element?.getID()).contains(element.id) );
|
||||
var storage = WorkspaceLocal.byTopic("storage", true).where(
|
||||
(element) => dash.elements.map( (e) => e.element?.getID()).contains(element.id) );
|
||||
var computing = WorkspaceLocal.byTopic("processing", true).where(
|
||||
(element) => dash.elements.map( (e) => e.element?.getID()).contains(element.id) );
|
||||
var workflows = WorkspaceLocal.byTopic("workflows", true).where(
|
||||
(element) => dash.elements.map( (e) => e.element?.getID()).contains(element.id) );
|
||||
var updateW = Workflow(
|
||||
name: dash.name,
|
||||
graph: Graph(),
|
||||
data: datas.map((e) => e.id).toSet().toList(),
|
||||
datacenter: dataCenter.map((e) => e.id).toSet().toList(),
|
||||
storage: storage.map((e) => e.id).toSet().toList(),
|
||||
processing: computing.map((e) => e.id).toSet().toList(),
|
||||
workflows: workflows.map((e) => e.id).toSet().toList(),
|
||||
);
|
||||
updateW.fromDashboard(dash.serialize());
|
||||
for (var item in (updateW.graph?.items.values ?? [] as List<GraphItem>)) {
|
||||
if (item.position == null) { continue; }
|
||||
item.position?.x = (item.position?.x ?? 0) + 52.5;
|
||||
item.position?.y = (item.position?.y ?? 0) + 52.5;
|
||||
}
|
||||
print(dash.getZoomFactor());
|
||||
updateW.graph?.zoom = dash.getZoomFactor();
|
||||
await _service.put(context, id, updateW.serialize(), {});
|
||||
}
|
||||
|
||||
FlowData? transformToData(Map<String, dynamic> data) {
|
||||
var d = WorkspaceLocal.getItem(data["id"] ?? "", true);
|
||||
if (d == null) { return null; }
|
||||
d.model = ResourceModel().deserialize(data["resource_model"]);
|
||||
if (d.topic == "data") { return d as DataItem; }
|
||||
if (d.topic == "datacenter") { return d as DataCenterItem; }
|
||||
if (d.topic == "storage") { return d as StorageItem; }
|
||||
if (d.topic == "processing") { return d as ProcessingItem; }
|
||||
if (d.topic == "workflows") { return d as WorkflowItem; }
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
Widget menuExtension() {
|
||||
var quart = MediaQuery.of(context).size.width / 6;
|
||||
return MenuWorkspaceWidget(simpliest: true, width: quart > 80 ? quart : 80,
|
||||
onWorkspaceChange: () { dash.selectedLeftMenuKey.currentState?.setState(() { }); });
|
||||
}
|
||||
|
||||
Widget onDashboardAlertOpened(BuildContext context, Dashboard dash) {
|
||||
return NewBoxWidget<RawData>(service: _service, dash: dash,
|
||||
return NewBoxWidget<Workflow>(service: _service, dash: dash,
|
||||
getItems: getItems);
|
||||
}
|
||||
@override Widget build(BuildContext context) {
|
||||
dash.load = loadDash;
|
||||
dash.save = saveDash;
|
||||
dash.transformToData = transformToData;
|
||||
dash.infoItemWidget = getForms;
|
||||
dash.infoWidget = getDashInfoForms;
|
||||
var quart = MediaQuery.of(context).size.width / 6;
|
||||
dash.defaultName = "workflow_${DateTime.now().toString().replaceAll(" ", "_").substring(0, DateTime.now().toString().length - 7)}";
|
||||
return FlowChart<AbstractItem>(
|
||||
onDashboardAlertOpened: onDashboardAlertOpened,
|
||||
dashboard: dash,
|
||||
itemWidget: itemBuild,
|
||||
categories: const ["computing", "data", "datacenter", "storage"],
|
||||
draggableItemBuilder: (cat) => WorkspaceLocal.byTopic(cat).toList(),
|
||||
categories: const ["processing", "data", "datacenter", "storage", "workflows"],
|
||||
draggableItemBuilder: (cat) => WorkspaceLocal.byTopic(cat, true).toList(),
|
||||
itemWidgetTooltip: itemTooltipBuild,
|
||||
innerMenuWidth: quart > 80 ? quart : 80,
|
||||
menuExtension: menuExtension,
|
||||
width: MediaQuery.of(context).size.width,
|
||||
height: MediaQuery.of(context).size.height - HeaderConstants.height,
|
||||
onNewConnection: (p1, p2) { },
|
||||
|
||||
@@ -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(
|
||||
|
||||
73
lib/widgets/forms/data_forms.dart
Normal file
73
lib/widgets/forms/data_forms.dart
Normal 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),
|
||||
),
|
||||
)))
|
||||
]);
|
||||
}
|
||||
}
|
||||
61
lib/widgets/forms/proxy_forms.dart
Normal file
61
lib/widgets/forms/proxy_forms.dart
Normal 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
|
||||
]);
|
||||
}
|
||||
}
|
||||
288
lib/widgets/forms/scheduler_forms.dart
Normal file
288
lib/widgets/forms/scheduler_forms.dart
Normal 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),
|
||||
))
|
||||
),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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)),
|
||||
],)
|
||||
)
|
||||
|
||||
@@ -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
73
lib/widgets/logs.dart
Normal 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))), ])
|
||||
]));
|
||||
}
|
||||
}
|
||||
116
lib/widgets/menu_clipper/workspace_menu.dart
Normal file
116
lib/widgets/menu_clipper/workspace_menu.dart
Normal 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)
|
||||
)
|
||||
)
|
||||
)
|
||||
])
|
||||
]);
|
||||
}
|
||||
}
|
||||
179
lib/widgets/sheduler_items/schedule.dart
Normal file
179
lib/widgets/sheduler_items/schedule.dart
Normal 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()
|
||||
]))
|
||||
)
|
||||
],
|
||||
),
|
||||
)
|
||||
]);
|
||||
}
|
||||
}
|
||||
175
lib/widgets/sheduler_items/scheduler_calendar.dart
Normal file
175
lib/widgets/sheduler_items/scheduler_calendar.dart
Normal 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;
|
||||
}
|
||||
115
lib/widgets/sheduler_items/scheduler_item.dart
Normal file
115
lib/widgets/sheduler_items/scheduler_item.dart
Normal 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))
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user