intermediate

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

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1 +1 @@
["/home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/libflutter_linux_gtk.so","/home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/icudtl.dat","/home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/flutter_linux/fl_dart_project.h","/home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/flutter_linux/fl_texture.h","/home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/flutter_linux/fl_event_channel.h","/home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/flutter_linux/fl_message_codec.h","/home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/flutter_linux/fl_json_message_codec.h","/home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/flutter_linux/fl_binary_codec.h","/home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/flutter_linux/fl_plugin_registry.h","/home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/flutter_linux/fl_json_method_codec.h","/home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/flutter_linux/fl_string_codec.h","/home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/flutter_linux/fl_method_codec.h","/home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/flutter_linux/fl_pixel_buffer_texture.h","/home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/flutter_linux/fl_texture_gl.h","/home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/flutter_linux/flutter_linux.h","/home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/flutter_linux/fl_value.h","/home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/flutter_linux/fl_view.h","/home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/flutter_linux/fl_method_channel.h","/home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/flutter_linux/fl_engine.h","/home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/flutter_linux/fl_binary_messenger.h","/home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/flutter_linux/fl_standard_message_codec.h","/home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/flutter_linux/fl_standard_method_codec.h","/home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/flutter_linux/fl_texture_registrar.h","/home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/flutter_linux/fl_method_response.h","/home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/flutter_linux/fl_plugin_registrar.h","/home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/flutter_linux/fl_basic_message_channel.h","/home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/flutter_linux/fl_method_call.h","/home/mr/Documents/OC/oc-front/build/flutter_assets/kernel_blob.bin","/home/mr/Documents/OC/oc-front/build/flutter_assets/assets/images/logo.svg","/home/mr/Documents/OC/oc-front/build/flutter_assets/assets/images/icon.svg","/home/mr/Documents/OC/oc-front/build/flutter_assets/packages/cupertino_icons/assets/CupertinoIcons.ttf","/home/mr/Documents/OC/oc-front/build/flutter_assets/packages/flutter_map/lib/assets/flutter_map_logo.png","/home/mr/Documents/OC/oc-front/build/flutter_assets/fonts/MaterialIcons-Regular.otf","/home/mr/Documents/OC/oc-front/build/flutter_assets/shaders/ink_sparkle.frag","/home/mr/Documents/OC/oc-front/build/flutter_assets/AssetManifest.json","/home/mr/Documents/OC/oc-front/build/flutter_assets/AssetManifest.bin","/home/mr/Documents/OC/oc-front/build/flutter_assets/FontManifest.json","/home/mr/Documents/OC/oc-front/build/flutter_assets/NOTICES.Z","/home/mr/Documents/OC/oc-front/build/flutter_assets/version.json"] ["/home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/libflutter_linux_gtk.so","/home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/icudtl.dat","/home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/flutter_linux/fl_dart_project.h","/home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/flutter_linux/fl_texture.h","/home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/flutter_linux/fl_event_channel.h","/home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/flutter_linux/fl_message_codec.h","/home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/flutter_linux/fl_json_message_codec.h","/home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/flutter_linux/fl_binary_codec.h","/home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/flutter_linux/fl_plugin_registry.h","/home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/flutter_linux/fl_json_method_codec.h","/home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/flutter_linux/fl_string_codec.h","/home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/flutter_linux/fl_method_codec.h","/home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/flutter_linux/fl_pixel_buffer_texture.h","/home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/flutter_linux/fl_texture_gl.h","/home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/flutter_linux/flutter_linux.h","/home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/flutter_linux/fl_value.h","/home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/flutter_linux/fl_view.h","/home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/flutter_linux/fl_method_channel.h","/home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/flutter_linux/fl_engine.h","/home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/flutter_linux/fl_binary_messenger.h","/home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/flutter_linux/fl_standard_message_codec.h","/home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/flutter_linux/fl_standard_method_codec.h","/home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/flutter_linux/fl_texture_registrar.h","/home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/flutter_linux/fl_method_response.h","/home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/flutter_linux/fl_plugin_registrar.h","/home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/flutter_linux/fl_basic_message_channel.h","/home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/flutter_linux/fl_method_call.h","/home/mr/Documents/OC/oc-front/build/flutter_assets/kernel_blob.bin","/home/mr/Documents/OC/oc-front/build/flutter_assets/assets/images/logo.svg","/home/mr/Documents/OC/oc-front/build/flutter_assets/assets/images/icon.svg","/home/mr/Documents/OC/oc-front/build/flutter_assets/packages/cupertino_icons/assets/CupertinoIcons.ttf","/home/mr/Documents/OC/oc-front/build/flutter_assets/packages/flutter_map/lib/assets/flutter_map_logo.png","/home/mr/Documents/OC/oc-front/build/flutter_assets/packages/timezone/data/latest_all.tzf","/home/mr/Documents/OC/oc-front/build/flutter_assets/fonts/MaterialIcons-Regular.otf","/home/mr/Documents/OC/oc-front/build/flutter_assets/shaders/ink_sparkle.frag","/home/mr/Documents/OC/oc-front/build/flutter_assets/AssetManifest.json","/home/mr/Documents/OC/oc-front/build/flutter_assets/AssetManifest.bin","/home/mr/Documents/OC/oc-front/build/flutter_assets/FontManifest.json","/home/mr/Documents/OC/oc-front/build/flutter_assets/NOTICES.Z","/home/mr/Documents/OC/oc-front/build/flutter_assets/version.json"]

View File

@ -8,8 +8,10 @@
import 'dart:io'; // flutter_ignore: dart_io_import. import 'dart:io'; // flutter_ignore: dart_io_import.
import 'package:path_provider_android/path_provider_android.dart'; import 'package:path_provider_android/path_provider_android.dart';
import 'package:shared_preferences_android/shared_preferences_android.dart'; import 'package:shared_preferences_android/shared_preferences_android.dart';
import 'package:webview_flutter_android/webview_flutter_android.dart';
import 'package:path_provider_foundation/path_provider_foundation.dart'; import 'package:path_provider_foundation/path_provider_foundation.dart';
import 'package:shared_preferences_foundation/shared_preferences_foundation.dart'; import 'package:shared_preferences_foundation/shared_preferences_foundation.dart';
import 'package:webview_flutter_wkwebview/webview_flutter_wkwebview.dart';
import 'package:device_info_plus/device_info_plus.dart'; import 'package:device_info_plus/device_info_plus.dart';
import 'package:path_provider_linux/path_provider_linux.dart'; import 'package:path_provider_linux/path_provider_linux.dart';
import 'package:shared_preferences_linux/shared_preferences_linux.dart'; import 'package:shared_preferences_linux/shared_preferences_linux.dart';
@ -43,6 +45,15 @@ class _PluginRegistrant {
); );
} }
try {
AndroidWebViewPlatform.registerWith();
} catch (err) {
print(
'`webview_flutter_android` threw an error: $err. '
'The app may not function as expected until you remove this plugin from pubspec.yaml'
);
}
} else if (Platform.isIOS) { } else if (Platform.isIOS) {
try { try {
PathProviderFoundation.registerWith(); PathProviderFoundation.registerWith();
@ -62,6 +73,15 @@ class _PluginRegistrant {
); );
} }
try {
WebKitWebViewPlatform.registerWith();
} catch (err) {
print(
'`webview_flutter_wkwebview` threw an error: $err. '
'The app may not function as expected until you remove this plugin from pubspec.yaml'
);
}
} else if (Platform.isLinux) { } else if (Platform.isLinux) {
try { try {
DeviceInfoPlusLinuxPlugin.registerWith(); DeviceInfoPlusLinuxPlugin.registerWith();

View File

@ -61,6 +61,12 @@
"packageUri": "lib/", "packageUri": "lib/",
"languageVersion": "2.18" "languageVersion": "2.18"
}, },
{
"name": "cron",
"rootUri": "file:///home/mr/.pub-cache/hosted/pub.dev/cron-0.6.1",
"packageUri": "lib/",
"languageVersion": "2.12"
},
{ {
"name": "crypto", "name": "crypto",
"rootUri": "file:///home/mr/.pub-cache/hosted/pub.dev/crypto-3.0.3", "rootUri": "file:///home/mr/.pub-cache/hosted/pub.dev/crypto-3.0.3",
@ -85,6 +91,12 @@
"packageUri": "lib/", "packageUri": "lib/",
"languageVersion": "2.19" "languageVersion": "2.19"
}, },
{
"name": "datetime_picker_formfield",
"rootUri": "file:///home/mr/.pub-cache/hosted/pub.dev/datetime_picker_formfield-2.0.1",
"packageUri": "lib/",
"languageVersion": "2.12"
},
{ {
"name": "desktop_window", "name": "desktop_window",
"rootUri": "file:///home/mr/.pub-cache/hosted/pub.dev/desktop_window-0.4.0", "rootUri": "file:///home/mr/.pub-cache/hosted/pub.dev/desktop_window-0.4.0",
@ -157,6 +169,12 @@
"packageUri": "lib/", "packageUri": "lib/",
"languageVersion": "3.2" "languageVersion": "3.2"
}, },
{
"name": "flutter_advanced_switch",
"rootUri": "file:///home/mr/.pub-cache/hosted/pub.dev/flutter_advanced_switch-3.1.0",
"packageUri": "lib/",
"languageVersion": "2.12"
},
{ {
"name": "flutter_box_transform", "name": "flutter_box_transform",
"rootUri": "file:///home/mr/.pub-cache/hosted/pub.dev/flutter_box_transform-0.4.4", "rootUri": "file:///home/mr/.pub-cache/hosted/pub.dev/flutter_box_transform-0.4.4",
@ -169,6 +187,12 @@
"packageUri": "lib/", "packageUri": "lib/",
"languageVersion": "2.14" "languageVersion": "2.14"
}, },
{
"name": "flutter_event_calendar",
"rootUri": "file:///home/mr/.pub-cache/hosted/pub.dev/flutter_event_calendar-1.0.0",
"packageUri": "lib/",
"languageVersion": "2.12"
},
{ {
"name": "flutter_flow_chart", "name": "flutter_flow_chart",
"rootUri": "../library/flutter_flow_chart", "rootUri": "../library/flutter_flow_chart",
@ -259,6 +283,18 @@
"packageUri": "lib/", "packageUri": "lib/",
"languageVersion": "3.0" "languageVersion": "3.0"
}, },
{
"name": "json_string",
"rootUri": "file:///home/mr/.pub-cache/hosted/pub.dev/json_string-3.0.1",
"packageUri": "lib/",
"languageVersion": "2.12"
},
{
"name": "json_util",
"rootUri": "file:///home/mr/.pub-cache/hosted/pub.dev/json_util-2.0.0",
"packageUri": "lib/",
"languageVersion": "2.12"
},
{ {
"name": "latlong2", "name": "latlong2",
"rootUri": "file:///home/mr/.pub-cache/hosted/pub.dev/latlong2-0.9.1", "rootUri": "file:///home/mr/.pub-cache/hosted/pub.dev/latlong2-0.9.1",
@ -421,6 +457,18 @@
"packageUri": "lib/", "packageUri": "lib/",
"languageVersion": "2.12" "languageVersion": "2.12"
}, },
{
"name": "scoped_model",
"rootUri": "file:///home/mr/.pub-cache/hosted/pub.dev/scoped_model-2.0.0",
"packageUri": "lib/",
"languageVersion": "2.12"
},
{
"name": "shamsi_date",
"rootUri": "file:///home/mr/.pub-cache/hosted/pub.dev/shamsi_date-0.15.0",
"packageUri": "lib/",
"languageVersion": "2.12"
},
{ {
"name": "shared_preferences", "name": "shared_preferences",
"rootUri": "file:///home/mr/.pub-cache/hosted/pub.dev/shared_preferences-2.2.3", "rootUri": "file:///home/mr/.pub-cache/hosted/pub.dev/shared_preferences-2.2.3",
@ -529,6 +577,24 @@
"packageUri": "lib/", "packageUri": "lib/",
"languageVersion": "3.3" "languageVersion": "3.3"
}, },
{
"name": "syncfusion_flutter_calendar",
"rootUri": "file:///home/mr/.pub-cache/hosted/pub.dev/syncfusion_flutter_calendar-26.2.7",
"packageUri": "lib/",
"languageVersion": "2.17"
},
{
"name": "syncfusion_flutter_core",
"rootUri": "file:///home/mr/.pub-cache/hosted/pub.dev/syncfusion_flutter_core-26.2.7",
"packageUri": "lib/",
"languageVersion": "2.17"
},
{
"name": "syncfusion_flutter_datepicker",
"rootUri": "file:///home/mr/.pub-cache/hosted/pub.dev/syncfusion_flutter_datepicker-26.2.7",
"packageUri": "lib/",
"languageVersion": "2.17"
},
{ {
"name": "table_calendar", "name": "table_calendar",
"rootUri": "file:///home/mr/.pub-cache/hosted/pub.dev/table_calendar-3.1.2", "rootUri": "file:///home/mr/.pub-cache/hosted/pub.dev/table_calendar-3.1.2",
@ -547,6 +613,12 @@
"packageUri": "lib/", "packageUri": "lib/",
"languageVersion": "3.0" "languageVersion": "3.0"
}, },
{
"name": "timezone",
"rootUri": "file:///home/mr/.pub-cache/hosted/pub.dev/timezone-0.9.3",
"packageUri": "lib/",
"languageVersion": "2.19"
},
{ {
"name": "typed_data", "name": "typed_data",
"rootUri": "file:///home/mr/.pub-cache/hosted/pub.dev/typed_data-1.3.2", "rootUri": "file:///home/mr/.pub-cache/hosted/pub.dev/typed_data-1.3.2",
@ -601,6 +673,30 @@
"packageUri": "lib/", "packageUri": "lib/",
"languageVersion": "3.3" "languageVersion": "3.3"
}, },
{
"name": "webview_flutter",
"rootUri": "file:///home/mr/.pub-cache/hosted/pub.dev/webview_flutter-4.8.0",
"packageUri": "lib/",
"languageVersion": "3.2"
},
{
"name": "webview_flutter_android",
"rootUri": "file:///home/mr/.pub-cache/hosted/pub.dev/webview_flutter_android-3.16.3",
"packageUri": "lib/",
"languageVersion": "3.2"
},
{
"name": "webview_flutter_platform_interface",
"rootUri": "file:///home/mr/.pub-cache/hosted/pub.dev/webview_flutter_platform_interface-2.10.0",
"packageUri": "lib/",
"languageVersion": "3.0"
},
{
"name": "webview_flutter_wkwebview",
"rootUri": "file:///home/mr/.pub-cache/hosted/pub.dev/webview_flutter_wkwebview-3.14.0",
"packageUri": "lib/",
"languageVersion": "3.2"
},
{ {
"name": "win32", "name": "win32",
"rootUri": "file:///home/mr/.pub-cache/hosted/pub.dev/win32-5.5.0", "rootUri": "file:///home/mr/.pub-cache/hosted/pub.dev/win32-5.5.0",
@ -638,7 +734,7 @@
"languageVersion": "3.3" "languageVersion": "3.3"
} }
], ],
"generated": "2024-07-17T08:10:14.640895Z", "generated": "2024-08-07T09:57:10.081261Z",
"generator": "pub", "generator": "pub",
"generatorVersion": "3.3.4" "generatorVersion": "3.3.4"
} }

View File

@ -38,6 +38,10 @@ convert
2.18 2.18
file:///home/mr/.pub-cache/hosted/pub.dev/convert-3.1.1/ file:///home/mr/.pub-cache/hosted/pub.dev/convert-3.1.1/
file:///home/mr/.pub-cache/hosted/pub.dev/convert-3.1.1/lib/ file:///home/mr/.pub-cache/hosted/pub.dev/convert-3.1.1/lib/
cron
2.12
file:///home/mr/.pub-cache/hosted/pub.dev/cron-0.6.1/
file:///home/mr/.pub-cache/hosted/pub.dev/cron-0.6.1/lib/
crypto crypto
2.19 2.19
file:///home/mr/.pub-cache/hosted/pub.dev/crypto-3.0.3/ file:///home/mr/.pub-cache/hosted/pub.dev/crypto-3.0.3/
@ -54,6 +58,10 @@ dashed_path
2.19 2.19
file:///home/mr/.pub-cache/hosted/pub.dev/dashed_path-1.0.1/ file:///home/mr/.pub-cache/hosted/pub.dev/dashed_path-1.0.1/
file:///home/mr/.pub-cache/hosted/pub.dev/dashed_path-1.0.1/lib/ file:///home/mr/.pub-cache/hosted/pub.dev/dashed_path-1.0.1/lib/
datetime_picker_formfield
2.12
file:///home/mr/.pub-cache/hosted/pub.dev/datetime_picker_formfield-2.0.1/
file:///home/mr/.pub-cache/hosted/pub.dev/datetime_picker_formfield-2.0.1/lib/
desktop_window desktop_window
2.12 2.12
file:///home/mr/.pub-cache/hosted/pub.dev/desktop_window-0.4.0/ file:///home/mr/.pub-cache/hosted/pub.dev/desktop_window-0.4.0/
@ -98,6 +106,10 @@ fixnum
2.19 2.19
file:///home/mr/.pub-cache/hosted/pub.dev/fixnum-1.1.0/ file:///home/mr/.pub-cache/hosted/pub.dev/fixnum-1.1.0/
file:///home/mr/.pub-cache/hosted/pub.dev/fixnum-1.1.0/lib/ file:///home/mr/.pub-cache/hosted/pub.dev/fixnum-1.1.0/lib/
flutter_advanced_switch
2.12
file:///home/mr/.pub-cache/hosted/pub.dev/flutter_advanced_switch-3.1.0/
file:///home/mr/.pub-cache/hosted/pub.dev/flutter_advanced_switch-3.1.0/lib/
flutter_box_transform flutter_box_transform
3.0 3.0
file:///home/mr/.pub-cache/hosted/pub.dev/flutter_box_transform-0.4.4/ file:///home/mr/.pub-cache/hosted/pub.dev/flutter_box_transform-0.4.4/
@ -106,6 +118,10 @@ flutter_colorpicker
2.14 2.14
file:///home/mr/.pub-cache/hosted/pub.dev/flutter_colorpicker-1.1.0/ file:///home/mr/.pub-cache/hosted/pub.dev/flutter_colorpicker-1.1.0/
file:///home/mr/.pub-cache/hosted/pub.dev/flutter_colorpicker-1.1.0/lib/ file:///home/mr/.pub-cache/hosted/pub.dev/flutter_colorpicker-1.1.0/lib/
flutter_event_calendar
2.12
file:///home/mr/.pub-cache/hosted/pub.dev/flutter_event_calendar-1.0.0/
file:///home/mr/.pub-cache/hosted/pub.dev/flutter_event_calendar-1.0.0/lib/
flutter_lints flutter_lints
3.1 3.1
file:///home/mr/.pub-cache/hosted/pub.dev/flutter_lints-3.0.2/ file:///home/mr/.pub-cache/hosted/pub.dev/flutter_lints-3.0.2/
@ -154,6 +170,14 @@ irondash_message_channel
3.0 3.0
file:///home/mr/.pub-cache/hosted/pub.dev/irondash_message_channel-0.7.0/ file:///home/mr/.pub-cache/hosted/pub.dev/irondash_message_channel-0.7.0/
file:///home/mr/.pub-cache/hosted/pub.dev/irondash_message_channel-0.7.0/lib/ file:///home/mr/.pub-cache/hosted/pub.dev/irondash_message_channel-0.7.0/lib/
json_string
2.12
file:///home/mr/.pub-cache/hosted/pub.dev/json_string-3.0.1/
file:///home/mr/.pub-cache/hosted/pub.dev/json_string-3.0.1/lib/
json_util
2.12
file:///home/mr/.pub-cache/hosted/pub.dev/json_util-2.0.0/
file:///home/mr/.pub-cache/hosted/pub.dev/json_util-2.0.0/lib/
latlong2 latlong2
3.0 3.0
file:///home/mr/.pub-cache/hosted/pub.dev/latlong2-0.9.1/ file:///home/mr/.pub-cache/hosted/pub.dev/latlong2-0.9.1/
@ -262,6 +286,14 @@ proj4dart
2.12 2.12
file:///home/mr/.pub-cache/hosted/pub.dev/proj4dart-2.1.0/ file:///home/mr/.pub-cache/hosted/pub.dev/proj4dart-2.1.0/
file:///home/mr/.pub-cache/hosted/pub.dev/proj4dart-2.1.0/lib/ file:///home/mr/.pub-cache/hosted/pub.dev/proj4dart-2.1.0/lib/
scoped_model
2.12
file:///home/mr/.pub-cache/hosted/pub.dev/scoped_model-2.0.0/
file:///home/mr/.pub-cache/hosted/pub.dev/scoped_model-2.0.0/lib/
shamsi_date
2.12
file:///home/mr/.pub-cache/hosted/pub.dev/shamsi_date-0.15.0/
file:///home/mr/.pub-cache/hosted/pub.dev/shamsi_date-0.15.0/lib/
shared_preferences shared_preferences
3.1 3.1
file:///home/mr/.pub-cache/hosted/pub.dev/shared_preferences-2.2.3/ file:///home/mr/.pub-cache/hosted/pub.dev/shared_preferences-2.2.3/
@ -330,6 +362,18 @@ super_native_extensions
3.3 3.3
file:///home/mr/.pub-cache/hosted/pub.dev/super_native_extensions-0.8.17/ file:///home/mr/.pub-cache/hosted/pub.dev/super_native_extensions-0.8.17/
file:///home/mr/.pub-cache/hosted/pub.dev/super_native_extensions-0.8.17/lib/ file:///home/mr/.pub-cache/hosted/pub.dev/super_native_extensions-0.8.17/lib/
syncfusion_flutter_calendar
2.17
file:///home/mr/.pub-cache/hosted/pub.dev/syncfusion_flutter_calendar-26.2.7/
file:///home/mr/.pub-cache/hosted/pub.dev/syncfusion_flutter_calendar-26.2.7/lib/
syncfusion_flutter_core
2.17
file:///home/mr/.pub-cache/hosted/pub.dev/syncfusion_flutter_core-26.2.7/
file:///home/mr/.pub-cache/hosted/pub.dev/syncfusion_flutter_core-26.2.7/lib/
syncfusion_flutter_datepicker
2.17
file:///home/mr/.pub-cache/hosted/pub.dev/syncfusion_flutter_datepicker-26.2.7/
file:///home/mr/.pub-cache/hosted/pub.dev/syncfusion_flutter_datepicker-26.2.7/lib/
table_calendar table_calendar
3.0 3.0
file:///home/mr/.pub-cache/hosted/pub.dev/table_calendar-3.1.2/ file:///home/mr/.pub-cache/hosted/pub.dev/table_calendar-3.1.2/
@ -342,6 +386,10 @@ test_api
3.0 3.0
file:///home/mr/.pub-cache/hosted/pub.dev/test_api-0.6.1/ file:///home/mr/.pub-cache/hosted/pub.dev/test_api-0.6.1/
file:///home/mr/.pub-cache/hosted/pub.dev/test_api-0.6.1/lib/ file:///home/mr/.pub-cache/hosted/pub.dev/test_api-0.6.1/lib/
timezone
2.19
file:///home/mr/.pub-cache/hosted/pub.dev/timezone-0.9.3/
file:///home/mr/.pub-cache/hosted/pub.dev/timezone-0.9.3/lib/
typed_data typed_data
2.17 2.17
file:///home/mr/.pub-cache/hosted/pub.dev/typed_data-1.3.2/ file:///home/mr/.pub-cache/hosted/pub.dev/typed_data-1.3.2/
@ -378,6 +426,22 @@ web
3.3 3.3
file:///home/mr/.pub-cache/hosted/pub.dev/web-0.5.1/ file:///home/mr/.pub-cache/hosted/pub.dev/web-0.5.1/
file:///home/mr/.pub-cache/hosted/pub.dev/web-0.5.1/lib/ file:///home/mr/.pub-cache/hosted/pub.dev/web-0.5.1/lib/
webview_flutter
3.2
file:///home/mr/.pub-cache/hosted/pub.dev/webview_flutter-4.8.0/
file:///home/mr/.pub-cache/hosted/pub.dev/webview_flutter-4.8.0/lib/
webview_flutter_android
3.2
file:///home/mr/.pub-cache/hosted/pub.dev/webview_flutter_android-3.16.3/
file:///home/mr/.pub-cache/hosted/pub.dev/webview_flutter_android-3.16.3/lib/
webview_flutter_platform_interface
3.0
file:///home/mr/.pub-cache/hosted/pub.dev/webview_flutter_platform_interface-2.10.0/
file:///home/mr/.pub-cache/hosted/pub.dev/webview_flutter_platform_interface-2.10.0/lib/
webview_flutter_wkwebview
3.2
file:///home/mr/.pub-cache/hosted/pub.dev/webview_flutter_wkwebview-3.14.0/
file:///home/mr/.pub-cache/hosted/pub.dev/webview_flutter_wkwebview-3.14.0/lib/
win32 win32
3.3 3.3
file:///home/mr/.pub-cache/hosted/pub.dev/win32-5.5.0/ file:///home/mr/.pub-cache/hosted/pub.dev/win32-5.5.0/

View File

@ -14,3 +14,6 @@ shared_preferences_linux=/home/mr/.pub-cache/hosted/pub.dev/shared_preferences_l
shared_preferences_web=/home/mr/.pub-cache/hosted/pub.dev/shared_preferences_web-2.3.0/ shared_preferences_web=/home/mr/.pub-cache/hosted/pub.dev/shared_preferences_web-2.3.0/
shared_preferences_windows=/home/mr/.pub-cache/hosted/pub.dev/shared_preferences_windows-2.3.2/ shared_preferences_windows=/home/mr/.pub-cache/hosted/pub.dev/shared_preferences_windows-2.3.2/
super_native_extensions=/home/mr/.pub-cache/hosted/pub.dev/super_native_extensions-0.8.17/ super_native_extensions=/home/mr/.pub-cache/hosted/pub.dev/super_native_extensions-0.8.17/
webview_flutter=/home/mr/.pub-cache/hosted/pub.dev/webview_flutter-4.8.0/
webview_flutter_android=/home/mr/.pub-cache/hosted/pub.dev/webview_flutter_android-3.16.3/
webview_flutter_wkwebview=/home/mr/.pub-cache/hosted/pub.dev/webview_flutter_wkwebview-3.14.0/

File diff suppressed because one or more lines are too long

View File

@ -5,10 +5,10 @@ FROM debian:latest AS build-env
RUN apt-get update RUN apt-get update
RUN apt-get install -y curl git unzip RUN apt-get install -y curl git unzip
ARG WORKSPACE_HOST="https://localhost:49618" ARG WORKSPACE_HOST="https://localhost:8089"
ARG WORKFLOW_HOST="https://localhost:49618" ARG WORKFLOW_HOST="https://localhost:8088"
ARG SEARCH_HOST="https://localhost:49618" ARG SEARCH_HOST="https://localhost:49618"
ARG ITEM_HOST="https://localhost:49618" ARG ITEM_HOST="https://localhost:8087"
# define variables # define variables
ARG FLUTTER_SDK=/usr/local/flutter ARG FLUTTER_SDK=/usr/local/flutter

View File

@ -1 +1 @@
assets/images/icon.svg  assetassets/images/icon.svgassets/images/logo.svg  assetassets/images/logo.svg2packages/cupertino_icons/assets/CupertinoIcons.ttf  asset2packages/cupertino_icons/assets/CupertinoIcons.ttf4packages/flutter_map/lib/assets/flutter_map_logo.png  asset4packages/flutter_map/lib/assets/flutter_map_logo.png assets/images/icon.svg  assetassets/images/icon.svgassets/images/logo.svg  assetassets/images/logo.svg2packages/cupertino_icons/assets/CupertinoIcons.ttf  asset2packages/cupertino_icons/assets/CupertinoIcons.ttf4packages/flutter_map/lib/assets/flutter_map_logo.png  asset4packages/flutter_map/lib/assets/flutter_map_logo.png%packages/timezone/data/latest_all.tzf  asset%packages/timezone/data/latest_all.tzf

View File

@ -1 +1 @@
{"assets/images/icon.svg":["assets/images/icon.svg"],"assets/images/logo.svg":["assets/images/logo.svg"],"packages/cupertino_icons/assets/CupertinoIcons.ttf":["packages/cupertino_icons/assets/CupertinoIcons.ttf"],"packages/flutter_map/lib/assets/flutter_map_logo.png":["packages/flutter_map/lib/assets/flutter_map_logo.png"]} {"assets/images/icon.svg":["assets/images/icon.svg"],"assets/images/logo.svg":["assets/images/logo.svg"],"packages/cupertino_icons/assets/CupertinoIcons.ttf":["packages/cupertino_icons/assets/CupertinoIcons.ttf"],"packages/flutter_map/lib/assets/flutter_map_logo.png":["packages/flutter_map/lib/assets/flutter_map_logo.png"],"packages/timezone/data/latest_all.tzf":["packages/timezone/data/latest_all.tzf"]}

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -1,65 +1,123 @@
# ninja log v5 # ninja log v5
3 5644 0 /home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/flutter_linux/fl_method_call.h df34b103123784f1 43 7102 0 /home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/flutter_linux/fl_method_channel.h df34b103123784f1
3 5644 0 /home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/flutter_linux/fl_plugin_registry.h df34b103123784f1 43 7102 0 /home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/flutter_linux/fl_method_codec.h df34b103123784f1
3 5644 0 /home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/flutter_linux/fl_string_codec.h df34b103123784f1 43 7102 0 /home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/flutter_linux/fl_basic_message_channel.h df34b103123784f1
4 320 1721230626649119048 plugins/super_native_extensions/_phony_ 74762aee97d0d662 43 7102 0 /home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/flutter_linux/fl_engine.h df34b103123784f1
5895 6038 1720171596542283915 plugins/desktop_window/libdesktop_window_plugin.so 26c8f2b838605d38 43 7102 0 /home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/flutter_linux/fl_dart_project.h df34b103123784f1
3 5644 0 flutter/_phony_ df34b103123784f1 43 7102 0 /home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/flutter_linux/fl_binary_messenger.h df34b103123784f1
3 5644 0 /home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/flutter_linux/fl_json_method_codec.h df34b103123784f1 19318 20273 0 CMakeFiles/install.util 558f353ee1373233
3 5644 0 /home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/flutter_linux/fl_method_channel.h df34b103123784f1 43 412 1723042867477311806 plugins/super_native_extensions/libsuper_native_extensions.so 74762aee97d0d662
3 5644 0 /home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/flutter_linux/fl_engine.h df34b103123784f1 18891 19318 1723042886400968232 intermediates_do_not_run/oc_front 4e630cc1de7b670a
3 5644 0 /home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/flutter_linux/fl_dart_project.h df34b103123784f1 43 7102 0 /home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/flutter_linux/fl_value.h df34b103123784f1
13608 16421 1720171474184250688 plugins/desktop_window/CMakeFiles/desktop_window_plugin.dir/desktop_window_plugin.cc.o 259dba9caad978aa
3 5644 0 /home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/flutter_linux/fl_binary_messenger.h df34b103123784f1
6240 6392 0 CMakeFiles/install.util 558f353ee1373233
7221 7661 1720190160103160034 CMakeFiles/oc_front.dir/main.cc.o b1d36a8b3fb9d7f7
3 5644 0 /home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/flutter_linux/fl_method_response.h df34b103123784f1
3 5644 0 /home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/libflutter_linux_gtk.so df34b103123784f1
3 5644 0 /home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/flutter_linux/fl_json_message_codec.h df34b103123784f1
3 5644 0 /home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/flutter_linux/flutter_linux.h df34b103123784f1
5644 6116 1721230632457031904 CMakeFiles/oc_front.dir/my_application.cc.o 3fd042b328f87769
3 5644 0 /home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/flutter_linux/fl_basic_message_channel.h df34b103123784f1
3 5644 0 /home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/flutter_linux/fl_method_codec.h df34b103123784f1
3 5644 0 /home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/flutter_linux/fl_standard_method_codec.h df34b103123784f1
3 5644 0 /home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/flutter_linux/fl_view.h df34b103123784f1
4 320 1721230626649119048 plugins/super_native_extensions/libsuper_native_extensions.so 74762aee97d0d662
6116 6240 1721230632585029984 intermediates_do_not_run/oc_front 4e630cc1de7b670a
3 5644 0 /home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/flutter_linux/fl_binary_codec.h df34b103123784f1
7223 7702 1720190160147159452 plugins/super_native_extensions/CMakeFiles/super_native_extensions_plugin.dir/super_native_extensions_plugin.cc.o e4e228e87b2f98cc
5645 6080 1721230632425032384 CMakeFiles/oc_front.dir/flutter/generated_plugin_registrant.cc.o 79b3e2ad61c9feb4
3 5644 0 /home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/flutter_linux/fl_message_codec.h df34b103123784f1
6105 7479 1720190159919162468 plugins/irondash_engine_context/CMakeFiles/irondash_engine_context_plugin.dir/irondash_engine_context_plugin.cc.o 439d26d301366f5a
3 5644 0 /home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/flutter_linux/fl_standard_message_codec.h df34b103123784f1
3 5644 0 /home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/flutter_linux/fl_plugin_registrar.h df34b103123784f1
7479 7597 1720190160043160828 plugins/irondash_engine_context/libirondash_engine_context_plugin.so a89d3772b0fb0935 7479 7597 1720190160043160828 plugins/irondash_engine_context/libirondash_engine_context_plugin.so a89d3772b0fb0935
3 5644 0 /home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/flutter_linux/fl_value.h df34b103123784f1 43 7102 0 flutter/_phony_ df34b103123784f1
5645 5781 1721230632125036886 plugins/super_native_extensions/libsuper_native_extensions_plugin.so 87d9259f3dbf9022 13608 16421 1720171474184250688 plugins/desktop_window/CMakeFiles/desktop_window_plugin.dir/desktop_window_plugin.cc.o 259dba9caad978aa
3 326 1721231108669887541 plugins/super_native_extensions/libsuper_native_extensions.so 74762aee97d0d662 43 7102 0 /home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/flutter_linux/fl_plugin_registry.h df34b103123784f1
3 326 1721231108669887541 plugins/super_native_extensions/_phony_ 74762aee97d0d662 43 7102 0 /home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/flutter_linux/fl_method_call.h df34b103123784f1
3 5916 0 /home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/libflutter_linux_gtk.so df34b103123784f1 43 7102 0 /home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/flutter_linux/fl_plugin_registrar.h df34b103123784f1
3 5916 0 /home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/flutter_linux/fl_basic_message_channel.h df34b103123784f1 6105 7479 1720190159919162468 plugins/irondash_engine_context/CMakeFiles/irondash_engine_context_plugin.dir/irondash_engine_context_plugin.cc.o 439d26d301366f5a
3 5916 0 /home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/flutter_linux/fl_binary_codec.h df34b103123784f1 43 7102 0 /home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/flutter_linux/fl_standard_message_codec.h df34b103123784f1
3 5916 0 /home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/flutter_linux/fl_binary_messenger.h df34b103123784f1 43 7102 0 /home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/libflutter_linux_gtk.so df34b103123784f1
3 5916 0 /home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/flutter_linux/fl_dart_project.h df34b103123784f1 43 7102 0 /home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/flutter_linux/fl_json_message_codec.h df34b103123784f1
3 5916 0 /home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/flutter_linux/fl_engine.h df34b103123784f1 43 7102 0 /home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/flutter_linux/flutter_linux.h df34b103123784f1
3 5916 0 /home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/flutter_linux/fl_json_message_codec.h df34b103123784f1 43 7102 0 /home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/flutter_linux/fl_string_codec.h df34b103123784f1
3 5916 0 /home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/flutter_linux/fl_json_method_codec.h df34b103123784f1 5895 6038 1720171596542283915 plugins/desktop_window/libdesktop_window_plugin.so 26c8f2b838605d38
3 5916 0 /home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/flutter_linux/fl_message_codec.h df34b103123784f1 43 412 1723042867477311806 plugins/super_native_extensions/_phony_ 74762aee97d0d662
3 5916 0 /home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/flutter_linux/fl_method_call.h df34b103123784f1 43 7102 0 /home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/flutter_linux/fl_method_response.h df34b103123784f1
3 5916 0 /home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/flutter_linux/fl_method_channel.h df34b103123784f1 43 7102 0 /home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/flutter_linux/fl_binary_codec.h df34b103123784f1
3 5916 0 /home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/flutter_linux/fl_method_codec.h df34b103123784f1 7223 7702 1720190160147159452 plugins/super_native_extensions/CMakeFiles/super_native_extensions_plugin.dir/super_native_extensions_plugin.cc.o e4e228e87b2f98cc
3 5916 0 /home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/flutter_linux/fl_method_response.h df34b103123784f1 7117 18885 1723042885952976327 CMakeFiles/oc_front.dir/flutter/generated_plugin_registrant.cc.o 79b3e2ad61c9feb4
3 5916 0 /home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/flutter_linux/fl_plugin_registrar.h df34b103123784f1 43 7102 0 /home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/flutter_linux/fl_message_codec.h df34b103123784f1
3 5916 0 /home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/flutter_linux/fl_plugin_registry.h df34b103123784f1 7117 16523 1723042883325023855 plugins/super_native_extensions/libsuper_native_extensions_plugin.so 87d9259f3dbf9022
3 5916 0 /home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/flutter_linux/fl_standard_message_codec.h df34b103123784f1 43 7102 0 /home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/flutter_linux/fl_json_method_codec.h df34b103123784f1
3 5916 0 /home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/flutter_linux/fl_standard_method_codec.h df34b103123784f1 43 7102 0 /home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/flutter_linux/fl_view.h df34b103123784f1
3 5916 0 /home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/flutter_linux/fl_string_codec.h df34b103123784f1 43 7102 0 /home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/flutter_linux/fl_standard_method_codec.h df34b103123784f1
3 5916 0 /home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/flutter_linux/fl_value.h df34b103123784f1 7221 7661 1720190160103160034 CMakeFiles/oc_front.dir/main.cc.o b1d36a8b3fb9d7f7
3 5916 0 /home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/flutter_linux/fl_view.h df34b103123784f1 7116 18891 1723042885956976255 CMakeFiles/oc_front.dir/my_application.cc.o 3fd042b328f87769
3 5916 0 /home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/flutter_linux/flutter_linux.h df34b103123784f1 58 466 1723042916288432161 plugins/super_native_extensions/libsuper_native_extensions.so 74762aee97d0d662
3 5916 0 flutter/_phony_ df34b103123784f1 58 466 1723042916288432161 plugins/super_native_extensions/_phony_ 74762aee97d0d662
5919 6044 1721231114401801556 plugins/super_native_extensions/libsuper_native_extensions_plugin.so 87d9259f3dbf9022 57 12620 0 /home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/libflutter_linux_gtk.so df34b103123784f1
5918 6335 1721231114689797236 CMakeFiles/oc_front.dir/flutter/generated_plugin_registrant.cc.o 79b3e2ad61c9feb4 57 12620 0 /home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/flutter_linux/fl_basic_message_channel.h df34b103123784f1
5917 6380 1721231114733796575 CMakeFiles/oc_front.dir/my_application.cc.o 3fd042b328f87769 57 12620 0 /home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/flutter_linux/fl_binary_codec.h df34b103123784f1
6380 6517 1721231114873794475 intermediates_do_not_run/oc_front 4e630cc1de7b670a 57 12620 0 /home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/flutter_linux/fl_binary_messenger.h df34b103123784f1
6517 6648 0 CMakeFiles/install.util 558f353ee1373233 57 12620 0 /home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/flutter_linux/fl_dart_project.h df34b103123784f1
57 12620 0 /home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/flutter_linux/fl_engine.h df34b103123784f1
57 12620 0 /home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/flutter_linux/fl_json_message_codec.h df34b103123784f1
57 12620 0 /home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/flutter_linux/fl_json_method_codec.h df34b103123784f1
57 12620 0 /home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/flutter_linux/fl_message_codec.h df34b103123784f1
57 12620 0 /home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/flutter_linux/fl_method_call.h df34b103123784f1
57 12620 0 /home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/flutter_linux/fl_method_channel.h df34b103123784f1
57 12620 0 /home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/flutter_linux/fl_method_codec.h df34b103123784f1
57 12620 0 /home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/flutter_linux/fl_method_response.h df34b103123784f1
57 12620 0 /home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/flutter_linux/fl_plugin_registrar.h df34b103123784f1
57 12620 0 /home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/flutter_linux/fl_plugin_registry.h df34b103123784f1
57 12620 0 /home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/flutter_linux/fl_standard_message_codec.h df34b103123784f1
57 12620 0 /home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/flutter_linux/fl_standard_method_codec.h df34b103123784f1
57 12620 0 /home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/flutter_linux/fl_string_codec.h df34b103123784f1
57 12620 0 /home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/flutter_linux/fl_value.h df34b103123784f1
57 12620 0 /home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/flutter_linux/fl_view.h df34b103123784f1
57 12620 0 /home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/flutter_linux/flutter_linux.h df34b103123784f1
57 12620 0 flutter/_phony_ df34b103123784f1
12638 21600 1723042936588072438 plugins/super_native_extensions/libsuper_native_extensions_plugin.so 87d9259f3dbf9022
12638 24688 1723042940476003931 CMakeFiles/oc_front.dir/flutter/generated_plugin_registrant.cc.o 79b3e2ad61c9feb4
12638 24698 1723042940524003086 CMakeFiles/oc_front.dir/my_application.cc.o 3fd042b328f87769
24698 25496 1723042941331988865 intermediates_do_not_run/oc_front 4e630cc1de7b670a
25496 27380 0 CMakeFiles/install.util 558f353ee1373233
93 17067 1723043023530568429 plugins/super_native_extensions/libsuper_native_extensions.so 74762aee97d0d662
93 17067 1723043023530568429 plugins/super_native_extensions/_phony_ 74762aee97d0d662
91 25502 0 /home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/libflutter_linux_gtk.so df34b103123784f1
91 25502 0 /home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/flutter_linux/fl_basic_message_channel.h df34b103123784f1
91 25502 0 /home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/flutter_linux/fl_binary_codec.h df34b103123784f1
91 25502 0 /home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/flutter_linux/fl_binary_messenger.h df34b103123784f1
91 25502 0 /home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/flutter_linux/fl_dart_project.h df34b103123784f1
91 25502 0 /home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/flutter_linux/fl_engine.h df34b103123784f1
91 25502 0 /home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/flutter_linux/fl_json_message_codec.h df34b103123784f1
91 25502 0 /home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/flutter_linux/fl_json_method_codec.h df34b103123784f1
91 25502 0 /home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/flutter_linux/fl_message_codec.h df34b103123784f1
91 25502 0 /home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/flutter_linux/fl_method_call.h df34b103123784f1
91 25502 0 /home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/flutter_linux/fl_method_channel.h df34b103123784f1
91 25502 0 /home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/flutter_linux/fl_method_codec.h df34b103123784f1
91 25502 0 /home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/flutter_linux/fl_method_response.h df34b103123784f1
91 25502 0 /home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/flutter_linux/fl_plugin_registrar.h df34b103123784f1
91 25502 0 /home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/flutter_linux/fl_plugin_registry.h df34b103123784f1
91 25502 0 /home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/flutter_linux/fl_standard_message_codec.h df34b103123784f1
91 25502 0 /home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/flutter_linux/fl_standard_method_codec.h df34b103123784f1
91 25502 0 /home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/flutter_linux/fl_string_codec.h df34b103123784f1
91 25502 0 /home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/flutter_linux/fl_value.h df34b103123784f1
91 25502 0 /home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/flutter_linux/fl_view.h df34b103123784f1
91 25502 0 /home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/flutter_linux/flutter_linux.h df34b103123784f1
91 25502 0 flutter/_phony_ df34b103123784f1
25503 26894 1723043048582145188 plugins/super_native_extensions/libsuper_native_extensions_plugin.so 87d9259f3dbf9022
25503 28785 1723043050470113462 CMakeFiles/oc_front.dir/flutter/generated_plugin_registrant.cc.o 79b3e2ad61c9feb4
25502 28787 1723043050470113462 CMakeFiles/oc_front.dir/my_application.cc.o 3fd042b328f87769
28787 28990 1723043050674110035 intermediates_do_not_run/oc_front 4e630cc1de7b670a
28990 29315 0 CMakeFiles/install.util 558f353ee1373233
26 384 1723043130512788850 plugins/super_native_extensions/libsuper_native_extensions.so 74762aee97d0d662
26 384 1723043130512788850 plugins/super_native_extensions/_phony_ 74762aee97d0d662
26 6081 0 /home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/libflutter_linux_gtk.so df34b103123784f1
26 6081 0 /home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/flutter_linux/fl_basic_message_channel.h df34b103123784f1
26 6081 0 /home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/flutter_linux/fl_binary_codec.h df34b103123784f1
26 6081 0 /home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/flutter_linux/fl_binary_messenger.h df34b103123784f1
26 6081 0 /home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/flutter_linux/fl_dart_project.h df34b103123784f1
26 6081 0 /home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/flutter_linux/fl_engine.h df34b103123784f1
26 6081 0 /home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/flutter_linux/fl_json_message_codec.h df34b103123784f1
26 6081 0 /home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/flutter_linux/fl_json_method_codec.h df34b103123784f1
26 6081 0 /home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/flutter_linux/fl_message_codec.h df34b103123784f1
26 6081 0 /home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/flutter_linux/fl_method_call.h df34b103123784f1
26 6081 0 /home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/flutter_linux/fl_method_channel.h df34b103123784f1
26 6081 0 /home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/flutter_linux/fl_method_codec.h df34b103123784f1
26 6081 0 /home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/flutter_linux/fl_method_response.h df34b103123784f1
26 6081 0 /home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/flutter_linux/fl_plugin_registrar.h df34b103123784f1
26 6081 0 /home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/flutter_linux/fl_plugin_registry.h df34b103123784f1
26 6081 0 /home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/flutter_linux/fl_standard_message_codec.h df34b103123784f1
26 6081 0 /home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/flutter_linux/fl_standard_method_codec.h df34b103123784f1
26 6081 0 /home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/flutter_linux/fl_string_codec.h df34b103123784f1
26 6081 0 /home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/flutter_linux/fl_value.h df34b103123784f1
26 6081 0 /home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/flutter_linux/fl_view.h df34b103123784f1
26 6081 0 /home/mr/Documents/OC/oc-front/linux/flutter/ephemeral/flutter_linux/flutter_linux.h df34b103123784f1
26 6081 0 flutter/_phony_ df34b103123784f1
6084 6259 1723043136404692840 plugins/super_native_extensions/libsuper_native_extensions_plugin.so 87d9259f3dbf9022
6083 6556 1723043136700688022 CMakeFiles/oc_front.dir/flutter/generated_plugin_registrant.cc.o 79b3e2ad61c9feb4
6082 6587 1723043136728687566 CMakeFiles/oc_front.dir/my_application.cc.o 3fd042b328f87769
6587 6802 1723043136948683986 intermediates_do_not_run/oc_front 4e630cc1de7b670a
6802 6962 0 CMakeFiles/install.util 558f353ee1373233

View File

@ -1 +1 @@
assets/images/icon.svg  assetassets/images/icon.svgassets/images/logo.svg  assetassets/images/logo.svg2packages/cupertino_icons/assets/CupertinoIcons.ttf  asset2packages/cupertino_icons/assets/CupertinoIcons.ttf4packages/flutter_map/lib/assets/flutter_map_logo.png  asset4packages/flutter_map/lib/assets/flutter_map_logo.png assets/images/icon.svg  assetassets/images/icon.svgassets/images/logo.svg  assetassets/images/logo.svg2packages/cupertino_icons/assets/CupertinoIcons.ttf  asset2packages/cupertino_icons/assets/CupertinoIcons.ttf4packages/flutter_map/lib/assets/flutter_map_logo.png  asset4packages/flutter_map/lib/assets/flutter_map_logo.png%packages/timezone/data/latest_all.tzf  asset%packages/timezone/data/latest_all.tzf

View File

@ -1 +1 @@
{"assets/images/icon.svg":["assets/images/icon.svg"],"assets/images/logo.svg":["assets/images/logo.svg"],"packages/cupertino_icons/assets/CupertinoIcons.ttf":["packages/cupertino_icons/assets/CupertinoIcons.ttf"],"packages/flutter_map/lib/assets/flutter_map_logo.png":["packages/flutter_map/lib/assets/flutter_map_logo.png"]} {"assets/images/icon.svg":["assets/images/icon.svg"],"assets/images/logo.svg":["assets/images/logo.svg"],"packages/cupertino_icons/assets/CupertinoIcons.ttf":["packages/cupertino_icons/assets/CupertinoIcons.ttf"],"packages/flutter_map/lib/assets/flutter_map_logo.png":["packages/flutter_map/lib/assets/flutter_map_logo.png"],"packages/timezone/data/latest_all.tzf":["packages/timezone/data/latest_all.tzf"]}

View File

@ -14,6 +14,7 @@
/home/mr/Documents/OC/oc-front/build/linux/x64/debug/bundle/data/flutter_assets/NOTICES.Z /home/mr/Documents/OC/oc-front/build/linux/x64/debug/bundle/data/flutter_assets/NOTICES.Z
/home/mr/Documents/OC/oc-front/build/linux/x64/debug/bundle/data/flutter_assets/packages/cupertino_icons/assets/CupertinoIcons.ttf /home/mr/Documents/OC/oc-front/build/linux/x64/debug/bundle/data/flutter_assets/packages/cupertino_icons/assets/CupertinoIcons.ttf
/home/mr/Documents/OC/oc-front/build/linux/x64/debug/bundle/data/flutter_assets/packages/flutter_map/lib/assets/flutter_map_logo.png /home/mr/Documents/OC/oc-front/build/linux/x64/debug/bundle/data/flutter_assets/packages/flutter_map/lib/assets/flutter_map_logo.png
/home/mr/Documents/OC/oc-front/build/linux/x64/debug/bundle/data/flutter_assets/packages/timezone/data/latest_all.tzf
/home/mr/Documents/OC/oc-front/build/linux/x64/debug/bundle/data/flutter_assets/version.json /home/mr/Documents/OC/oc-front/build/linux/x64/debug/bundle/data/flutter_assets/version.json
/home/mr/Documents/OC/oc-front/build/linux/x64/debug/bundle/data/flutter_assets/FontManifest.json /home/mr/Documents/OC/oc-front/build/linux/x64/debug/bundle/data/flutter_assets/FontManifest.json
/home/mr/Documents/OC/oc-front/build/linux/x64/debug/bundle/data/flutter_assets/AssetManifest.bin /home/mr/Documents/OC/oc-front/build/linux/x64/debug/bundle/data/flutter_assets/AssetManifest.bin

View File

@ -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 }) {
}
}

View File

@ -1,84 +1,177 @@
import 'package:flutter/material.dart'; 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/search.dart';
import 'package:oc_front/models/workspace.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/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 { class WorkspaceLocal {
static Workspace? workspace; static String? current;
static Map<String, Workspace> workspaces = {};
static final WorkspaceService _service = WorkspaceService(); static final WorkspaceService _service = WorkspaceService();
static List<AbstractItem> items = []; static List<AbstractItem> items = [];
static void init(BuildContext context) {
static void init(BuildContext context, bool changeCurrent) {
_service.all(context).then((value) { _service.all(context).then((value) {
workspace = value.data; if (value.data != null && value.data!.values.isNotEmpty ) {
if (workspace != null) { var vals = value.data!.values;
if (workspace!.data.isNotEmpty) { for (var element in vals) {
ItemService<DataItem, DataItem> dataService = ItemService<DataItem, DataItem>(); var ws = Workspace().deserialize(element);
for (var element in workspace!.data) { if (ws.id == null) { continue; }
if (WorkspaceLocal.hasItemByID(element)) { continue; } workspaces[ws.id!] = ws;
dataService.get(context, element).then( if (current == null) {
(value) { if (value.data != null) { items.add(value.data!); } } current ??= ws.id;
); workspaces[current!] = ws;
_service.put(context, ws.id!, { "active" : true }, {});
} }
if (ws.active == true && changeCurrent) {
current = ws.id;
} }
if (workspace!.computing.isNotEmpty) { fill();
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!); } }
);
}
} }
} 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(); 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); var found = WorkspaceLocal.items.where((element) => element.id.toString() == id);
return found.isEmpty ? null : found.first; return found.isEmpty ? null : found.first;
} }
static void addItem(AbstractItem item) { static void addItem(AbstractItem item) {
if (!WorkspaceLocal.hasItem(item)) { if (!WorkspaceLocal.hasItem(item) && workspaces[current] != null && workspaces[current]!.id != null) {
items.add(item); items.add(item);
try { if (item.topic == "data") { workspaces[current]!.datas.add(item as DataItem); }
_service.post(null, {}, { "id" : item.id.toString(), "rtype" : item.type.toString() }); 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) { /* */ } } catch (e) { /* */ }
_service.put(null, item.id ?? "", workspaces[current]!.serialize(), {});
} }
} }
static void removeItem(AbstractItem item) { static void removeItem(AbstractItem item) {
items = items.where((element) => element.name != item.name).toList(); 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) { /* */ } } catch (e) { /* */ }
_service.put(null, item.id ?? "", workspaces[current]!.serialize(), {});
} }
static bool hasItemByID(String id) { static bool hasItemByID(String id) {
return items.where((element) => element.id == id).isNotEmpty; return items.where((element) => element.id == id).isNotEmpty;
} }
static bool hasItem(AbstractItem item) { 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(); static void clear() => items.clear();
} }

View File

@ -3,6 +3,7 @@ import 'package:oc_front/models/search.dart';
import 'package:oc_front/pages/catalog.dart'; import 'package:oc_front/pages/catalog.dart';
import 'package:oc_front/core/models/workspace_local.dart'; import 'package:oc_front/core/models/workspace_local.dart';
import 'package:oc_front/widgets/items/item_row.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>(); GlobalKey<EndDrawerWidgetState> endDrawerKey = GlobalKey<EndDrawerWidgetState>();
class EndDrawerWidget extends StatefulWidget { 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, color: Colors.grey.shade300,
child: const Center(child: Text("WORKSPACE IS EMPTY", child: const Center(child: Text("WORKSPACE IS EMPTY",
style: TextStyle(fontSize: 25, fontWeight: FontWeight.w600, color: Colors.white)))) style: TextStyle(fontSize: 25, fontWeight: FontWeight.w600, color: Colors.white))))

View File

@ -61,7 +61,7 @@ class SearchWidgetState extends State<SearchWidget> {
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
children: [ children: [
Container( 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, height: 50,
color: Colors.white, color: Colors.white,
child: TextField( child: TextField(

View File

@ -82,18 +82,17 @@ class APIService<T extends SerializerDeserializer> {
_dio.options.headers["authorization"] = auth; _dio.options.headers["authorization"] = auth;
_dio.interceptors.clear(); _dio.interceptors.clear();
var response = await _request(url, method, body, options); var response = await _request(url, method, body, options);
print(response);
if (response.statusCode != null && response.statusCode! < 400) { if (response.statusCode != null && response.statusCode! < 400) {
if (method == "delete") { cache.remove(url); return APIResponse<T>(); } if (method == "delete") { cache.remove(url); return APIResponse<T>(); }
APIResponse<T> resp = APIResponse<T>().deserialize(response.data); APIResponse<T> resp = APIResponse<T>().deserialize(response.data);
if (resp.error == "") { if (resp.error == "") {
if (method == "get") { cache[url]=resp; }
if (context != null && succeed != "") { if (context != null && succeed != "") {
// ignore: use_build_context_synchronously // ignore: use_build_context_synchronously
showAlertBanner(context, () {}, InfoAlertBannerChild(text: succeed), // <-- Put any widget here you want! showAlertBanner(context, () {}, InfoAlertBannerChild(text: succeed), // <-- Put any widget here you want!
alertBannerLocation: AlertBannerLocation.bottom,); alertBannerLocation: AlertBannerLocation.bottom,);
} }
try { return cache[url] as APIResponse<T>; return resp;
} catch (e) { return APIResponse(); }
} }
err = resp.error ?? "internal error"; err = resp.error ?? "internal error";
} }

View File

@ -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.", 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()); factory: WorkflowFactory());
static final RouterItem catalogItem = RouterItem(description: "", help: "", route: "catalog/:id", factory: CatalogItemFactory(), args: ["id"]); 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 = [ static List<RouterItem> zones = [
RouterItem(icon: Icons.book_outlined, label: "catalog searcher", route: home, factory: CatalogFactory()), catalog,
workflowItem, workflowItem,
RouterItem(icon: Icons.schedule, label: "scheduled tasks", route: "scheduler", factory: SchedulerFactory()), RouterItem(icon: Icons.schedule, label: "scheduled tasks", route: "scheduler", factory: SchedulerFactory()),
RouterItem(icon: Icons.dns_outlined, label: "my datacenter", route: "datacenter", RouterItem(icon: Icons.dns_outlined, label: "my datacenter", route: "datacenter",

View File

@ -7,9 +7,21 @@ abstract class AbstractService<T extends SerializerDeserializer> {
abstract APIService<T> service; abstract APIService<T> service;
abstract String subPath; abstract String subPath;
Future<APIResponse<T>> all(BuildContext? context) { throw UnimplementedError(); } Future<APIResponse<T>> search(BuildContext? context, List<String> words, Map<String, dynamic> params) { throw UnimplementedError(); }
Future<APIResponse<T>> get(BuildContext? context, String id); Future<APIResponse<RawData>> all(BuildContext? context) {
Future<APIResponse<T>> post(BuildContext? context, Map<String, dynamic> body, Map<String, String> params); return service.raw(subPath, null, "get");
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(); }
} }
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);
}
}

View File

@ -1,24 +1,11 @@
import 'package:flutter/material.dart';
import 'package:oc_front/core/services/api_service.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/core/services/specialized_services/abstract_service.dart';
import 'package:oc_front/models/abstract.dart'; import 'package:oc_front/models/abstract.dart';
import 'package:oc_front/models/response.dart';
import 'package:oc_front/models/search.dart'; import 'package:oc_front/models/search.dart';
class ItemService<S extends AbstractItem, T extends SerializerDeserializer<S>> extends AbstractService<T> { class ItemService<S extends AbstractItem, T extends SerializerDeserializer<S>> extends AbstractService<T> {
@override APIService<T> service = APIService<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 String subPath = "/oc/${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(); }
} }

View 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();
}
}

View 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();
}
}

View File

@ -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(); }
}

View 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/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();
}
}

View File

@ -1,26 +1,10 @@
import 'package:flutter/material.dart';
import 'package:oc_front/core/services/api_service.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/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> { class WorflowService extends AbstractService<Workflow> {
@override APIService<RawData> service = APIService<RawData>( @override APIService<Workflow> service = APIService<Workflow>(
baseURL: const String.fromEnvironment('WORKFLOW_HOST', defaultValue: 'http://localhost:49618') baseURL: const String.fromEnvironment('WORKFLOW_HOST', defaultValue: 'http://localhost:8088')
); );
@override String subPath = "/v1/workflow/"; @override String subPath = "/oc/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();
}
} }

View File

@ -1,30 +1,10 @@
import 'package:flutter/material.dart';
import 'package:oc_front/core/services/api_service.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/core/services/specialized_services/abstract_service.dart';
import 'package:oc_front/models/response.dart';
import 'package:oc_front/models/workspace.dart'; import 'package:oc_front/models/workspace.dart';
class WorkspaceService extends AbstractService<Workspace> { class WorkspaceService extends AbstractService<Workspace> {
@override APIService<Workspace> service = APIService<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 String subPath = "/oc/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);
}
} }

View File

@ -50,7 +50,7 @@ class _MainPageState extends State<MainPage> {
// The Flutter framework has been optimized to make rerunning build methods // The Flutter framework has been optimized to make rerunning build methods
// fast, so that you can just rebuild anything that needs updating rather // fast, so that you can just rebuild anything that needs updating rather
// than having to individually change instances of widgets. // than having to individually change instances of widgets.
WorkspaceLocal.init(context); WorkspaceLocal.init(context, false);
scaffoldKey = GlobalKey<ScaffoldState>(); scaffoldKey = GlobalKey<ScaffoldState>();
return Scaffold( return Scaffold(
key: scaffoldKey, key: scaffoldKey,

View File

@ -1,5 +1,4 @@
import 'dart:convert'; import 'dart:convert';
import 'dart:developer' as developer;
abstract class SerializerDeserializer<T> { abstract class SerializerDeserializer<T> {
T deserialize(dynamic json); T deserialize(dynamic json);

116
lib/models/logs.dart Normal file
View 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 { }; }
}

View File

@ -1,5 +1,7 @@
import 'package:oc_front/models/abstract.dart'; 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/search.dart';
import 'package:oc_front/models/workflow.dart';
import 'package:oc_front/models/workspace.dart'; import 'package:oc_front/models/workspace.dart';
Map<Type, SerializerDeserializer> refs = <Type, SerializerDeserializer> { Map<Type, SerializerDeserializer> refs = <Type, SerializerDeserializer> {
@ -9,15 +11,21 @@ Map<Type, SerializerDeserializer> refs = <Type, SerializerDeserializer> {
DataItem: DataItem(), DataItem: DataItem(),
DataCenterItem: DataCenterItem(), DataCenterItem: DataCenterItem(),
StorageItem: StorageItem(), StorageItem: StorageItem(),
ComputingItem: ComputingItem(), ProcessingItem: ProcessingItem(),
Workflow: Workflow(),
Resource: Resource(),
WorkflowExecutions: WorkflowExecutions(),
LogResults: LogResults(),
}; };
class APIResponse<T extends SerializerDeserializer> { class APIResponse<T extends SerializerDeserializer> {
APIResponse({ APIResponse({
this.data, this.data,
this.code = 200,
this.error = "", this.error = "",
this.offset = 0, this.offset = 0,
}); });
int code = 200;
int offset = 0; int offset = 0;
T? data ; T? data ;
String? error = ""; String? error = "";
@ -28,18 +36,22 @@ class APIResponse<T extends SerializerDeserializer> {
} }
APIResponse<T> deserialize(dynamic j) { APIResponse<T> deserialize(dynamic j) {
dynamic data;
try { data = j["data"];
} catch (e) { data = j; }
try { try {
return APIResponse<T>( 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"] : "", 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> { class RawData extends SerializerDeserializer<RawData> {
RawData({ this.values = const []}); RawData({ this.values = const []});
dynamic values; List<dynamic> values = [];
@override deserialize(dynamic json) { return RawData(values: json); } @override deserialize(dynamic json) { return RawData(values: json ?? []); }
@override Map<String, dynamic> serialize() => { }; @override Map<String, dynamic> serialize() => { };
} }

View File

@ -1,6 +1,7 @@
import 'package:flutter_flow_chart/flutter_flow_chart.dart';
import 'package:oc_front/models/abstract.dart'; import 'package:oc_front/models/abstract.dart';
const List<ComputingItem> _emptyComputing = []; const List<ProcessingItem> _emptyComputing = [];
const List<DataItem> _emptyData = []; const List<DataItem> _emptyData = [];
const List<DataCenterItem> _emptyDataCenter = []; const List<DataCenterItem> _emptyDataCenter = [];
const List<StorageItem> _emptyStorage = []; const List<StorageItem> _emptyStorage = [];
@ -11,248 +12,539 @@ class Search extends SerializerDeserializer<Search> {
this.data = _emptyData, this.data = _emptyData,
this.storage = _emptyStorage, this.storage = _emptyStorage,
}); });
List<ComputingItem> computing; List<ProcessingItem> computing;
List<DataCenterItem> datacenter; List<DataCenterItem> datacenter;
List<DataItem> data; List<DataItem> data;
List<StorageItem> storage; List<StorageItem> storage;
@override deserialize(dynamic json) { @override deserialize(dynamic json) {
json = json as Map<String, dynamic>; json = json as Map<String, dynamic>;
return Search( 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()) : [], datacenter: json.containsKey("datacenter") ? fromListJson(json["datacenter"], DataCenterItem()) : [],
data: json.containsKey("data") ? fromListJson(json["data"], DataItem()) : [], data: json.containsKey("data") ? fromListJson(json["data"], DataItem()) : [],
storage: json.containsKey("storage") ? fromListJson(json["storage"], StorageItem()) : [], 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 = []; 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? id;
String? name; String? name;
String? logo; String? logo;
String? type;
String? owner; String? owner;
String? ownerLogo;
String? source;
String? description; String? description;
String? shortDescription; String? shortDescription;
double? price;
String? licence;
List<dynamic> inputs = [];
List<dynamic> outputs = [];
ResourceModel? model;
String topic = ""; 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) { Type? getTopicType(String topic) {
if (topic == "computing") { return ComputingItem; } if (topic == "processing") { return ProcessingItem; }
else if (topic == "data") { return DataItem; } else if (topic == "data") { return DataItem; }
else if (topic == "datacenter") { return DataCenterItem; } else if (topic == "datacenter") { return DataCenterItem; }
else if (topic == "storage") { return StorageItem; } else if (topic == "storage") { return StorageItem; }
else if (topic == "workflow") { return WorkflowItem; }
else { return null; } else { return null; }
} }
String getTopic(Type type) { 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 == DataItem) { return "data"; }
if (type == DataCenterItem) { return "datacenter"; } if (type == DataCenterItem) { return "datacenter"; }
if (type == StorageItem) { return "storage"; } if (type == StorageItem) { return "storage"; }
if (type == WorkflowItem) { return "workflow"; }
return ""; return "";
} }
bool isComputing(String topic) => topic == "computing"; bool isComputing(String topic) => topic == "processing";
bool isData(String topic) => topic == "data"; bool isData(String topic) => topic == "data";
bool isDataCenter(String topic) => topic == "datacenter"; bool isDataCenter(String topic) => topic == "datacenter";
bool isStorage(String topic) => topic == "storage"; bool isStorage(String topic) => topic == "storage";
bool isWorkflow(String topic) => topic == "workflow";
class ComputingItem extends SerializerDeserializer<ComputingItem> implements AbstractItem { class ProcessingItem extends SerializerDeserializer<ProcessingItem> implements AbstractItem<ProcessingItem> {
ComputingItem({ ProcessingItem({
this.id, this.id,
this.name, this.name,
this.logo, this.logo,
this.type,
this.owner, this.owner,
this.ownerLogo,
this.price, this.price,
this.image, this.source,
this.command,
this.licence, this.licence,
this.description, this.description,
this.requirements,
this.ports = _empty,
this.shortDescription, this.shortDescription,
this.dinputs = _empty, this.inputs = _empty,
this.doutputs = _empty, this.outputs = _empty,
this.arguments = _empty,
this.environment = _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? id;
@override String? name; @override String? name;
@override String? logo; @override String? logo;
@override String? type; @override String? source;
@override String? ownerLogo;
@override String? owner; @override String? owner;
@override String topic = "computing"; @override String topic = "processing";
double? price; @override double? price;
String? image; @override String? licence;
String? command; @override List<dynamic> inputs;
String? licence; @override List<dynamic> outputs;
List<dynamic> ports;
List<dynamic> dinputs;
List<dynamic> doutputs;
List<dynamic> arguments;
@override String? description; @override String? description;
@override String? shortDescription; @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) { @override deserialize(dynamic json) {
try { json = json as Map<String, dynamic>; try { json = json as Map<String, dynamic>;
} catch (e) { return ComputingItem(); } } catch (e) { return ProcessingItem(); }
return ComputingItem( return ProcessingItem(
id: json.containsKey("ID") ? json["ID"] : null, id: json.containsKey("id") ? json["id"] : null,
name: json.containsKey("name") ? json["name"] : null, name: json.containsKey("name") ? json["name"] : null,
logo: json.containsKey("logo") ? json["logo"] : null, logo: json.containsKey("logo") ? json["logo"] : null,
type: json.containsKey("type") ? json["type"] : null,
owner: json.containsKey("owner") ? json["owner"] : 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, 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, licence: json.containsKey("licence") ? json["licence"] : null,
description: json.containsKey("description") ? json["description"] : null, description: json.containsKey("description") ? json["description"] : null,
ports: json["ports"] ?? [],
shortDescription: json.containsKey("short_description") ? json["short_description"] : null, shortDescription: json.containsKey("short_description") ? json["short_description"] : null,
dinputs: json["dinputs"] ?? [], inputs: json["inputs"] ?? [],
doutputs: json["doutputs"] ?? [], outputs: json["outputs"] ?? [],
arguments: json["arguments"] ?? [], source: json.containsKey("source") ? json["source"] : null,
environment: json["environment"] ?? [],
requirements: json.containsKey("requirements") ? ExecRequirements().deserialize(json["execution_requirements"]) : 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> { class WorkflowItem extends SerializerDeserializer<WorkflowItem> implements AbstractItem<WorkflowItem> {
ExecRequirements({ WorkflowItem({
this.ram, this.id,
this.cpus, this.name,
this.gpus, this.logo,
this.diskIO, this.owner,
this.scallingModel, this.ownerLogo,
this.parallel = false, this.price,
this.source,
this.licence,
this.description,
this.shortDescription,
this.inputs = _empty,
this.outputs = _empty,
this.model,
this.workflowID,
}); });
double? ram; @override ResourceModel? model;
double? cpus; @override String? id;
double? gpus; @override String? name;
String? diskIO; @override String? logo;
bool parallel = false; @override String? source;
double? scallingModel; @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) { @override deserialize(dynamic json) {
try { json = json as Map<String, dynamic>; try { json = json as Map<String, dynamic>;
} catch (e) { return ExecRequirements(); } } catch (e) { return WorkflowItem(); }
return ExecRequirements( return WorkflowItem(
ram: json.containsKey("ram") ? json["ram"]?.toDouble() : null, id: json.containsKey("id") ? json["id"] : null,
cpus: json.containsKey("cpus") ? json["cpus"]?.toDouble() : null, name: json.containsKey("name") ? json["name"] : null,
gpus: json.containsKey("gpus") ? json["gpus"]?.toDouble() : null, logo: json.containsKey("logo") ? json["logo"] : null,
diskIO: json.containsKey("disk_io") ? json["disk_io"] : null, owner: json.containsKey("owner") ? json["owner"] : null,
scallingModel: json.containsKey("scaling_model") ? json["scaling_model"]?.toDouble() : null, ownerLogo: json.containsKey("owner_logo") ? json["owner_logo"] : null,
parallel: json.containsKey("parallel") ? json["parallel"] : false, 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({ DataItem({
this.id, this.id,
this.name, this.name,
this.logo, this.logo,
this.type,
this.dtype,
this.owner, this.owner,
this.example, this.ownerLogo,
this.location, this.price,
this.source,
this.licence,
this.description, this.description,
this.protocol = _empty,
this.shortDescription, this.shortDescription,
this.inputs = _empty,
this.outputs = _empty,
this.model,
this.protocols = const [],
this.dataType,
this.exemple,
}); });
@override String? id; @override String? id;
@override String? name; @override String? name;
@override String? logo; @override String? logo;
@override String? type; @override String? source;
@override String topic = "data"; @override String? ownerLogo;
String? dtype;
String? example;
String? location;
@override String? description;
List<dynamic> protocol;
@override String? shortDescription;
@override String? owner; @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) { @override deserialize(dynamic json) {
try { json = json as Map<String, dynamic>; try { json = json as Map<String, dynamic>;
} catch (e) { return DataItem(); } } catch (e) { return DataItem(); }
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, name: json.containsKey("name") ? json["name"] : null,
logo: json.containsKey("logo") ? json["logo"] : null, logo: json.containsKey("logo") ? json["logo"] : null,
type: json.containsKey("type") ? json["type"] : null,
owner: json.containsKey("owner") ? json["owner"] : null, owner: json.containsKey("owner") ? json["owner"] : null,
dtype: json.containsKey("dtype") ? json["dtype"] : null, ownerLogo: json.containsKey("owner_logo") ? json["owner_logo"] : null,
example: json.containsKey("example") ? json["example"] : null, price: json.containsKey("price") ? json["price"]?.toDouble() : null,
location: json.containsKey("location") ? json["location"] : null, licence: json.containsKey("licence") ? json["licence"] : null,
description: json.containsKey("description") ? json["description"] : 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({ DataCenterItem({
this.id, this.id,
this.cpu,
this.ram,
this.name, this.name,
this.logo, this.logo,
this.type,
this.owner, this.owner,
this.acronym, this.ownerLogo,
this.bookingPrice, this.price,
this.source,
this.licence,
this.description, this.description,
this.hosts = _empty,
this.gpus = _emptyGPU,
this.shortDescription, 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? id;
@override String? name; @override String? name;
@override String? logo; @override String? logo;
@override String? type; @override String? source;
@override String? ownerLogo;
@override String? owner; @override String? owner;
@override String topic = "datacenter"; @override String topic = "datacenter";
String? acronym; @override double? price;
List<GPU> gpus = []; @override String? licence;
@override List<dynamic> inputs;
@override List<dynamic> outputs;
@override String? description; @override String? description;
List<dynamic> hosts;
double? bookingPrice;
@override String? shortDescription; @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) { @override deserialize(dynamic json) {
try { json = json as Map<String, dynamic>; try { json = json as Map<String, dynamic>;
} catch (e) { return DataCenterItem(); } } catch (e) { return DataCenterItem(); }
return DataCenterItem( return DataCenterItem(
id: json.containsKey("ID") ? json["ID"] : null, 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,
name: json.containsKey("name") ? json["name"] : null, name: json.containsKey("name") ? json["name"] : null,
logo: json.containsKey("logo") ? json["logo"] : null, logo: json.containsKey("logo") ? json["logo"] : null,
type: json.containsKey("type") ? json["type"] : null,
owner: json.containsKey("owner") ? json["owner"] : 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, description: json.containsKey("description") ? json["description"] : null,
hosts: json["hosts"] ?? [],
shortDescription: json.containsKey("short_description") ? json["short_description"] : null, 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> { class CPU extends SerializerDeserializer<CPU> {
CPU({ CPU({
@ -279,7 +571,13 @@ class CPU extends SerializerDeserializer<CPU> {
shared: json.containsKey("shared") ? json["shared"] : false, 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> { class GPU extends SerializerDeserializer<GPU> {
GPU({ GPU({
@ -303,7 +601,12 @@ class GPU extends SerializerDeserializer<GPU> {
tensorCores: json.containsKey("tensor_cores") ? json["tensor_cores"]?.toDouble() : null, 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> { class RAM extends SerializerDeserializer<RAM> {
RAM({ RAM({
@ -321,61 +624,108 @@ class RAM extends SerializerDeserializer<RAM> {
size: json.containsKey("size") ? json["size"]?.toDouble() : null, 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({ StorageItem({
this.id, this.id,
this.url,
this.size,
this.name, this.name,
this.logo, this.logo,
this.type,
this.owner, this.owner,
this.acronym, this.ownerLogo,
this.throughput, this.price,
this.redundancy, this.source,
this.licence,
this.description, this.description,
this.bookingPrice,
this.shortDescription, this.shortDescription,
this.inputs = _empty,
this.outputs = _empty,
this.acronym,
this.type,
this.size,
this.url,
this.encryption = false, this.encryption = false,
this.redundancy,
this.throughput,
this.model,
}); });
@override String? id; @override String? id;
String? url;
@override String? name; @override String? name;
@override String? logo; @override String? logo;
@override String? type; @override String? source;
@override String topic = "storage"; @override String? ownerLogo;
double? size;
@override String? owner; @override String? owner;
@override String topic = "storage";
@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? acronym;
String? type;
int? size;
String? url;
bool encryption = false;
String? redundancy; String? redundancy;
String? throughput; String? throughput;
@override String? description; @override String getName() {
double? bookingPrice; return name ?? "";
bool encryption = false; }
@override String? shortDescription; @override String getID() {
return id ?? "";
}
@override deserialize(dynamic json) { @override deserialize(dynamic json) {
try { json = json as Map<String, dynamic>; try { json = json as Map<String, dynamic>;
} catch (e) { return StorageItem(); } } catch (e) { return StorageItem(); }
return StorageItem( return StorageItem(
id: json.containsKey("ID") ? json["ID"] : null, id: json.containsKey("id") ? json["id"] : null,
url: json.containsKey("URL") ? json["URL"] : null,
size: json.containsKey("size") ? json["size"]?.toDouble() : null,
name: json.containsKey("name") ? json["name"] : null, name: json.containsKey("name") ? json["name"] : null,
logo: json.containsKey("logo") ? json["logo"] : null, logo: json.containsKey("logo") ? json["logo"] : null,
type: json.containsKey("type") ? json["type"] : null,
owner: json.containsKey("owner") ? json["owner"] : null, owner: json.containsKey("owner") ? json["owner"] : null,
acronym: json.containsKey("DCacronym") ? json["DCacronym"] : null, ownerLogo: json.containsKey("owner_logo") ? json["owner_logo"] : null,
bookingPrice: json.containsKey("bookingPrice") ? json["bookingPrice"]?.toDouble() : null, price: json.containsKey("price") ? json["price"]?.toDouble() : null,
licence: json.containsKey("licence") ? json["licence"] : null,
description: json.containsKey("description") ? json["description"] : null, description: json.containsKey("description") ? json["description"] : null,
throughput: json.containsKey("throughput") ? json["throughput"] : [],
shortDescription: json.containsKey("short_description") ? json["short_description"] : null, 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, 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
View 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,
};
}

View File

@ -1,29 +1,48 @@
import 'package:oc_front/models/abstract.dart'; import 'package:oc_front/models/abstract.dart';
import 'package:oc_front/models/search.dart';
class Workspace extends SerializerDeserializer<Workspace> { class Workspace extends SerializerDeserializer<Workspace> {
String? id; String? id;
List<dynamic> data; String? name;
List<dynamic> datacenter; bool? active;
List<dynamic> storage; List<DataItem> datas;
List<dynamic> computing; List<DataCenterItem> datacenters;
List<StorageItem> storages;
List<ProcessingItem> processings;
List<WorkflowItem> workflows;
Workspace({ Workspace({
this.id, this.id,
this.computing = const [], this.name,
this.data = const [], this.active = false,
this.datacenter = const [], this.workflows = const [],
this.storage = const [], this.datas = const [],
this.datacenters = const [],
this.storages = const [],
this.processings = const [],
}); });
@override deserialize(dynamic json) { @override deserialize(dynamic json) {
try { json = json as Map<String, dynamic>; try { json = json as Map<String, dynamic>;
} catch (e) { return Workspace(); } } catch (e) { return Workspace(); }
return Workspace( return Workspace(
computing: json.containsKey("computing") ? json["computing"] : [], id: json.containsKey("id") ? json["id"] : null,
datacenter: json.containsKey("datacenter") ? json["datacenter"] : [], name: json.containsKey("name") ? json["name"] : null,
data: json.containsKey("data") ? json["data"] : [], active: json.containsKey("active") ? json["active"] : false,
storage: json.containsKey("storage") ? json["storage"] : [], 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(),
};
} }

View File

@ -1,11 +1,12 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart'; import 'package:go_router/go_router.dart';
import 'package:oc_front/core/sections/header/header.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/models/search.dart';
import 'package:oc_front/widgets/catalog.dart'; import 'package:oc_front/widgets/catalog.dart';
import 'package:oc_front/pages/abstract_page.dart'; import 'package:oc_front/pages/abstract_page.dart';
import 'package:oc_front/core/sections/header/search.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 { class CatalogFactory implements AbstractFactory {
static List<AbstractItem> items = []; static List<AbstractItem> items = [];
@ -13,10 +14,10 @@ class CatalogFactory implements AbstractFactory {
@override bool searchFill() { return CatalogFactory.items.isEmpty; } @override bool searchFill() { return CatalogFactory.items.isEmpty; }
@override Widget factory(GoRouterState state, List<String> args) { return CatalogPageWidget(); } @override Widget factory(GoRouterState state, List<String> args) { return CatalogPageWidget(); }
@override void search(BuildContext context) { @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; } if (value.data == null) { return; }
CatalogFactory.items = [ CatalogFactory.items = [ ...value.data!.workflows,
...value.data!.computing, ...value.data!.data, ...value.data!.storage, ...value.data!.datacenter,]; ...value.data!.processings, ...value.data!.datas, ...value.data!.storages, ...value.data!.datacenters,];
searchWidgetKey.currentState?.setState(() {}); searchWidgetKey.currentState?.setState(() {});
CatalogFactory.key.currentState?.setState(() {}); CatalogFactory.key.currentState?.setState(() {});
}); });
@ -24,16 +25,17 @@ class CatalogFactory implements AbstractFactory {
} }
class CatalogPageWidget extends StatefulWidget { class CatalogPageWidget extends StatefulWidget {
final SearchService search = SearchService(); final ResourceService search = ResourceService();
CatalogPageWidget (): super(key: CatalogFactory.key); CatalogPageWidget (): super(key: CatalogFactory.key);
@override CatalogPageWidgetState createState() => CatalogPageWidgetState(); @override CatalogPageWidgetState createState() => CatalogPageWidgetState();
} }
class CatalogPageWidgetState extends State<CatalogPageWidget> { class CatalogPageWidgetState extends State<CatalogPageWidget> {
@override Widget build(BuildContext context) { @override Widget build(BuildContext context) {
return Column( children : [ return Column( children : [
CatalogFactory.items.isEmpty ? Container() : MenuWorkspaceWidget(),
SizedBox( SizedBox(
width: MediaQuery.of(context).size.width, 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) ) child: CatalogWidget(items: CatalogFactory.items) )
] ]
); );

View File

@ -16,8 +16,8 @@ class CatalogItemFactory implements AbstractFactory {
var item = CatalogFactory.items.firstWhere( (element) => element.id == id ); var item = CatalogFactory.items.firstWhere( (element) => element.id == id );
return CatalogItemPageWidget(item : item); return CatalogItemPageWidget(item : item);
} catch (e) { } catch (e) {
var item = WorkspaceLocal.getItem(id ?? ""); var item = WorkspaceLocal.getItem(id ?? "", false);
if (item != null) { return CatalogItemPageWidget(item : item); } if (item != null) { return CatalogItemPageWidget(item : item as AbstractItem); }
return Container(); return Container();
} }
} }

View File

@ -1,7 +1,11 @@
import 'package:datetime_picker_formfield/datetime_picker_formfield.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:intl/intl.dart' as intl;
import 'package:go_router/go_router.dart'; 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: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 { class SchedulerFactory implements AbstractFactory {
static GlobalKey<SchedulerPageWidgetState> key = GlobalKey<SchedulerPageWidgetState>(); static GlobalKey<SchedulerPageWidgetState> key = GlobalKey<SchedulerPageWidgetState>();
@ -11,18 +15,169 @@ class SchedulerFactory implements AbstractFactory {
} }
class SchedulerPageWidget extends StatefulWidget { 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); SchedulerPageWidget(): super(key: SchedulerFactory.key);
@override SchedulerPageWidgetState createState() => SchedulerPageWidgetState(); @override SchedulerPageWidgetState createState() => SchedulerPageWidgetState();
static void search(BuildContext context) { } static void search(BuildContext context) { }
static Widget factory() { return SchedulerPageWidget(); } static Widget factory() { return SchedulerPageWidget(); }
} }
class SchedulerPageWidgetState extends State<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) { @override Widget build(BuildContext context) {
return TableCalendar( return FutureBuilder(
firstDay: DateTime.utc(2010, 10, 16), future: widget._service.search(context, [
lastDay: DateTime.utc(2030, 3, 14), "${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}"}",
focusedDay: DateTime.now(), "${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 )
]);
});
} }
} }

View File

@ -1,5 +1,3 @@
import 'dart:convert';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_flow_chart/flutter_flow_chart.dart'; import 'package:flutter_flow_chart/flutter_flow_chart.dart';
import 'package:go_router/go_router.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/core/services/specialized_services/workflow_service.dart';
import 'package:oc_front/models/response.dart'; import 'package:oc_front/models/response.dart';
import 'package:oc_front/models/search.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/pages/abstract_page.dart';
import 'package:oc_front/widgets/dialog/new_box.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'; 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 { class WorkflowFactory implements AbstractFactory {
static GlobalKey<WorkflowPageWidgetState> key = GlobalKey<WorkflowPageWidgetState>(); static GlobalKey<WorkflowPageWidgetState> key = GlobalKey<WorkflowPageWidgetState>();
@override bool searchFill() { return false; } @override bool searchFill() { return false; }
@ -29,8 +33,10 @@ class WorkflowPageWidgetState extends State<WorkflowPageWidget> {
final WorflowService _service = WorflowService(); final WorflowService _service = WorflowService();
Widget itemBuild(Object item) { Widget itemBuild(Object item) {
var e = item as AbstractItem; var e = item as AbstractItem;
return e.logo != null ? Image.memory(base64Decode(e.logo ?? ""), fit: BoxFit.fill) return Tooltip( message: item.name ?? "",
: Image.network('https://get-picto.com/wp-content/uploads/2024/01/logo-instagram-png.webp', fit: BoxFit.fill); 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) { Widget itemTooltipBuild(Object item) {
var e = item as AbstractItem; var e = item as AbstractItem;
@ -39,30 +45,113 @@ final WorflowService _service = WorflowService();
List<DropdownMenuItem> getItems(Object? data) { List<DropdownMenuItem> getItems(Object? data) {
data = data as APIResponse<RawData>?; data = data as APIResponse<RawData>?;
if (data != null && data.data != null && data.data!.values.isNotEmpty) { 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>( return DropdownMenuItem<String>(
value: value.toString(), value: "${value["id"] ?? ""}~${value["name"] ?? ""}",
child: Text(value.toString()), child: Text(value["name"]?.toString() ?? ""),
); );
}).toList(); }).toList();
} }
return []; 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) { Widget onDashboardAlertOpened(BuildContext context, Dashboard dash) {
return NewBoxWidget<RawData>(service: _service, dash: dash, return NewBoxWidget<Workflow>(service: _service, dash: dash,
getItems: getItems); getItems: getItems);
} }
@override Widget build(BuildContext context) { @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; var quart = MediaQuery.of(context).size.width / 6;
dash.defaultName = "workflow_${DateTime.now().toString().replaceAll(" ", "_").substring(0, DateTime.now().toString().length - 7)}"; dash.defaultName = "workflow_${DateTime.now().toString().replaceAll(" ", "_").substring(0, DateTime.now().toString().length - 7)}";
return FlowChart<AbstractItem>( return FlowChart<AbstractItem>(
onDashboardAlertOpened: onDashboardAlertOpened, onDashboardAlertOpened: onDashboardAlertOpened,
dashboard: dash, dashboard: dash,
itemWidget: itemBuild, itemWidget: itemBuild,
categories: const ["computing", "data", "datacenter", "storage"], categories: const ["processing", "data", "datacenter", "storage", "workflows"],
draggableItemBuilder: (cat) => WorkspaceLocal.byTopic(cat).toList(), draggableItemBuilder: (cat) => WorkspaceLocal.byTopic(cat, true).toList(),
itemWidgetTooltip: itemTooltipBuild, itemWidgetTooltip: itemTooltipBuild,
innerMenuWidth: quart > 80 ? quart : 80, innerMenuWidth: quart > 80 ? quart : 80,
menuExtension: menuExtension,
width: MediaQuery.of(context).size.width, width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height - HeaderConstants.height, height: MediaQuery.of(context).size.height - HeaderConstants.height,
onNewConnection: (p1, p2) { }, onNewConnection: (p1, p2) { },

View File

@ -1,5 +1,7 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_flow_chart/flutter_flow_chart.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/core/services/specialized_services/abstract_service.dart';
import 'package:oc_front/models/abstract.dart'; import 'package:oc_front/models/abstract.dart';
import 'package:oc_front/models/response.dart'; import 'package:oc_front/models/response.dart';
@ -24,13 +26,33 @@ class NewBoxWidgetState<T extends SerializerDeserializer<dynamic>> extends State
widget._ctrl.value = TextEditingValue(text: widget.dash.defaultName); widget._ctrl.value = TextEditingValue(text: widget.dash.defaultName);
return Container( return Container(
color: Colors.white, color: Colors.white,
padding: const EdgeInsets.all(20), padding: const EdgeInsets.only( top: 0, bottom: 20, left: 20, right: 20),
child: Column( child: Column(
children: [ children: [
Row( Container(
mainAxisAlignment: MainAxisAlignment.center, alignment: Alignment.centerRight,
children : [ height: 50,
FutureBuilder<APIResponse<T>>( 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), future: (widget.service as AbstractService<T>).all(context),
builder: (context, snapshot) { builder: (context, snapshot) {
List<DropdownMenuItem> items = widget.getItems != null ? widget.getItems!(snapshot.data) : []; List<DropdownMenuItem> items = widget.getItems != null ? widget.getItems!(snapshot.data) : [];
@ -41,7 +63,10 @@ class NewBoxWidgetState<T extends SerializerDeserializer<dynamic>> extends State
child: Text(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, return Row(
mainAxisAlignment: MainAxisAlignment.center,
children : [
SizedBox( width: MediaQuery.of(context).size.width <= 540 ? MediaQuery.of(context).size.width - 140 : 400, height: 50,
child: DropdownButtonFormField( child: DropdownButtonFormField(
value: widget._selected, value: widget._selected,
isExpanded: true, isExpanded: true,
@ -59,12 +84,12 @@ class NewBoxWidgetState<T extends SerializerDeserializer<dynamic>> extends State
border: OutlineInputBorder( borderRadius: BorderRadius.zero, border: OutlineInputBorder( borderRadius: BorderRadius.zero,
borderSide: BorderSide(color: Colors.grey.shade300, width: 0)), borderSide: BorderSide(color: Colors.grey.shade300, width: 0)),
), ),
items: items, onChanged: (value) { items: items,
onChanged: (value) {
setState(() { setState(() {
widget._selected = value.toString(); widget._selected = value.toString();
}); });
})); })),
}),
Tooltip( Tooltip(
message: 'empty selection', message: 'empty selection',
child: InkWell( child: InkWell(
@ -86,9 +111,13 @@ class NewBoxWidgetState<T extends SerializerDeserializer<dynamic>> extends State
child: InkWell( child: InkWell(
mouseCursor: widget._selected == null || widget._selected!.isEmpty mouseCursor: widget._selected == null || widget._selected!.isEmpty
? MouseCursor.defer : SystemMouseCursors.click, ? MouseCursor.defer : SystemMouseCursors.click,
onTap: () { onTap: () async {
if (widget._selected == null || widget._selected!.isEmpty) { return; } 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(); widget.dash.notifyListeners();
Navigator.pop(context); Navigator.pop(context);
}, },
@ -100,7 +129,8 @@ class NewBoxWidgetState<T extends SerializerDeserializer<dynamic>> extends State
) )
) )
) )
]), ]);}),
Row( Row(
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center,
@ -115,7 +145,7 @@ class NewBoxWidgetState<T extends SerializerDeserializer<dynamic>> extends State
minLines: null, minLines: null,
cursorColor: const Color.fromARGB(38, 166, 154, 1), cursorColor: const Color.fromARGB(38, 166, 154, 1),
controller: widget._ctrl, controller: widget._ctrl,
onChanged: (value) => setState(() { widget._ctrl.value = TextEditingValue(text: value); }), onChanged: (value) {},
validator: (value) => value == null || value.isEmpty ? "name is required" : null, validator: (value) => value == null || value.isEmpty ? "name is required" : null,
decoration: InputDecoration( decoration: InputDecoration(
hintText: "name a new workflow...", hintText: "name a new workflow...",
@ -137,14 +167,20 @@ class NewBoxWidgetState<T extends SerializerDeserializer<dynamic>> extends State
mouseCursor: widget._ctrl.value.text.isEmpty ? MouseCursor.defer : SystemMouseCursors.click, mouseCursor: widget._ctrl.value.text.isEmpty ? MouseCursor.defer : SystemMouseCursors.click,
onTap: () async { onTap: () async {
if (widget._ctrl.value.text.isNotEmpty) { if (widget._ctrl.value.text.isNotEmpty) {
await widget.service.post(context, {}, { "workflowName" : widget._ctrl.value.text }); await widget.service.post(context, { "name" : widget._ctrl.value.text }, {}).then(
(value) {
widget._selected = widget._ctrl.value.text; widget._selected = widget._ctrl.value.text;
widget._ctrl.value = const TextEditingValue(text: ""); widget._ctrl.value = const TextEditingValue(text: "");
widget.dash.name = widget._selected ?? widget.dash.name; widget.dash.id = value.data?.serialize()["id"];
widget.dash.name = widget._selected ?? "";
widget.dash.notifyListeners(); widget.dash.notifyListeners();
WorkspaceLocal.init(context, true);
widget.dash.isOpened = true;
// ignore: use_build_context_synchronously // ignore: use_build_context_synchronously
Navigator.pop(context); Navigator.pop(context);
} }
);
}
}, },
child: Container( child: Container(
margin: const EdgeInsets.only(top: 10), margin: const EdgeInsets.only(top: 10),

View File

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

View File

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

View File

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

View File

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

View File

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

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

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

View File

@ -0,0 +1,116 @@
import 'dart:ffi';
import 'package:flutter/material.dart';
import 'package:oc_front/core/models/workspace_local.dart';
class MenuWorkspaceWidget extends StatefulWidget {
bool simpliest = false;
double? width;
void Function()? onWorkspaceChange;
TextEditingController ctrl = TextEditingController();
MenuWorkspaceWidget ({ Key? key, this.simpliest = false, this.width, this.onWorkspaceChange }): super(key: key);
@override MenuWorkspaceWidgetState createState() => MenuWorkspaceWidgetState();
}
class MenuWorkspaceWidgetState extends State<MenuWorkspaceWidget> {
@override Widget build(BuildContext context) {
return Row( children: [
Tooltip( message: "current workspace", child:
Theme(
data: Theme.of(context).copyWith(
canvasColor: widget.simpliest ? Colors.grey.shade300 : Colors.grey,
),
child: Container( height: 50, width: widget.width ?? MediaQuery.of(context).size.width / ( widget.simpliest ? 1 : 2),
decoration: BoxDecoration(
color: widget.simpliest ? Colors.white : const Color.fromRGBO(38, 166, 154, 1),
border: Border(bottom: BorderSide(color: widget.simpliest ? Colors.grey.shade300 : Colors.transparent, width: 1))
),
padding: EdgeInsets.only(left: (widget.width ?? 400) < 400 ? 20 : 50, right: (widget.width ?? 400) < 400 ? 20 : 0),
child: DropdownButtonFormField(
value: WorkspaceLocal.getCurrentWorkspace()?.id,
isExpanded: true,
style: TextStyle(color: widget.simpliest ? Colors.black : Colors.white, fontSize: 15),
hint: Text("load workspace...", style: TextStyle(color: Colors.grey.shade300, fontSize: 15)),
icon: Icon( // Add this
Icons.arrow_drop_down, // Add this
color: widget.simpliest ? Colors.grey : Colors.white, // Add this
),
decoration: InputDecoration(
filled: true,
prefixIconColor: widget.simpliest ? Colors.grey : Colors.white,
icon: Icon(Icons.shopping_cart, color: Colors.grey.shade300),
suffixIconColor: widget.simpliest ? Colors.grey : Colors.white,
focusedBorder: const OutlineInputBorder( borderRadius: BorderRadius.zero,
borderSide: BorderSide(color: Colors.transparent, width: 0),
),
fillColor: widget.simpliest ? Colors.white : const Color.fromRGBO(38, 166, 154, 1),
contentPadding: EdgeInsets.only(left: (widget.width ?? 400) < 400 ? 0 : 30, right: (widget.width ?? 400) < 400 ? 0 : 30, top: 10, bottom: 30),
enabledBorder: const OutlineInputBorder( borderRadius: BorderRadius.zero,
borderSide: BorderSide(color: Colors.transparent, width: 0),
),
border: const OutlineInputBorder( borderRadius: BorderRadius.zero,
borderSide: BorderSide(color: Colors.transparent, width: 0)),
),
items: WorkspaceLocal.getWorkspacesIDS().map((e) => DropdownMenuItem(
value: e.id,child: Text(e.name ?? ""),)).toList(),
onChanged: (value) {
setState(() {
WorkspaceLocal.changeWorkspace(value.toString());
if (widget.onWorkspaceChange != null) {
widget.onWorkspaceChange!();
}
});
})))),
widget.simpliest ? Container() : Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Container(
width: (MediaQuery.of(context).size.width / 2) - 50,
height: 50,
decoration: const BoxDecoration(border: Border(left: BorderSide(color: Colors.white))),
child: TextFormField(
expands: true,
maxLines: null,
minLines: null,
style: const TextStyle(color: Colors.white, fontSize: 15),
cursorColor: const Color.fromARGB(38, 166, 154, 1),
controller: widget.ctrl,
onChanged: (value) { setState(() { }); },
validator: (value) => value == null || value.isEmpty ? "name is required" : null,
decoration: InputDecoration(
hintText: "name a new workspace...",
fillColor: const Color.fromRGBO(38, 166, 154, 1),
filled: true,
contentPadding: const EdgeInsets.only(left: 30, right: 30, top: 15, bottom: 5),
hintStyle: TextStyle(
color: Colors.grey.shade300,
fontSize: 15,
fontWeight: FontWeight.w400
),
border: InputBorder.none
)
)
),
Tooltip(
message: 'add',
child:InkWell(
mouseCursor: widget.ctrl.value.text.isEmpty ? MouseCursor.defer : SystemMouseCursors.click,
onTap: () async {
if (widget.ctrl.value.text.isNotEmpty) {
WorkspaceLocal.createWorkspace(widget.ctrl.value.text, context);
}
},
child: Container(
width: 50,
height: 50,
color: Colors.black,
child: Icon(Icons.add, color: widget.ctrl.value.text.isEmpty ? Colors.grey : Colors.white)
)
)
)
])
]);
}
}

View File

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

View File

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

View File

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

View File

@ -5,5 +5,5 @@ export 'src/dashboard.dart';
export 'src/elements/connection_params.dart'; export 'src/elements/connection_params.dart';
export 'src/elements/flow_element.dart'; export 'src/elements/flow_element.dart';
export 'src/flow_chart.dart'; export 'src/flow_chart.dart';
export 'src/ui/draw_arrow.dart' show ArrowParams, ArrowStyle; export 'src/ui/draw_arrow.dart' show ArrowParams, ArrowStyle, ArrowDirection;
export 'src/ui/grid_background.dart' show GridBackgroundParams; export 'src/ui/grid_background.dart' show GridBackgroundParams;

View File

@ -2,6 +2,7 @@
import 'dart:io'; import 'dart:io';
import 'dart:convert'; import 'dart:convert';
import 'package:flutter_flow_chart/src/flow_chart_left_menu.dart';
import 'package:uuid/uuid.dart'; import 'package:uuid/uuid.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
@ -23,10 +24,15 @@ typedef ConnectionListener = void Function(
// //
class Dashboard extends ChangeNotifier { class Dashboard extends ChangeNotifier {
GlobalKey<FlowChartSelectedMenuState> selectedMenuKey = GlobalKey<FlowChartSelectedMenuState>(); GlobalKey<FlowChartSelectedMenuState> selectedMenuKey = GlobalKey<FlowChartSelectedMenuState>();
GlobalKey<FlowChartLeftMenuState> selectedLeftMenuKey = GlobalKey<FlowChartLeftMenuState>();
GlobalKey<FlowChartMenuState> chartMenuKey = GlobalKey<FlowChartMenuState>(); GlobalKey<FlowChartMenuState> chartMenuKey = GlobalKey<FlowChartMenuState>();
GlobalKey<ChartWidgetState> chartKey = GlobalKey<ChartWidgetState>(); GlobalKey<ChartWidgetState> chartKey = GlobalKey<ChartWidgetState>();
List<Map<String, dynamic>> tempHistory = []; List<Map<String, dynamic>> tempHistory = [];
List<Map<String, dynamic>> history = []; List<Map<String, dynamic>> history = [];
Map<String, dynamic> scheduler = {};
Map<String, bool> schedulerState = {};
bool schedulerSave = false;
String? id;
String name; String name;
String defaultName = ""; String defaultName = "";
bool isMenu = true; bool isMenu = true;
@ -39,11 +45,17 @@ class Dashboard extends ChangeNotifier {
double defaultDashWidth = 0; double defaultDashWidth = 0;
double defaultBackWidth = 10; double defaultBackWidth = 10;
double defaultForwardWidth = 10; double defaultForwardWidth = 10;
final void Function()? save; Future<void> Function(String? id)? save;
List<Widget> Function(FlowData? obj)? infoItemWidget;
List<Widget> Function()? infoWidget;
FlowData? Function(Map<String, dynamic> json)? transformToData;
/// ///
Dashboard({ Dashboard({
this.id,
this.transformToData,
required this.name, required this.name,
this.save, this.save,
this.scheduler = const {},
Offset? handlerFeedbackOffset, Offset? handlerFeedbackOffset,
this.isMenu = true, this.isMenu = true,
this.defaultDashSpace = 0, this.defaultDashSpace = 0,
@ -53,6 +65,8 @@ class Dashboard extends ChangeNotifier {
this.defaultArrowDirection = ArrowDirection.forward, this.defaultArrowDirection = ArrowDirection.forward,
this.defaultArrowStyle = ArrowStyle.curve, this.defaultArrowStyle = ArrowStyle.curve,
this.loadedGraph, this.loadedGraph,
this.infoWidget,
this.load,
}) : elements = [], }) : elements = [],
_dashboardPosition = Offset.zero, _dashboardPosition = Offset.zero,
dashboardSize = Size.zero, dashboardSize = Size.zero,
@ -80,25 +94,28 @@ class Dashboard extends ChangeNotifier {
addToHistory(); addToHistory();
} }
Future<void> Function(String cat)? load;
/// ///
factory Dashboard.fromMap(Map<String, dynamic> map) { factory Dashboard.fromMap(Map<String, dynamic> map) {
final d = Dashboard( final d = Dashboard(
name: map['name'] as String, name: map['name'] as String,
isMenu: map['isMenu'] as bool, isMenu: map['isMenu'] as bool,
scheduler: map['schedule'] as Map<String, String>? ?? {},
defaultDashSpace: map['defaultDashSpace'] as double? ?? 0, defaultDashSpace: map['defaultDashSpace'] as double? ?? 0,
defaultDashWidth: map['defaultDashWidth'] as double? ?? 0, defaultDashWidth: map['defaultDashWidth'] as double? ?? 0,
defaultArrowDirection: ArrowDirection.values[ defaultArrowDirection: ArrowDirection.values[
map['defaultArrowDirection'] as int? ?? 0], map['defaultArrowDirection'] as int? ?? 0],
defaultArrowStyle: ArrowStyle.values[map['arrowStyle'] as int? ?? 0], defaultArrowStyle: ArrowStyle.values[map['arrowStyle'] as int? ?? 0],
) );
..arrows = List<ArrowPainter>.from( d..arrows = List<ArrowPainter>.from(
(map['arrows'] as List<dynamic>).map<ArrowPainter>( (map['arrows'] as List<dynamic>).map<ArrowPainter>(
(x) => ArrowPainter.fromMap(x as Map<String, dynamic>), (x) => ArrowPainter.fromMap(x as Map<String, dynamic>),
), ),
) )
..elements = List<FlowElement>.from( ..elements = List<FlowElement>.from(
(map['elements'] as List<dynamic>).map<FlowElement>( (map['elements'] as List<dynamic>).map<FlowElement>(
(x) => FlowElement.fromMap(x as Map<String, dynamic>), (x) => FlowElement.fromMap(d, x as Map<String, dynamic>),
), ),
) )
..dashboardSize = Size( ..dashboardSize = Size(
@ -120,6 +137,7 @@ class Dashboard extends ChangeNotifier {
} }
void copyFromMap(Map<String, dynamic> map) { void copyFromMap(Map<String, dynamic> map) {
scheduler = map['schedule'] as Map<String, String>? ?? {};
defaultArrowStyle = ArrowStyle.values[map['arrowStyle'] as int? ?? 0]; defaultArrowStyle = ArrowStyle.values[map['arrowStyle'] as int? ?? 0];
defaultDashSpace = map['defaultDashSpace'] as double? ?? 0; defaultDashSpace = map['defaultDashSpace'] as double? ?? 0;
defaultDashWidth = map['defaultDashWidth'] as double? ?? 0; defaultDashWidth = map['defaultDashWidth'] as double? ?? 0;
@ -132,7 +150,7 @@ class Dashboard extends ChangeNotifier {
); );
elements = List<FlowElement>.from( elements = List<FlowElement>.from(
(map['elements'] as List<dynamic>).map<FlowElement>( (map['elements'] as List<dynamic>).map<FlowElement>(
(x) => FlowElement.fromMap(x as Map<String, dynamic>), (x) => FlowElement.fromMap(this, x as Map<String, dynamic>),
), ),
); );
dashboardSize = Size( dashboardSize = Size(
@ -148,7 +166,6 @@ class Dashboard extends ChangeNotifier {
blockDefaultZoomGestures = blockDefaultZoomGestures =
(map['blockDefaultZoomGestures'] as bool? ?? false); (map['blockDefaultZoomGestures'] as bool? ?? false);
minimumZoomFactor = map['minimumZoomFactor'] as double? ?? 0.25; minimumZoomFactor = map['minimumZoomFactor'] as double? ?? 0.25;
if (save != null) { save!(); }
} }
/// ///
@ -194,22 +211,34 @@ class Dashboard extends ChangeNotifier {
final List<ConnectionListener> _connectionListeners = []; final List<ConnectionListener> _connectionListeners = [];
Map<String, dynamic> serialize() { Map<String, dynamic> serialize() {
Map<String, dynamic> d = {};
Map<String, dynamic> graph = {}; Map<String, dynamic> graph = {};
graph['zoom'] = getZoomFactor();
graph['elements'] = {}; graph['elements'] = {};
for(var el in elements) { for(var el in elements) {
graph['elements'][el.id] = el.serialize(); graph['elements'][el.id] = el.serialize();
} }
graph['arrows'] = arrows.map((e) => e.serialize()).toList(); graph['arrows'] = arrows.map((e) => e.serialize()).toList();
return graph; d["id"]=id;
d["name"]=name;
d["graph"]=graph;
if (schedulerSave) {
d["schedule"]=scheduler;
}
return d;
} }
void deserialize(Map<String, dynamic> graph) { void deserialize(Map<String, dynamic> graph) {
elements.clear(); elements = [];
arrows.clear(); arrows = [];
for(var el in graph['elements'].values) { print(graph['schedule']);
scheduler = graph['schedule'] ?? {};
setZoomFactor(graph["graph"]?["zoom"] ?? 1.0);
for(var el in graph['graph']?['elements'] ?? []) {
List<ConnectionParams> nexts = []; List<ConnectionParams> nexts = [];
var flow = FlowElement.deserialize(el); var flow = FlowElement.deserialize(this, el);
for(var ar in graph['arrows']) { for(var ar in graph['graph']['arrows']) {
if (ar['from']['id'] != flow.id) { continue; }
nexts.add(ConnectionParams( nexts.add(ConnectionParams(
srcElementId: ar['from']['id'], srcElementId: ar['from']['id'],
destElementId: ar['to']['id'], destElementId: ar['to']['id'],
@ -221,8 +250,22 @@ class Dashboard extends ChangeNotifier {
)); ));
} }
flow.next = nexts; flow.next = nexts;
List<FlowData> arr = [];
for (var cat in chartKey.currentState?.widget.flowChart.widget.categories ?? []) {
for (var build in chartKey.currentState!.widget.flowChart.widget.draggableItemBuilder(cat)) {
arr.add(build);
} }
} }
try {
FlowData data = arr.firstWhere((element) => element.getID() == flow.element?.getID());
flow.kind = ElementKind.widget;
flow.widget = chartKey.currentState?.widget.flowChart.widget.itemWidget(data);
} catch (e) { print(e); }
elements.add(flow);
}
selectedMenuKey.currentState?.setState(() { });
chartMenuKey.currentState?.setState(() { });
}
/// add listener called when a new connection is created /// add listener called when a new connection is created
void addConnectionListener(ConnectionListener listener) { void addConnectionListener(ConnectionListener listener) {
@ -249,7 +292,7 @@ class Dashboard extends ChangeNotifier {
void addToHistory() { void addToHistory() {
if (tempHistory.length >= 50) { tempHistory.removeAt(0); } if (tempHistory.length >= 50) { tempHistory.removeAt(0); }
tempHistory.add(toMap()); tempHistory.add(toMap());
if (save != null) { save!(); } if (save != null) { save!(id); }
history = tempHistory.map((e) => e).toList(); history = tempHistory.map((e) => e).toList();
chartKey.currentState?.setState(() { }); chartKey.currentState?.setState(() { });
chartMenuKey.currentState?.setState(() { }); chartMenuKey.currentState?.setState(() { });
@ -774,7 +817,7 @@ class Dashboard extends ChangeNotifier {
final loadedElements = List<FlowElement>.from( final loadedElements = List<FlowElement>.from(
(source['elements'] as List<dynamic>).map<FlowElement>( (source['elements'] as List<dynamic>).map<FlowElement>(
(x) => FlowElement.fromMap(x as Map<String, dynamic>), (x) => FlowElement.fromMap(this, x as Map<String, dynamic>),
), ),
); );
elements elements

View File

@ -4,7 +4,7 @@ import 'dart:convert';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_flow_chart/flutter_flow_chart.dart'; import 'package:flutter_flow_chart/flutter_flow_chart.dart';
import 'package:flutter_flow_chart/src/elements/connection_params.dart'; import 'package:flutter_flow_chart/src/dashboard.dart';
import 'package:uuid/uuid.dart'; import 'package:uuid/uuid.dart';
/// Kinf od element /// Kinf od element
@ -61,12 +61,16 @@ enum Handler {
} }
/// Class to store [ElementWidget]s and notify its changes /// Class to store [ElementWidget]s and notify its changes
class FlowElement extends ChangeNotifier { class FlowElement<T extends FlowData> extends ChangeNotifier {
Dashboard dashboard;
bool isSelected = false; bool isSelected = false;
T? element;
/// ///
FlowElement({ FlowElement({
required this.dashboard,
Offset position = Offset.zero, Offset position = Offset.zero,
String? id, String? id,
this.element,
this.size = Size.zero, this.size = Size.zero,
this.text = '', this.text = '',
this.textColor = Colors.black, this.textColor = Colors.black,
@ -103,8 +107,12 @@ class FlowElement extends ChangeNotifier {
} }
return false; return false;
} }
factory FlowElement.fromMap(Map<String, dynamic> map) { factory FlowElement.fromMap(Dashboard dashboard, Map<String, dynamic> map) {
final e = FlowElement( final e = FlowElement<T>(
element: (dashboard.transformToData != null
? dashboard.transformToData!(map['element'] ?? {})
: null) as T?,
dashboard: dashboard,
widget: map['widget'] as Widget?, widget: map['widget'] as Widget?,
size: Size(map['size.width'] as double, map['size.height'] as double), size: Size(map['size.width'] as double, map['size.height'] as double),
text: map['text'] as String, text: map['text'] as String,
@ -141,8 +149,8 @@ class FlowElement extends ChangeNotifier {
/// ///
factory FlowElement.fromJson(String source) => factory FlowElement.fromJson(Dashboard dashboard, String source) =>
FlowElement.fromMap(json.decode(source) as Map<String, dynamic>); FlowElement.fromMap(dashboard, json.decode(source) as Map<String, dynamic>);
/// Unique id set when adding a [FlowElement] with [Dashboard.addElement()] /// Unique id set when adding a [FlowElement] with [Dashboard.addElement()]
late String id; late String id;
@ -365,14 +373,18 @@ class FlowElement extends ChangeNotifier {
graphElement['y'] = position.dy; graphElement['y'] = position.dy;
graphElement['width'] = size.width; graphElement['width'] = size.width;
graphElement['height'] = size.height; graphElement['height'] = size.height;
graphElement['element']=element?.serialize();
return graphElement; return graphElement;
} }
static FlowElement deserialize(Map<String, dynamic> map) { static FlowElement deserialize<T extends FlowData>(Dashboard dashboard, Map<String, dynamic> map) {
return FlowElement( return FlowElement<T>(
dashboard: dashboard,
id: map['id'], id: map['id'],
position: Offset(map['x'], map['y']), kind: ElementKind.widget,
size: Size(map['width'], map['height']), position: Offset(double.parse("${map['x']}"), double.parse("${map['y']}")),
size: Size(double.parse("${map['width']}"), double.parse("${map['height']}")),
element: (dashboard.transformToData != null ? dashboard.transformToData!(map['element'] ?? {}) : null) as T?,
); );
} }
} }

View File

@ -1,10 +1,11 @@
// ignore: directives_ordering // ignore: directives_ordering
import 'dart:developer';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:flutter_flow_chart/flutter_flow_chart.dart'; import 'package:flutter_flow_chart/flutter_flow_chart.dart';
import 'package:flutter_flow_chart/src/dashboard.dart'; import 'package:flutter_flow_chart/src/flow_chart_left_menu.dart';
import 'package:flutter_flow_chart/src/elements/flow_element.dart';
import 'package:flutter_flow_chart/src/flow_chart_menu.dart'; import 'package:flutter_flow_chart/src/flow_chart_menu.dart';
import 'package:flutter_flow_chart/src/flow_chart_selected_menu.dart'; import 'package:flutter_flow_chart/src/flow_chart_selected_menu.dart';
import 'package:flutter_flow_chart/src/ui/draw_arrow.dart'; import 'package:flutter_flow_chart/src/ui/draw_arrow.dart';
@ -15,7 +16,14 @@ import 'package:uuid/uuid.dart';
/// Main flow chart Widget. /// Main flow chart Widget.
/// It displays the background grid, all the elements and connection lines /// It displays the background grid, all the elements and connection lines
class FlowChart<T extends Object> extends StatefulWidget { abstract class FlowData {
String getID();
String getName();
Map<String, dynamic> serialize();
FlowData deserialize(Map<String, dynamic> data);
}
class FlowChart<T extends FlowData> extends StatefulWidget {
FlowChart({ FlowChart({
required this.dashboard, required this.dashboard,
required this.itemWidget, required this.itemWidget,
@ -44,13 +52,15 @@ class FlowChart<T extends Object> extends StatefulWidget {
this.categories = const [], this.categories = const [],
required this.draggableItemBuilder, required this.draggableItemBuilder,
this.onDashboardAlertOpened, this.onDashboardAlertOpened,
this.menuExtension,
}) {} }) {}
final List<String> categories; final List<String> categories;
final double width; final double width;
final double height; final double height;
final double innerMenuWidth; final double innerMenuWidth;
Widget Function()? menuExtension;
double itemWidth = 80; double itemWidth = 80;
double zoom = 1; double zoom = 1;
@ -161,7 +171,6 @@ class HoverMenuController {
currentState?.hideSubMenu(); currentState?.hideSubMenu();
} }
} }
bool isPopUp = false;
class HoverMenu extends StatefulWidget { class HoverMenu extends StatefulWidget {
final Widget title; final Widget title;
final double? width; final double? width;
@ -277,49 +286,8 @@ class HoverMenuState extends State<HoverMenu> {
} }
var node = FocusNode(); var node = FocusNode();
class FlowChartState<T extends Object> extends State<FlowChart> { class FlowChartState<T extends FlowData> extends State<FlowChart> {
List<Draggable<T>> getDraggable(List<T> items) {
List<Draggable<T>> res = [];
double realSize = widget.itemWidth * widget.zoom;
GlobalKey<HoverMenuState> hoverKey = GlobalKey<HoverMenuState>();
for (var e in items) {
res.add(Draggable<T>(
// Data is the value this Draggable stores.
data: e,
onDragStarted: () => hoverKey.currentState?.hideSubMenu(),
onDragEnd: (d) => node.requestFocus(),
childWhenDragging: Opacity(opacity: .5,
child: Padding( padding: const EdgeInsets.all(10),
child: Container( height: realSize - 20, child: widget.itemWidget(e) ))),
feedback: Container( height: realSize, child: widget.itemWidget(e) ),
child: InkWell( mouseCursor: SystemMouseCursors.grab, child: Padding( padding: const EdgeInsets.all(10),
child: widget.itemWidgetTooltip != null ? HoverMenu( key: hoverKey, width: 400, title: Container(
height: realSize - 20, child: widget.itemWidget(e) ),
items: [
Container(child: widget.itemWidgetTooltip!(e)),
]
) : Container(
height: realSize - 20, child: widget.itemWidget(e)
)
) )));
}
if (!widget.dashboard.isOpened && widget.onDashboardAlertOpened != null && isPopUp == false) {
isPopUp = true;
widget.dashboard.isOpened = true;
Future.delayed(Duration(milliseconds: 1), () => showDialog(
barrierDismissible: false,
context: context, builder: (context) {
return AlertDialog(
titlePadding: EdgeInsets.zero,
insetPadding: EdgeInsets.zero,
backgroundColor: Colors.white,
shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(0)),
title: widget.onDashboardAlertOpened!(context, widget.dashboard));
}));
}
widget.dashboard.isOpened = true;
return res;
}
@override @override
void initState() { void initState() {
@ -342,48 +310,14 @@ class FlowChartState<T extends Object> extends State<FlowChart> {
} }
} }
}); });
// disabling default browser context menu on web // disabling default browser context menu on web
if (kIsWeb) BrowserContextMenu.disableContextMenu(); if (kIsWeb) BrowserContextMenu.disableContextMenu();
List<Widget> menuItems = [];
for (var cat in widget.categories) {
menuItems.add(
Container( width: widget.dashboard.isMenu ? widget.innerMenuWidth : 0, margin: const EdgeInsets.only(bottom: 0.3),
decoration: const BoxDecoration(border: Border(bottom: BorderSide(color: Colors.grey, width: .5))),
child: Stack( children: [
widget.dashboard.isMenu && widget.innerMenuWidth < 200 ? Wrap( alignment: WrapAlignment.start,
children: getDraggable(widget.draggableItemBuilder(cat) as List<T>))
: ExpansionTile(
shape: const ContinuousRectangleBorder(side: BorderSide(color: Colors.transparent)),
initiallyExpanded: true,
title: SizedBox(
child : Row( children: [
Padding(padding: const EdgeInsets.only(right: 10),
child: Icon(cat.toUpperCase().contains("DATA") ? Icons.grid_on : Icons.bookmark, color: Colors.grey)),
Flexible(
child: Padding(
padding: const EdgeInsets.only(right: 5),
child: Text(cat.toUpperCase(), overflow: TextOverflow.ellipsis,
style: const TextStyle(color: Colors.black, fontSize: 11, fontWeight: FontWeight.w500))))
])
),
iconColor: Colors.white,
collapsedIconColor: Colors.white,
children: [
Container( width: widget.dashboard.isMenu ? widget.innerMenuWidth : 0, color: Colors.white,
child : Wrap( alignment: WrapAlignment.start,
children: getDraggable(widget.draggableItemBuilder(cat) as List<T>))
)],
)
]
))
);
}
return KeyboardListener( return KeyboardListener(
focusNode: node, focusNode: node,
onKeyEvent: (event) { onKeyEvent: (event) {
bool change = false;
if ((event is KeyDownEvent || event is KeyRepeatEvent) && event.logicalKey == LogicalKeyboardKey.arrowUp) { if ((event is KeyDownEvent || event is KeyRepeatEvent) && event.logicalKey == LogicalKeyboardKey.arrowUp) {
change = true;
for (var el in widget.dashboard.elements) { for (var el in widget.dashboard.elements) {
if (el.isSelected) { if (el.isSelected) {
el.position = Offset(el.position.dx, el.position.dy - 10); el.position = Offset(el.position.dx, el.position.dy - 10);
@ -391,6 +325,7 @@ class FlowChartState<T extends Object> extends State<FlowChart> {
} }
} }
if ((event is KeyDownEvent || event is KeyRepeatEvent) && event.logicalKey == LogicalKeyboardKey.arrowDown) { if ((event is KeyDownEvent || event is KeyRepeatEvent) && event.logicalKey == LogicalKeyboardKey.arrowDown) {
change = true;
for (var el in widget.dashboard.elements) { for (var el in widget.dashboard.elements) {
if (el.isSelected) { if (el.isSelected) {
el.position = Offset(el.position.dx, el.position.dy + 10); el.position = Offset(el.position.dx, el.position.dy + 10);
@ -398,6 +333,7 @@ class FlowChartState<T extends Object> extends State<FlowChart> {
} }
} }
if ((event is KeyDownEvent || event is KeyRepeatEvent) && event.logicalKey == LogicalKeyboardKey.arrowLeft) { if ((event is KeyDownEvent || event is KeyRepeatEvent) && event.logicalKey == LogicalKeyboardKey.arrowLeft) {
change = true;
for (var el in widget.dashboard.elements) { for (var el in widget.dashboard.elements) {
if (el.isSelected) { if (el.isSelected) {
el.position = Offset(el.position.dx - 10, el.position.dy); el.position = Offset(el.position.dx - 10, el.position.dy);
@ -405,6 +341,7 @@ class FlowChartState<T extends Object> extends State<FlowChart> {
} }
} }
if ((event is KeyDownEvent || event is KeyRepeatEvent) && event.logicalKey == LogicalKeyboardKey.arrowRight) { if ((event is KeyDownEvent || event is KeyRepeatEvent) && event.logicalKey == LogicalKeyboardKey.arrowRight) {
change = true;
for (var el in widget.dashboard.elements) { for (var el in widget.dashboard.elements) {
if (el.isSelected) { if (el.isSelected) {
el.position = Offset(el.position.dx + 10, el.position.dy); el.position = Offset(el.position.dx + 10, el.position.dy);
@ -413,8 +350,11 @@ class FlowChartState<T extends Object> extends State<FlowChart> {
} }
if (event is KeyDownEvent && event.logicalKey == LogicalKeyboardKey.add) { if (event is KeyDownEvent && event.logicalKey == LogicalKeyboardKey.add) {
change = true;
for (var el in widget.dashboard.elementSelected) { for (var el in widget.dashboard.elementSelected) {
widget.dashboard.elements.add(FlowElement( widget.dashboard.elements.add(FlowElement<T>(
element: el.element as T,
dashboard: widget.dashboard,
id: const Uuid().v4(), id: const Uuid().v4(),
position: el.position + const Offset(100, 100), position: el.position + const Offset(100, 100),
size: el.size, size: el.size,
@ -427,6 +367,7 @@ class FlowChartState<T extends Object> extends State<FlowChart> {
} }
} }
if (event is KeyDownEvent && event.logicalKey == LogicalKeyboardKey.delete) { if (event is KeyDownEvent && event.logicalKey == LogicalKeyboardKey.delete) {
change = true;
widget.dashboard.elements.removeWhere( (el) => el.isSelected ); widget.dashboard.elements.removeWhere( (el) => el.isSelected );
for (var arrow in widget.dashboard.arrowsSelected) { for (var arrow in widget.dashboard.arrowsSelected) {
for (var el in widget.dashboard.elements.where((element) => element.id == arrow.fromID.split("_")[0])) { for (var el in widget.dashboard.elements.where((element) => element.id == arrow.fromID.split("_")[0])) {
@ -435,11 +376,13 @@ class FlowChartState<T extends Object> extends State<FlowChart> {
} }
widget.dashboard.arrows.removeWhere( (el) => el.isSelected ); widget.dashboard.arrows.removeWhere( (el) => el.isSelected );
} }
if (change) {
DrawingArrow.instance.notifyListeners(); DrawingArrow.instance.notifyListeners();
widget.dashboard.chartKey.currentState?.setState(() { }); widget.dashboard.chartKey.currentState?.setState(() { });
Future.delayed(Duration(milliseconds: 10), () { /*Future.delayed(Duration(milliseconds: 10), () {
node.requestFocus(); node.requestFocus();
}); });*/
}
}, },
child: ClipRect( child: ClipRect(
child: Stack( child: Stack(
@ -456,7 +399,7 @@ class FlowChartState<T extends Object> extends State<FlowChart> {
return SizedBox( return SizedBox(
width: widget.width, width: widget.width,
height: widget.height, height: widget.height,
child: ChartWidget( child: ChartWidget<T>(
key: widget.dashboard.chartKey, key: widget.dashboard.chartKey,
flowChart: this, flowChart: this,
dashboard: widget.dashboard, dashboard: widget.dashboard,
@ -478,8 +421,10 @@ class FlowChartState<T extends Object> extends State<FlowChart> {
onAcceptWithDetails: (DragTargetDetails<T> details) { onAcceptWithDetails: (DragTargetDetails<T> details) {
var e = details.data; var e = details.data;
String newID = const Uuid().v4(); String newID = const Uuid().v4();
FlowElement el = FlowElement( FlowElement<T> el = FlowElement<T>(
dashboard: widget.dashboard,
id: newID, id: newID,
element: e,
position: details.offset, position: details.offset,
size: const Size(100, 100), size: const Size(100, 100),
text: '${widget.dashboard.elements.length}', text: '${widget.dashboard.elements.length}',
@ -497,16 +442,70 @@ class FlowChartState<T extends Object> extends State<FlowChart> {
}, },
))] ))]
), ),
widget.dashboard.isMenu ? Positioned(top: 50, child: Container( widget.dashboard.isMenu ? Positioned(top: 50, child: FlowChartLeftMenu<T>(
height: widget.height - 50, key: widget.dashboard.selectedLeftMenuKey,
constraints: BoxConstraints(minWidth: widget.itemWidth), dashboard: widget.dashboard,
width: widget.dashboard.isMenu ? widget.innerMenuWidth : 0, categories: widget.categories,
color: Colors.grey.shade300, height: widget.height,
child: SingleChildScrollView( child: Column( children: menuItems ) ) innerMenuWidth: widget.innerMenuWidth,
)) : Container(), itemWidth: widget.itemWidth,
menuExtension: widget.menuExtension,
draggableItemBuilder: widget.draggableItemBuilder as List<T> Function(String cat),
getDraggable: getDraggable,
) )
: Container(),
widget.dashboard.isInfo ? Positioned(top: 50, right: 0, child:
FlowChartSelectedMenu(
key: widget.dashboard.selectedMenuKey,
dashboard: widget.dashboard,
height: MediaQuery.of(context).size.height - 100
)
) : Container()
]) ])
)); ));
} }
List<Draggable<T>> getDraggable(List<T> items) {
List<Draggable<T>> res = [];
double realSize = widget.itemWidth * widget.zoom;
for (var e in items) {
GlobalKey<HoverMenuState> hoverKey = GlobalKey<HoverMenuState>();
res.add(Draggable<T>(
// Data is the value this Draggable stores.
data: e,
onDragStarted: () => hoverKey.currentState?.hideSubMenu(),
onDragEnd: (d) => node.requestFocus(),
childWhenDragging: Opacity(opacity: .5,
child: Padding( padding: const EdgeInsets.all(10),
child: Container( height: realSize - 20, child: widget.itemWidget(e) ))),
feedback: Container( height: realSize, child: widget.itemWidget(e) ),
child: InkWell( mouseCursor: SystemMouseCursors.grab, child: Padding( padding: const EdgeInsets.all(10),
child: widget.itemWidgetTooltip != null ? HoverMenu( key: hoverKey, width: 400, title: Container(
height: realSize - 20, child: widget.itemWidget(e) ),
items: [
Container(child: widget.itemWidgetTooltip!(e)),
]
) : Container(
height: realSize - 20, child: widget.itemWidget(e)
)
) )));
}
if (!widget.dashboard.isOpened && widget.onDashboardAlertOpened != null ) {
Future.delayed(Duration(milliseconds: 100), () {
showDialog(
barrierDismissible: false,
context: context, builder: (context) {
return AlertDialog(
titlePadding: EdgeInsets.zero,
insetPadding: EdgeInsets.zero,
backgroundColor: Colors.white,
shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(0)),
title: widget.onDashboardAlertOpened!(context, widget.dashboard));
}); });
}
return res;
}
} }
/// Widget to draw interactive connection when the user tap on handlers /// Widget to draw interactive connection when the user tap on handlers
@ -553,8 +552,7 @@ class _DrawingArrowWidgetState extends State<DrawingArrowWidget> {
} }
} }
class ChartWidget extends StatefulWidget { class ChartWidget<T extends FlowData> extends StatefulWidget {
ChartWidget ({ Key? key, ChartWidget ({ Key? key,
required this.flowChart, required this.flowChart,
this.onElementPressed, this.onElementPressed,
@ -667,9 +665,9 @@ class ChartWidget extends StatefulWidget {
final Dashboard dashboard; final Dashboard dashboard;
@override ChartWidgetState createState() => ChartWidgetState(); @override ChartWidgetState createState() => ChartWidgetState<T>();
} }
class ChartWidgetState extends State<ChartWidget> { class ChartWidgetState<T extends FlowData> extends State<ChartWidget> {
bool hoverImportant = false; bool hoverImportant = false;
final segmentedTension = ValueNotifier<double>(1); final segmentedTension = ValueNotifier<double>(1);
@ -710,8 +708,7 @@ class ChartWidgetState extends State<ChartWidget> {
var secondaryTapDownPos = Offset.zero; var secondaryTapDownPos = Offset.zero;
for (int i = 0; i < widget.dashboard.elements.length; i++) for (int i = 0; i < widget.dashboard.elements.length; i++)
widget.dashboard.elements[i].next.removeWhere((element) => widget.dashboard.elements[i].next.removeWhere((element) =>
widget.dashboard.findElementIndexById(element.destElementId) < 0 widget.dashboard.findElementIndexById(element.destElementId) < 0);
);
return Stack( children: [ return Stack( children: [
Positioned.fill( Positioned.fill(
child: GestureDetector( child: GestureDetector(
@ -801,7 +798,7 @@ class ChartWidgetState extends State<ChartWidget> {
), ),
// Draw elements // Draw elements
for (int i = 0; i < widget.dashboard.elements.length; i++) for (int i = 0; i < widget.dashboard.elements.length; i++)
ElementWidget( ElementWidget<T>(
key: UniqueKey(), key: UniqueKey(),
dashboard: widget.dashboard, dashboard: widget.dashboard,
element: widget.dashboard.elements.elementAt(i), element: widget.dashboard.elements.elementAt(i),
@ -904,10 +901,6 @@ class ChartWidgetState extends State<ChartWidget> {
dashboard: widget.dashboard, dashboard: widget.dashboard,
width: MediaQuery.of(context).size.width) width: MediaQuery.of(context).size.width)
), ),
widget.dashboard.isInfo ? Positioned(top: 50, right: 0, child:
FlowChartSelectedMenu(key: widget.dashboard.selectedMenuKey, chart: this,
dashboard: widget.dashboard, height: MediaQuery.of(context).size.height - 100)
) : Container()
], ],
); );
} }

View File

@ -0,0 +1,107 @@
import 'package:flutter/material.dart';
import 'package:flutter_flow_chart/flutter_flow_chart.dart';
class FlowChartLeftMenu<T extends FlowData> extends StatefulWidget {
Dashboard dashboard;
List<String> categories;
double height;
double itemWidth;
double innerMenuWidth;
Widget Function()? menuExtension;
TextEditingController ctrl = TextEditingController();
final List<T> Function(String cat) draggableItemBuilder;
List<Draggable<T>> Function(List<T> items) getDraggable;
FlowChartLeftMenu ({ super.key, required this.categories, required this.dashboard,
this.height = 100,
this.innerMenuWidth = 100,
this.itemWidth = 100,
this.menuExtension,
required this.getDraggable,
required this.draggableItemBuilder
});
@override FlowChartLeftMenuState createState() => FlowChartLeftMenuState();
}
class FlowChartLeftMenuState<T extends FlowData> extends State<FlowChartLeftMenu> {
@override Widget build(BuildContext context) {
List<Widget> menuItems = [];
for (var cat in widget.categories) {
if (widget.draggableItemBuilder(cat).isEmpty) continue;
var items = widget.draggableItemBuilder(cat).where(
(element) => element.getName().toLowerCase().contains(widget.ctrl.value.text.toLowerCase())).toSet().toList();
menuItems.add(
Container( width: widget.dashboard.isMenu ? widget.innerMenuWidth : 0, margin: const EdgeInsets.only(bottom: 0.3),
decoration: const BoxDecoration(border: Border(bottom: BorderSide(color: Colors.grey, width: .5))),
child: Stack( children: [
widget.dashboard.isMenu && widget.innerMenuWidth < 200 ? Wrap( alignment: WrapAlignment.start,
children: widget.getDraggable(items))
: ExpansionTile(
shape: const ContinuousRectangleBorder(side: BorderSide(color: Colors.transparent)),
initiallyExpanded: true,
title: SizedBox(
child : Row( children: [
Padding(padding: const EdgeInsets.only(right: 10),
child: Icon(cat.toUpperCase().contains("DATA") ? Icons.grid_on : Icons.bookmark, color: Colors.grey)),
Flexible(
child: Padding(
padding: const EdgeInsets.only(right: 5),
child: Text(cat.toUpperCase(), overflow: TextOverflow.ellipsis,
style: const TextStyle(color: Colors.black, fontSize: 11, fontWeight: FontWeight.w500))))
])
),
iconColor: Colors.white,
collapsedIconColor: Colors.white,
children: [
Container( width: widget.dashboard.isMenu ? widget.innerMenuWidth : 0, color: Colors.white,
child : Wrap( alignment: WrapAlignment.center,
children: widget.getDraggable(items))
)],
)
]
))
);
}
return Container(
height: widget.height - 50,
color: Colors.grey.shade300,
child: Stack( children: [
Container(
width: widget.innerMenuWidth,
height: 50,
decoration: const BoxDecoration(border: Border(left: BorderSide(color: Colors.white))),
child: TextFormField(
style: const TextStyle(color: Colors.black, fontSize: 15),
cursorColor: const Color.fromARGB(38, 166, 154, 1),
controller: widget.ctrl,
onChanged: (value) { setState(() { }); },
decoration: InputDecoration(
hintText: "search item...",
fillColor: Colors.white,
filled: true,
contentPadding: const EdgeInsets.only(left: 30, right: 30, top: 5, bottom: 5),
hintStyle: TextStyle(
color: Colors.grey,
fontSize: 15,
fontWeight: FontWeight.w400
),
border: InputBorder.none
)
)
),
Container(
margin: EdgeInsets.only(top: 50),
height: widget.height - 150,
constraints: BoxConstraints(minWidth: widget.itemWidth),
width: widget.dashboard.isMenu ? widget.innerMenuWidth : 0,
color: Colors.grey.shade300,
child: SingleChildScrollView( child: Column( children: [
...menuItems
]) )
),
Positioned( bottom: 0, height: 50,
child: widget.menuExtension != null ? widget.menuExtension!() : Container(),),
])
);
}
}

View File

@ -35,6 +35,7 @@ class FlowChartMenuState extends State<FlowChartMenu> {
child: InkWell( mouseCursor: SystemMouseCursors.click, child: InkWell( mouseCursor: SystemMouseCursors.click,
onTap: () { onTap: () {
widget.dashboard.defaultName = "graph_${DateTime.now().toString().replaceAll(" ", "_").substring(0, DateTime.now().toString().length - 7)}"; widget.dashboard.defaultName = "graph_${DateTime.now().toString().replaceAll(" ", "_").substring(0, DateTime.now().toString().length - 7)}";
widget.dashboard.isOpened = true;
showDialog( showDialog(
barrierDismissible: false, barrierDismissible: false,
context: context, builder: (context) { context: context, builder: (context) {

View File

@ -6,16 +6,78 @@ import 'package:flutter_colorpicker/flutter_colorpicker.dart';
import 'package:number_text_input_formatter/number_text_input_formatter.dart'; import 'package:number_text_input_formatter/number_text_input_formatter.dart';
class FlowChartSelectedMenu extends StatefulWidget { class FlowChartSelectedMenu extends StatefulWidget {
ChartWidgetState chart;
Dashboard dashboard; Dashboard dashboard;
double height = 100; double height = 100;
bool isDashboardInfo = true;
FlowChartSelectedMenu ({ super.key, required this.chart, required this.dashboard, this.height = 100 }); FlowChartSelectedMenu ({ super.key, required this.dashboard, this.height = 100 });
@override FlowChartSelectedMenuState createState() => FlowChartSelectedMenuState(); @override FlowChartSelectedMenuState createState() => FlowChartSelectedMenuState();
} }
class FlowChartSelectedMenuState extends State<FlowChartSelectedMenu> { class FlowChartSelectedMenuState extends State<FlowChartSelectedMenu> {
@override Widget build(BuildContext context) { @override Widget build(BuildContext context) {
return Container( // SHORTCUT Widget? w;
if (widget.isDashboardInfo && widget.dashboard.elementSelected.length == 1) {
w = Container(
width: 200,
height: widget.height,
color: Colors.grey.shade300,
child: Column( children: [ ...widget.dashboard.infoItemWidget != null ?
widget.dashboard.infoItemWidget!(widget.dashboard.elementSelected.first.element)
: [],
widget.dashboard.arrowsSelected.isNotEmpty || widget.dashboard.elementSelected.isNotEmpty ? Container(
width: 200,
margin: EdgeInsets.only(top: 15),
decoration: BoxDecoration(border: Border(
top: BorderSide(color: Colors.grey, width: 1),
bottom: BorderSide(color: Colors.grey, width: 1))),
child: Column(crossAxisAlignment: CrossAxisAlignment.center, children: [
Tooltip( message: "remove",
child: InkWell( mouseCursor: SystemMouseCursors.click,
onTap: () {
widget.dashboard.arrows.removeWhere((element) {
if (element.isSelected && element.elementIndex != null && element.connIndex != null) {
widget.dashboard.elements[element.elementIndex!].next.removeAt(element.connIndex!);
}
return element.isSelected;
});
widget.dashboard.elements.removeWhere((element) => element.isSelected);
Future.delayed(Duration(milliseconds: 100), () {
widget.dashboard.chartKey.currentState?.setState(() { });
});
}, child: Container( margin: EdgeInsets.all(10),
decoration: BoxDecoration(borderRadius: BorderRadius.circular(5), border: Border.all(color: Colors.black, width: 1)),
width: 140, height: 30,
child: Icon(Icons.delete_outline, color: Colors.black),
))
),
Tooltip( message: "copy",
child: InkWell( mouseCursor: SystemMouseCursors.click,
onTap: () {
for (var sel in widget.dashboard.elementSelected) {
widget.dashboard.elements.add(FlowElement.fromMap(widget.dashboard, sel.toMap()));
widget.dashboard.elements.last.position += Offset(50, 50);
}
Future.delayed(Duration(milliseconds: 100), () {
widget.dashboard.chartKey.currentState?.setState(() { });
});
}, child: Container( margin: EdgeInsets.all(10),
decoration: BoxDecoration(borderRadius: BorderRadius.circular(5), border: Border.all(color: Colors.black, width: 1)),
width: 140, height: 30,
child: Icon(Icons.copy, color: Colors.black),
))
),
])
) : Container()
])
);
} else if (widget.isDashboardInfo && widget.dashboard.infoWidget != null) {
w = Container(
width: 200,
height: widget.height,
color: Colors.grey.shade300,
child: Column( children: widget.dashboard.infoWidget != null ? widget.dashboard.infoWidget!() : [])
);
} else {
w = Container( // SHORTCUT
width: 200, width: 200,
height: widget.height, height: widget.height,
color: Colors.grey.shade300, color: Colors.grey.shade300,
@ -292,6 +354,9 @@ class FlowChartSelectedMenuState extends State<FlowChartSelectedMenu> {
))) )))
]), ]),
])), ])),
widget.dashboard.elementSelected.isNotEmpty && widget.dashboard.elementSelected.length == 1 ? Container(
// TODO : TEST OMG
) : Container(),
widget.dashboard.elementSelected.isNotEmpty ? Container() : Container( padding: EdgeInsets.only(left: 10, right: 10, bottom: 20, top: 15), widget.dashboard.elementSelected.isNotEmpty ? Container() : Container( padding: EdgeInsets.only(left: 10, right: 10, bottom: 20, top: 15),
decoration: BoxDecoration(border: Border(bottom: BorderSide(color: Colors.grey, width: 1))), decoration: BoxDecoration(border: Border(bottom: BorderSide(color: Colors.grey, width: 1))),
child: Column( children: [ child: Column( children: [
@ -477,7 +542,7 @@ class FlowChartSelectedMenuState extends State<FlowChartSelectedMenu> {
child: InkWell( mouseCursor: SystemMouseCursors.click, child: InkWell( mouseCursor: SystemMouseCursors.click,
onTap: () { onTap: () {
for (var sel in widget.dashboard.elementSelected) { for (var sel in widget.dashboard.elementSelected) {
widget.dashboard.elements.add(FlowElement.fromMap(sel.toMap())); widget.dashboard.elements.add(FlowElement.fromMap(widget.dashboard, sel.toMap()));
widget.dashboard.elements.last.position += Offset(50, 50); widget.dashboard.elements.last.position += Offset(50, 50);
} }
Future.delayed(Duration(milliseconds: 100), () { Future.delayed(Duration(milliseconds: 100), () {
@ -495,6 +560,35 @@ class FlowChartSelectedMenuState extends State<FlowChartSelectedMenu> {
]) ])
); );
} }
return Column( children: [
Container( // SHORTCUT
width: 200,
height: 50,
decoration: BoxDecoration(color: Colors.grey.shade300, border: Border(bottom: BorderSide(color: Colors.grey, width: 1))),
child: Row( children: [
Tooltip(
message: "dashboard information",
child: InkWell( onTap: () => setState(() {widget.isDashboardInfo = true; }),
mouseCursor: SystemMouseCursors.click,
child: Container( alignment: Alignment.center,
padding: EdgeInsets.symmetric(vertical: 10),
color: widget.isDashboardInfo ? Colors.grey : Colors.grey.shade300,
width: 100, child: Icon(Icons.info, color: Colors.white))
)
),
Tooltip(
message: "element style",
child: InkWell( onTap: () => setState(() {widget.isDashboardInfo = false; }),
mouseCursor: SystemMouseCursors.click,
child: Container( alignment: Alignment.center,
padding: EdgeInsets.symmetric(vertical: 10),
color: !widget.isDashboardInfo ? Colors.grey : Colors.grey.shade300,
width: 100, child: Icon(Icons.format_paint, color: Colors.white)),
))
])),
w
]);
}
} }
class MySeparator extends StatelessWidget { class MySeparator extends StatelessWidget {

View File

@ -3,6 +3,8 @@ import 'dart:convert';
import 'dart:ui' as ui; import 'dart:ui' as ui;
import 'dart:math' as math; import 'dart:math' as math;
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter_flow_chart/flutter_flow_chart.dart'; import 'package:flutter_flow_chart/flutter_flow_chart.dart';
import 'package:flutter_flow_chart/src/ui/segment_handler.dart'; import 'package:flutter_flow_chart/src/ui/segment_handler.dart';
@ -349,6 +351,7 @@ class DrawArrowState extends State<DrawArrow> {
if ( widget.flow.widget.dashboard.arrows.where( if ( widget.flow.widget.dashboard.arrows.where(
(element) => element.fromID == "${widget.srcElement.id}_${widget.index}").isEmpty) { (element) => element.fromID == "${widget.srcElement.id}_${widget.index}").isEmpty) {
widget.flow.widget.dashboard.arrows.add(painter); widget.flow.widget.dashboard.arrows.add(painter);
widget.flow.widget.dashboard.save!(widget.flow.widget.dashboard.id);
} else { } else {
var i = widget.flow.widget.dashboard.arrows.indexWhere( var i = widget.flow.widget.dashboard.arrows.indexWhere(
(element) => element.fromID == "${widget.srcElement.id}_${widget.index}"); (element) => element.fromID == "${widget.srcElement.id}_${widget.index}");
@ -416,24 +419,24 @@ class ArrowInfoWidgetState extends State<ArrowInfoWidget> {
/// [ArrowParams.startArrowPosition] and /// [ArrowParams.startArrowPosition] and
/// [ArrowParams.endArrowPosition] alignment. /// [ArrowParams.endArrowPosition] alignment.
class ArrowPainter extends CustomPainter { class ArrowPainter extends CustomPainter {
final String fromID; String fromID;
final String toID; String toID;
bool isSelected = false; bool isSelected = false;
/// ///
ArrowPainter({ ArrowPainter({
this.elementIndex, this.elementIndex,
this.connIndex, this.connIndex,
required this.toID, this.toID = "",
required this.fromID, this.fromID = "",
this.isSelected = false, this.isSelected = false,
required this.params, required this.params,
required this.from, this.from = Offset.zero,
required this.to, this.to = Offset.zero,
List<Pivot>? pivots, List<Pivot>? pivots,
}) : pivots = pivots ?? []; }) : pivots = pivots ?? [];
/// ///
final ArrowParams params; ArrowParams params;
/// ///
Offset from; Offset from;
int? elementIndex; int? elementIndex;
@ -457,6 +460,15 @@ class ArrowPainter extends CustomPainter {
final arrowSize = 15; final arrowSize = 15;
final arrowAngle= 25 * math.pi / 180; final arrowAngle= 25 * math.pi / 180;
ArrowPainter deserialize(Map<String, dynamic> map) {
params = ArrowParams.fromMap(map['params']);
fromID = map['from']['id'];
toID = map['to']['id'];
from = Offset(map['from']['x'], map['from']['y']);
to = Offset(map['to']['x'], map['to']['y']);
return this;
}
Map<String, dynamic> serialize() { Map<String, dynamic> serialize() {
Map<String, dynamic> graphElement = {}; Map<String, dynamic> graphElement = {};
graphElement['from'] = { "id" : fromID.split("_")[0], "x" : from.dx, "y" : from.dy }; graphElement['from'] = { "id" : fromID.split("_")[0], "x" : from.dx, "y" : from.dy };

View File

@ -12,7 +12,7 @@ import 'package:flutter_flow_chart/src/ui/resize_widget.dart';
import 'package:flutter_flow_chart/src/objects/any_widget.dart'; import 'package:flutter_flow_chart/src/objects/any_widget.dart';
/// Widget that use [element] properties to display it on the dashboard scene /// Widget that use [element] properties to display it on the dashboard scene
class ElementWidget extends StatefulWidget { class ElementWidget<T extends FlowData> extends StatefulWidget {
/// ///
ElementWidget({ ElementWidget({
required this.dashboard, required this.dashboard,
@ -84,10 +84,10 @@ class ElementWidget extends StatefulWidget {
)? onHandlerSecondaryLongTapped; )? onHandlerSecondaryLongTapped;
@override @override
State<ElementWidget> createState() => ElementWidgetState(); State<ElementWidget> createState() => ElementWidgetState<T>();
} }
class ElementWidgetState extends State<ElementWidget> { class ElementWidgetState<T extends FlowData> extends State<ElementWidget> {
// local widget touch position when start dragging // local widget touch position when start dragging
Offset delta = Offset.zero; Offset delta = Offset.zero;
@ -219,6 +219,7 @@ class ElementWidgetState extends State<ElementWidget> {
sel.changePosition(sel.position + diff); sel.changePosition(sel.position + diff);
} }
} }
widget.dashboard.save!(widget.dashboard.id);
}, },
), ),
), ),
@ -228,7 +229,8 @@ class ElementWidgetState extends State<ElementWidget> {
element: widget.element, element: widget.element,
dashboard: widget.dashboard, dashboard: widget.dashboard,
handlerColor: widget.isHovered ? Color.fromRGBO(38, 166, 154, 1) : Colors.transparent, handlerColor: widget.isHovered ? Color.fromRGBO(38, 166, 154, 1) : Colors.transparent,
child: w ); child: w
);
return Transform.translate( return Transform.translate(
offset: widget.element.position, offset: widget.element.position,
transformHitTests: true, transformHitTests: true,
@ -245,7 +247,9 @@ class ElementWidgetState extends State<ElementWidget> {
widget.dashboard.removeElement(widget.element); widget.dashboard.removeElement(widget.element);
}, icon: Icon(Icons.delete_outline)), }, icon: Icon(Icons.delete_outline)),
IconButton(tooltip: "copy element", onPressed: () { IconButton(tooltip: "copy element", onPressed: () {
FlowElement newElement = FlowElement( FlowElement<T> newElement = FlowElement<T>(
element: widget.element.element as T?,
dashboard: widget.dashboard,
kind: widget.element.kind, kind: widget.element.kind,
position: widget.element.position + Offset(widget.element.size.width, widget.element.size.height), position: widget.element.position + Offset(widget.element.size.width, widget.element.size.height),
size: widget.element.size, size: widget.element.size,

View File

@ -81,6 +81,14 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "3.1.1" version: "3.1.1"
cron:
dependency: "direct main"
description:
name: cron
sha256: e1b379dec3d7967c8e521a92832a6ac97a11ea4046cbc3e584193a470e3ad8f5
url: "https://pub.dev"
source: hosted
version: "0.6.1"
crypto: crypto:
dependency: transitive dependency: transitive
description: description:
@ -113,6 +121,14 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.0.1" version: "1.0.1"
datetime_picker_formfield:
dependency: "direct main"
description:
name: datetime_picker_formfield
sha256: "6d0412c98cc5da18a5dca1f81f82a834fbacdb5d249fd6d9bed42d912339720e"
url: "https://pub.dev"
source: hosted
version: "2.0.1"
desktop_window: desktop_window:
dependency: "direct main" dependency: "direct main"
description: description:
@ -206,6 +222,14 @@ packages:
description: flutter description: flutter
source: sdk source: sdk
version: "0.0.0" version: "0.0.0"
flutter_advanced_switch:
dependency: "direct main"
description:
name: flutter_advanced_switch
sha256: e1147161a3dd9b708a71c65e76174d4d1a0a5908a571b8b38b65c79b142c52a0
url: "https://pub.dev"
source: hosted
version: "3.1.0"
flutter_box_transform: flutter_box_transform:
dependency: "direct main" dependency: "direct main"
description: description:
@ -222,6 +246,14 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.1.0" version: "1.1.0"
flutter_event_calendar:
dependency: "direct main"
description:
name: flutter_event_calendar
sha256: f5b6f22ae01c24a1fc3f6432d3080130bb40efc976e53941b5f6422b6a4f9d64
url: "https://pub.dev"
source: hosted
version: "1.0.0"
flutter_flow_chart: flutter_flow_chart:
dependency: "direct main" dependency: "direct main"
description: description:
@ -312,7 +344,7 @@ packages:
source: hosted source: hosted
version: "2.4.2" version: "2.4.2"
intl: intl:
dependency: transitive dependency: "direct main"
description: description:
name: intl name: intl
sha256: d6f56758b7d3014a48af9701c085700aac781a92a87a62b1333b46d8879661cf sha256: d6f56758b7d3014a48af9701c085700aac781a92a87a62b1333b46d8879661cf
@ -335,6 +367,22 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.7.0" version: "0.7.0"
json_string:
dependency: "direct main"
description:
name: json_string
sha256: "1350ec63197d3df7e7141092085b2b2c93ff18fb8d4cc8cede3ab7ce39a5c925"
url: "https://pub.dev"
source: hosted
version: "3.0.1"
json_util:
dependency: transitive
description:
name: json_util
sha256: "67d9af645042cb6e4f3acf100fe5eda769e92db8ef118bc3783e3571e4e3d22b"
url: "https://pub.dev"
source: hosted
version: "2.0.0"
latlong2: latlong2:
dependency: "direct main" dependency: "direct main"
description: description:
@ -551,6 +599,22 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.1.0" version: "2.1.0"
scoped_model:
dependency: transitive
description:
name: scoped_model
sha256: "8dacc77cb5de78d5e159d54cab883847491a73dfaa3d28c52f4ec8b0be32645b"
url: "https://pub.dev"
source: hosted
version: "2.0.0"
shamsi_date:
dependency: transitive
description:
name: shamsi_date
sha256: "5df195a0b7794b7d4a8dc9321244400147896def157b7530c5b8a2f9cfc6a7a4"
url: "https://pub.dev"
source: hosted
version: "0.15.0"
shared_preferences: shared_preferences:
dependency: "direct main" dependency: "direct main"
description: description:
@ -692,6 +756,30 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.8.17" version: "0.8.17"
syncfusion_flutter_calendar:
dependency: "direct main"
description:
name: syncfusion_flutter_calendar
sha256: "1daa6077a8fb388b692d5d050d58eaa4c01ef92f064a882eb330ef47dc51cf2e"
url: "https://pub.dev"
source: hosted
version: "26.2.7"
syncfusion_flutter_core:
dependency: transitive
description:
name: syncfusion_flutter_core
sha256: fd4d2cdbf8d0d1e3441817cb8a03f896566fad5187788957e78492fe16800388
url: "https://pub.dev"
source: hosted
version: "26.2.7"
syncfusion_flutter_datepicker:
dependency: transitive
description:
name: syncfusion_flutter_datepicker
sha256: e541929ccf95a9188ef9f32dfca544f29b3fc222d4dc5da9cb1112305021a615
url: "https://pub.dev"
source: hosted
version: "26.2.7"
table_calendar: table_calendar:
dependency: "direct main" dependency: "direct main"
description: description:
@ -716,6 +804,14 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.6.1" version: "0.6.1"
timezone:
dependency: transitive
description:
name: timezone
sha256: a6ccda4a69a442098b602c44e61a1e2b4bf6f5516e875bbf0f427d5df14745d5
url: "https://pub.dev"
source: hosted
version: "0.9.3"
typed_data: typed_data:
dependency: transitive dependency: transitive
description: description:
@ -788,6 +884,38 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.5.1" version: "0.5.1"
webview_flutter:
dependency: "direct main"
description:
name: webview_flutter
sha256: "6869c8786d179f929144b4a1f86e09ac0eddfe475984951ea6c634774c16b522"
url: "https://pub.dev"
source: hosted
version: "4.8.0"
webview_flutter_android:
dependency: "direct main"
description:
name: webview_flutter_android
sha256: "0d21cfc3bfdd2e30ab2ebeced66512b91134b39e72e97b43db2d47dda1c4e53a"
url: "https://pub.dev"
source: hosted
version: "3.16.3"
webview_flutter_platform_interface:
dependency: transitive
description:
name: webview_flutter_platform_interface
sha256: d937581d6e558908d7ae3dc1989c4f87b786891ab47bb9df7de548a151779d8d
url: "https://pub.dev"
source: hosted
version: "2.10.0"
webview_flutter_wkwebview:
dependency: "direct main"
description:
name: webview_flutter_wkwebview
sha256: "9c62cc46fa4f2d41e10ab81014c1de470a6c6f26051a2de32111b2ee55287feb"
url: "https://pub.dev"
source: hosted
version: "3.14.0"
win32: win32:
dependency: transitive dependency: transitive
description: description:

View File

@ -61,6 +61,16 @@ dependencies:
number_text_input_formatter: ^1.0.0+8 number_text_input_formatter: ^1.0.0+8
flutter_colorpicker: ^1.1.0 flutter_colorpicker: ^1.1.0
hover_menu: ^1.1.1 hover_menu: ^1.1.1
datetime_picker_formfield: ^2.0.1
intl: ^0.19.0
flutter_advanced_switch: ^3.1.0
cron: ^0.6.1
flutter_event_calendar: ^1.0.0
syncfusion_flutter_calendar: ^26.2.7
webview_flutter: ^4.8.0
webview_flutter_android: ^3.16.3
webview_flutter_wkwebview: ^3.14.0
json_string: ^3.0.1
dev_dependencies: dev_dependencies:
flutter_test: flutter_test: